Цитата(Alt.F4 @ Jan 19 2017, 09:32)

Я не против volatile, просто хочется понять, когда без него ну совсем не обойтись и код точно не будет работать.
Ожидание готовности периферии - sp, twi, usart и прочее.
Регистры, содержащие флаги объявлены как volatile: в противном случае неизбежно зацикливание.
Но у volatile есть и обратная сторона: использовать их нужно через не-volatile копии.
Совершенно искуственный, но показательный пример:
Код
volatile unsigned char tick = 1;
volatile unsigned char res_yes_volatile=0;
unsigned char res_no_volatile=0;
unsigned char flag=0;
__irq void IRQ_Handler(void)
{
tick++;
flag = tick;
}
int main()
{
while(flag < 6)
{
res_yes_volatile = tick*tick; // 2*2 = 6
res_no_volatile = tick*tick;
}
return 0;
}
Имеем в итоге:
1. вечный цикл из-за того, что flag не объявлена как volatile.
2. второй оператор умножения в цикле компилятор просто выбросил за ненадобностью.
3. команды для первого оператора цикла компилятор добросовестно сгенерировал, но так как volatile-ный tick использован
напрямую, без посредников, возможны коллизии типа 2*2 = 6, 5*5 = 30.
Код
// 16 int main()
// 17
// 18 {
main:
LDR.N R0,??DataTable1
// 19
// 20
// 21 while(flag < 6)
LDRB R1,[R0, #+3]
CMP R1,#+6
BGE.N ??main_0
// 22 {
// 23 res_yes_volatile = tick*tick;
??main_1:
LDRB R1,[R0, #+0]
LDRB R2,[R0, #+0]
MULS R1,R2,R1
STRB R1,[R0, #+1]
// 24 res_no_volatile = tick*tick;
LDRB R1,[R0, #+0]
LDRB R1,[R0, #+0]
B.N ??main_1
// 25 }
// 26
// 27 return 0;
??main_0:
MOVS R0,#+0
BX LR ;; return