Страница 1 из 1

[?] RC5+mega БЕЗ внешнего прерывания?

Добавлено: Пн фев 18, 2013 08:18:10
Johnson
Здравствуйте, премногоуважаемые коты!

Без предисловий к делу: нужна Ваша помощь.

Дано: от одного самого умного инженера досталась плата на меге с ик-приемником (TSOP-31236) и кучей обвеса.
Сей премудрый инженер умудрился повесить приемник НЕ на внешнее прерывание, а на ногу PB.0
Программист написал под это дело программу, работает. Пришло время править код - у программиста аврал, не до того. Запрягли самого близко знакомого с мегами :)
Плата находится в массовом производстве, исправлять трассировку - нельзя.

Начал практиччески с нуля вспоминать си и меги в частности... Сам работаю для удовольствия в джаве.
Для лучшего понимания начал писать программу с нуля, а не перепиливать имеющуюся...

Итак...
Частота процессора 11059200 гц. Соответствующая константа FCLK наличествует в заголовке основого файла, и в проекте указана (CodeVision).

Есть старый код обработки данных:

Код: Выделить всё

//#define DivOvfTC2 37 // Константа выверена для FCLK=11059200 уточнена для FCLK=16MHz
//#define DivOvfTC2 (FCLK/296296) // 37 для FCLK=11059200
#define DivOvfTC2   (FCLK/291031) // 38 для FCLK=11059200

unsigned char cntOvfTC2=0,rc5command;
unsigned char RC5cnt14=0,RC5prev1=0x1,RC5prev2=0x1;
unsigned int RC5code=0xFFFF,RC5temp=0xFFFF,RC5delay=0;

// Timer2 overflow interrupt service routine
interrupt [TIM2_OVF] void timer2_ovf_isr(void){
   unsigned char RC5tek;
   cntOvfTC2++;
   if (cntOvfTC2>=DivOvfTC2){
      // Константа DivOvfTC2 выверена для кварца на 11059200 МГц... (определена в RC5_T2.h)
      RC5delay++;
      if (RC5delay>562){
         RC5tek=PINRC5 & (1<<DD_RC5);
         if ((RC5tek==0) || (RC5prev1==0) || (RC5prev2==0)){
            RC5cnt14++;
            if ((RC5cnt14 & 1)==0){ // Есть очередной разряд
               RC5temp<<=1;  // Накопление результата
               if (RC5prev1==0) RC5temp|=1;
            }
            if ((RC5cnt14==28) && ((RC5temp & 0xF0)!=0xF0)){
               RC5code=RC5temp;
               RC5delay=0;
               rc5command=RC5code&0x3F;
            }
            RC5prev2=RC5prev1; RC5prev1=RC5tek;
         }else{
            RC5cnt14=0; RC5temp=0x00;
         }
      }
      cntOvfTC2=0;
   }
}


Далее в основном цикле программы опрашиваются переменные и выводится полученная команда на экран:

Код: Выделить всё

        if (RC5code != 0xFFFF){
            clearBuffer();
            flushBuffer();
            delay_ms(100);
               
            putNumberIntoBuffer(0,rc5command,4);
       
            RC5code=0xFFFF; // Нажатие кнопки ПДУ отработано...
            flushBuffer();   
        }


Но, работает это дело очень криво: часть кнопок не работает. Если сработало - выдает не всегда одинаковый код на дисплей.

Есть ли у кого-нибудь опыт "разборок" с RC5 без внешнего прерывания, чисто по таймерам?
Буду очень благодарен за помощь!

Re: [?] RC5+mega БЕЗ внешнего прерывания?

Добавлено: Пн фев 18, 2013 09:29:16
zero648
Сей премудрый инженер умудрился повесить приемник НЕ на внешнее прерывание, а на ногу PB.0

Какой камень, может на PB0 имеется всетаки какое прерывание? Обязательно INTn использовать чтоли, можно любой вектор использовать, а событие обрабатывать уже как угодно.

Re: [?] RC5+mega БЕЗ внешнего прерывания?

