论坛元老
 
- 积分
- 3571
- 金钱
- 3571
- 注册时间
- 2014-12-2
- 在线时间
- 365 小时
|
发表于 2016-8-16 19:02:11
|
显示全部楼层
本帖最后由 xkwy 于 2016-8-16 19:15 编辑
举个例子,
我们在PA7上产生100个1us的方波可能会这样写:
//somethings A......
GPIOA->ODR &= ~(1<<7);
for (i = 0; i < 100; i++)
{
GPIOA->ODR ^= (1<<7);
delay_us(1);
}
GPIOA->ODR &= ~(1<<7);
//somethings B......
GPIOA->ODR,这个寄存器是被volatile修饰过的,因此程序完美。
但是,如果没有volatile修饰,,
编译器就会想,你这循环前寄存器值是啥样循环后寄存器值还是啥样,
那干脆在循环里把寄存器的赋值拿掉吧(寄存器的读-改-写操作非常费时间),
所以代码直接变成了:
//somethings A......
GPIOA->ODR &= ~(1<<7);
for (i = 0; i < 100; i++)
{
delay_us(1);
}
//somethings B......
然后又想,循环里啥事不干,就延时,那还等啥,直接跑啊,多聪明,又节省了100us的运行时间,
所以,代码就这样了:
//somethings A......
GPIOA->ODR &= ~(1<<7);
//somethings B......
看到这样的结果你傻眼了吧,虽然如今编译器更加智能话,可能不加volatile,它也能猜出来你在这延时究竟是想干啥,但是,使用volatile一来防止不太聪明的编译器不会出错,二来可以当做注释,给自己提醒也好。
诚然,volatile会强制禁止编译器优化,如果滥用的话也会使原本可以优化的没优化。
一般来说,有可能会被“别的东西”修改的变量,都应该用volatile修饰,
比如单片机寄存器,IO状态变化就会自动改变,
又比如会在中断里使用的外部变量(这很容易被忽视掉)。
|
|