Keil5中写的软件延时函数不起作用现象解析_ARM_Compiler_volatile关键字

news/2024/5/10 6:48:19/文章来源:https://blog.csdn.net/weixin_44911552/article/details/131522306

一、问题描述

在学习野火霸天虎F407寄存器点亮LED时,出现实验现象:LED灯不亮,野火霸天虎F407资料。
在这里插入图片描述

main.c代码如下:

#include "stm32f4xx.h"void Delay(unsigned int count);int main(void)
{   
#if 0/* 第一步:开启GPIO端口的时钟 *//* 打开GPIOF端口的时钟 */*(unsigned int *)(0x40023800+0x3f0) |= (1<<5);/* 第二步:控制GPIO的方向 *//* GPIOF 配置为输出 */*(unsigned int *)(0x40021400+0x00) &= ~((0x03) << (2*6));*(unsigned int *)(0x40021400+0x00) |= (1 << (2*6));/* 第三步:控制GPIO的数据输出寄存器 *//* PF6 输出高电平 */*(unsigned int *)(0x40021400+0x14) |= (1 << 6);/* PF6 输出低电平 */*(unsigned int *)(0x40021400+0x14) &= ~(1 << 6);#elif 0/* 第一步:开启GPIO端口的时钟 *//* 打开GPIOF端口的时钟 */RCC_AHB1ENR |= (1<<5);/* 第二步:控制GPIO的方向 *//* GPIOF 配置为输出 */GPIO_MODER &= ~((0x03) << (2*6));GPIO_MODER |= (1 << (2*6));/* 第三步:控制GPIO的数据输出寄存器 *//* PF6 输出高电平 */GPIO_ODR |= (1 << 6);/* PF6 输出低电平 */GPIO_ODR &= ~(1 << 6);
#elif 0//任务1-把其他两个灯也点亮RCC_AHB1ENR |= (1<<5); //开启GPIO端口时钟//设置GPIOF6为推挽输出GPIO_MODER &= ~((0x03) << (2*6));  GPIO_MODER |= (1 << (2*6));GPIO_ODR |= (1 << 6);GPIO_ODR &= ~(1 << 6);//设置GPIOF7为推挽输出GPIO_MODER &= ~((0x03) << (2*7));  GPIO_MODER |= (1 << (2*7));GPIO_ODR |= (1 << 7);GPIO_ODR &= ~(1 << 7);//设置GPIOF8为推挽输出GPIO_MODER &= ~((0x03) << (2*8));  GPIO_MODER |= (1 << (2*8));GPIO_ODR |= (1 << 8);GPIO_ODR &= ~(1 << 8);#elif 1//任务1-把其他两个灯也点亮RCC_AHB1ENR |= (1<<5); //开启GPIO端口时钟//设置GPIOF6为推挽输出GPIO_MODER &= ~((0x03) << (2*6));  GPIO_MODER |= (1 << (2*6));//设置GPIOF7为推挽输出GPIO_MODER &= ~((0x03) << (2*7));  GPIO_MODER |= (1 << (2*7));//设置GPIOF8为推挽输出GPIO_MODER &= ~((0x03) << (2*8));  GPIO_MODER |= (1 << (2*8));while(1){GPIO_ODR &= ~(1 << 6);Delay(0xfffff);GPIO_ODR |= (1 << 6);Delay(0xfffff);GPIO_ODR &= ~(1 << 7);Delay(0xfffff);GPIO_ODR |= (1 << 7);Delay(0xfffff);GPIO_ODR &= ~(1 << 8);Delay(0xfffff);GPIO_ODR |= (1 << 8);Delay(0xfffff);}  #endif 
}//延时函数
void Delay(unsigned int count)
{for(;count!=0;count--);
}void SystemInit(void)
{/* 函数体为空,目的是为了骗过编译器不报错 */
}/*
1-把其他两个灯也点亮
2-实现三个灯闪烁(时间的控制使用软件延时)
*/

二、问题分析

通过分析main.c代码,导致出现上述现象的间接原因是延时函数没有起作用。检查延时函数的实现代码,并没有错误。这不禁使我想起《程序员的自我修养——链接、装载、库》一书所提到的程序源代码经过预编译-》编译-》汇编-》链接,所以极大可能是编译器在编译过程中优化掉了我的延时函数,使得整个程序不能按照预定功能实现。

打开keil5的调试功能,查看对应main.c的反汇编文件:
经过优化的delay函数:
在这里插入图片描述
未经过优化的delay函数:
在这里插入图片描述
优化之后的 delay 函数没有for循环延时操作,因此失去延时的效果。

