前言
在HAL库中有ms毫秒级延时HAL_Delay(),其原理是使用Systick里的计数器实现的。在CubeMX配置的工程里可以通过把HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq))中的1000U改成1000000U配置成微秒级延时。但是不建议修改。可以通过配置通用定时器也能达到同一效果。
1. 基本实现原理
在参考手册的第14章节中,有详细的说到通用定时器TIM2、TIM3、TIM4和TIM5包括了16位的向上/向下的自动装载计数器。
在下图的框图中重点CK_PSC信号右边的框图,分别是计数器寄存器TIMx_CNT、预分频器寄存器TIMx_PSC、自动装载寄存器TIMx_ARR。
自动装载寄存器是预先装载的,另外在第2章的存储器和总线架构中可以看到各定时器是连接那一条总线。本文使用了TIM3,APB1时钟速度为72Mhz,可以在CubeMX中Clock Configuration配置时得到。然后修改预分频寄存器PSC控制计数器计数速度。PSC为16位所以最大值为65535,配置71(72-1分频器也是从0开始)分频后得到1000000hz每秒。也就是CNT每记一次数为1us。
2. 定时器配置
时钟树的配置为如下
定时器的配置为如下
3. 代码实现
因为计数器为16位,所以最大计数为65535,也就是65.5ms。可以定义一个局部的计数器来记录总的延时时间,这样最大延时可以达到0xFFFFFFFF/1000个毫秒,最大4294秒。最小延时为2us,其它参数很准确。
void HAL_Delayus(INT32U us)
{
INT32U ticks = us - 1;
INT32U told,tnow,tcnt = 0;
told = htim3.Instance->CNT; //刚进入时的计数器值
while(1)
{
tnow = htim3.Instance->CNT;
if(tnow != told)
{
if(tnow > told)
tcnt += tnow - told; //递增计数器
else
tcnt += 0xFFFF - told + tnow;
told = tnow;
if(tcnt >= ticks)
break; //时间超过/等于要延迟的时间,则退出.
}
}
}
/* 应用代码 */
MX_TIM3_Init(); //初始化
HAL_TIM_Base_Start(&htim3); //启动定时器
/* 以上执行一次即可 */
HAL_Delayus(1); //延时
4. 效果
分别延时了1us和5us。
欢迎各位同学优化程序并指出问题!