关键字volatile是什么声明?
一、
将一个变量说明为volatile表示这个变量是“易变的”。如果一个变量会被其它引用改变,或在其它并行的任务中会被改变(例如中断服务程序),都要显式地说明为“volatile”,否则在编译器优化阶段会作出错误的判断,例如将这个变量读入寄存器以后,在没有对这个变量赋值以前,会一直使用寄存器中的值,而实际上这个变量的值可能已经被一个指针引用改变了,或者是在中断服务程序中被改变了,下面这个例子说明这种错误:
有一个变量T,在定时中断中每隔一个固定时间减一,然后在主程序中等待它减到0
unsigned char T;
void T0_int(void) interrupt 1
{
...
T--;
...
}
void main(void)
{
...
T=10;
while (T!=0); /* 这在某些编译器中将成为一个死循环,而不是预想的等待一段时间 */
...
}
正确的写法应该是将第一句改为:
volatile unsigned char T;
*注:这个例子并不是针对特定的编译器,所以可能在有些编译器中能正确编译。但作为一个健壮的程序,一定要注意这一点,否则即使能得到正确结果,也会给程序移植或升级带来意想不到的问题。
二、
如果一个变量的值可能会被程序操作之外的其它操作所改变,那么你必需用volatile 声明。在嵌入式系统中其它操作是:中断服务程序的操作、硬件动作的操作。用volatile声明的变量是不会被编译器优化掉的
例如:
#define PortA ( * ( volatile unsigned int * ) 0x0000 )
这样 PortA 成为一个地址在0x0000的unsigned char类型变量。这个定义看起来很复杂,其实它也可以分解成几个很简单的部分来看。 ( volatile unsigned int * )是C语言中的强制类型转换,它的作用是把0x0000这个纯粹的十六进制数转换成为一个(地址)指针,其中volatile并不是必要的,它只是告诉编译器,这个值与外界环境有关,不要对它优化接下来在外面又加了一个*号,就表示0x0000内存单元中的内容了。经过这个宏定义之后,PortA就被可以做为一个普通的变量来操作,所有出现PortA的地方编译的时候都被替换成( * ( volatile unsigned int * ) 0x0000 ),外面一层括号是为了保证里面的操作不会因为运算符优先级或者其它不可预测的原因被改变而无法得到预期的结果。
PORTA做为一个输入端口,其值是由外部设备决定的,由于外部设备的变化是随机的,因此第一次读取的值和第二次读取的值很可能不同,所以我们把它声明为volatile变量。
a = PORTA; (PORT为AVR的IO口)
a = PORTA;
由于PORTA是用volatile声明的变量,编译器不会把它优化成一句,而如果不是volatile声明的编译器就会将第二句优化掉,从而程序将会忽略输入端口的变化。
通常把嵌入式设备的所有外围器件寄存器都声明为volatile 的。
这种定义方法适合所有的C编译器,可移植性好,但PortA并不是一个真正的变量,只是一个宏名,当你调试一个程序的时候,无法在调试窗口观察它的值。另外连接器也失去了灵活性,它得防止其它变量跟此变量冲突。
摘自:http://www.51eda.com/Article/embed_system/singlechip/200307/45.html
http://blog.csai.cn/user1/21439/archives/2007/19598.html
文章评论(0条评论)
登录后参与讨论