STM32中精确延时函数的实现
时间:2025-08-18 22:03:54
手机看文章
扫描二维码
随时随地手机看文章
在与传感器或者模块的总线进行通信的时候,常常需要使用到精确延时,一般我们会封装几个常用延时函数,下面我们以STM32F103芯片为例,详细介绍一下STM32下一种精确延时函数的实现:
时钟树
下图中紫色的 to Cortex System timer(MHz)就是Systick的时钟频率;
SYSTICK原理
SysTick 是一个24位的倒计数定时器,当计到0时,将从RELOAD寄存器中自动重装载定时初值并继续计数,且同时触发中断。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。SysTick 的最大使命,就是定期地产生异常请求,作为系统的时基,产生一个周期性的中断。
Systick定时器的四个寄存器:
CTRL: Systick控制和状态寄存器LOAD: Systick重装载寄存器VAL: Systick当前值寄存器CALIB: Systick校准值寄存器 (不常用,可忽略)
/** @addtogroup CMSIS_CM3_SysTick CMSIS CM3 SysTick memory mapped structure for SysTick @{*/typedef struct{ __IO uint32_t CTRL; /*!< Offset: 0x00 SysTick Control and Status Register */ __IO uint32_t LOAD; /*!< Offset: 0x04 SysTick Reload Value Register */ __IO uint32_t VAL; /*!< Offset: 0x08 SysTick Current Value Register */ __I uint32_t CALIB; /*!< Offset: 0x0C SysTick Calibration Register */} SysTick_Type;
SysTick->CTRL寄存器:
CLKSOURCE-时钟源[2]: select the clock soruce, 0 : AHB / 8, 1 : AHB.
0:STCLK=外部时钟源HCLK(AHB总线时钟)/8=72M/8 = 9M
1:FCLK=内核时钟=72M
FCLK:空闲运行时钟
SysTick-> LOAD寄存器:
SysTick-> VAL寄存器:
#include "delay.h" static u8 fac_us=0; //us延时倍乘数 static u16 fac_ms=0; //ms延时倍乘数 //初始化延迟函数//SYSTICK的时钟固定为HCLK时钟的1/8,即SYSTICK=SYSCLK/8//SYSCLK:系统时钟void delay_init(){ SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8 fac_us=SystemCoreClock/8000000; //SYSTICK时钟为9M(即8分频)时,fac_us=9,即SysTick倒数9个数,耗时1us fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数 } //查询SysTick->CTRL寄存器bit0是否为1,当为1时,说明倒计时时间到;//整个延时方法中,不进入SysTick中断;//延时nus//nus为要延时的us数. void delay_us(u32 nus){ u32 temp; SysTick->LOAD=nus*fac_us; //延时时间加载 SysTick->VAL=0x00; //清空计数器 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 //do while 判断就是 systick 使能(bit0)位为 1 且(bit16)为1的时候等待结束 do { temp=SysTick->CTRL; }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick->VAL =0X00; //清空计数器 } //延时nms//注意nms的范围//SysTick->LOAD为24位寄存器,所以,最大延时为://nms<=0xffffff*8*1000/SYSCLK//SYSCLK单位为Hz,nms单位为ms//对72M条件下,nms<=1864void delay_ms(u16 nms){ u32 temp; SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit) 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; //清空计数器 }