STM32CubeMX HAL delay_us() 微秒延时函数

STM32CubeMX HAL delay_us() 微秒延时函数

以 stm32f103 为例:
系统时钟配置为72M。
在这里插入图片描述

delay.c

#include "delay.h"
		   
static uint8_t  fac_us=0;							//us延时倍乘数			   
//static uint8_t  fac_ms=0;							//ms延时倍乘数			   
	
//初始化延迟函数, 在SystemClock_Config()后初始化,否则SystemCoreClock不正确
void delay_init()
{
	HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);	//SysTick频率为HCLK
															// 用SYSTICK_CLKSOURCE_HCLK_DIV8的话会使 HAL_Delay()变慢为8倍 HAL_Delay(1)实际会为8ms
	fac_us=SystemCoreClock/1000000;							//72M/1M=72 数72次为 1us
//	fac_ms=fac_us*1000;
}								    

// 延时nus
// nus为要延时的us数.
// 对 SysTick 寄存器进行了操作,可能会对其他使用了 SysTick 的定时造成影响?如 HAL_Delay() ?
//void delay_us(uint32_t nus)
//{		
//	uint32_t temp;	    	 
//	SysTick->LOAD=nus*fac_us; 					//时间加载	  		 
//	SysTick->VAL=0x00;        					//清空计数器
//	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//开始倒数	  
//	do
//	{
//		temp=SysTick->CTRL;
//	}while((temp&0x01)&&!(temp&(1<<16)));		//等待时间到达   
//	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//关闭计数器
//	SysTick->VAL =0X00;      					 //清空计数器	 
//}

// 延时nus
// nus为要延时的us数
// 没有对 SysTick 进行改动,相对安全。但精准度可能会轻微降低??
void delay_us(uint32_t nus)
{		
	uint32_t ticks;
	uint32_t told,tnow,tcnt=0;
	uint32_t reload=SysTick->LOAD;				//LOAD的值	    	 
	ticks=nus*fac_us; 						//需要的节拍数 
	told=SysTick->VAL;        				//刚进入时的计数器值
	while(1)
	{
		tnow=SysTick->VAL;	
		if(tnow!=told)
		{	    
			if(tnow<told)tcnt+=told-tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.
			else tcnt+=reload-tnow+told;	    
			told=tnow;
			if(tcnt>=ticks)break;			//时间超过/等于要延迟的时间,则退出.
		}  
	};
}

//延时nms
//nms:要延时的ms数
void delay_ms(uint16_t nms)
{
	uint32_t i;
	for(i=0;i<nms;i++) delay_us(1000);
}

delay.h

#ifndef __DELAY_H_
#define __DELAY_H_ 			   
#include "main.h"  
	 
void delay_init(void);
void delay_us(uint32_t nus);
void delay_ms(uint16_t nms);

