21ic电子技术开发论坛

标题: STM32精确延时时间设置 [打印本页]

作者: janewood    时间: 2023-9-28 15:23
标题: STM32精确延时时间设置
1、普通延时
这种延时方式应该是大家在51单片机时候,接触最早的延时函数。这个比较简单,让单片机做一些无关紧要的工作来打发时间,经常用循环来实现,在某些编译器下,代码会被优化,导致精度较低,用于一般的延时,对精度不敏感的应用场景中。
//微秒级的延时void delay_us(uint32_t delay_us){  volatile unsigned int num;  volatile unsigned int t;  for (num = 0; num < delay_us; num++)  {    t = 11;    while (t != 0)    {      t--;    }  }}//毫秒级的延时void delay_ms(uint16_t delay_ms){  volatile unsigned int num;  for (num = 0; num < delay_ms; num++)  {    delay_us(1000);  }}

2、定时器中断
定时器具有很高的精度,我们可以配置定时器中断,比如配置1ms中断一次,然后间接判断进入中断的次数达到精确延时的目的。这种方式精度可以得到保证,但是系统一直在中断,不利于在其他中断中调用此延时函数,有些高精度的应用场景不适合,比如其他外设正在输出,不允许任何中断打断的情况。
STM32任何定时器都可以实现,下面我们以SysTick 定时器为例介绍:
初始化SysTick 定时器:
/* 配置SysTick为1ms */RCC_GetClocksFreq(&RCC_Clocks);SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);
中断服务函数:
void SysTick_Handler(void){  TimingDelay_Decrement();}void TimingDelay_Decrement(void){  if (TimingDelay != 0x00)  {    TimingDelay--;  }}
延时函数:
void Delay(__IO uint32_t nTime){  TimingDelay = nTime;  while(TimingDelay != 0);}

3、查询定时器
为了解决定时器频繁中断的问题,我们可以使用定时器,但是不使能中断,使用查询的方式去延时,这样既能解决频繁中断问题,又能保证精度。
STM32任何定时器都可以实现,下面我们以SysTick 定时器为例介绍。
STM32的CM3内核的处理器,内部包含了一个SysTick定时器,SysTick是一个24位的倒计数定时器,当计到0时,将从RELOAD寄存器中自动重装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。
SYSTICK的时钟固定为HCLK时钟的1/8,在这里我们选用内部时钟源120M,所以SYSTICK的时钟为(120/8)M,即SYSTICK定时器以(120/8)M的频率递减。SysTick 主要包含CTRL、LOAD、VAL、CALIB 等4 个寄存器。

CTRL:控制和状态寄存器
LOAD:自动重装载除值寄存器
VAL:当前值寄存器
CALIB:校准值寄存器,使用不到,不再介绍。
示例代码:
void delay_us(uint32_t nus){  uint32_t temp;  SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000000/8*nus;  SysTick->VAL=0X00;//清空计数器  SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源  do  {    temp=SysTick->CTRL;//读取当前倒计数值  }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达  SysTick->CTRL=0x00; //关闭计数器  SysTick->VAL =0X00; //清空计数器}void delay_ms(uint16_t nms){  uint32_t temp;  SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000/8*nms;  SysTick->VAL=0X00;//清空计数器  SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源  do  {    temp=SysTick->CTRL;//读取当前倒计数值  }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达  SysTick->CTRL=0x00; //关闭计数器  SysTick->VAL =0X00; //清空计数器}




作者: Stahan    时间: 2023-9-30 13:38
不是可以加关键字禁止优化嘛

作者: MessageRing    时间: 2023-9-30 17:27
while里面的时间也是不可确定的吧

作者: hilahope    时间: 2023-10-5 09:58
根据你的需求设置延时时间。你可以通过计算定时器的周期数来确定延时时间。例如,假设你使用的是 1ms 定时器周期,那么延时 1000 毫秒(1 秒)需要设置的周期数为 1000。

作者: vivilyly    时间: 2023-10-5 12:06
需要使用定时器中断来实现延时。你首先需要配置定时器,设定好延时的时长,然后开启定时器中断。

作者: louliana    时间: 2023-10-7 14:10
当定时器的计时时间到达设定的值时,会产生一个中断,你可以在这个中断服务函数中执行你的延时任务。这种方法的优点是代码简洁,易于理解和维护,而且延时时间不会因为频繁的指令执行而受到影响。但是缺点是延时时间可能会受到系统其他任务的影响,可能无法做到绝对的精确。

作者: vivilyly    时间: 2023-10-7 21:39
// 配置TIM2定时器
HAL_TIM_Base_Start(&htim2);

// 延时函数
void delay_us(uint32_t us)
{
    __HAL_TIM_SET_COUNTER(&htim2, 0); // 重置定时器计数器
    while (__HAL_TIM_GET_COUNTER(&htim2) < us); // 等待延时时间过去
}

作者: Jacquetry    时间: 2023-10-7 22:59
这个软件延时不可靠吧

作者: dspmana    时间: 2023-10-8 22:39
// 配置SysTick定时器
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); // 设置为每毫秒触发一次中断

