STM32HAL库使用HAL_GetTick()和形参Timeout实现超时退出

STM32HAL库使用HAL_GetTick()和形参Timeout实现超时退出

Timeout

​ 在使用STM32CubeMX生成的HAL库模板编程时,我们会发现部分用于轮询模式的函数会有一个入口参数Timeout, 注释为超时时间.

例如串口轮询模式的发送接收函数的最后一个参数

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);

​ Timeout参数定义了在执行如串口接收、‌SPI传输等函数时,‌等待操作完成的最长时间。‌如果在这个时间内操作没有完成,‌ 函数就会停止等待并返回一个HAL_StatusTypeDef类型的状态值HAL_TIMEOUT,‌表明操作因超时而未完成, 实现跳出本句代码继续执行后续代码。‌

通过分析程序我们发现函数是通过这句代码 (HAL_GetTick() - Tickstart) > Timeout) 来实现函数内处理超时跳出,防止系统瘫痪。‌

HAL_GetTick()

​ HAL_GetTick()函数是STM32 HAL库中的一个重要函数,用于获取系统启动以来的毫秒级计数‌, 该函数基于SysTick中断实现,‌每当SysTick定时器定时中断时,‌全局变量uwTick会自增1,‌表示当前系统时间增加了1ms。‌因此,‌通过读取uwTick的值,‌HAL_GetTick()能够返回自系统启动以来经过的毫秒数‌。‌

__weak uint32_t HAL_GetTick(void)
{
  return uwTick;//返回自系统启动以来经过的毫秒
}

​ 写到这里是笔者产生了一个疑问, 我们在图形化配置CubeMX时STM32的NVIC中SysTick的抢占优先级默认为15, 也就是默认配置优先级为最低, 如此的话我们在进入到一些外设中断的时候SysTick中断还能精准的计时吗?

​ 经过探索笔者查询到HAL_GetTick()的机制: HAL_GetTick()函数是基于SysTick定时器实现的,‌用于获取系统启动以来的毫秒级计数。‌这一机制主要依赖于SysTick定时器的持续计数,‌而非其中断优先级‌。‌尽管SysTick中断的优先级最低,‌但SysTick定时器本身是一个24位的倒计数定时器,‌当计到0时会自动重装载定时初值并继续计数‌。‌因此,‌HAL_GetTick()函数能够保持精准计时,‌不受中断优先级的影响。‌

超时跳出的原理

​ 通过分析函数HAL_UART_Transmit (), 我们发现函数开始会定义一个变量tickstart,‌这个变量就是用来存储函数刚开始执行时系统的毫秒数

uint32_t tickstart = 0U;
tickstart = HAL_GetTick();//接收当前的系统毫秒数

​ 在HAL_UART_Transmit中又调用了函数UART_WaitOnFlagUntilTimeout,我们在这个函数中会看到以下代码:

      if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U))
      {

        return HAL_TIMEOUT;
      }

HAL_GetTick()的返回值为当前时刻系统的毫秒数,

而Tickstart又是HAL_UART_Transmit传递到UART_WaitOnFlagUntilTimeout形参, 里面存储的是HAL_UART_Transmit开始执行时系统毫秒数.

也就是说如果 我们在函数入口输入Timeout的参数为1000,也就是1000毫秒,‌则当HAL_GetTick() - Tickstart > 1000时就会跳出函数, 然后返回一个HAL_TIMEOUT。‌

此外我们发现如果Timeout给定的参数如果是0, 会直接超时. 这就导致函数不会执行任何指令而直接退出并返回HAL_TIMEOUT。‌

超时函数实现

​ 通过模仿HAL库函数的超时机制, 我们也可以实现自己的超时函数, 下面是一个例子;

HAL_StatusTypeDef prototype(uint32_t Timeout)//prototype为函数名
{
	uint32_t tickstart = 0U;
	tickstart = HAL_GetTick();//接收当前的系统毫秒数
    
    //可以将超时跳出函数放在while或者for循环中, 用于需要重复执行多次的操作, 在每次操作时进行超时的判断
    while
    {
        /*需要执行的操作*/
        
        
        if(((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U))
            return HAL_TIMEOUT;
    }
}
for(判断)
{
    /*需要执行的操作*/
    
    
    if(((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U))
        return HAL_TIMEOUT;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值