проблема с таймером

Обсуждаем контроллеры компании Atmel.
Ответить
Встал на лапы
Аватара пользователя
Сообщения: 123
Зарегистрирован: Вс дек 13, 2009 01:04:42

Сообщение goodspeedmen »

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

if(.....)
 {
   timer_COMPA_ON();
   ........
  PORTB |= (1<<2);
   timer_COMPB_ON();
 }

//======

void timer_COMPA_ON()
 {
  TCNT1 = 0x00;	 
  OCR1A = 0x1194;           // 4500
  TCCR1A = 0b00000000;  // (0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
  TCCR1B = 0b00000101;  // (0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (1<<CS12) | (0<<CS11) | (1<<CS10);
  TIMSK1 = 0b00000010;  // (0<<ICIE1) | (0<<OCIE1B) | (1<<OCIE1A) | (0<<TOIE1); 
 }
 
void timer_COMPB_ON()
 {
  TCNT1=0x00;
  OCR1A=0x1194;                                          //4500
  OCR1B=0x6978;                                          //2700
  TIMSK1 |= (1<<OCIE1B);
 }   
   
ISR(TIMER1_COMPA_vect)
 {
  /*код обслуживания lcd*/
  OCR1A += 0x1194;                                      // dec = 4500;
 }

ISR(TIMER1_COMPB_vect)
 {
  PORTB &= ~(1<<2);                                                                             // инвертировать состояние пин  2 port B ***                                                   
  TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10); //
  TIMSK1=(0<<ICIE1) | (0<<OCIE1B) | (0<<OCIE1A) | (0<<TOIE1);
  nterrupt_off();                                                                               
  triger = 0;                                                                                   
 }

Парни объясните в чем проблема, прерывание ISR(TIMER1_COMPA_vect) примерно раз в 0.4 сек обслуживает lcd. ISR(TIMER1_COMPB_vect) включает порт PORTB2 и выключает его через промежуток времени. Проблема в том что если OCR1A содержит число меньшее чем OCR1B то происходит обнуление TCNT1 и промежуток времени отсчитывается нормально, но если в момент вызова timer_COMPB_ON(); в OCR1A содержит число большее чем OCR1B то на PORTB2 возникает импульс примерно 3 миллисекунды, как я понимаю при вызове сразу происходит вызов прерывания :shock: как так получается вить флаг прерывания еще не установлен :o
Голосовой чат.
Контактная информация:
Реклама
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

Кто за кем идёт не совсем понятно, но полагаю, что нужно ещё дёргать регистр TIFR.
Реклама
Модератор
Аватара пользователя
Сообщения: 19055
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

в "угадайку" будем играть?
1. какой МК?
2. какая тактовая частота?
3. что такое "if(.....)" и когда оно срабатывает?
4. у тебя ISR(TIMER1_COMPB_vect) останавливает таймер. сколько времени проходит до "срабатывания" if(.....) ?
5. у тебя 27000 / 4500 = ровно 6. поэтому флаги обоих прерываний выставляются одновременно. но первым всегда выполняется прерывание по OCR1A.
попробуй OCR1B сделать чуточку побольше, чтобы это прерывание гарантированно произошло позже, чем прерывание по OCR1A.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Встал на лапы
Аватара пользователя
Сообщения: 123
Зарегистрирован: Вс дек 13, 2009 01:04:42

Сообщение goodspeedmen »

mega328.
16 мегагерц.
if операция это условно для понимания как используется код, время может быть разное от секунды до более минуты.
Голосовой чат.
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Друг Кота
Аватара пользователя
Сообщения: 15600
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

А сменить контрольные регистры таймера (приоритет прерываний у АВРки к сожалению НЕ ИЗМЕНЯЕТСЯ)?
Или наворотить разрешение вложенного прерывания?
:roll:
Реклама
Встал на лапы
Аватара пользователя
Сообщения: 123
Зарегистрирован: Вс дек 13, 2009 01:04:42

Сообщение goodspeedmen »

Я не понял вы спрашиваете или отвечаете? Так в том то и дело, что при заходе в timer_COMPB_ON(); происходит обнуление счетного регистра, инициализация регистров сравнения обоих и только после этого происходит разрешение прерывания регистра сравнения OCR1B.
Голосовой чат.
Контактная информация:
Реклама
Друг Кота
Аватара пользователя
Сообщения: 15600
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