// 延时函数
void delay_ms(uint32_t ms)
{
    uint32_t start = HAL_GetTick(); // 获取当前的SysTick计数值
    while (HAL_GetTick() - start < ms); // 等待延时时间过去
}

作者: Bowclad    时间: 2023-10-8 22:53
软件延时是不是容易被优化掉啊

作者: Undshing    时间: 2023-10-9 21:50
定时器中断好用还是

作者: Henryko    时间: 2023-10-10 12:51
软件延时有时候会被编译器优化掉

作者: AloneKaven    时间: 2023-10-10 18:26
Bowclad 发表于 2023-10-8 22:53
软件延时是不是容易被优化掉啊

可以把编译器优化关掉啊

作者: Stahan    时间: 2023-10-11 20:12
精确延时也跟晶振频率有关吧

作者: jonas222    时间: 2023-10-11 22:29
通过开启定时器中断,在中断服务程序中累计定时器溢出次数实现延时。这种方法可以实现相对精确的延时,但需要在中断服务程序中进行累计计算,程序相对复杂一点。

作者: cashrwood    时间: 2023-10-14 10:19
STM32微控制器上的定时器也可以用于实现精确的延时。可以配置一个定时器,并使用定时器的计数器和预分频器来生成所需的延时时间。

作者: vivilyly    时间: 2023-10-14 12:45
设置定时器的计数器初值后,可以通过启动定时器来开始计数。

作者: 1988020566    时间: 2023-10-14 13:01
在计数器溢出时,可以通过读取定时器的计数器值来获取当前的延时时间。

作者: eefas    时间: 2023-10-14 16:32
通过不断地执行for循环来产生延时,这种方法精度不高,延时时间不准确,但程序简单易懂。

作者: kkzz    时间: 2023-10-14 20:30
HAL_Delay()是STM32微控制器中最常用的精确延时函数之一

作者: tabmone    时间: 2023-10-14 22:14
TIM2定时器是一种基于CPU时钟的定时器,可以用来测量时间间隔。在使用TIM2定时器时,需要先进行初始化,然后设置重载值和预分频值,最后等待定时器溢出即可。

作者: everyrobin    时间: 2023-10-14 22:26
需要配置定时器的时钟源、计数方式、计数器溢出方式等参数,然后开启定时器的中断功能。

作者: yeates333    时间: 2023-10-14 22:42
SysTick定时器是一种基于CPU时钟的定时器,可以用来测量时间间隔。在使用SysTick定时器时,需要先进行初始化,然后设置重载值,最后等待定时器溢出即可。具体实现方法可以参考这篇文章。

作者: Mowergy    时间: 2023-10-16 10:44
先配置定时器,设定好延时的时长,然后开启定时器中断。

作者: lzbf    时间: 2023-10-16 13:26
通过开启系统定时器SysTick并设置其触发方式和定时器周期,可以实现相对精确的延时,且不需要进入中断服务程序进行累计计算,程序简单易懂。

作者: claretttt    时间: 2023-10-16 15:57
需要在代码中精确地计算出延时的时长,然后使用for循环或者delay函数来实现延时。

作者: jtracy3    时间: 2023-10-22 11:19
STM32微控制器上的SysTick定时器是一个24位倒计时器,可以用于生成精确的延时。可以通过配置SysTick定时器的时钟源和重载值来实现所需的延时时间。





欢迎光临 21ic电子技术开发论坛 (https://bbs.21ic.com/)