Прерывание от таймера с заданной частотой 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