Еще один отсчет таймера
- Войдите на сайт для отправки комментариев
Чт, 22/06/2017 - 16:04
Использую таймер для генерациии прерывания на частоте 250 ГЦ
void set_timer_T2A(void)
{
TCCR2B=0; // Т2 стоп
TCNT2=0; // счётный регистр
OCR2B=0;
TIFR2&=0xff;
TCCR2A=(1<<WGM21); //Mode2(CTC)
OCR2A=249; // 500 Гц
TIMSK2=(1<<OCIE2A); //прерывание по совпадению с OCR2A
TCCR2B=(1<<CS22)|(1<<CS21); // делитель на 256
}
ISR (TIMER2_COMPA_vect) { ; ; }
Как описать настройку таймера T2B, чтобы он вызывал другое прерывание,
ISR (TIMER2_COMPB_vect) { ; ; }
по частоте синхронное с T2A, но исполняемое при значении OCR2B=83 и при этом T2 бы не начинал отсчет заново как в случае с OCR2A=249, а вызывал его прерывание TIMER2_COMPA и только после этого перезапускался ?
Те частота вызовов нового и старого прерываний должна остаться без изменения.
Нахрена такие сложности, при входе в аервое прерывание запустите другой таймер, который через 83 клока даст вам прерывание . И на этом всё !
при этом T2 бы не начинал отсчет заново как в случае с OCR2A=249, а вызывал его прерывание TIMER2_COMPA и только после этого перезапускался ?
Частота тут неизменна, она жёстко задана регистром OCR2A. Таймер не в состоянии начать отчёт заново не досчитав до OCR2A. Стало быть если вы допишите OCR2B=83; TIMSK2|=1<<OCIE1B; то второе прерывание будет работать с той же частотой, но сдвинуто по времени на OCR2A-OCR2B тактов.
OCR2A и OCR2B не равноценны, частоту задает OCR2A, а не OCR2B?
Можете тыкнуть на пункт в описании от Microchip (владелец компании Atmel) или книгу Евстифеева?
Kunzo, даташит, страница 155 Table 18-8. Mode 2. Графа "Top" говорит о том, что будет конец счёта. Регистры не равноценны. Регистр OCR2A в данном случае работает в 2х качествах -как число, до которого считает счётчик, и как число при сравнении с которым произойдёт прерывание. Регистр OCR2B только в одном качестве.
volatile int ndx=0; # define SL 56 volatile byte LogSequense[SL]; volatile int LogPeriod[SL]; volatile bool printed=false, writed=false; uint64_t T1, T2, TA=0, TB=0; void setup(void) { int i; for(i=0; i<SL; i++) { LogSequense[i]=0xFFFF; LogPeriod[i]=0; } Serial.begin(115200); Serial.println("Start"); T1=micros(); Serial.print(" Start time=");Serial.println((unsigned int)T1); setup_timers(); } void loop(void) { int i; T2=micros(); if( (writed==true) & (printed==false)) { Serial.print(" Summ. time=");Serial.print((unsigned int)(T2-T1));Serial.println(" mic"); for(i=0; i<SL; i++) { Serial.print(" i="); Serial.print(i); Serial.print(" IRQn="); Serial.print(LogSequense[i]); Serial.print(" dT="); Serial.print(LogPeriod[i]); Serial.println(""); } printed=true; } } void setup_timers(void) { TCCR2B=0; TCNT2=0; TIFR2&=0xff ; TCCR2A=(1<<WGM21); OCR2A=200; TIMSK2=(1<<OCIE2A); // комп с OCR2A OCR2B=30; TIMSK2|=1<<OCIE1B; //комп с OCR2B TCCR2B=(1<<CS22)|(1<<CS20); } ISR (TIMER2_COMPB_vect) // прерывание B выполняется первым { TB=micros(); if( ndx>=SL) {writed=true; return;} else; LogSequense[ndx]=100+ndx; LogPeriod[ndx]=TB-TA; ndx++; } ISR (TIMER2_COMPA_vect)// прерывание A выполняется вторым { TA=micros(); if( ndx>=SL) {writed=true; return;} else; LogSequense[ndx]=200+ndx; LogPeriod[ndx]=TA-TB; ndx++; }а если добавить задержку, то первый отсчет вообще печатается ка отрицательный
Serial.print(" Start time=");Serial.println((unsigned int)T1); delay(2000); //----------------------------------------------------------------------------------- setup_timers();Kunzo, вы недостаточно ясно описали что не так. Из того, что бросается в глаза -TIFR лучше обнулять после настройки TIMSK, ибо после его конфигурации сразу может сработать прерывание. Ну и можно на всякий случай перед всей этой конструкцией запретить прерывания. Т.е. запрет, потом настройка таймера, потом разрешение прерываний, и в конце всей очереди T1=micros.
Изменил все указанное, только местоположение T1=micros(); менять не стал тк он привязан к Serial.print(), который распечатывает его значение. Если выполнить Serial.print() после инициализации таймера, то возможно вывод в COM сдвинет (предположение) по времени входы в прерывания компараторов A и B ?
volatile int ndx=0; # define SL 56 volatile byte LogSequense[SL]; volatile int LogPeriod[SL]; volatile bool printed=false, writed=false; uint64_t T1, T2, TA=0, TB=0; void setup(void) { int i; for(i=0; i<SL; i++) { LogSequense[i]=0xFFFF; LogPeriod[i]=0; } Serial.begin(115200); Serial.println("Start"); T1=micros(); Serial.print(" Start time=");Serial.println((unsigned int)T1); noInterrupts(); setup_timers(); interrupts(); } void loop(void) { int i; T2=micros(); if( (writed==true) & (printed==false)) { Serial.print(" Summ. time=");Serial.print((unsigned int)(T2-T1));Serial.println(" mic"); for(i=0; i<SL; i++) { Serial.print(" i="); Serial.print(i); Serial.print(" IRQn="); Serial.print(LogSequense[i]); Serial.print(" dT="); Serial.print(LogPeriod[i]); Serial.println(""); } printed=true; } } void setup_timers(void) { TCCR2B=0; TCNT2=0; //-------------------------------------- TIFR2&=0xff ; TCCR2A=(1<<WGM21); OCR2A=200; TIMSK2=(1<<OCIE2A); // комп с OCR2A OCR2B=30; TIMSK2|=1<<OCIE1B; //комп с OCR2B TCCR2B=(1<<CS22)|(1<<CS20); TIFR2&=0xff ; } ISR (TIMER2_COMPB_vect) // прерывание B выполняется первым { TB=micros(); if( ndx>=SL) {writed=true; return;} else; LogSequense[ndx]=100+ndx; LogPeriod[ndx]=TB-TA; ndx++; } ISR (TIMER2_COMPA_vect)// прерывание A выполняется вторым { TA=micros(); if( ndx>=SL) {writed=true; return;} else; LogSequense[ndx]=200+ndx; LogPeriod[ndx]=TA-TB; ndx++; }А если добавить задержку, то результат еще более изменяется, я писал об этом выше
Serial.print(" Start time=");Serial.println((unsigned int)T1); delay(2000); //----------------------------------------------------------------------------------- setup_timers();Kunzo, не понимаю что вам не понятно.. У вас первым срабатывает прерывание COMPB, и в нём вы уже делаете операцию TB-TA , а TA на этот момент =0. Т.к. второе прерывание ещё не сработало. В резульате вы имеете то что запрограммировано -первый отсчёт -это время от глобального старта микрос до прерывания.
dimax, поскольку мне был нужен еще один таймер, я добавил прерывание от T0. Инициализировал однотипно с T2, но T0 испортил работу прежней программы.
В чем конфликт не знаю. МК Atmega328P - вместо T0 придется использовать T1 ?
В программе еще будут задействованы библиотечные функции: аппаратный SPI, аппаратный Serial COM1 на время отладки и аппаратный I2C для LCD.
volatile int ndx=0; # define SL 56 volatile byte LogSequense[SL]; volatile int LogPeriod[SL]; volatile bool printed=false, writed=false; uint64_t T1, T2, TA=0, TB=0; void setup(void) { int i; for(i=0; i<SL; i++) { LogSequense[i]=0xFFFF; LogPeriod[i]=0; } Serial.begin(115200); Serial.println("Start"); T1=micros(); Serial.print(" Start time=");Serial.println((unsigned int)T1); noInterrupts(); setup_timers(); interrupts(); } void loop(void) { int i; T2=micros(); if( (writed==true) & (printed==false)) { Serial.print(" Summ. time=");Serial.print((unsigned int)(T2-T1));Serial.println(" mic"); for(i=0; i<SL; i++) { Serial.print(" i="); Serial.print(i); Serial.print(" IRQn="); Serial.print(LogSequense[i]); Serial.print(" dT="); Serial.print(LogPeriod[i]); Serial.println(""); } printed=true; } } void setup_timers(void) { noInterrupts(); //// timer 2 -------------------------------------- TCCR2B=0; TCNT2=0; TCCR2A=(1<<WGM21); OCR2A=200; TIMSK2=(1<<OCIE2A); // комп с OCR2A OCR2B=30; TIMSK2|=1<<OCIE1B; //комп с OCR2B TCCR2B=(1<<CS22)|(1<<CS20); TIFR2&=0xff ; ///// timer 0 ------------------------------------ TCCR0B=0; TCNT0=0; TCCR0A=(1<<WGM21); OCR0A=150; TIMSK0=(1<<OCIE0A); //по комп OCR0A OCR2B=15; TIMSK0|=(1<<OCIE0B); // по комп OCR0B TCCR0B=(1<<CS22)|(1<<CS20); TIFR0&=0xff ; interrupts(); } ISR (TIMER0_COMPB_vect){ return;} // пока пустышка ISR (TIMER0_COMPA_vect){ return;} // пока пустышка ISR (TIMER2_COMPB_vect) { TB=micros(); if( ndx>=SL) {writed=true; return;} else; LogSequense[ndx]=100+ndx; LogPeriod[ndx]=TB-TA; ndx++; } ISR (TIMER2_COMPA_vect) { TA=micros(); if( ndx>=SL) {writed=true; return;} else; LogSequense[ndx]=200+ndx; LogPeriod[ndx]=TA-TB; ndx++; }Kunzo, Timer0 использует ардуиновские системные функции (миллисы, микросы, и прочее)
Тогда нужно использовать оставшийся T1 если библиотечные функции: аппаратный SPI, аппаратный Serial COM1 на время отладки и аппаратный I2C для LCD на него не претендуют ?
Кстати, почему он в datasheet называется 3,4-16 битным и ATmega328PB устроена также как ATmega328P AU ?