还是为了自己学习啊 自己基础太差了
在C/C++嵌入式代码中,你是否经历过以下情况:
-
代码执行正常–直到你打开了编译器优化
-
代码执行正常–直到打开了中断
-
古怪的硬件驱动
-
RTOS的任务独立运行正常–直到生成了其他任务
如果你的回答是“yes”,很有可能你没有使用C语言关键字volatile。你并不是唯一的,很多程序员都不能正确使用volatile。不幸的是,大多数c语言书籍对volatile的藐视,只是简单地一带而过。
volatile用于声明变量时的使用的限定符。它告诉编译器该变量值可能随时发生变化,且这种变化并不是代码引起的。给编译器这个暗示是很重要的。在开始前,我们向来看一看volatile的语法。
C语言关键字volatile语法
声明一个变量为volatile,可以在数据类型之前或之后加上关键字volatile。下面的语句,把foo声明一个volatile的整型。 - volatile int foo;int volatile foo;
复制代码
把指针指向的变量声明为volatile很常见,尤其是I/O寄存器的地址映射。下面的语句,把pReg声明为一个指向8-bit无符号指针,指针指向的内容为volatile。 - volatile uint8_t * pReg;uint8_t volatile * pReg;
复制代码
volatile的指针指向非volatile的变量很少见(我只使用过一次),但我还是给出相应的语法。
顺便提一下,关于为什么要在数据类型前使用volatile关键字,请自行百度搜素。
最后,如果你再struct或者union前使用volatile关键字,表明struct或者union的所有内容都是volatile。如果这不是你的本意,可以在struct或者union成员上使用volatile关键字。
正确使用C语言关键字volatile
只要变量可能被意外的修改,就需要把该变量声明为volatile。在实际应用中,只有三种类型数据可能被修改:
-
外设寄存器地址映射
-
在中断服务程序中修改全局变量
-
在多线程、多任务应用中,全局变量被多个任务读写
接下来,我们将分别讨论上述三种情况。
外设寄存器
嵌入式系统包含真正的硬件,通常会有复杂的外设。这些外设寄存器的值可能被异步的修改。举个简单的例子,我们要把一个8-bit状态寄存器的地址映射到0x1234。在程序中循环查看该状态寄存器的值是否变为非0。
下面是最容易想到,但错误的实现方法:
当你打开编译器优化时,程序总是执行失败。因为编译器会生成下面的汇编代码:
程序被优化的原因很简单,既然已经把变量的值读入累加器,就没有必要重新一遍,编译器认为值是不会变化的。就这样,在第三行,程序进入了无限死循环。为了告诉编译器我们的真正意图,我们需要修改函数的声明 |