打印
[STM32G4]

跟着chatGPT学HAL库之深入理解HAL库延时函数

[复制链接]
10779|64
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 gaoyang9992006 于 2023-4-10 16:48 编辑

#申请原创#  @21小跑堂      在STM32开发中,延时函数是一种常见的工具,可以帮助我们实现一些简单的时间控制功能,如LED闪烁、蜂鸣器发声等。而HAL库则是ST公司针对STM32系列微控制器开发的一套软件库,提供了丰富的函数接口,方便我们进行STM32的开发。其中,HAL_Delay()和HAL_Delay_us()是HAL库提供的两个常用的延时函数,本文将通过与chatGPT对话的方式深入介绍这两个函数的实现原理及使用方法,希望能对大家有所帮助。

问:STM32 HAL库提供了哪些延时函数

chatGPT:
STM32 HAL库提供了以下几个延时函数:
HAL_Delay()函数:该函数可以在毫秒级别上进行延时。它接受一个参数,表示需要延时的毫秒数。

HAL_SuspendTick()和HAL_ResumeTick()函数:这两个函数用于暂停和恢复HAL库的滴答定时器,从而在低功耗模式下实现延时功能。

HAL_Delay_us()函数:该函数可以在微秒级别上进行延时。它接受一个参数,表示需要延时的微秒数。注意:这个函数依赖于系统时钟频率和编译器优化等因素,因此实际的延时可能会有一定的误差。

需要注意的是,使用延时函数会占用CPU资源,因此在实际应用中应该尽量避免过多地使用延时函数,而是采用中断或DMA等方式来实现需要定时或延时的功能。



问:介绍一下HAL_Delay_us()函数
chatGPT:
HAL_Delay_us()函数是STM32 HAL库提供的一个延时函数,可以用于在微秒级别上进行延时。该函数的定义如下:
void HAL_Delay_us(uint32_t microseconds)
该函数接受一个参数microseconds,表示需要延时的微秒数。函数内部会使用HAL库提供的滴答定时器进行计时,并在达到指定的延时时间后返回。需要注意的是,由于该函数的实现依赖于系统时钟频率和编译器优化等因素,因此实际的延时可能会有一定的误差。

在使用HAL_Delay_us()函数时,需要确保滴答定时器已经正确初始化。如果滴答定时器未初始化,则会导致延时函数无法正常工作。另外,由于该函数会占用CPU资源,因此在实际应用中应该尽量避免过多地使用延时函数,而是采用中断或DMA等方式来实现需要定时或延时的功能。


问:我想看该函数的实现代码
chatGPT:
HAL_Delay_us()函数的实现代码如下:
void HAL_Delay_us(uint32_t microseconds)
{
  uint32_t tickstart = 0;
  tickstart = HAL_GetTick();
  while ((HAL_GetTick() - tickstart) < (microseconds / 1000));
}


该函数的实现比较简单,主要使用了HAL_GetTick()函数获取系统滴答定时器的计数值,并在计数值达到指定的延时时间后返回。具体实现过程如下:

首先,使用HAL_GetTick()函数获取当前的系统滴答定时器计数值,即tickstart。

然后,使用一个while循环不断检查当前的系统滴答定时器计数值与tickstart之间的差值是否达到指定的延时时间。这里需要注意的是,由于HAL_GetTick()函数返回的是以毫秒为单位的计数值,因此需要将延时时间从微秒转换为毫秒,并除以1000来得到需要循环的次数。

当系统滴答定时器计数值与tickstart之间的差值达到指定的延时时间时,while循环结束,函数返回。

需要注意的是,由于HAL_GetTick()函数返回的计数值是一个32位无符号整数,因此在延时时间较长时,需要考虑计数器溢出的情况。此外,由于该函数的实现依赖于系统时钟频率和编译器优化等因素,因此实际的延时可能会有一定的误差。


问:HAL_Delay()的实现代码也给我提供一下
chatGPT:
当然,下面是HAL_Delay()函数的实现代码:
void HAL_Delay(uint32_t milliseconds)
{
  uint32_t tickstart = 0;
  tickstart = HAL_GetTick();
  while ((HAL_GetTick() - tickstart) < milliseconds);
}
HAL_Delay()函数的实现方式与HAL_Delay_us()函数类似,不同之处在于HAL_Delay()函数的参数表示需要延时的毫秒数,而不是微秒数。具体实现过程如下:

首先,使用HAL_GetTick()函数获取当前的系统滴答定时器计数值,即tickstart。

然后,使用一个while循环不断检查当前的系统滴答定时器计数值与tickstart之间的差值是否达到指定的延时时间。由于HAL_GetTick()函数返回的计数值已经是以毫秒为单位的,因此不需要进行单位转换。

当系统滴答定时器计数值与tickstart之间的差值达到指定的延时时间时,while循环结束,函数返回。

与HAL_Delay_us()函数一样,HAL_Delay()函数的实现也依赖于系统时钟频率和编译器优化等因素,因此实际的延时时间也可能会有一定的误差。

最后我们通过一个简单的例子,演示如何使用HAL_Delay()函数来实现LED灯的闪烁。

假设我们的STM32开发板上连接了一个LED灯,我们希望让它每隔一段时间就闪烁一次。为了实现这个功能,我们可以编写如下的代码:
#include "stm32f4xx_hal.h"

#define LED_PIN GPIO_PIN_5
#define LED_PORT GPIOA

int main(void)
{
  HAL_Init();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = LED_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
  
  while (1)
  {
    HAL_GPIO_TogglePin(LED_PORT, LED_PIN);
    HAL_Delay(500);
  }
}


