Задача компилятора - перевести описание с языка, понятного человеку (ЯВУ), на язык, "понятный" МК или CPU, используя
формализованные правила. Причем
формализованные правила составляет тоже человек или группа людей, те, которые компилятор писали. Если в дилемме: кто был первым яйцо или курица?, то бишь что первично компилятор или программист, его использующий?, считать первичным компилятор, то так и выходит - в 99,9% виноват программист, который не прочитал, не понял или недопонял правила по которым работает компилятор. 0,1% отнесем на ошибки, допущенные теми, кто писал компилятор или документацию для него, т.к. никто полностью от ошибок не застрахован.
Использование квалификатора
volatile для описания глобальных переменных, модифицируемых в прерываниях, это всего лишь начальные азы понимания о том, по каким правилам работает компилятор. Но ради справедливости стоит уточнить, что на эти "грабли" наступает очень много начинающих программировать на Си, которые бегло прочитали стандарт Си, но не удосужились прочитать документацию на используемый ими компилятор. Поэтому программа вида
Код
unsigned int cntr;
void main(void)
{
...
cntr=1000;
while(cntr!=0);
...
}
#pragma vector=TIMER_VECTOR
#pragma type_attribute=__interrupt
void TIMER_ISR (void)
{ if (cntr>0)
cntr--;
}
практически всегда будет компилироваться так, что оператор
while скомпилируется в "вечный цикл", вне зависимости от правильности инициализации/функционирования таймера и описания функции обработчика его прерывания. А чтобы этого не произошло обычно достаточно пояснить компилятору, что именно вы от него хотите, объявив переменную
cntr как
Код
volatile unsigned int cntr;