Следующие фрагменты взяты из исходного кода библиотеки TimerOne :
// TimerOne.h:
void (*isrCallback)();
// TimerOne.cpp:
ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
Timer1.isrCallback();
}
// TimerOne.cpp:
void TimerOne::attachInterrupt(void (*isr)(), long microseconds)
{
if(microseconds > 0) setPeriod(microseconds);
isrCallback = isr; // register the user's callback with the real ISR
TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit
resume();
}
Вопрос: если таймер уже запущен и основная программа вызывает attachInterrupt()
, может ли прерывание таймера произойти там во время назначения указателя функции isrCallback = isr;
? Тогда при удачной синхронизации Timer1.isrCallback();
указатель на функцию будет состоять частично из старого и частично из нового адреса, вызывая скачок ISR в фиктивное местоположение?
Я полагаю, что это может быть так, поскольку указатели на функции, безусловно, шире, чем 1 байт, и доступ к данным размером более 1 байта не является атомарным. Возможные обходные пути могут быть:
- Всегда звоните,
detachInterrupt()
чтобы убедиться, что таймер не работает, прежде чем звонитьattachInterrupt()
, то есть уточнить документы Timer1. - Или измените Timer1, временно отключив прерывания переполнения таймера
isrCallback = isr;
Имеет ли это смысл, или есть что-то в Timer1
источниках или назначениях указателей на функции, которые я пропустил?
Похоже, у вас есть точка. Логично было бы отключить прерывания таким образом, чтобы вы не включали их повторно, если они были отключены в первую очередь. Например:
Цель этого состоит в том, чтобы позволить вам написать код, подобный этому:
Без этого условия вы могли бы получить прерывание между этими двумя линиями и, таким образом, спать бесконечно (потому что прерывание, которое должно было вас разбудить, произошло до того, как вы заснули). Условие в процессоре, что следующая инструкция после того, как прерывания становятся включенными, если они не были включены ранее, всегда выполняется, защищает от этого.
источник
TIMSK1=0; TIFR1=_BV(TOV1); isrCallback=isr; TIMSK1=_BV(TOIE1);
? Он экономит один регистр процессора и не вносит задержку прерывания.