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中断打开:

TIM配置
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电平。

输出波形