一、使用HAL库在STM32上实现微秒级延时
一、应用场景
STM32CubeMX可视化初始化配置,结合 HAL 库,给STM32软件开发提高了效率,但 HAL 库封装的延时函数目前仅支持 mS 级别的延时,日常很多情况下会用到 uS延时,比如I2C时序(不知为啥HAL库提供的I2C我使用有问题,这个以后在研究吧),还有一些传感器的数据读取过程,对时序要求比较严格,us 延时必不可少,基于此项需求,写写这个东东。
二、STM32CubeMX图形化初始化的配置
1、大体思路
通过定时器通过轮询的方式实现微秒级延时。(对于微秒级延时,如果通过中断方式实现会导致过于频繁的进入中断,干扰其他中断的及时响应)
2、打开CubeMX软件,配置时钟。
(1)选择时钟源,这里的外部时钟是指外部晶振+内部晶振电路提供时钟。
HSE(High speed external clock,高速外部时钟)
LSE(Low speed external clock,低速外部时钟)
)时钟;
选项有:
Disable 禁用(关闭)
BYPASS Clock Source 旁路时钟源,指无需使用外部晶体时所需的内部晶振电路,直接从外界导入时钟信号,这种模式只用到引脚RCC_XXXX_IN引脚。
Crystal/Ceramic Resonator 晶体/陶瓷 晶振,使用晶振+内部晶振电路产生时钟。这种模式用到引脚RCC_XXXX_IN引脚和RCC_XXXX_OUT引脚。
(2)时钟树的配置
这里低速时钟和高速时钟均选择外部的
注意外部晶振的频率
3、STM32F103RET6芯片定时器
(1)STM32定时器可以分为 Advanced-control timers(高级控制定时器),STM32F103RET6包含TIME1和TIME8。
(2)General-purpose timers(通用定时器),STM32F103RET6包含TIME2、TIME3、TIME4和TIME5。
(3)Basic timers(基本定时器),STM32F103RET6包含TIME6和TIME7。
4、定时器的配置
(1)定时器的选择,这里选择通用定时器2。
(2)CubeMX配置,定时器2时钟源的选择
定时器的配置项有很多,用不到的可以不用考虑。
Clock Source:这里是选择定时器的时钟脉冲源,某些定时器只能选择Internal Clock。
定时器2时钟脉冲源的选择有:
Internal Clock:内部时钟
ETR2:外部时钟模式2(外部触发输入),可用于记脉冲数。
这里选择内部时钟
(3)通过参考手册中的图,如下。可知定时器2连接APB1总线。
(4)查看APB1总线时钟频率:72MHz
(5)配置定时器参数
Prescaler(预分频器,分频系数)
Counter Mode(计数器模式):up向上计数、down向下计数等。
Counter Period (AutoReload Register – 16 bits value ):计数器周期(自动重载寄存器- 16位值)计数器周期(自动重载寄存器- 16位值)必须在0到65 535之间。
配置分频系数为:72-1;计数器模式为up;计数器周期为0。
5、生成KeilMDK工程
完成以上配置后点击右上角的GENERATE CODE。
三、KeilMDK中代码的编写
/*
*功能:定时器I2C延时
*参数:延时的us数,us 范围-0~65535us
*注意:使用定时器2产生延时
*返回值:无
*/
void I2C_Delay_us(uint16_t t)
{
uint16_t counter = 0;
__HAL_TIM_SET_AUTORELOAD(&htim2, t); // 设置定时器自动加载值,到该值后重新计数
__HAL_TIM_SET_COUNTER(&htim2, 0); // 设置定时器初始值
HAL_TIM_Base_Start(&htim2); // 启动定时器
while(counter != t) // 直到定时器计数从 0 计数到 us 结束循环,刚好 us
{
counter = __HAL_TIM_GET_COUNTER(&htim2); // 获取定时器当前计数
}
HAL_TIM_Base_Stop(&htim2); // 停止定时器
}
根据CubeMX配置,定时器时钟有APB1提供的72MHz提供,然后进行72分频,得到1MHz。
当上述函数参数为1时,延时时长为:1/(1MHz) = 1/(1*10^6Hz) = 1us。
———————————————————————————————————————————
如有不足,请忽略。