Добавлено: Пн фев 18, 2013 09:34:54
shads
Сей премудрый инженер умудрился повесить приемник НЕ на внешнее прерывание, а на ногу PB.0
Я тоже делал декодирование не по внешнему прерыванию, все отлично работает (мне даже больше нравится такой вариант чем по внешнему прерыванию), просто настраиваеш таймер счетчик на частоту в 10 раз больше чем частота RC5 и в каждом прерывании анализируеш состояние линии.....

Re: [?] RC5+mega БЕЗ внешнего прерывания?

Добавлено: Пн фев 18, 2013 11:07:50
Johnson
Камень AtMega8, там нет вектора...

По поводу частоты - можете пример дать рассчета или Вашего кода? Частоту нашего камня я писал в первом посте...

Re: [?] RC5+mega БЕЗ внешнего прерывания?

Добавлено: Пн фев 18, 2013 11:15:22
polyname
программній прием одним таймером, частота опроса желательно >5кГц:
http://we.easyelectronics.ru/reptile/bi ... ik-du.html

Re: [?] RC5+mega БЕЗ внешнего прерывания?

Добавлено: Пн фев 18, 2013 11:23:37
blackx
Johnson писал(а):Камень AtMega8, там нет вектора....

Почему? В меге 8 есть поддержка внешнего прерывания (ноги PD2 и PD3).

Если вы имели ввиду конкретно пин PB0, то по нему тоже можно прерывание сгенерить. Его альтернативная функция - ICP1 - Input Capture Pin 1.

Atmel datashit писал(а):When a change of the logic level (an event) occurs on the Input Capture Pin (ICP1), alternatively
on the Analog Comparator Output (ACO), and this change confirms to the setting of the edge
detector, a capture will be triggered. When a capture is triggered, the 16-bit value of the counter
(TCNT1) is written to the Input Capture Register (ICR1). The Input Capture Flag (ICF1) is set at
the same system clock as the TCNT1 value is copied into ICR1 Register. If enabled (TICIE1 =
1), the Input Capture Flag generates an Input Capture interrupt. The ICF1 Flag is automatically
cleared when the interrupt is executed. Alternatively the ICF1 Flag can be cleared by software
by writing a logical one to its I/O bit location.


При изменении уровня на ноге происходит копирование значения TCNT1 в регистр ICR1, одновмеренно устанавливается флаг ICF1, и если TICIE1 = 1 то генерируется прерывание.

В сообщении ниже также уже ответили, собственно :)

Re: [?] RC5+mega БЕЗ внешнего прерывания?

Добавлено: Пн фев 18, 2013 11:29:29
zero648
Johnson писал(а):Камень AtMega8, там нет вектора...

Как нет, а ICP1 чем не вектор, возможно через него все и работает.

Re: [?] RC5+mega БЕЗ внешнего прерывания?

Добавлено: Пн фев 18, 2013 12:57:08
Johnson
Спасибо за ответы!
Порылся в коде - нет, этот вектор не используется.

Всё, что связано с ремоутом - только в прерывании таймера.
Предполагаю, что проблема в таймингах, попробую методом тыка "поймать" нужный.

Хотя тут немного не понимаю, таймер настроил в точности как в существующем проекте, код использовал тот же, а результат разный...

Про прерывание ICP1 - можете пример показать, как настроить его и использовать для этих целей?


PS: Про отсутствие векторов - имел в виду именно эту ногу. Про вектор ICP1 не слышал раньше...

polyname, спасибо большое за код! Буду разбираться и кастрировать его под конкретный пульт! :)

Re: [?] RC5+mega БЕЗ внешнего прерывания?

Добавлено: Пн фев 18, 2013 13:24:10
zero648
На асме настраивается так:

cbi DDRB, 0
.......
ldi r16, (1<<TICIE1)
out TIMSK, r16 ; Включаем вектор TIMER1 CAPT
in r16, TIFR
out TIFR, r16
sei
.........

MAIN_loop:
rjmp MAIN_loop ; Go again

TMR1_ICP:
.....
reti


P.S. еще подтяжку забыл: sbi PORTB,0

Re: [?] RC5+mega БЕЗ внешнего прерывания?

Добавлено: Чт фев 21, 2013 11:08:22
Johnson
Блин, весь мозг себе сломал с этим капчером.

