| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 嵌入式 -> 单片机中volatile的应用 -> 正文阅读 |
|
[嵌入式]单片机中volatile的应用 |
01、简述一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。 如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。 简单来说,如果这变量很重要,且你不想它被编译器优化,就用volatile修饰。 02、用处关于编译器优化 如果你在编译器器开了优化,那么就要小心了。以下代码使用IAR7.20,优化等级High,选Balanced。main函数的主循环如下
其中LCD_refresh_flg变量在串口中断中
其中延时函数如下
这是简单的示例代码(为了说明问题,实际项目开发应该没有类似的代码),代码设计的意图是串口收到数据,LCD显示字符串。但debug时如下 在单步执行时,第85行代码被直接跳过了,且在85行也无法打断点。查看反汇编代码,确认第85,87,88,89代码直接被编译器优化没了。 可能编译器在想,在85行将LCD_refresh_flg变量清零,而86行代码量又不大,所以认为87行的if条件不成立,这全部优化掉了。编译器完全没有想到我们的延时长达500ms,且在串口中断中会将LCD_refresh_flg置1,这完全违背我们的设计意图。 如果我们将LCD_refresh_flg使用volatile修饰,volatileuint8_t LCD_refresh_flg;在编译器不变,优化等级不变时,运行如下: 虽然编译器和优化等级都是一样的,但是这个时候,不再优化LCD_refresh_flg变量。 当然这是编译优化的结果,并不是说,在main函数的主循环的先对变量清零,再后边判断变量就会被编译器优化。如下代码,LCD_refresh_flg没有使用volatile修饰。 此时LCD_ShowString函数是代码量很大的函数,这个时候编译器就不敢轻易优化LCD_refresh_flg变量了。希望大家能从这个例子中理解volatile对编译优化的影响。 关于访问硬件 存储器映射的硬件寄存器通常也要加voliate,因为每次对它的读写都可能有不同意义。例如:假设要对一个设备进行初始化,此设备的某一个寄存器为0xff800000。(例子仅为说明问题,不具有实战意义)
经过编译器优化后,编译器认为前面循环半天都是废话,对最后的结果毫无影响,因为最终只是将output这个指针赋值为9,所以编译器最后给你编译编译的代码结果相当于:
这明显是不符合我们的设计意图的。 不仅仅是写操作,读操作亦是如此。如果你需要反复读取一个寄存器的值,那么编译器在优化只有读取1次。这时候就该使用volatile通知编译器在遇到此变量时候不要优化。在这里多说一句,我们这里说的是编译器,且是嵌入式方面的,不同的编译器会有不同结果,所以上面的例子并非是在不同的编译器必现的。但是在嵌入式领域反复访问硬件寄存器,加上volatile是有必要的。 中断服务程序 在断服务程序中修改的供其它程序检测的变量,需要加volatile,中断是会突然发生的,当变量在触发某中断程序中修改,而编译器判断主函数里面没有修改该变量,因此可能只执行一次从内存到某寄存器的读操作,而后每次只会从该寄存器中读取变量副本,使得中断程序的操作被短路。加上volatile修饰,内核每次都会小心的从该变量存储的内存中重新读取数据,而不是从已经加载到内核寄存器中的值。 RTOS系统下需要注意 这个问题本质上和上一个是一样的,都是为了防止内核从寄存器中读取变量的值,而不是从变量存储的内存读取。特别是具有抢占属性的RTOS,本质上也是中断时,紧急的任务立即打断了正在执行的任务,“类似”于中断。如果有同学了解RTOS的话,可以想一下RTOS的临界区的概念,都是为了保护变量。这里不再对RTOS进行详述。如果有同学了解Linux的话,那就更好了,volatile的作用和linux的原子操作是差不过的。这里也不再详述,只是发散一下思维。 3、volatile问题volatile在面试中是非常容易见到的,下面总结一下常见的 1.一个参数既可以是const还可以是volatile吗? 可以的,例如只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。 2.一个指针可以是volatile吗? 可以,当一个中服务子程序修改一个指向buffer的指针时。 3.下面的函数有什么错误?
该程序的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
由于*ptr的值可能被意想不到地改变,因此a和b可能是不同的。结果,这段代码可能返回不是你所期望的平方值!正确的代码如下:
注意:频繁地使用volatile很可能会增加可执行文件的大小和降低性能,因此要合理的使用volatile,不能滥用volatile。 4、总结volatile 关键字是一种类型修饰符,它的总结如下
嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,这是区分C程序员和嵌入式系统程序员的最基本的问题,所以在嵌入式应用中这些要求使用volatile变量。不懂得volatile的话可能将会带来灾难。 点击查看:C语言进阶专辑 |
|
嵌入式 最新文章 |
基于高精度单片机开发红外测温仪方案 |
89C51单片机与DAC0832 |
基于51单片机宠物自动投料喂食器控制系统仿 |
《痞子衡嵌入式半月刊》 第 68 期 |
多思计组实验实验七 简单模型机实验 |
CSC7720 |
启明智显分享| ESP32学习笔记参考--PWM(脉冲 |
STM32初探 |
STM32 总结 |
【STM32】CubeMX例程四---定时器中断(附工 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 8:52:30- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |