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

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 相关的芯片。
其他的芯片,需要修改参数校准时间。


<think>好的,用户现在想用STM32HAL实现微秒级的延时。之前他们问过关于W5500和SPI驱动的问题,现在转向了定时器相关的功能。首先,我需要确定用户的需求是什么。他们可能需要精确的微秒级延时,用于外设的时序控制,比如SPI通信中的等待时间,或者传感器读取时的精确时序。 接下来,我得考虑HAL本身提供的延时函数。HAL_Delay()是基于SysTick的毫秒级延时,无法满足微秒需求。所以用户需要自己实现更细粒度的延时。常见的实现方法有几种:使用定时器、使用SysTick、或者使用NOP指令的空循环。但NOP的方法受编译器优化和CPU频率影响大,可能不准。所以更可靠的是定时器或SysTick。 用户可能已经知道这些方法,但需要具体的代码实现。我需要提供基于定时器和DWT的两种方法,因为这两种比较常见。使用定时器的话,需要配置一个基本定时器,比如TIM2,设置时钟为1MHz,这样每个计数就是1微秒。然后编写启动、延时、停止的函数。这种方法需要用户根据自己MCU的时钟配置调整定时器的预分频值。 另一种方法是使用DWT(Data Watchpoint and Trace)的Cycle Counter,这需要启用DWT模块,通过读取时钟周期数来实现精确延时。这种方法不需要占用定时器资源,但需要确认MCU支持DWT,并且时钟配置正确。比如,如果系统主频是72MHz,那么每微秒有72个周期,这样计算起来方便。 用户可能关心代码的可移植性和准确性,所以需要给出注意事项,比如时钟配置、中断的影响等。此外,他们可能在实际使用中遇到问题,比如延时不准,这时候需要提示检查系统时钟和定时器配置是否正确。 还要考虑到代码的兼容性,不同STM32型号可能有不同的定时器或DWT支持情况,所以需要用户根据具体情况调整。最后,示例代码需要简洁明了,直接给出关键部分,让用户能够快速集成到自己的项目中。</think>以下提供两种基于STM32 HAL的微秒级延时实现方案(推荐方案1): --- ### **方案1:定时器实现(高精度)** ```c // timer.h #define DELAY_TIM TIM2 #define DELAY_TIM_CLK_ENABLE() __HAL_RCC_TIM2_CLK_ENABLE() // 初始化函数(时钟配置为1MHz) void Delay_TIM_Init(void) { TIM_HandleTypeDef htim; htim.Instance = DELAY_TIM; htim.Init.Prescaler = HAL_RCC_GetPCLK1Freq()/(2*1000000) - 1; // 1MHz时钟 htim.Init.CounterMode = TIM_COUNTERMODE_UP; htim.Init.Period = 0xFFFF-1; htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&htim); HAL_TIM_Base_Start(&htim); } // 微秒延时函数 void delay_us(uint16_t us) { __HAL_TIM_SET_COUNTER(&htim, 0); while(__HAL_TIM_GET_COUNTER(&htim) < us); } ``` --- ### **方案2:DWT周期计数器实现(无需硬件定时器)** ```c // dwt.h #include "core_cm4.h" // 根据内核型号选择 void Delay_DWT_Init(void) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; } void delay_us(uint32_t us) { uint32_t cycles = SystemCoreClock / 1000000 * us; uint32_t start = DWT->CYCCNT; while((DWT->CYCCNT - start) < cycles); } ``` --- ### **使用示例** ```c int main(void) { HAL_Init(); SystemClock_Config(); // 选择其中一种初始化方式 Delay_TIM_Init(); // 或者 Delay_DWT_Init(); while(1) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); delay_us(500); // 500微秒延时 } } ``` --- ### **关键参数说明** | 参数 | 方案1要求 | 方案2要求 | |--------------|-------------------------|-------------------------| | 时钟精度 | 依赖定时器配置 | 依赖系统主频 | | 适用场景 | 需要严格时序控制 | 通用延时 | | 误差范围 | ±0.5us(72MHz主频) | ±1us(无中断干扰) | | 资源占用 | 占用一个定时器 | 无需硬件资源 | --- ### **注意事项** 1. 方案1需根据实际APB时钟调整预分频值 2. 方案2要求: - 内核必须支持DWT(Cortex-M3/M4/M7) - 系统时钟需准确配置(通过`SystemCoreClock`变量反映) 3. 两种方案均需关闭全局中断才能保证最高精度 4. 对于100us以上延时,建议结合HAL_Delay()使用
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

根号五

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

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

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

打赏作者

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

抵扣说明:

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

余额充值