Страница 1 из 1
проблема с таймером
Добавлено: Чт дек 14, 2017 16:02:34
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 миллисекунды, как я понимаю при вызове сразу происходит вызов прерывания

как так получается вить флаг прерывания еще не установлен

Re: проблема с таймером
Добавлено: Чт дек 14, 2017 17:44:13
uk8amk
Кто за кем идёт не совсем понятно, но полагаю, что нужно ещё дёргать регистр TIFR.
Re: проблема с таймером
Добавлено: Чт дек 14, 2017 20:17:14
Starichok51
в "угадайку" будем играть?
1. какой МК?
2. какая тактовая частота?
3. что такое "if(.....)" и когда оно срабатывает?
4. у тебя ISR(TIMER1_COMPB_vect) останавливает таймер. сколько времени проходит до "срабатывания" if(.....) ?
5. у тебя 27000 / 4500 = ровно 6. поэтому флаги обоих прерываний выставляются одновременно. но первым всегда выполняется прерывание по OCR1A.
попробуй OCR1B сделать чуточку побольше, чтобы это прерывание гарантированно произошло позже, чем прерывание по OCR1A.
Re: проблема с таймером
Добавлено: Пн дек 18, 2017 11:15:40
goodspeedmen
mega328.
16 мегагерц.
if операция это условно для понимания как используется код, время может быть разное от секунды до более минуты.
Re: проблема с таймером
Добавлено: Ср дек 20, 2017 13:45:50
BOB51
А сменить контрольные регистры таймера (приоритет прерываний у АВРки к сожалению НЕ ИЗМЕНЯЕТСЯ)?
Или наворотить разрешение вложенного прерывания?

Re: проблема с таймером
Добавлено: Ср дек 20, 2017 21:30:15
goodspeedmen
Я не понял вы спрашиваете или отвечаете? Так в том то и дело, что при заходе в timer_COMPB_ON(); происходит обнуление счетного регистра, инициализация регистров сравнения обоих и только после этого происходит разрешение прерывания регистра сравнения OCR1B.
Re: проблема с таймером
Добавлено: Чт дек 21, 2017 08:25:41
BOB51
МНДЯаа...
Я-то привык САМ режимы задавать, какие захочу - ассемблер однако штука удобная...
Си - потребует или библиотеку досконально изучить или свое написать. В этом плане (СИшные прожки) я пока не советчик...

Re: проблема с таймером
Добавлено: Чт дек 21, 2017 09:58:34
uk8amk
Создайте новый проект только с TIM1, без всяких LCD и др. ненужной периферии. если проблема останется, то выложите весь новый проект сюда.
Re: проблема с таймером
Добавлено: Чт дек 21, 2017 10:51:48
goodspeedmen
[uquote="uk8amk",url="/forum/viewtopic.php?p=3265135#p3265135"]Создайте новый проект только с TIM1, без всяких LCD и др. ненужной периферии. если проблема останется, то выложите весь новый проект сюда.[/uquote]
Попробую нацарапать как будет время

Re: проблема с таймером
Добавлено: Сб дек 23, 2017 17:00:25
goodspeedmen
Написал я значит код и честно сказать я в шоке, не могу понять как такое получается.
В AVR Studio 4 код получился 400 bytes и он вообще работает не правильно, Arduino код занял 686 байт код работает но прежняя проблема осталась, при переполнении OCR1A более чем OCR1B прерывание по OCR1B не отрабатывает.
======= 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;
}
Re: проблема с таймером
Добавлено: Сб дек 23, 2017 20:51:50
uk8amk
Вы опять пытаетесь запутать себя и нас.
Выкинуть из кода всякие if((PIND & (1<<0)) != 0), temp и т.д. Ваш алгоритм начнёт чётко спотыкаться на месте каждый раз.
Прочитать про volatile
В студии хороший симулятор. Запустить и прошагать по циклам и обработчикам прерываний с просмотром битов регистров. Я думаю, что вы недостаточно хорошо понимаете работу самого таймера.
Когда вы запускаете таймер timer_COMPA_ON(); значение OCR1B=0. Поэтому сразу выставляется флаг запроса OCF1B.
Как только вы повторно запускаете таймер timer_COMPB_ON(); разрешается прерывание OCIE1B и сразу же отрабатывается ранее запрошенное событие OCF1B.
Re: проблема с таймером
Добавлено: Чт дек 28, 2017 21:34:37
goodspeedmen
Я смотрел симуляцию и флаг прерывания по регистру OCR1B не выставляется сразу а вместе с флагом переполнения когда счетчик начнет считать по новой с нуля и это подтверждается моими опытами в протеусе. volatile - защита переменной от изменения. Это я так решаю проблему дребезга контакта без использования пауз и остановки выполнения кода микроконтроллером.