volatile
Posted yuhaowen_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了volatile相关的知识,希望对你有一定的参考价值。
volatile a不稳定的;易变的;结合程序,我更愿意理解为“不优化的”。volatile类型的变量,程序每次读取时都会到原地址读取变量值,而不是直接获取寄存器内缓存的变量副本。这一点,我还没有深切的感受。但是“不优化”概念在Os优化等级下,我有些理解。
GCC编译器存在四个优化等级(optimization level),从低到高依次为O0(不优化)、O1(默认优化等级)、O2、Os、O3。以嵌入式开发为例,在main.c中声明变量 int temp=0,在主循环中判断 temp是否等于255,在不同优化等级下程序执行会存在不同的结果。
全局头文件 #includes.h文件
//(4)声明全局变量。命名规范见注2。
//【不动】宏定义全局变量前缀G_VAR_PREFIX。实现原理见注3。
#ifdef GLOBLE_VAR //GLOBLE_VAR在main.c文件中有宏定义
#define G_VAR_PREFIX //前缀G_VAR_PREFIX定义为空
#else //GLOBLE_VAR在非main.c文件中无定义
#define G_VAR_PREFIX extern //前缀G_VAR_PREFIX定义为"extern"
#endif
//(在此增加全局变量)
//(系统保留)
G_VAR_PREFIX vuint16_t gcRecvLen;
G_VAR_PREFIX vuint16_t gcRecvDCLen;
G_VAR_PREFIX vuint8_t gcReccrc32[4];
G_VAR_PREFIX vuint8_t gcRecvBuf[MCU_SECTORSIZE];
//(用户增加)
G_VAR_PREFIX vuint8_t temp;
中断处理程序源文件isr.c文件
//======================================================================
//程序名称:UART_User_Handler
//触发条件:UART_User串口收到一个字节触发
//备 注:进入本程序后,可使用uart_get_re_int函数可再进行中断标志判断
// (1-有UART接收中断,0-没有UART接收中断)
//======================================================================
void UART_User_Handler(void)
//(1)变量声明
uint8_t flag,ch;
DISABLE_INTERRUPTS; //关总中断 防止其他中断程序影响串口接收中断程序
//(2)未触发串口接收中断,退出
if(!uart_get_re_int(UART_User)) goto UART_User_Handler_EXIT;
//(3)收到一个字节,读出该字节数据
ch = uart_re1(UART_User,&flag); //调用接收一个字节的函数
if(!flag) goto UART_User_Handler_EXIT; //实际未收到数据,退出
//(4)接收到数据后,对temp变量重新赋值
if(ch=='P'||ch=='p')
temp=255;
//(5)【公共退出区】
UART_User_Handler_EXIT:
ENABLE_INTERRUPTS;//开总中断
main.c 文件
//(1.1)声明main函数使用的局部变量
uint32_t mMainLoopCount; //主循环次数变量
uint8_t mFlag; //灯的状态标志
uint32_t mLightCount; //灯的状态切换次数
//(1.2)【不变】关总中断
DISABLE_INTERRUPTS;
//(1.3)给主函数使用的局部变量赋初值
temp=0; //主循环次数变量
mMainLoopCount=0; //主循环次数变量
mFlag='A'; //灯的状态标志
mLightCount=0; //灯的闪烁次数
//(1.4)给全局变量赋初值
temp=0;
//(1.5)用户外设模块初始化
gpio_init(LIGHT_BLUE,GPIO_OUTPUT,LIGHT_ON); //初始化蓝灯
uart_init(UART_User,115200);
//(1.6)使能模块中断
uart_enable_re_int(UART_User);
(2)======主循环部分(开头)========================================
for(;;) //for(;;)(开头)
//(2.1)主循环次数变量+1
mMainLoopCount++;
//(2.2)未达到主循环次数设定值,继续循环
if (mMainLoopCount<=12888999) continue;
//(2.3)达到主循环次数设定值,执行下列语句,进行灯的亮暗处理
//(2.3.1)清除循环次数变量
mMainLoopCount=0;
//O0优化等级下,temp为非volatile变量,该语句编译后不变,仍为 while(temp==!255)
//Os优化等级下,temp为非volatile变量,该语句编译后改变,被优化为 while(true)
//Os优化等级下,temp为volatile变量,该语句编译后不变,仍为 while(temp==!255)
while(temp==!255)
//(2.3.2)如灯状态标志mFlag为'L',灯的闪烁次数+1并显示,改变灯状态及标志
if (mFlag=='L') //判断灯的状态标志
mLightCount++;
printf("灯的闪烁次数 mLightCount = %d\\n",mLightCount);
mFlag='A'; //灯的状态标志
gpio_set(LIGHT_BLUE,LIGHT_ON); //灯“亮”
printf(" LIGHT_BLUE:ON--\\n"); //串口输出灯的状态
//(2.3.3)如灯状态标志mFlag为'A',改变灯状态及标志
else
mFlag='L'; //灯的状态标志
gpio_set(LIGHT_BLUE,LIGHT_OFF); //灯“暗”
printf(" LIGHT_BLUE:OFF--\\n"); //串口输出灯的状态
//for(;;)结尾
//(2)======主循环部分(结尾)========================================
//main函数(结尾)
O0优化等级下,temp是否volatile变量,while(temp==!255)语句编译后不变,仍为 while(temp==!255),程序运行结果不变。
Os优化等级下,temp为非volatile变量,while(temp==!255)语句编译后改变,被优化为 while(true),小灯亮暗永远不会改变。
Os优化等级下,temp为volatile变量,该语句编译后不变,仍为 while(temp==!255),UART_User串口接收到数据后,temp变量被赋值为255,程序从while循环跳出,小灯亮暗状态不断切换。
以上是关于volatile的主要内容,如果未能解决你的问题,请参考以下文章