ARTS 挑战打卡的第8天 ---volatile 关键字在MCU中的作用,四个实例讲解(Tips)

news2025/1/17 0:22:52

前言

(1)volatile 关键字作为嵌入式面试的常考点,很多人都不是很了解,或者说一知半解。
(2)可能有些人会说了,volatile 关键字不就是防止编译器优化的吗?有啥好详细讲解的?那么,我就反问一句,为什么要防止编译器优化,编译器优化什么?编译器优化之后会产生什么问题?
(3)今天我就来详细解答一下这些疑惑。

软件延时所造成的bug

(1)在初学51单片机的时候,我们都是使用软件延时,例如下面是STC89,12MHZ晶振的1ms的软件延时。
(2)有些人说,这样写延时可以啊,没有问题。但是,假如你在MSP430中这样写,一定会产生bug。你会发现,软件延时没效果。
(3)这个时候,有些人会告诉你,要让CCS的编辑优化等级降低然后就可以了。
(4)这是为什么呢?如下代码,编译会发现,这就是让两个变量进行自减,于是编译器自作主张,认为这是没有意义的代码,并且将其删除。于是,你看汇编代码会发现,这里没有进行自减操作。
(5)但是,如果你加上volatile 关键字,就会发现,软件延时能够正常运行。这个是为什么呢?volatile 关键字会告诉编译器,这个变量你没有权限动,你不要擅自主张的进行优化。
(6)因此,我们可以知道,volatile 关键字其实就是告诉编译器,不要对变量进行优化。

void Delay1ms()		//@12.000MHz
{
	unsigned char i, j;
	//加上volatile 关键字
	//volatile unsigned char i, j;
	
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}

外设寄存器被异步修改所产生的bug

(1)假设我们现在有一个外设寄存器叫做ExternalDevice ,这个寄存器会自动减少,地址为0x1000。(例如定时器的计数器就会自己增加或减少)
(2)现在我们要等ExternalDevice 寄存器值变成0的时候,再进行一些操作。
(3)但是你实际跑的时候会发现,这个地方要么无法阻塞,要么永远阻塞。这是为什么呢?编译器是不知道ExternalDevice这个变量是一个寄存器的,也不知道他最终是怎么变化的。所以他就会认为,这个地方是一个不变的变量进行反复判断。他就会把while()这一行代码删除,认为是没有意义的。
(4)于是我们需要加上volatile 告诉编译器,这个东西你别动。

int main()
{
	//下面这三种写法是等价的
	//int volatile *ExternalDevice = (uint8_t volatile *)0x1000;  
	//volatile int *ExternalDevice = (uint8_t volatile *)0x1000; 
	//volatile int *ExternalDevice = (volatile uint8_t *)0x1000; 
    int *ExternalDevice = (uint8_t *)0x1000;  // 假设外设寄存器的地址是 0x1000
	while(*ExternalDevice == 0); //等待这个外设寄存器的值变成0再进行操作
}


全局变量在中断和正常运行的程序存在竞争问题

(1)比如群友给出一个这样的代码,发现一直无法实现点灯。感到非常的疑惑。
(2)这个地方就涉及到全局变量在中断和正常运行的程序存在竞争问题。我们会发现,中断程序和主函数里面都调用了全局变量a。但是,我们要知道,编译器是无法知道运行态的情况的,他只能够进行静态优化
(3)比如这里,编译器他会认为,变量a的赋值是0。然后主函数里面的while()判断是判断他是否为0。这个时候,他无法查看到串口中断的情况,就会认为,你就是要进行一个死循环。所以,最终这个程序最终会卡死在while(a == 0);这里。
(4)因此我们要将a加上volatile 关键字。

在这里插入图片描述

多线程共享变量

(1)当我们上了操作系统之后,都是会跑多线程的。
(2)但是跑多线程,就会存在一个问题,我们很可能会让一个变量让多个线程之间共享。例如,下面我们需要创建两个线程,一个是GUI图像显示,一个是按键扫描。他们都需要共享要给变量key_num。这个时候,编译器无法知道key_num什么时候会进行改变,所以他可能就会想,既然我不知道,我就不要他。所以,我们需要加上volatile 关键字,告诉编译器,这里不要搞骚操作