在这个例子中,我们使用了HAL库提供的GPIO_InitTypeDef结构体和HAL_GPIO_Init()函数初始化了LED灯所连接的GPIO端口,然后使用了HAL_GPIO_TogglePin()函数来切换LED灯的状态。在每次状态切换后,我们使用HAL_Delay()函数来延时500毫秒,实现了LED灯每隔一段时间闪烁一次的功能。

需要注意的是,HAL_Delay()函数会阻塞程序的执行,因此在使用它时需要谨慎考虑,避免出现无法响应其他事件的情况。此外,HAL_Delay()函数的延时精度也受到系统时钟频率和编译器优化等因素的影响,因此在实际使用中需要进行一定的测试和调试。

于是我补充提问
问:如何使用非阻塞实现该例子中的效果?

要使用非阻塞方式实现该例子中的效果,我们可以使用定时器中断来代替延时函数。下面是一个使用TIM6定时器来实现LED灯闪烁的例子代码:
#include "stm32f4xx_hal.h"

#define LED_PIN GPIO_PIN_5
#define LED_PORT GPIOA

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);

int main(void)
{
  HAL_Init();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_TIM6_CLK_ENABLE();

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = LED_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);

  TIM_HandleTypeDef htim6 = {0};
  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 84 - 1;
  htim6.Init.Period = 5000 - 1;
  HAL_TIM_Base_Init(&htim6);
  HAL_TIM_Base_Start_IT(&htim6);

  while (1)
  {
    // Do other tasks here
  }
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Instance == TIM6)
  {
    HAL_GPIO_TogglePin(LED_PORT, LED_PIN);
  }
}

在这个例子中,我们使用了HAL库提供的定时器功能,使用TIM6定时器产生500ms的定时器中断,从而触发HAL_TIM_PeriodElapsedCallback()回调函数,实现LED灯的闪烁效果。需要注意的是,定时器中断是一种非阻塞方式,可以在闪烁LED灯的同时处理其他任务,避免了使用延时函数时的阻塞问题。


使用特权

评论回复
沙发
gaoyang9992006|  楼主 | 2023-4-10 16:50 | 只看该作者
只要学会合理科学的提问,通过有效的沟通,我们使用chatGPT来学习编程与开发,是很容易的。另外还可以让GPT帮我们检查自己写的代码是否存在语法上的问题,或可能存在的问题。另外还可以帮我们优化某些代码段。

使用特权

评论回复
板凳
Bowclad| | 2023-4-10 20:42 | 只看该作者
chatGPT都让人告了

使用特权

评论回复
地板
chenjun89| | 2023-4-10 20:49 | 只看该作者
chatGPT比直接用浏览器搜索方便多了

使用特权

评论回复
5
gaoyang9992006|  楼主 | 2023-4-11 10:10 | 只看该作者
Bowclad 发表于 2023-4-10 20:42
chatGPT都让人告了

怎么告,为何告?

使用特权

评论回复
6
gaoyang9992006|  楼主 | 2023-4-11 10:11 | 只看该作者
chenjun89 发表于 2023-4-10 20:49
chatGPT比直接用浏览器搜索方便多了

是的,这是一个时代的伟大创举,就好比当年出现了互联网搜索引擎。这个更牛X,基于知识结构再重组的生产力工具。

使用特权

评论回复
7
jkl21| | 2023-4-12 20:27 | 只看该作者
chatGPT靠谱嘛?                  

使用特权

评论回复
8
robincotton| | 2023-4-12 20:58 | 只看该作者
延时函数了HAL_Delay吧   

使用特权

评论回复
9
phoenixwhite| | 2023-4-12 21:04 | 只看该作者
可以查看HAL_Delay()函数具体的定义

使用特权

评论回复
10
jkl21| | 2023-4-12 21:51 | 只看该作者
秒级延迟 void HAL_Delay(__IO uint32_t Delay)  

使用特权

评论回复
11
jkl21| | 2023-4-12 22:06 | 只看该作者
只需要调用HAL库的一个虚函数  

使用特权

评论回复
12
elsaflower| | 2023-4-12 22:12 | 只看该作者
有系统学习stm32 HAL库开发相关的书籍或者例程吗

使用特权

评论回复
13
gaoyang9992006|  楼主 | 2023-4-13 08:59 | 只看该作者
elsaflower 发表于 2023-4-12 22:12
有系统学习stm32 HAL库开发相关的书籍或者例程吗

跟着chatGPT什么都可以学。书籍你可以找野火的,野火出过书籍,还有电子版,你搜一下。

使用特权

评论回复
14
gaoyang9992006|  楼主 | 2023-4-13 08:59 | 只看该作者

靠谱。

使用特权

评论回复
15
caoenq| | 2023-4-13 08:59 | 只看该作者
us延时函数有问题,50us怎么延时?用ms的时基去做us延时,不太现实

使用特权

评论回复
16
昊430| | 2023-4-13 14:48 | 只看该作者
怎么能使用chatGPT

使用特权

评论回复
17
mikewalpole| | 2023-4-13 15:50 | 只看该作者
使用普通定时器实现 us 延时

使用特权

评论回复
18
sheflynn| | 2023-4-13 21:21 | 只看该作者
STM32 的 HAL 库好用吗  

使用特权

评论回复
19
yorkbarney| | 2023-4-13 22:17 | 只看该作者
HAL_Delay() 吗              

使用特权

评论回复
20
sheflynn| | 2023-4-13 22:34 | 只看该作者
hal库串口中断回调怎能延时  

使用特权

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

本版积分规则

认证:西安公路研究院南京院
简介:主要工作从事监控网络与通信网络设计,以及从事基于嵌入式的通信与控制设备研发。擅长单片机嵌入式系统物联网设备开发,音频功放电路开发。

1897

主题

15634

帖子

198

粉丝