Keil MDK查看延时函数延时时间

本文介绍了两种测量延时函数的方法:一是使用Debug模式并利用断点来计算延时时间;二是采用逻辑分析仪进行仿真测量。前者通过计算两次断点间的时间差得到延时函数的实际延时时间,后者虽然精度较低但更为直观。
方法一:
1)进入Debug模式,在延时函数两侧打上断点  
2)全速运行,到第一个断点处,在左侧Registers->Internal->Sec可以看到执行断点处用时:0.00006106s,如下图
34.jpg

3)再次全速运行,到另一个断点处,用时:0.30006172s,如下图
34.jpg

4)两者相减即得delay_ms(300)函数延时时间:300.00066ms
34.jpg

方法二:
采用仿真的逻辑分析仪,如下图
其精度不如硬件仿真得出的结果
34.jpg
<think>我们参考了用户提供的引用内容,特别是引用[2]和[3]中关于延时函数的实现和调试方法,以及引用[4]中关于编译器选择的问题。 在Keil MDK中,延时函数通常有两种实现方式:阻塞延时和非阻塞延时。阻塞延时会占用CPU直到延时结束,而非阻塞延时则通过定时器中断等方式实现,允许CPU执行其他任务。 用户询问如何编写或生成延时函数,我们将介绍两种常见的阻塞延时函数编写方法,并说明如何利用Keil的调试功能验证延时时间。 方法一:使用SysTick定时器实现阻塞延时(推荐) SysTick定时器是Cortex-M内核的一个24位倒计时定时器,通常用于操作系统的时钟节拍,也可以用来实现精确延时。 步骤: 1. 配置SysTick定时器,设置重装载值(根据系统时钟频率和所需延时时间计算)。 2. 编写延时函数,通过查询SysTick的计数标志位来实现延时。 示例代码(以1ms延时为例,假设系统时钟频率为72MHz): ```c #include <stdint.h> // 定义SysTick控制寄存器地址 #define SysTick_CTRL (*(volatile uint32_t *)0xE000E010) #define SysTick_LOAD (*(volatile uint32_t *)0xE000E014) #define SysTick_VAL (*(volatile uint32_t *)0xE000E018) // 系统时钟频率(单位Hz) #define SYSTEM_CLOCK_FREQ 72000000 // 初始化SysTick定时器 void SysTick_Init(void) { // 设置重装载值,用于1ms中断 SysTick_LOAD = (SYSTEM_CLOCK_FREQ / 1000) - 1; // 清空当前计数值 SysTick_VAL = 0; // 选择时钟源为系统时钟,开启SysTick定时器(不使能中断) SysTick_CTRL = 0x05; // 0b0101: 使能SysTick,使用处理器时钟,不使能中断 } // 阻塞延时函数,单位ms void delay_ms(uint32_t ms) { // 设置重装载值(每次延时都需要重新设置,因为重装载值可能被中断修改) SysTick_LOAD = (SYSTEM_CLOCK_FREQ / 1000) - 1; SysTick_VAL = 0; // 清空计数器 for (uint32_t i = 0; i < ms; i++) { // 等待计数到0 while (!(SysTick_CTRL & 0x00010000)); // 等待COUNTFLAG标志置位 } } ``` 方法二:使用循环计数实现阻塞延时(不精确,受优化影响) 这种方法通过执行空循环来消耗时间,但延时精度受编译器优化和CPU频率影响。 示例代码: ```c void delay_ms(uint32_t ms) { for (uint32_t i = 0; i < ms; i++) { for (volatile uint32_t j = 0; j < 1000; j++); // 调整循环次数以适应系统时钟 } } ``` 注意:循环延时的精确性需要根据实际时钟频率调整循环次数,且容易受编译器优化影响。建议使用volatile关键字防止被优化。 方法三:利用Keil内置的__nop()函数(精确到单周期) 如果需要精确的短延时(几个机器周期),可以使用内联汇编或Keil提供的__nop()函数(在头文件intrins.h中)。 示例代码(延时10个nop): ```c #include <intrins.h> void delay_10nop(void) { __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); } ``` 关于编译器优化问题(参考引用[4]): 在Keil MDK中,如果使用循环计数延时,可能会因为编译器优化(尤其是AC6)而导致延时时间不准确。解决方法: 1. 将循环变量声明为volatile。 2. 或者使用AC5编译器(在Target Options->C/C++->AC5或AC6中选择)。 3. 或者调整优化等级(例如设置为-O0不优化)。 验证延时时间: 可以使用Keil的调试功能(如引用[2]所述)来验证延时时间: 1. 在延时函数前后设置断点。 2. 运行程序,记录两次断点处的时间戳,计算差值。 步骤: 1. 在Debug配置中设置正确的晶振频率(Target选项卡)。 2. 在Debug选项卡中设置硬件仿真,并在Trace选项卡中设置正确的系统时钟频率,并启用Trace。 3. 进入调试模式,在延时函数前后打上断点,记录时间。 注意:使用SysTick定时器实现的延时更精确,推荐使用。 总结: 1. 对于精确延时,推荐使用SysTick定时器。 2. 对于简单的短延时,可以使用__nop()或循环延时(注意优化问题)。 3. 使用Keil调试功能验证延时时间。 如果用户使用的是STM32CubeMX生成的代码,也可以使用HAL库提供的延时函数HAL_Delay(),该函数也是基于SysTick实现的。 相关问题: 1. 如何配置SysTick定时器以实现精确延时? 2. 在Keil中如何调试延时函数时间? 3. 为什么循环延时函数Keil AC6编译器中不工作,如何解决? 4. 除了SysTick,还有哪些定时器可以用来实现延时? 5. 如何实现非阻塞延时?</think>在Keil MDK中编写延时函数主要有两种方式:**阻塞延时**(占用CPU)和**非阻塞延时**(基于中断)。以下是具体实现方法和注意事项: --- ### 一、阻塞延时函数(简单但占用CPU) #### 1. **循环计数法** ```c #include <stdint.h> // 通过空循环消耗时间(精度低,受优化影响) void delay_ms(uint32_t ms) { for (uint32_t i = 0; i < ms * 1000; i++) { for (volatile uint32_t j = 0; j < 1000; j++); // volatile防止被优化 } } ``` **注意**: - 使用 `volatile` 关键字防止编译器优化空循环[^3][^4]。 - 循环次数需根据实际时钟频率调整(如72MHz系统可能需要 `j < 7200`)。 #### 2. **SysTick定时器法(推荐)** ```c volatile uint32_t SysTickCnt; // 全局计数器 void SysTick_Handler(void) { // 中断服务函数 SysTickCnt++; } void delay_ms(uint32_t ms) { uint32_t start = SysTickCnt; while (SysTickCnt - start < ms); // 阻塞等待 } int main() { // 初始化SysTick(1ms中断一次) SysTick_Config(SystemCoreClock / 1000); // ... 其他代码 } ``` **优势**:精度高,不受编译器优化影响[^3]。 --- ### 二、非阻塞延时函数(高效,不占用CPU) ```c uint32_t target_time = 0; void start_delay(uint32_t ms) { target_time = SysTickCnt + ms; // 设置目标时间 } int is_delay_done(void) { return (SysTickCnt >= target_time); // 检查是否超时 } // 使用示例 start_delay(1000); // 开始1s延时 while (!is_delay_done()) { // 此处可执行其他任务 } ``` --- ### 三、关键注意事项 1. **编译器优化问题**: - 若循环延时失效,尝试切换编译器版本(如AC5→AC6或反之)[^4]。 - 在 `Options for Target → C/C++` 中调整优化等级(建议用 `-O0` 调试)。 2. **时钟配置**: - 确保 `Target` 选项卡中设置的晶振频率与实际硬件一致[^2]。 - 使用 `SysTick_Config()` 前需正确初始化系统时钟。 3. **调试延时时间**: - 在Keil调试模式中: 1. 在延时函数前后设置断点。 2. 查看运行时差(`Debug → View → System Viewer → SysTick`)[^2]。 --- ### 四、生成延时函数的工具 1. **STM32CubeMX**: 生成HAL库的延时函数 `HAL_Delay()`(基于SysTick实现)。 2. **在线延时计算器**: 输入时钟频率和所需延时,自动生成循环计数代码。 --- ### 相关问题 1. 如何用SysTick实现微秒级延时? 2. 为什么阻塞延时Keil AC6编译器下可能失效?如何解决? 3. 非阻塞延时如何结合RTOS使用? 4. 如何用硬件定时器(如TIM2)实现高精度延时? 5. Keil调试时如何验证延时函数的实际执行时间? [^1]: Keil MDK5安装与stm32寄存器开发基础 [^2]: 使用KEIL调试延时函数 [^3]: keil MDK中阻塞延时函数和非阻塞延时函数记录 [^4]: Keil中的软件延时函数不起作用问题查找
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值