三、问题解决

3.1 降低ARM Compiler version

在Target设置界面下,Code Generation默认的是ARM Compiler version 6。
在这里插入图片描述
将ARM Compiler version 6改为ARM Compiler version 5即可。在这里插入图片描述

3.2 volatile关键字修饰

volatile关键字影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错。volatile关键字最通俗的解释是,告诉编译器这个变量我有其他用,不要给我随便优化掉。

原延时函数

//延时函数
void Delay(unsigned int count)
{for(;count!=0;count--);
}

添加volate关键字修饰

//延时函数
void Delay(volatile unsigned int count)
{for(;count!=0;count--);
}

推荐使用方法2,原因如下:

1.自定义延时函数中使用 volatile 去声明 val 变量可以解决编译器优化带来的延时失效问题;
2.编译器优化可以使代码更加精炼,执行效率更高。

参考资料

1. Keil AC5 和 AC6的一些区别
2. 编译器优化对自定义延时程序的影响(volatile详解实验一)
3. C语言丨深入理解volatile关键字

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

oracle rowscn 简单记录

可以通过ROWSCN 侦测row是否有变化&#xff0c;但需要注意&#xff1a; 默认是一个block的scn 相同可以通过create table ROWDEPENDENCIES 在每行上记录无论哪种模式&#xff0c;ROW SCN是一个大致值&#xff0c;不是准确值 NOROWDEPENDENCIES | ROWDEPENDENCIES This claus…

Maven安装和配置详细教程

Maven安装和配置详细教程 1、Maven简介 Maven 是 Apache 软件基金会的一个开源项目,是一个优秀的项目构建工具,它用来帮助开发者管理项目中的 jar,以及 jar 之间的依赖关系、完成项目的编译、测试、打包和发布等工作。 2、Maven下载 点击Maven下载官方地址下载Maven。或者去…

C#与C++编程环境对比:优点与应用场景详解

C#与C是两种常用的编程语言&#xff0c;它们在编程环境方面有一些相同点和不同点。首先&#xff0c;它们都可以用于开发跨平台的应用程序。其次&#xff0c;它们都具有强大的面向对象编程能力。但是&#xff0c;它们在语法、性能和应用领域等方面存在一些不同点 。 在语法方面…

使用Wireshark 找出 TCP 吞吐瓶颈

Debug 网络质量的时候&#xff0c;我们一般会关注两个因素&#xff1a;延迟和吞吐量&#xff08;带宽&#xff09;。延迟比较好验证&#xff0c;Ping 一下或者 mtr[1] 一下就能看出来。这篇文章分享一个 debug 吞吐量的办法。 看重吞吐量的场景一般是所谓的长肥管道(Long Fat …

【C】数据在内存中的存储

前言 > 在内存中&#xff0c;整型和浮点型存储的方式是不同的&#xff0c;从内存中读取的方式也是有所差异的&#xff0c;这篇文章主要介绍整型和浮点型在内存中存储的方式。 整型在内存中的存储 计算机中有符号数有3种表示方式&#xff1a; 原码&#xff1a;直接将二进制按…

GO语言包相关总结 -引用(本地和远程),自定义,安装,使用

本篇文章总结以下go语言包相关的知识。 目录 一.导入包 &#xff08;1&#xff09;常规导入 &#xff08;2&#xff09;别名导入 &#xff08;3&#xff09;特殊导入 二.自定义包 三.安装自定义包 四.调用自定义包调用 五.获取远程包 六.go中的保留函数 七.实战 - G…

机器学习技术(二)——Python科学运算模块(Numpy、Pandas)

机器学习技术&#xff08;二&#xff09;——Python科学运算模块&#xff08;Numpy、Pandas&#xff09; 文章目录 机器学习技术&#xff08;二&#xff09;——Python科学运算模块&#xff08;Numpy、Pandas&#xff09;一、Numpy1、介绍、安装与导入2、Numpy常用操作 二、Pan…

mybatis多参数传递报错问题分析+硬核mybatis底层源码分析+@Param注解+图文实战环境分析【4500字详解打通,没有比这更详细的了!】

文章目录 1.问题描述2.问题场景模拟再现2.1 场景环境2.2 数据库与表创建2.3 Maven环境搭建&#x1f340; pom.xml导入依赖&#x1f340; jdbc.properties&#x1f340; mybatis-config.xml&#x1f340; User实体类&#x1f340; Mapper 接口&#x1f340; UserMapper.xml 映射…

IT-OT 安全融合是优化风险管理的关键