Есть у кого-нибудь соображения, как с его помощью читать команду с RC5?

Re: [?] RC5+mega БЕЗ внешнего прерывания?

Добавлено: Чт фев 21, 2013 11:47:50
shads
Вечером соображу, поделюсь.....

Re: [?] RC5+mega БЕЗ внешнего прерывания?

Добавлено: Чт фев 21, 2013 12:42:34
Johnson
Вообщем, нашел исходник, слегка переделал его на прерывание ICP1...
Работает даже более, чем идеально: команды посылаются каждые 114мс, и слишком часто обрабатываются нажатия.

Пока решил эту проблему простым таймаутом, но хотелось бы более правильно: обработкой третьего бита команды.

Полностью "переварить" код пока не могу, прощу помощи.

Итак, код, который работает:

Код: Выделить всё

unsigned char rc5command,rc5temp1,rc5temp2;
unsigned int rc5time,rc5data;

#define rc5_max 1400
#define rc5_min 900

void rc5init(){
   TCCR1A = 0;TCCR1B = 1<<CS11|1<<ICNC1;
   TCNT1H = 0;TCNT1L = 0;
   OCR1AH = 0X0B;OCR1AL = 0XB8;
   ICR1H = 0;ICR1L = 0;
   TIFR = 1<<ICF1|1<<OCIE1A;
   TIMSK |= 1<<TICIE1|1<<OCIE1A;
   rc5temp1=0;
    rc5temp2=0;
    rc5data=0;
}

void rc5_recive_bit(void){
   if (rc5temp1 == 0x00){
      TCCR1B |= 1<<ICES1|1<<ICNC1;
      rc5temp1 = 0xff;
      if ((rc5time > rc5_min) && (rc5time < rc5_max)){
         rc5data = (rc5data << 1)& 0xfffe;
         ++rc5temp2;
         goto rbok;
      }
      if ((rc5time > (rc5_min*2)) && (rc5time < (rc5_max*2))){
         rc5data = (rc5data << 2)& 0xfffc;
         rc5temp2+=2;
         goto rbok;
      }
   }else{
      TCCR1B = (1<<CS11)|(1<<ICNC1);
      rc5temp1 = 0;
      if ((rc5time > rc5_min) && (rc5time < rc5_max)){
         rc5data = (rc5data << 1) | 0x0001;
         ++rc5temp2;
         if (rc5temp2 == 27){
            ++rc5temp2;
            rc5data = (rc5data << 1)& 0xfffe;
         }
         goto rbok;
      }
      if ((rc5time > (rc5_min*2)) && (rc5time < (rc5_max*2))){
         rc5data = (rc5data << 2) | 0x0003;
         rc5temp2+=2;
         if (rc5temp2 == 27){
            ++rc5temp2;
            rc5data = (rc5data << 1)& 0xfffe;
         }
         goto rbok;
      }
   }
   rc5init();
   return;
   rbok:
   TIFR = 1<<ICF1;
}

interrupt [TIM1_CAPT] void timer1_capt_isr(void){
   unsigned char templ,temph,ttst=0;
   templ= ICR1L;temph= ICR1H;
   rc5time = templ;
   rc5time = rc5time | (temph << 8);
   TCNT1H = 0;TCNT1L = 0;
   ICR1H = 0;ICR1L = 0;
   if (rc5temp2 == 0){
      TCCR1B |= (1 << ICES1)|(1<<ICNC1);
      TIFR = (1 << ICF1);
      rc5temp1 = 0xff;
      ++rc5temp2;
   }else
        rc5_recive_bit();
   
   if (rc5temp2 == 28){
      rc5command = 0;
      while (ttst != 7){
         switch (rc5data & 0x0003){
            case 0x01:   rc5temp2 = 1;break;
            case 0x02:   rc5temp2 = 0;break;
         }
         rc5command |= rc5temp2 << ttst;
         rc5data >>= 2;
         ++ttst;
      }
      rc5init();
   }
}

interrupt [TIM1_COMPA] void timer1_compa_isr(void){
    rc5init();
}


Нужно его подправить так, чтобы значение третьего бита команды сохранялось в отдельную переменную.
Буду очень благодарен за помощь!