Изменчивая переменная не обновляется с таймера ISR
Я знаю, что эта проблема возникала много раз, но я не могу заставить этот фрагмент кода обновлять переменную count на ATMEGA328P. Я использую Arduino Uno в качестве платы для разработки, а светодиод на контакте 13 настроен на вспышку для отладки. Я убедился, что таймер и светодиодная часть работают, переключив контакт 5 порта B в процедуре ISR.
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint8_t count;
void init_100us_tick(void) {
TCCR0A = _BV(WGM01) | _BV(WGM00); // Режим WGM 7 с OCRA наверху
TCCR0B = _BV(WGM02) | _BV(CS01); // CLK/8 прескалер
TIMSK0 = _BV(OCIE0B) | _BV(TOIE0); // Прерывание разрешено на OCR0A
OCR0A = 200; // 16 МГц / 8 / 200 = 100 мкс
sei(); // Разрешить прерывания
}
ISR(TIMER0_COMPB_vect) {
count++;
}
int main(void) {
DDRB |= _BV(DDB5); // вывод PB5
init_100us_tick(); // Инициализировать 100 мкс тик
count = 0; // В случае микросброса
for (;;) {
if (count >= 100) { // Каждые 10 мс
count = 0;
PORTB ^= _BV(DDB5); // Переключить PB5
}
}
return 0;
}
Это скомпилировано и записано на Arduino Uno со следующим:
avr-gcc -Os -DF_CPU=16000000UL -mmcu=atmega328p -c -o test.o test.c
avr-gcc -mmcu=atmega328p test.o -o test
avr-objcopy -O ihex -R .eeprom test test.hex
avrdude -F -V -c arduino -p ATMEGA328P -P /dev/ttyUSB0 -b 115200 -U flash:w:test.hex
Я пытался отключить оптимизацию, но безрезультатно. AVR-GCC версии 4.9.2
@, 👍1
Обсуждение1 ответ
Лучший ответ:
Для этого вам нужен режим CTC. Как в:
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint8_t count;
void init_100us_tick(void) {
TCCR0A = _BV(WGM01); // CTC режим 2 с OCRA наверху
TCCR0B = _BV(CS01); // CLK/8 прескалер
TIMSK0 = _BV(OCIE0B) | _BV(TOIE0); // Прерывание разрешено на OCR0B
OCR0A = 200; // 16 МГц / 8 / 200 = 100 мкс
sei(); // Разрешить прерывания
}
ISR(TIMER0_COMPB_vect) {
count++;
}
int main(void) {
DDRB |= _BV(DDB5); // вывод PB5
init_100us_tick(); // Инициализировать 100 мкс тик
count = 0; // В случае микросброса
for (;;) {
if (count >= 100) { // Каждые 10 мс
count = 0;
PORTB ^= _BV(PORTB5); // Переключить PB5
}
}
return 0;
}
Переключается каждые 10 мс.
(Отредактировано для добавления)
Выбранный вами режим ШИМ будет работать, если вы включите правильное прерывание. Это также выводит импульсы 10 мс:
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint8_t count;
void init_100us_tick(void) {
TCCR0A = _BV(WGM01) | _BV(WGM00); // Режим Fast PWM 7 с OCRA наверху
TCCR0B = _BV(WGM02) | _BV(CS01); // CLK/8 прескалер
TIMSK0 = _BV(OCIE0A); // Прерывание разрешено на OCR0A ***
OCR0A = 200; // 16 МГц / 8 / 200 = 100 мкс
sei(); // Разрешить прерывания
}
ISR(TIMER0_COMPA_vect) { // Сравнить вектор ***
count++;
}
int main(void) {
DDRB |= _BV(DDB5); // вывод PB5
init_100us_tick(); // Инициализировать 100 мкс тик
count = 0; // В случае микросброса
for (;;) {
if (count >= 100) { // Каждые 10 мс
count = 0;
PORTB ^= _BV(PORTB5); // Переключить PB5 ***
}
}
return 0;
}
Измененные строки, обозначенные ***
Обратите внимание, что не следует включать _BV(TOIE0)
, поскольку у вас нет обработчика прерываний для переполнения таймера 0. Без обработчика прерываний компилятор, вероятно, сгенерировал код для перехода к вектору сброса.
Прерывание происходит, когда таймер соответствует количеству Compare A (не Compare B), поэтому вам нужно прерывание на стороне A.
Возможно, вы захотите установить для OCR0B
определенное значение, вместо того, чтобы полагаться на значение по умолчанию 0
., @Gerben
Спасибо, это сработало! Не могли бы вы объяснить, почему переход в режим CTC имеет такой эффект?, @Matthew Curlis
Смотрите измененный ответ., @Nick Gammon
- Генерация стабильной частоты
- AVRdude неправильно считывает значения байтов предохранителя
- Прерывания TIMER1 CTC не работают с avr-gcc
- ATmega328P - проблема с использованием таймера 2 для генерации тона
- Точность синхронизации Arduino nano
- ISR для очень быстрых процессов, обнаружен странный код. Влияет ли ISR на поведение таймера?
- Интервальный таймер на Arduino: Сомнения по поводу библиотеки TimerOne
- Как контролировать мигание светодиода во время работы таймера?
Прерывание включено на OCR0A
- не забудьте изменить комментарии, если вы меняете код! У вас есть прерывание наTIMER0_COMPB_vect
!, @Nick Gammon