最新报告揭示了运营技术检测和响应方面的显着可见性差距。 全球网络安全运营商趋势科技宣布了一项新研究&#xff0c;显示企业安全运营中心 (SOC) 正在将其能力扩展到 OT 领域。 然而&#xff0c;重大的可见性和技能相关的挑战仍然造成障碍。 研究发现&#xff0c;一半的组织…

决策树ID3

文章目录 题目一基础知识解题过程①算总的信息量②求解各个指标的信息增益&#xff0c;以此比较得出根节点③ 从根节点下的晴天节点出发循环上述步骤④ 从根节点下的多云节点出发&#xff0c;循环上述步骤⑤ 从根节点下的雨节点出发&#xff0c;循环上述步骤⑥画出最终的决策树…

4.设计模式之后七种模式后11种模式命令访问者迭代器发布订阅中介者忘备录解释器状态策略职责链和空模式

1.命令(command)模式 不知道命令接收者(对象)是谁,支持撤销 (接受者 间接调用执行 的具体行为) 命令调用者和接收者解耦 //只要实现命令接口即可 (就是客户端给个命令,然后命令类传给接收类执行) 优点和缺点 容易撤销操作 命令队列可以多线程操作 增加过多的命令类 空命令也是一…

揭秘元宇宙背后的最炫科技风

&#xff1a;元宇宙&#xff0c;这个词汇在近年来越来越被人们所熟知。它是一个虚拟的世界&#xff0c;由数字化的现实世界和虚拟现实技术所构成。在元宇宙中&#xff0c;人们可以自由地探索、交互、创造和享受各种虚拟体验。而这一切&#xff0c;都离不开最炫科技风的支持。 …

道路车辆功能安全第2 部分:功能安全管理

道路车辆功能安全 第2 部分&#xff1a;功能安全管理 1 范围 GB/T 34590的本部分规定了应用于汽车领域的功能安全管理的要求&#xff0c;包括&#xff1a; ——独立于项目的关于所涉及组织的要求&#xff08;整体安全管理&#xff09;&#xff1b;及 ——项目特定的在安全生命周…

Docker常见问题集合

一、Docker安装 1、yum 安装 1&#xff09;更新yum包到最新 yum update2&#xff09;安装软件需要的软件&#xff0c;yum-util&#xff08;提供 yum-config-manager 功能&#xff09;&#xff0c;device-mapper-persistent-data、lvm2&#xff08;devicemapper 驱动依赖&…

【Linux】Redis 集群部署

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 Redis 集群部署 Redis 主从复制主从复制的作用主从复制的流程搭建Redis 主从复制安装 Redis修改 Redis 配置文件&#xff08;Master节点操作&#xff09;修改 Redis 配置文件…

STM32——建工程

文章目录 一、建工程步骤1. 创建一个工程文件2. 里面创建四个文件3. Lib&#xff1a;存放标准库的.c和.h文件&#xff0c;其中inc放置.h文件&#xff0c;src放置.c文件4. Startup中存放驱动文件5.User文件中包含以下路径以下文件6.创建工程Project 一、建工程步骤 以STM32F10X…

百万连接实现01:使用epoll+多线程+多IP地址管理tcp客户端集群

操作系统采用 <客户端IP : 客户端端口> : <服务端IP : 服务端端口> 四元组来标识一条TCP连接。 所以要想实现百万连接&#xff1a; 第一种是服务器端只开启一个进程&#xff0c;然后使用很多个客户端进程绑定不同的客户端 ip 来连接&#xff0c;假设 20个ip * 5w&a…

AIGC - Easy Diffusion (Stable Diffusion) 图像生成工具的环境配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/131524075 版本v2.5.41 Stable Diffusion 图像生成工具是一种基于深度学习的技术&#xff0c;可以从随机噪声中生成高质量的图像&#x…

计模式篇(Java):桥接模式

上一篇&#xff1a;计模式篇(Java)&#xff1a;适配器模式 九、桥接模式 需求示例 当我们对不同手机类型的不同品牌实现操作编程&#xff0c;如图&#xff1a; 那么它对应的类图就是 传统方式解决需求分析&#xff1a; 扩展性问题&#xff0c;如果需要在增加手机的样式&#x…

自学网络安全究竟该从何学起?

一、为什么选择网络安全&#xff1f; 这几年随着我国《国家网络空间安全战略》《网络安全法》《网络安全等级保护2.0》等一系列政策/法规/标准的持续落地&#xff0c;网络安全行业地位、薪资随之水涨船高。 未来3-5年&#xff0c;是安全行业的黄金发展期&#xff0c;提前踏入行…