МНДЯаа...
Я-то привык САМ режимы задавать, какие захочу - ассемблер однако штука удобная...
Си - потребует или библиотеку досконально изучить или свое написать. В этом плане (СИшные прожки) я пока не советчик...
:(
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

Создайте новый проект только с TIM1, без всяких LCD и др. ненужной периферии. если проблема останется, то выложите весь новый проект сюда.
Встал на лапы
Аватара пользователя
Сообщения: 123
Зарегистрирован: Вс дек 13, 2009 01:04:42

Сообщение goodspeedmen »

[uquote="uk8amk",url="/forum/viewtopic.php?p=3265135#p3265135"]Создайте новый проект только с TIM1, без всяких LCD и др. ненужной периферии. если проблема останется, то выложите весь новый проект сюда.[/uquote]
Попробую нацарапать как будет время :wink:
Голосовой чат.
Контактная информация:
Встал на лапы
Аватара пользователя
Сообщения: 123
Зарегистрирован: Вс дек 13, 2009 01:04:42

Сообщение goodspeedmen »

Написал я значит код и честно сказать я в шоке, не могу понять как такое получается.
В AVR Studio 4 код получился 400 bytes и он вообще работает не правильно, Arduino код занял 686 байт код работает но прежняя проблема осталась, при переполнении OCR1A более чем OCR1B прерывание по OCR1B не отрабатывает. :shock:
======= AVR Studio ====

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

 
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>

bool triger = 0;
uint8_t temp = 0;

//====================
void timer_COMPA_ON(void);
void timer_COMPB_ON(void);

//====================
int main(void)
        {
         DDRD  = 0b00000000; // ddr D. 
         PORTD = 0b11110111; // port D.
         DDRB  = 0b00000110; // ddr B. 
         PORTB = 0b11111001; // port B.

         while(1)            // loop.
              {
                if(((PIND & (1<<0)) == 0)&&(triger == 0))                         
                  {
                   temp++;                                                       
                   if(temp == 0xFF)  
                     {
                      triger = 1;                 
                      timer_COMPA_ON(); 
		      PORTB |= (1<<1);                                           
	              while((PIND & (1<<0)) == 0)
	                     {
			     }
		      PORTB |= (1<<2);   
                      timer_COMPB_ON();			
	             }
                   }
	      if((PIND & (1<<0)) != 0){temp = 0x00;}   
              }
        }

//====================
void timer_COMPA_ON()
{
 TCNT1=0x00;	 
 OCR1A=0x13EC;                                          //5100
 TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
 TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (1<<CS12) | (0<<CS11) | (1<<CS10);
 TIMSK1=(0<<ICIE1) | (0<<OCIE1B) | (1<<OCIE1A) | (0<<TOIE1); 
}
 
void timer_COMPB_ON()
{
 TCNT1=0x00;
 OCR1A=0x13EC;                                          //5100
 OCR1B=0xCB20;                                          //52000
 TIMSK1 |= (1<<OCIE1B);
}  

ISR(TIMER1_COMPA_vect)
{
 OCR1A +=0x13EC; 	
 PORTB ^= (1<<1);
}

ISR(TIMER1_COMPB_vect)
{
 PORTB &= ~(1<<1);                                                                                                                                      // off portb.1                                                                         
 PORTB &= ~(1<<2);                                                                                                                                      // off portb.2  
 TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);    //
 TIMSK1=(0<<ICIE1) | (0<<OCIE1B) | (0<<OCIE1A) | (0<<TOIE1);
 triger = 0;
} 


============ Arduino ======================

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

bool triger = 0;
uint8_t temp = 0;


void setup() 
          {
           DDRD  = 0b00000000; //настраиваем выводы порта D. 
           PORTD = 0b11110111; //записывае значение в порт D.
           DDRB  = 0b00000110; //настраиваем выводы порта B. 
           PORTB = 0b11111001; //записывае значение в порт B.
          }

void loop() 
         {
          if(((PIND & (1<<0)) == 0)&&(triger == 0))                       
            {
             temp++;                                                      .
             if(temp == 0xFF)                                               
               {
                triger = 1;                 
                timer_COMPA_ON();                                          
                PORTB |= (1<<1); 
                while((PIND & (1<<0)) == 0)
                     {
              
                     }
                PORTB |= (1<<2);   
                timer_COMPB_ON();     
                }
               }
          if((PIND & (1<<0)) != 0){temp = 0x00;}   
         }

void timer_COMPA_ON()
{
 TCNT1=0x00;   
 OCR1A=0x13EC;                                          //5100
 TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
 TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (1<<CS12) | (0<<CS11) | (1<<CS10);
 TIMSK1=(0<<ICIE1) | (0<<OCIE1B) | (1<<OCIE1A) | (0<<TOIE1); 
}
 
void timer_COMPB_ON()
{
 TCNT1=0x00;
 OCR1A=0x13EC;                                          //5100
 OCR1B=0xCB20;                                          //52000
 TIMSK1 |= (1<<OCIE1B);
}  

ISR(TIMER1_COMPA_vect)
{
 OCR1A +=0x13EC;  
 PORTB ^= (1<<1);
}

ISR(TIMER1_COMPB_vect)
{
 PORTB &= ~(1<<1);                                                                                                                                     // off portb.1 
 PORTB &= ~(1<<2);                                                                                                                                     // off portb.2  
 TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);   //
 TIMSK1=(0<<ICIE1) | (0<<OCIE1B) | (0<<OCIE1A) | (0<<TOIE1);
 triger = 0;
} 
Голосовой чат.
Контактная информация:
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

Вы опять пытаетесь запутать себя и нас.

Выкинуть из кода всякие if((PIND & (1<<0)) != 0), temp и т.д. Ваш алгоритм начнёт чётко спотыкаться на месте каждый раз.
Прочитать про volatile
В студии хороший симулятор. Запустить и прошагать по циклам и обработчикам прерываний с просмотром битов регистров. Я думаю, что вы недостаточно хорошо понимаете работу самого таймера.

Когда вы запускаете таймер timer_COMPA_ON(); значение OCR1B=0. Поэтому сразу выставляется флаг запроса OCF1B.
Как только вы повторно запускаете таймер timer_COMPB_ON(); разрешается прерывание OCIE1B и сразу же отрабатывается ранее запрошенное событие OCF1B.
Встал на лапы
Аватара пользователя
Сообщения: 123
Зарегистрирован: Вс дек 13, 2009 01:04:42

Сообщение goodspeedmen »

Я смотрел симуляцию и флаг прерывания по регистру OCR1B не выставляется сразу а вместе с флагом переполнения когда счетчик начнет считать по новой с нуля и это подтверждается моими опытами в протеусе. volatile - защита переменной от изменения. Это я так решаю проблему дребезга контакта без использования пауз и остановки выполнения кода микроконтроллером.
Голосовой чат.
Контактная информация:
Ответить

Вернуться в «AVR»