Os seguintes trechos são do código-fonte da biblioteca 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();
}
A pergunta: se o cronômetro já estiver em execução, e o programa principal chamar attachInterrupt()
, o temporizador poderá ocorrer durante a atribuição do ponteiro de função isrCallback = isr;
? Então, com um tempo de sorte, o Timer1.isrCallback();
ponteiro de função consistiria em parte no antigo e em parte no novo endereço, fazendo com que o ISR pulasse para um local falso?
Suponho que possa ser esse o caso, pois os ponteiros de função certamente são maiores que 1 byte e o acesso a dados de> 1 byte não é atômico. As soluções possíveis podem ser:
- Sempre ligue
detachInterrupt()
para garantir que o cronômetro não esteja funcionando antes de chamarattachInterrupt()
, ou seja, esclareça os documentos do Timer1. - Ou modifique o Timer1, desativando temporariamente o estouro de temporizador interrompe temporariamente antes de
isrCallback = isr;
Isso faz sentido ou há algo nas Timer1
fontes ou atribuições de ponteiros de função que eu perdi?
Parece que você tem razão. A coisa lógica a ser seria desativar as interrupções de forma que você não as reative se elas foram desativadas em primeiro lugar. Por exemplo:
A intenção disso é permitir que você escreva um código como este:
Sem essa disposição, você poderá interromper essas duas linhas e, assim, dormir indefinidamente (porque a interrupção que iria acordar você ocorreu antes de você dormir). A disposição no processador de que a próxima instrução, após as interrupções, seja ativada se elas não foram ativadas antes, é sempre executada, protege contra isso.
fonte
TIMSK1=0; TIFR1=_BV(TOV1); isrCallback=isr; TIMSK1=_BV(TOIE1);
? Poupa um registro da CPU e não contribui com latência de interrupção.