uint8_t key_num;
//线程1
void GUI()
{
	while(1)
	{
		switch(key_num)
		{
			case key_short_down:
				//...
				break;
			case key_long_down:
				//...
				break;
			case key_up:
				//...
				break;
		}
	}
}
//线程2
void key_scanf()
{
	while(1)
	{
		if(key_Pin == HIGH) key_num = key_up;
		else if(key_time < 2000) key_num = key_short_down;
		else  key_num = key_short_down;
	}
}
void main()
{
	register_task(GUI);
	register_task(key_scanf);
	while(1);
}

总结

(1)volatile 关键字本质就是编译器防止优化。但是我们也要明白,为什么编译器会进行优化。知道这个以后,我们才能够更好的使用volatile 关键字。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/869085.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

清除pip安装库时的缓存

目录 1、命令清除缓存 2、路径手动清除 在使用pip安装Python库时&#xff0c;如果之前已经下载过该库&#xff0c;pip会默认使用缓存来安装库&#xff0c;而不是重新从网络上下载。缓存文件通常存储在用户目录下的缓存文件夹中&#xff0c;具体位置因操作系统和Python版本而异…

C语言中几种常见数据类型所占字节数

**16位编译器&#xff1a; char/unsigned char &#xff1a;1字节 char &#xff1a;2字节 short int&#xff1a;2字节 int/unsigned int&#xff1a;2字节 long int&#xff1a;4字节 float&#xff1a;4字节 double&#xff1a;8字节* 32位编译器&#xff1a; *char/unsi…

腾讯云服务器标准型CVM实例详细介绍S5/S6/SA2/SR1/SA3/S4等

腾讯云CVM服务器标准型实例的各项性能参数平衡&#xff0c;标准型云服务器适用于大多数常规业务&#xff0c;例如&#xff1a;web网站及中间件等&#xff0c;常见的标准型云服务器有CVM标准型S5、S6、SA3、SR1、S5se等规格&#xff0c;腾讯云服务器网来详细说下云服务器CVM标准…

悬崖传感器调试问题总结

悬崖传感器原理 使用ADC采样电路&#xff0c;周期的进行开/关灯&#xff0c;获取ADC采样值。根据预先设置好ADC门限&#xff0c;判断是否为悬崖。ADC的精度是12位&#xff0c;对应电路的电压是3.3伏&#xff0c;悬崖传感器通过开灯和关灯&#xff0c;接收的不同灯光强度&#x…

【福建事业单位-数学运算】02工程问题-行程问题

【福建事业单位-数学运算】02工程问题-行程问题 一、工程问题1.1给完工时间型&#xff08;给多个完工时间&#xff09;——从时间赋值总量例题 1.2 给效率比例型&#xff08;给效率的比例关系&#xff09;直接给效率间接给效率&#xff08;★&#xff09;特殊给效率 1.3 给具体…

掌握Python的X篇_30_使用python解析网页HTML

本篇将会介绍beutifulsoup4模块&#xff0c;可以用于网络爬虫、解析HTML和XML&#xff0c;对于没有接触过前端&#xff0c;不了解HTML是如何工作的&#xff0c;需要先解释一下什么事HTML。 1. HTML 网页中的各种布局等的背后都是非常简单的纯文本格式&#xff0c;那种格式称为…

【JDBC系列】- 扩展提升学习

扩展提升学习 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f3c6; 博客首页 怒放吧德德 To记录领地 &#x1f31d;分享学习心得&#xff0c;欢迎指正&#xff0…

Golang 基本常量声明及 iota 使用

文章目录 一、局部常量声明二、全局常量声明三、多行常量定义&#xff0c;值表达式为空时自动继承前一个四、常量声明 - iota 一、局部常量声明 package mainimport "fmt"func main() {//局部常量声明//方式一&#xff1a;主动声明类型const lengthA int 10//方式二…

tomcat设置PermSize

最近tomcat老是报错,查看了日志出现PermGen 内存不够用,重启tomcat后查询使用情况 通过启动参数发现没有设置 PermGen,继续通过jmap查看 jmap -heap 21179 发现99%已使用,而且默认是30.5M,太小了,这里设置成256M 1. 创建setenv.sh文件 在/usr/local/tomcat/bin目录下创建一个…

