Прерывание от таймера с заданной частотой Arduino AVR Atmega328 пример

Пример работы

На низкой частоте наблюдать работу можно смотря на светодиод на плате:

Посмотреть переключение выходного состояния высокой частоты можно с помощью осциллографа HS101 на STM32:

А также при помощи логического анализатора:

Полный код

/* Includes BEGIN */ #include "Arduino.h" /* Includes END */ /* PFP BEGIN */ void LedToggle(void); /* PFP END */ /* Defines BEGIN */ #define TIM1_FREQ 1UL // UL - unsigned long #define DEBUG 1 /* Defines END */ /* PVP BEGIN */ uint8_t Tim1OcFlg = 0; /* PVP END */ void setup() { /* Pin Config */ pinMode(LED_BUILTIN, OUTPUT); // led on 13 pin /* For debug */ Serial.begin(9600); /* Timer1 Interrupt Config */ TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; #if(DEBUG) Serial.print("MCU frequency: F_CPU = "); Serial.print(F_CPU); Serial.println(";"); #endif OCR1A = F_CPU/(256*TIM1_FREQ); #if(DEBUG) Serial.print("Compare register: OCR1A = "); Serial.print(OCR1A); Serial.println(";"); #endif TCCR1B |= (1 << WGM12); #if(DEBUG) Serial.print("CTC mode ennable: "); Serial.print("TCCR1B = "); Serial.print(TCCR1B, BIN); Serial.println(";"); #endif TCCR1B |= (1 << CS12); #if(DEBUG) Serial.print("Prescaler 256: "); Serial.print("TCCR1B = "); Serial.print(TCCR1B, BIN); Serial.println(";"); #endif TIMSK1 |= (1 << OCIE1A); #if(DEBUG) Serial.print("Compare interrupt: "); Serial.print(" TIMSK1 = "); Serial.print(TIMSK1, BIN); Serial.println(";"); #endif sei(); #if(DEBUG) Serial.print("Interrupts ennable:"); Serial.print(" SREG = "); Serial.print(SREG, BIN); Serial.println(";"); #endif } void loop() { if(Tim1OcFlg) { /* Led Toggle */ LedToggle(); /* Nullify */ Tim1OcFlg = 0; } } /* Interrupt Service Routine */ ISR(TIMER1_COMPA_vect) { Tim1OcFlg = 255; } void LedToggle(void) { digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) ^ 1); }

Как задается частота прерываний?

Тактовая частота по умолчанию определена через F_CPU, для Arduino Nano это 16 МГц. Это очень просто посмотреть используя новую среду разработки Arduino IDE 2.0 (буква L в конце означает тип long) .

Непосредственно частота прерываний задается с помощью определения TIM1_FREQ, но следует помнить, что расчетное значение для регистра сравнения не должно превышать 65535 (см. ниже почему).

Возможная частота будет может иметь разный диапазон, в зависимости от предделителя (см. ниже, другие делители настраиваются в регистре TCCR1B). Например, при делении 16000000/256 = 62500 наименьшая частота, которая может быть это 65535/62500 = 1.048 Гц, то есть, если нужно меньше, то используем делитель 1024.

Обычно ходовое значение 10 Гц (период 100 мс), чтобы получить его задаем:

#define TIM1_FREQ 10UL

Как создаются прерывания (подробно)?

Используется режим CTC (Clear Timer On Compare Match).

Выбирается режим работы, здесь это CTC, в таблице видно, что наибольшее значение в нем может быть 65535 (т.к. он состоит из двух 8-ми разрядных регистров).

Здесь есть делители частоты (напоминаю, что в случае Arduino Nano частота тактирования 16 МГц) на 1, 8, 64, 256 и 1024. Для выбора делителя 256 выставляется бит CS12:

Далее обязательно включаем нужное прерывание в регистре TIMSK1:

Разрешаем прерывания с помощью функции sei (SEt Interrupt flag):

sei();

После запуска таймера он будет считать и значения счетчика увеличиваться, что можно смотреть в регистре TCNT1:

А прерывание будет вызываться когда это значение (счетчика таймера TCNT1) совпадёт со значением, заданным в регистре OCR1:будет равно значению в OCR1 (при этом нужно не забывать, что эти регистры 16-ти разрядные, то есть наибольшее значение 16² - 1 = 65535):

Теперь программа будет заходить в соответствующий обработчик прерывания, где можно выполнять свой код (здесь может происходить переключение логического уровня на выводе, к которому подключен светодиод)

ISR(TIMER1_COMPA_vect) { LedToggle(); }

По умолчанию в коде есть строки для отладки, если она включена, то вот что покажет:


Купить на Aliexpress

🏷️ Arduino Nano Atmega328 Mini-USB (4.5💲)
🏷️ Arduino Nano CH340 (1.93💲)
🏷️ Arduino Board USB Mini (4.13💲)


Дополнительно

Видно, но использован канал A для сравнения, но, если нужно можно задействовать по такому же принципу и канал B, тем более что у него есть свой обработчик прерывания ( TIMER1_COMPB_vect).

Скачать проект: timer1_oc_irq.zip

214
RSS
Нет комментариев. Ваш будет первым!
Загрузка...