世界杯最大比分

今天使用了OLED驱动代码,其中为了适应MCU较高速度而加入了Delay_us(4),后来再调用HAL库的HAL_Delay()出现了程序卡死在HAL库延迟函数之中。为此对延迟函数作进一步学习。

问题原因

首先是Delay_us()函数原型(代码来源江科大的代码)

void Delay_us(uint32_t xus)

{

SysTick->LOAD = 72 * xus; //设置定时器重装值

SysTick->VAL = 0x00; //清空当前计数值

SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器

while(!(SysTick->CTRL & 0x00010000)); //等待计数到0

SysTick->CTRL = 0x00000004; //关闭定时器

}

该程序通过清空滴答定时器计数值后再从零计数来实现延迟。该过程直接操作、修改滴答定时器的句柄 SysTick 。而HAL库的逻辑是先记录当前的时间点(计数值)为start,阻塞等待计数值为start+wait_time。其中并未操作SysTick句柄,该句柄在初始化之初已配置好。

Delay_us函数最后关闭了定时器是一方面,另外还有SysTick->CTRL = 0x00000005。这个值对应的二进制是0101,即:

Bit 0 (ENABLE) = 1:启用 SysTick 定时器。

Bit 1 (TICKINT) = 0:禁用 SysTick 中断。

Bit 2 (CLKSOURCE) = 1:选择处理器时钟(HCLK)

函数结束后由于SysTick中断关闭,HAL全局计时变量 uwTick 无法得到更新,程序一直卡在HAL_Delay。即使最后 Delay_us 函数结束时恢复 CTRL 寄存器的值,HAL 库的中断逻辑可能已经被破坏,所以最好使用其他方法实现微妙延迟控制。HAL库SysTick句柄初始化配置具体如下:

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks){

if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)

{

return (1UL); /* Reload value impossible */

}

SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */

NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */

SysTick->VAL = 0UL; /* Load the SysTick Counter Value */

SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |

SysTick_CTRL_TICKINT_Msk |

SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */

return (0UL); /* Function successful */

}

关于SysTick

SysTick句柄