Программирование таймера 0
- Войдите на сайт для отправки комментариев
Чт, 02/04/2015 - 14:31
Не могу монять почему прерывание не срабатывает по совпадению, а работает как по переполнению.
void setup() {
pinMode(13, OUTPUT);
OCR0A =125; //регистр совпадения
//Timer in CTC mode (TCCR0A)
TCCR0B =(1<<CS00)|(1<<CS01); // Тактировать с делителем 64
TIMSK0|=(1<<OCIE0A); // Разрешить прерывание по совпадению
// turn on CTC mode:CTC (сброс при совпадении)Clear Timer on Compare (CTC) установкой бит WGMn1 в TCCRn.
//При этом счётчик после совпадения с регистром сравнения будет сбрасываться автоматически.
TCCR0A |= (1 << WGM01);
sei(); //бит общего разрешения прерываний
}
void loop() {
}
//ОБРАБОТЧИК ПРЕРЫВАНИЙ ПО ТАЙМЕРУ
ISR(TIMER0_COMPA_vect) {
//TCNT0 = 0;// счетный регистр
if (iiii==1000){
digitalWrite(13,!digitalRead (13)); iiii=0;}
iiii++;
}
Чувствую что где-то туплю, а где непонятно, ткните носом если кто знает. Нулевой таймер под ардуиной решил использовать так как не буду использовать функции delay, millis, и pwm
Всё вроде правильно, но не объявлена переменная iiii. Atmel Studio такой код даже не компилирует.
volatile int iiii;
Объявил переменную, прогнал код через отладчик в студии - всё работает. Происходит прерывание по совпадению с OCR0A.
Olm, Вы тупите в 11 строке :) Записываете бит, видимо подразумевая, что регистр TCCR0A=0. Откуда такая уверенность? Делайте как в 7 строке. Всё что не указано - сбросится в ноль.
Записываете бит, видимо подразумевая, что регистр TCCR0A=0. Откуда такая уверенность?
В даташите написано Initial Value 0 0 0 0 0 0 0 0, т.е. в теории TCCR0A=0. Но на практике черт его знает.....
Я ненужные мне биты никогда не сбрасываю специально в ноль, всё и так работает. Как по даташиту. Мож от конкретного экземпляра МК зависит.
Jeka_M, Лучше сбрасывать :)) Дуняша свой порядок наводит, тем более timer0 её любимчик :)
Спасибо за такие нюансы, буду знать.
Ничего что-то не помогает. Прерывание наступает вовремя, но регистр TCNT0 не обнуляется автоматически по совпадению и продолжает тикать до переполнения. Только если его вручную обнулять в обработчике прерывания. Но в даташите сказано что в режиме CTC должен счетчик сбрасываться автоматически при совпадении с регистром сравнения
Я всё это дело из среды ардуино компилирую и прошиваю, может она что-то меняет?
В общем заработало. Регистры TCCR0A и TCCR0B надо сначала грузить, чтоб работали прерывания по совпадению.
И еще пожалуй лучше обнулить перед разрешением прерываний счетный регистр TCNT0.
volatile int iiii; void setup() { pinMode(13, OUTPUT); // TCCR0A=B00000010; // TCCR0B =B00000011; TCCR0A = (1 << WGM01);// режим CTC TCCR0B =(1<<CS00)|(1<<CS01); // Тактировать с делителем 64 OCR0A =125; //регистр совпадения TIMSK0|=(1<<OCIE0A); // Разрешить прерывание по совпадению sei(); //бит общего разрешения прерываний } void loop() { } //ОБРАБОТЧИК ПРЕРЫВАНИЙ ПО ТАЙМЕРУ ISR(TIMER0_COMPA_vect) { //TCNT0 = 0;// счетный регистр if (iiii==1000){ digitalWrite(13,!digitalRead (13)); iiii=0;} iiii++; }Olm, по идее стартовой "кнопкой" таймера является запись клоков. Желательно их первой же строкой обнулить, потом сперва сконфигурировать все другие регистры, и в конце дать нужные клоки (7 строка) , тогда всё должно стартовать правильно.
Еще перед запуском таймера (CS01, CS00) можно обнулять "буфер" предделителя (бит PSRSYNC в регистре GTCCR). Т.к. даже когда таймер остановлен - предделитель постоянно тикает.
Но надо быть осторожным, если используются два таймера (Timer0 и Timer1), т.к. "буфер" предделителя у них общий. Будет сбрасываться у обоих.
Здравствуйте написал код использующий таймер 0 для подсчета количество переполнений для борьбы с дребезгом и прерывание по изменению состояния вывода PCINT в данном случае с кнопкой на выводе РВ0 подтянутой внутренним резистором к питанию.
[Плата pro mini на mega168, памяти не особо много остается и такой вариант кода опроса на регистровом уровне считаю оптимальным в плане расхода памяти.]
Тестовый светодиод должен инвертироваться по каждому нажатию
Дребезг часто проскакивает, в чем может быть причина?
#include <avr/io.h> #include <avr/interrupt.h> static volatile uint32_t ovfCount = 0; static volatile boolean flag = 0; #define BOUNCE_DELAY 50 static uint32_t lastINTtime0 = 0; // для первой кнопки static uint32_t lastINTtime1 = 0; // для второй кнопки void timer_init(void) { cli();//stop interrupts TCCR0A = 0;// set entire TCCR0A register to 0 TCCR0B = 0;// same for TCCR0B TCNT0 = 0;//initialize counter value to 0 //Устанавливаем источник тактов -> 1/(16000000/64)* 256 = 1 мс TCCR0B =(1<<CS00)|(1<<CS01); // Тактировать с делителем 64 TIMSK0 |= _BV(TOIE0); // разрешаем прерывание по переполнению //разрешаем прерывания sei(); } ISR (TIMER0_OVF_vect) { ovfCount++; } uint32_t getOverflowCount(void) { return ovfCount; } ISR (PCINT0_vect) { /* interrupt code here */ uint32_t currINTtime = getOverflowCount(); if ((currINTtime - lastINTtime0) > BOUNCE_DELAY) { lastINTtime0 = currINTtime; if( !(PINB & (1 << PINB0))) PORTB ^= (1 << PB5); // main operation } } int main(void) { DDRB |= (1 << PB5); // set output led DDRB &= ~(1 << PB0); // Clear the PB0 pin // PB0 (PCINT0 pin) is now an input PORTB &= ~(1 << PB5); // turn Off led PORTB |= (1 << PB0); // turn On the Pull-up // PB0 is now an input with pull-up enabled PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change timer_init(); //sei(); // turn on interrupts while(1) {}; }ПС: подскажите если не трудно как перейти к setup() и loop() Возникает конфликт с delayMicroseconds
#include <avr/io.h> #include <avr/interrupt.h> static volatile uint32_t ovfCount = 0; static volatile boolean flag = 0; #define BOUNCE_DELAY 50 static uint32_t lastINTtime0 = 0; // для первой кнопки static uint32_t lastINTtime1 = 0; // для второй кнопки void timer_init(void) { cli();//stop interrupts TCCR0A = 0;// set entire TCCR0A register to 0 TCCR0B = 0;// same for TCCR0B TCNT0 = 0;//initialize counter value to 0 //Устанавливаем источник тактов -> 1/(16000000/64)* 256 = 1 мс TCCR0B =(1<<CS00)|(1<<CS01); // Тактировать с делителем 64 TIMSK0 |= _BV(TOIE0); // разрешаем прерывание по переполнению //разрешаем прерывания sei(); } ISR (TIMER0_OVF_vect) { ovfCount++; } uint32_t getOverflowCount(void) { return ovfCount; } ISR (PCINT0_vect) { /* interrupt code here */ uint32_t currINTtime = getOverflowCount(); if ((currINTtime - lastINTtime0) > BOUNCE_DELAY) { lastINTtime0 = currINTtime; if( !(PINB & (1 << PINB0))) PORTB ^= (1 << PB5); // main operation } } //int main(void) void setup() { DDRB |= (1 << PB5); // set output led DDRB &= ~(1 << PB0); // Clear the PB0 pin // PB0 (PCINT0 pin) is now an input PORTB &= ~(1 << PB5); // turn Off led PORTB |= (1 << PB0); // turn On the Pull-up // PB0 is now an input with pull-up enabled PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change timer_init(); //sei(); // turn on interrupts //while(1) {}; } void loop() {}Дребезг часто проскакивает, в чем может быть причина?
Плохой алгоритм. Дребезг возникает как при нажатии кнопки, так и при отпускании её. У вас прерывание срабатывает и на нажатие и на отпускание, и счёт времени запускается и так и так, в результате получается что и алгоритм срабатывает и на нажатие и на отпускание, и ваше условие if( !(PINB & (1 << PINB0))) легко срабатывает от дребезга, а не от нажатия кнопки. Короче аглоритм негодный.
ПС: подскажите если не трудно как перейти к setup() и loop() Возникает конфликт с delayMicroseconds
Разумеется, таймер0 - системный таймер ардуины, который по умолчанию занят. Так что либо не используёте таймер0, либо не используйте функцию setup(), которая прогружает все настройки по умолчанию.
dimax, спасибо. Понял свою ошибку и решил несколько упростить код - убрал прерывание по таймеру 0. Подавление дребезга произвожу аппаратно - параллельно каждой кнопке поставил керамический конденсатор на 100 нФ. Дребезг пропал.
#include <avr/io.h> #include <avr/interrupt.h> // Необходимо использовать прерывания volatile uint8_t flag = 0; int main(void) { DDRB |= (1 << PB5); // set output led DDRB &= ~(1 << PB0); // Clear the PB0 pin PORTB |= (1 << PB0); // turn On the Pull-up PORTB &= ~(1 << PB5); // turn Off led PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change sei(); // turn on interrupts while(1){} } ISR (PCINT0_vect) { if( !(PINB & (1 << PB0)) == 1) { PORTB ^= (1 << PB5); } }