volatile关键字使用说明

在嵌入式系统开发中,volatile 是一个关键字,用于告知编译器不要对被声明为 volatile 的变量进行优化,从而可以提供对特殊地址的稳定访问。

以下是一些使用 volatile 关键字的常见情况:

  1. 外部设备寄存器:当嵌入式系统需要与外部设备进行通信时,通常会使用 volatile 关键字声明用于访问设备寄存器的变量。这样可以确保对寄存器的读写操作不会被优化掉,以及保持与设备的同步。

  2. 共享变量:当多个任务或中断服务程序同时访问和修改同一个变量时,该变量应该声明为 volatile,以确保对变量的读写操作的顺序和可见性。这可以防止编译器对变量的读写操作进行优化,从而避免潜在的并发访问问题。

  3. 中断标志:在中断处理程序中,通常会使用 volatile 关键字声明用于标识中断状态的变量。这样可以确保对中断标志的读写操作不会被优化掉,以及保持与中断的同步。

需要注意的是,volatile 只能保证对变量的读写操作的可见性和顺序,但不能解决并发访问的同步问题。在多线程或多任务的环境中,还需要使用其他同步机制(如互斥锁或信号量)来保证对共享资源的安全访问。

注:程序为了提高运行速度,可能会将变量值缓存在寄存器中,等下次再用到这个变量时直接从寄存器中取数据,而不是从内存中取数据。如果使用volatile对变量进行修饰,那么系统总是从它所在的内存取数据。

volatile int i=10;

int a = i;

...

// 其他代码,并未明确告诉编译器,对 i 进行过操作

int b = i;

volatile 指出 i 是随时可能发生变化的,每次使用它的时候必须从 i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在 b 中。而优化做法是,由于编译器发现两次从 i读数据的代码之间的代码没有对 i 进行过操作,它会自动把上次读的数据放在 b 中(这会导致在其他地方对i的值进行改变了(例如在中断中对i的值进行累加),b读到的值是之前缓存在寄存器中的值,也就是i改变之前的值),而不是重新从 i 里面读。这样以来,如果 i是一个寄存器变量或者表示一个端口数据就容易出错,所以说 volatile 可以保证对特殊地址的稳定访问。

/*在单片机开发中等待某个时间的触发并相应经常会有如下程序:*/
Boolean flag=0;
void test()
{
    Task1();
    while(flag==0);
    Task2();
}

这段程序等待内存变量flag的值变为1之后才运行do2()。变量flag的值由别的程序更改,这个程序可能是某个硬件中断服务程序。例如

void EXTI1_IRQHandler(void)
{
	delay_ms(10);	//消抖
	if(KEY2==0)	  
	{				 
   		flag=1; 
	}		 
	EXTI_ClearITPendingBit(EXTI_Line2);//清除LINE2上的中断标志位 
}

flag值被按键KEY2的中断服务函数修改成为1,一旦KEY2被按下则flag被置为1。如果flag变量不被声明为volatile,则编译器并不知道flag的值会被别的程序修改,因此在它进行优化的时候,可能会把flag的值先读入某个寄存器,然后等待那个寄存器变为1。如果不幸进行了这样的优化,那么while循环就变成了死循环,因为寄存器的内容不可能被中断服务程序修改。为了让程序每次都读取flag变量真正的值,应该定义为:volatile Boolean flag=0;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发生了什么Bug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值