Jest wyraźnie udokumentowane, że gdy dane globalne są udostępniane ISR i programowi głównemu, dane muszą zostać zadeklarowane volatile
w celu zagwarantowania widoczności pamięci (i to wystarcza tylko dla danych 1-bajtowych; cokolwiek większego wymaga specjalnych ustaleń, aby zagwarantować również atomowość) . Tutaj mamy dobre zasady:
- Zmienne używane tylko poza ISR nie powinny być niestabilne.
- Zmienne używane tylko wewnątrz ISR nie powinny być lotne.
- Zmienne stosowane zarówno wewnątrz, jak i na zewnątrz ISR powinny być niestabilne.
Ale czy jest volatile
potrzebny, gdy zmienna jest dostępna z> 1 ISR, ale nie jest dzielona poza ISR? Na przykład mam funkcję, która utrzymuje stan wewnętrzny za pomocą static
zmiennej:
void func() {
static volatile long counter; // volatile or not?
// Do stuff with counter etc.
}
Ta funkcja jest wywoływana na dwa sposoby: z przerwań pinów i z biblioteki TimerOne :
attachInterrupt(0, func, CHANGE);
Timer1.attachInterrupt(func);
Nie ma problemów z atomicznością, ponieważ po wprowadzeniu ISR przerwania są automatycznie wyłączane , ale volatile
jest to raczej pytanie kompilatora: co jest buforowane, a co nie.
Oczywiście lepiej niż żałować ...
volatile
, ponieważ nie jest modyfikowana przez nic innego niż generowany kod; kompilator może „założyć”, że ISR wykonuje się liniowo i robi to, o ile przerwania nie zagnieżdżają się. To ma sens. Dzięki!