#endif
<think>嗯,用户想用STM32CubeMX配置微秒级别的延时函数。首先,我得回忆一下STM32CubeMX的基本用法,以及延时函数的实现方式。通常,STM32HAL库提供了HAL_Delay()函数,但那是基于SysTick定时器的毫秒级延时。用户需要的是微秒级别的,所以得找其他方法。 首先,可能需要使用更高频率的时钟源,比如系统时钟是168MHz的话,每个时钟周期大约5.94纳秒,这样通过循环计数来实现微秒延时。但要注意,不同的STM32系列时钟配置可能不同,比如F1、F4、H7系列的时钟树不一样,所以需要用户确认自己的芯片型号。 接下来,用户使用STM32CubeMX配置的时候,可能需要配置一个定时器,比如基本定时器TIM6或TIM7,或者通用定时器。配置定时器的时钟分频和重载值,使其产生1微秒的中断,或者在定时器中断中计数。不过,微秒级别的延时如果频繁使用中断可能会影响系统性能,所以更好的方法可能是使用定时器的计数器直接进行轮询。 比如,配置定时器的时钟为比如84MHz,那么每个计数周期是1/84微秒,也就是大约11.9纳秒。要延时1微秒的话,需要计数84个周期。这时候可以编写一个函数,启动定时器,然后等待计数器达到指定值。或者直接使用DWT(Data Watchpoint and Trace)单元中的CYCCNT寄存器,这个寄存器在启用后会自动递增,每个时钟周期加1,可以用来做高精度延时。不过DWT的使用可能需要直接访问寄存器,HAL库可能没有直接支持,需要用户自己写代码。 不过,使用DWT的话,需要注意是否在芯片中可用,有些型号可能没有这个功能。此外,还要确保时钟配置正确,DWT的CYCCNT是否已经启用。例如,在初始化时需要启用DWT的跟踪功能,这可能涉及到CoreDebug模块的设置。 再回到STM32CubeMX的配置,用户可能需要配置一个定时器,比如TIM2,设置其预分频器和自动重载值,使得计数器每微秒递增一次。比如,如果APB1定时器时钟是84MHz,预分频器设置为83,这样定时器时钟为84MHz/(83+1)=1MHz,即每微秒计数一次。然后,自动重载值设为最大值0xFFFF,这样定时器可以连续计数。然后,在代码中,通过读取定时器的计数器值来计算经过的时间。 编写微秒延时函数时,可以使用类似以下的方法:记录当前的计数器值,然后等待直到经过指定的微秒数。例如,函数void delay_us(uint16_t us) { uint16_t start = TIM2->CNT; while ((TIM2->CNT - start) < us); }。不过需要考虑计数器溢出的情况,可能需要使用带溢出处理的代码,或者确保延时时间不超过定时器的周期。 另外,HAL库中的某些函数可能会有一定的开销,比如函数调用和寄存器访问的时间,这可能影响微秒延时的精度。因此,可能需要使用直接寄存器操作来提高速度。 总结来说,步骤大概是:1. 在STM32CubeMX中配置一个定时器,设置合适的预分频器和重载值,使其每微秒计数一次。2. 生成代码后,在工程中编写延时函数,利用定时器的计数器值来计算延时。3. 处理可能的溢出问题,或者使用DWT的方法来避免定时器配置的复杂性。 用户可能需要具体的步骤,比如在CubeMX中选择哪个定时器,如何设置参数,以及代码示例。同时,需要注意不同STM32系列的区别,比如F1和F4的时钟配置可能不同,需要根据具体情况调整预分频器和重载值。 另外,还需要提醒用户,微秒延时的精度受系统时钟和中断的影响,如果在高优先级中断频繁发生的情况下,可能会有延迟。因此,这种方法适用于对时间要求不是极端精确的场景,或者需要禁用中断的情况。 最后,生成相关问题的时候,可以考虑常见的后续问题,比如如何提高精度、不同定时器的选择、使用DWT的方法,或者如何处理长时间延时等。</think>### 使用STM32CubeMX配置微秒延时函数教程 #### 1. 系统时钟配置 - 在STM32CubeMX中,首先配置系统时钟(如使用HSE或HSI),确保主频达到芯片支持的最大值(例如STM32F4系列可配置为168MHz)[^1]。 - 时钟树配置示例: ```c System Clock -> HSE -> PLL Source -> PLLM=8, PLLN=336, PLLP=2 ``` 输出系统时钟为 $f_{sys} = \frac{HSE \cdot PLLN}{PLLM \cdot PLLP} = \frac{8MHz \cdot 336}{8 \cdot 2} = 168MHz$。 #### 2. 定时器配置(以TIM2为例) 1. **选择定时器** - 在`Pinout & Configuration`标签页中选择一个基本/通用定时器(如TIM2) - 配置定时器参数: - **Clock Source**: Internal Clock - **Prescaler (PSC)**: 计算值 $PSC = \frac{f_{timer}}{1MHz} - 1$ 例如,若定时器时钟为84MHz,则 $PSC = 84 - 1 = 83$,使计数器频率为1MHz(周期1μs) - **Counter Period (ARR)**: 设为最大值65535(16位定时器) - **Auto-reload preload**: Enable 2. **生成代码** - 点击`Generate Code`生成初始化代码,确保定时器时钟使能: ```c __HAL_RCC_TIM2_CLK_ENABLE(); ``` #### 3. 编写延时函数 在生成的工程中添加以下代码: ```c // 启动定时器 HAL_TIM_Base_Start(&htim2); // 微秒延时函数 void delay_us(uint16_t us) { uint16_t start = __HAL_TIM_GET_COUNTER(&htim2); while ((__HAL_TIM_GET_COUNTER(&htim2) - start) < us) { // 处理计数器溢出 if (__HAL_TIM_GET_COUNTER(&htim2) < start) { start -= 65535; } } } ``` #### 4. 验证延时精度 通过示波器测量GPIO翻转时间验证: ```c HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0); delay_us(10); // 实测应产生20MHz方波(周期0.5μs) HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0); ``` #### 注意事项 - 中断影响:若系统频繁响应中断,可能导致延时误差,建议在关键时序代码中禁用中断 - 时钟一致性:确保实际时钟频率与CubeMX配置一致,可通过`SystemCoreClock`变量验证 ```mermaid graph TD A[配置系统时钟] --> B[选择定时器] B --> C[设置预分频器PSC] C --> D[生成代码] D --> E[编写延时函数] E --> F[验证精度] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值