【HAL库】STM32CubeMX开发----delay延时实验----NOP空指令

本文详细介绍了STM32F407的HAL库延时问题,并提供了自定义us级和ms/s级延时的解决方案,包括使用__NOP()实现的延迟函数,以及针对PB6引脚的高频电平切换实验结果。特别适合STM32F407系列MCU开发者。

STM32CubeMX 下载和安装 详细教程
【HAL库】STM32CubeMX开发----STM32F103/F207/F407----目录


前言

HAL库有自带的 ms级 延时函数: HAL_Delay();

缺点1:

无法实现 us级延时

缺点2:

此延时函数是由SysTick滴答定时器中断产生的,滴答定时器的中断优先级是所有中断中最低的,无法在其他中断中产生延时。

一、 STM32F407----delay延时实验

本次实验以 STM32F407VET6 芯片为MCU,使用 25MHz 外部时钟源。
系统时钟 SYSCLK = 168MHz,使用 __NOP();空指令实现延时。

User_delay.c

#include "User_delay.h"

void delay_us(uint16_t us)
{
	uint32_t Tdata = us*SYSCLK_MHZ/5;
	for(uint32_t i=0;i<Tdata;i++)
	{
		__NOP();
	}
}

void delay_ms(uint16_t ms)
{ 
	while( ms-- != 0)
	{
		delay_us(1000);	
	}
}

void delay_s(uint16_t s)
{ 	  
	while( s-- != 0)
	{
		delay_ms(1000);	
	}
}

User_delay.h

#ifndef __User_delay_H__
#define	__User_delay_H__

#include "main.h"

#define SYSCLK_MHZ    (SystemCoreClock/1000000) //系统时钟频率

void delay_us(uint16_t us);
void delay_ms(uint16_t ms);
void delay_s(uint16_t s);

#endif

实验测试

具体测试内容:让PB6引脚,每隔10us,实现高低电平切换。
具体代码如下:

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
delay_us(10);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
delay_us(10);

通过逻辑分析仪,采集的结果如下:
在这里插入图片描述
亲测可用,只适用于 STM32F407 相关的芯片。
其他的芯片,需要修改参数校准时间。


### STM32 HAL中的微妙级空指令延时实现 在STM32 HAL中,可以通过调用`HAL_Delay()`函数来实现毫秒级别的延迟。然而,对于微秒级别的延迟,通常会使用`__HAL_TIM_SET_COUNTER()`配合定时器或者直接利用循环计数的方式完成。如果需要通过空指令NOP)的方式来实现微秒级别延时,则可以借助汇编语言中的`nop`指令并结合CPU频率计算具体执行时间。 以下是基于ARM Cortex-M系列处理器的示例代码: ```c #include "stm32g4xx_hal.h" // 定义一个简单的微秒级延时函数 void delay_us(uint32_t us) { uint32_t ticks_start, ticks_end; // 获取当前SysTick计数值 ticks_start = SysTick->VAL; // 计算目标结束值 ticks_end = ticks_start - ((us * (SystemCoreClock / 1000000)) & 0xFFFFFF); while (((ticks_start - SysTick->VAL) & 0xFFFFFF) > ticks_end); } ``` 上述代码片段展示了如何通过操作SysTick寄存器来间接实现微秒级延时[^1]。需要注意的是,这种方法依赖于系统的时钟配置以及SysTick初始化状态。另外一种更简单但精度较低的方法是采用循环加空操作的形式: ```c #define NOP_DELAY_US(us) { \ volatile uint32_t i; \ for(i=0;i<(us*SystemCoreClock/1000000);i++) __asm__("nop"); \ } int main(void) { HAL_Init(); // 使用自定义的微秒延时NOP_DELAY_US(10); // 延迟10微秒 while (1){ // 主程序逻辑 } } ``` 此方法虽然易于理解且无需额外硬件资源支持,但由于每次执行`nop`所需的实际周期可能受到多种因素影响(如流水线填充、缓存命中率等),因此其准确性难以保障[^2]。 当涉及到多任务环境下的同步机制时,还可以考虑FreeRTOS提供的信号量功能作为替代方案之一。例如,`xSemaphoreGiveFromISR()`允许从中断上下文中发送消息给其他任务,从而达到精确控制的目的[^3]。 #### 注意事项 - 如果项目已经启用了SysTick中断服务例程(SVR),则需谨慎修改相关参数以免引发冲突。 - 对于更高精度的需求建议启用专门的TIM外设进行管理而非单纯依靠软件模拟手段。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

根号五

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值