HAL老麻烦了
首先,在CubeMX里面一波操作:
开外部HSE,开Debug为Serial Wire(SWD),配置HCLK为72MHz,同时配置一个GPIO驱动LED来指示计数情况。
因为要使用TIM2做Tick计数,所以把TIM2的时钟源改为Internal Clock。该定时器的时钟挂载在APB1上,输入频率为36MHz * 2 = 72MHz。
接下来配置TIM2。
关于TIM的配置说明网上一抓一大把,就不详细叙述了。贴一个计数时间的式子:$T = \frac{(PSC+1)\times (Reload+1)}{TIMxCLK}$,在这里,$T = \frac{72\times 1000}{72MHz}=\frac{1}{1000}=1ms$。
接下来把NVIC中断打开:
然后在Project Manager -> Code Generator中把“为每个外设初始化过程生成 c/h 文件”,这样就会把外设的初始化流程分开文件存放,看起来比较美观。
下来开始实现Tick逻辑。
打开 Core/Src下的 stm32f1xx_it.c,找到 TIM2_IRQHandler
,可以发现该函数调用了 HAL_TIM_IRQHandler
函数来进行中断处理。看起来在这里实现中断逻辑很美妙对吗?不对。中断业务逻辑的编写另有他处。
右键 HAL_TIM_IRQHandler
函数跳转至声明,可以看见HAL库实现好的中断处理分支:
大致阅读该函数,可以找到如下标志性函数调用,分别对应各种中断事件:
HAL_TIM_IC_CaptureCallback(htim); //输入捕获中断 HAL_TIM_TriggerCallback(htim); //输入触发中断 HAL_TIM_OC_DelayElapsedCallback(htim); //输出比较中断 HAL_TIM_PWM_PulseFinishedCallback(htim); //PWM计数器比较完成中断 HAL_TIM_PeriodElapsedCallback(htim); //计数完成,ARR溢出中断 HAL_TIMEx_BreakCallback(htim); HAL_TIMEx_CommutCallback(htim);
随便点一个HAL_TIM_PeriodElapsedCallback
转到声明,代码实现基本如下:
观察就会发现,这些函数声明中都有__weak
标记,表示编译时以用户实现代码优先。(有点像abstract method
搞清楚了中断处理流程,就可以编写中断服务逻辑了:
先判断中断源是否为TIM2,然后Tick加一,简单暴力。
在main函数中先用HAL_TIM_Base_Start_IT(&htim2);
开启TIM2并开启中断,然后在无限循环中判断Tick值并且与翻转过的上一个Tick是否相同,翻转IO电平。