CDN是什么?CDN的好处

近段时间开组会的时候组内的大佬多次提及CDN这个名词&#xff0c;因为以前没有接触过&#xff0c;所以上网查询后写一篇博客来巩固自己对于CDN的理解 1、什么是CDN CDN的全称是Content Delivery Network&#xff0c;即内容分发网络。其目的是通过在现有的Internet中增加一层新…

Linux命令200例:ls用于列出指定目录下的文件和子目录

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &…

Java实现对称加密(DES,AES)快速入门示例

对称加密是使用相同的密码进行加密和解密&#xff0c; 对称加密实现简单&#xff0c;安全性相比非对称加密较弱&#xff0c; 常用的对称加密算法有 DES&#xff0c;AES以及PDE等&#xff0c;关于对称加密相关概念参考&#xff1a; 对称加密、非对称加密深度解析 本篇介绍Java的…

【CSH 入门基础 5 -- csh 文件监控脚本实现】

文章目录 背景CSHLL 代码实现cshell 中 unset 的介绍bash 中监控文件的方法 背景 由于开发代码是在外网编译&#xff0c;而镜像的烧写是在内网中的EDA工具中进行的&#xff0c;所以就需要先将代码在外网编译好后&#xff0c;再通过FTP工具将镜像传输到内网中&#xff0c;然后在…

MyBatis配置文件:配置连接数据库的环境,实现数据库连接

目录 1、MyBatis配置数据库环境的连接方式 1.1连接方式一&#xff1a;MyBatis核心配置文件配置数据库连接信息 1.2连接方式二&#xff1a;在MyBatis核心配置文件中引入properties文件&#xff0c;配置数据库的环境 2、MyBatisd核心配置文件连接数据库的环境完整配置信息 3…

Win11麦克风说话别人听不见解决办法

Win11麦克风说话别人听不到声音怎么办&#xff1f;麦克风没有声音可能有三种原因造成的&#xff0c;第一种声音设置里面确认麦克风设备是否启用&#xff0c;第二种查看麦克风的访问权限&#xff0c;第三种是检查驱动是否有问题&#xff0c;下面就简单的讲一下解决方法&#xff…

【loadbalancer】还在用Ribbon?试试Spring自带的LoadBalancer吧

Spring Cloud LoadBalancer是Spring Cloud官方自己提供的客户端负载均衡器, 用来替代Ribbon。 Spring官方提供了两种客户端都可以使用loadbalancer&#xff1a; RestTemplate&#xff1a;Spring提供的用于访问Rest服务的客户端&#xff0c;RestTemplate提供了多种便捷访问远程…

【第二阶段】it关键字

1.invoke&#xff08;&#xff09;函数 meThod1(1,2,3)等价meThod1.invoke(1,2,3) fun main() {val meThod1:(Int,Int,Int)->String{n1,n2,n3->val num"kotlin"println("num$num,n1$n1,n2$n2,,n3$n3")"num$num,n1$n1,n2$n2,,n3$n3,"}//调…

Vue响应式数据的原理

在 vue2 的响应式中&#xff0c;存在着添加属性、删除属性、以及通过下标修改数组&#xff0c;但页面不会自动更新的问题。而这些问题在 vue3 中都得以解决。 vue3 采用了 proxy 代理&#xff0c;用于拦截对象中任意属性的变化&#xff0c;包括&#xff1a;属性的读写、属性的…

前端使用ReadableStream.getReader来处理流式渲染

文章目录 前言一、纯css二、vue-typed-js插件1.安装2.注册3.使用总结 三、ReadableStream1.ReadableStream是什么&#xff1f;2.ReadableStream做什么&#xff1f;3.ReadableStream怎么用 前言 需求&#xff1a;让接口返回的文章根据请求一段一段的渲染&#xff0c;同时可以点击…

Spring MVC视图解析器

Spring MVC视图解析器 ➢ AbstractCachingViewResolver&#xff1a;➢ XmlViewResolver&#xff1a;➢ ResourceBundleViewResolver➢ UrlBasedViewResolver&#xff1a;➢ InternalResourceViewResolver&#xff1a;➢ FreeMarkerViewResolver➢ ContentNegotiatingViewResolv…