打印
[STM32F1]

STM32精确延时时间设置

[复制链接]
1133|26
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
janewood|  楼主 | 2023-9-28 15:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
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。

使用特权

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

使用特权

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

使用特权

评论回复
7
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); // 等待延时时间过去
}

使用特权

评论回复
8
Jacquetry| | 2023-10-7 22:59 | 只看该作者
这个软件延时不可靠吧

使用特权

评论回复
9
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); // 等待延时时间过去
}

使用特权

评论回复
10
Bowclad| | 2023-10-8 22:53 | 只看该作者
软件延时是不是容易被优化掉啊

使用特权

评论回复
11
Undshing| | 2023-10-9 21:50 | 只看该作者
定时器中断好用还是

使用特权

评论回复
12
Henryko| | 2023-10-10 12:51 | 只看该作者
软件延时有时候会被编译器优化掉

使用特权

评论回复
13
AloneKaven| | 2023-10-10 18:26 | 只看该作者
Bowclad 发表于 2023-10-8 22:53
软件延时是不是容易被优化掉啊

可以把编译器优化关掉啊

使用特权

评论回复
14
Stahan| | 2023-10-11 20:12 | 只看该作者
精确延时也跟晶振频率有关吧

使用特权

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

使用特权

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

使用特权

评论回复
17
vivilyly| | 2023-10-14 12:45 | 只看该作者
设置定时器的计数器初值后,可以通过启动定时器来开始计数。

使用特权

评论回复
18
1988020566| | 2023-10-14 13:01 | 只看该作者
在计数器溢出时,可以通过读取定时器的计数器值来获取当前的延时时间。

使用特权

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

使用特权

评论回复
20
kkzz| | 2023-10-14 20:30 | 只看该作者
HAL_Delay()是STM32微控制器中最常用的精确延时函数之一

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

57

主题

1273

帖子

1

粉丝