目录:
1. STM32时钟系统
2. STM32的定时器典型配置之溢出中断
3. STM32的定时器典型配置之PWM输出
1. STM32时钟系统
(1)Clock tree
可以在官方手册(Stm32x-series-Reference-manual)的clock tree中可以对相应MCU的时钟系统有个大致了解。
也可以从中了解到STM32哪些外设挂在哪一条总线上,然后根据Cube中配置的时钟频率和各种分频就可以得到各总线的时钟频率,注意挂在这些总线上的外设还需要在配置时经过分频得到外设的时钟频率。
(2)STM32总线与时钟配置
假如STM32时钟源为HSE高速外部晶振,HSE一般为8MHz,经过x分频和y倍频后得到系统时钟,即PLLCLK = (8/x)*y MHz。
AHB总线上时钟由系统时钟PLLCLK经过z分频得到,HCLK = PLLCLK/z。
APB2上的总线时钟PCLK2经过HCLK的m分频得到,PCLK2 = HCLK/m。
APB1上的总线时钟PCLK1经过HCLK的n分频得到,PCLK1 = HCLK/n。
外设时钟举例: 挂在高速总线APB2上的ADC时钟经过APB2总线时钟2分频得到,即ADCCLK = PCLK2/2 。
外设时钟举例:挂在低速总线APB1上的TIM2时钟经过APB1总线时钟2分频得到,即TIM2CLK = PCLK1/2 。
2. STM32的定时器典型配置之溢出中断
(1)定时器分类
STM32的物理定时器解决了MCU单任务运行使用CPU计数对性能的影响,定时器根据功能从多到少分为高级定时器、通用定时器、基本定时器。低功耗定时器、看门狗定时器、某些MCU还有HRTIM等。
(2)定时器挂在哪条总线上
以STM32F10x系列的MCU为例,TIM1/8挂在APB2高速总线上,TIM2-7挂在APB1低速总线上。
(3)定时器初始时钟频率
有人说如果APB1和APB2经过HCLK都进行1分频,那么TIM1/8的时钟为APB2的时钟,TIM2-7的时钟为APB1的时钟。
如果APB1和APB2经过HCLK进行分频,分频系数不为1,那么TIM1/8的时钟为APB2时钟的两倍,TIM2-7为APB1的时钟的两倍。
在实际应用中,要根据不同的MCU和时钟系统配置得到相应定时器的初始时钟频率。
(4)定时器计数时钟频率
所谓计数时钟频率,就是上面提到每种外设具体时钟频率还要经过外设本身的外设分频(PSC)配置,从而得到最终定时器时钟频率,这个频率就是定时器每计数一次花的时间。
(5)在CubeMX中定时器的配置
下面是对TIM2配置的实例:
图1
选中左侧TIM2,然后在Clock Source选择Internal Clock,在下面Parameter Settings处就会展示出相关参数,主要需要配置PSC,Mode,ARR值。
PSC即Prescaler,预分频系数,就是上面第(4)点中提到的再次分频系数,基于第(3)点的时钟频率分频。比如要配置定时器每一微妙(最终定时器技术频率为1MHz)计数一次,那么首先看第(3)点的时钟频率是多少:
从系统时钟树配置中可以看出,APB1总线时钟频率为72MHz,TIM2挂在APB1总线上,然后根据第(3)点的规则可知TIM2的初始频率为72MHz,那么要让TIM2的计数频率为1MHz,那么PSC就应该配置为72-1,这就是图1中72的由来。 注意这里是16bit位值,因此这个值不能超过65535,另外,STM32手册中提到这里PSC的值一定是你想要的值减1,可能是从0开始的吧,所以这里是72-1。
Counter Mode可以选择计数模式,这里选择向上计数。
Counter Period即上面提到的ARR值,即重装载值。即定时器计到这个值后响应一个事件(一般可以配置中断),然后重新开始计时。这个值也是有限制的,这里从图1中可以知道它是一个32bit的数。同样,由于TIM2是1us计数一次,如果我们希望500ms响应一次中断,那么就需要把ARR的值配置为500000,即TIM2计数500000次后响应中断,每次1us,500000刚好500ms。同样配置时的值是实际想要的值减1,即500000-1。
如果要使用中断方式,需要配置中断:
上图中可以选中TIM2的global interrupt,即使能了中断,然后根据实际应用配置中断优先级。
(6)Cube生成代码
1) 开启定时器
HAL_TIM_Base_Start_IT(&htimx); htimx是一个结构体变量,这里就是TIM2的句柄。这个函数的作用是开启定时器及溢出中断。
HAL_TIM_Base_Stop_IT(&htimx); 这个函数是关闭定时器及溢出中断HAL库函数。
HAL_TIM_Base_Start(&htimx); 这个函数是开启定时器,但是不开启中断的HAL库函数。
HAL_TIM_Base_Stop(&htimx); 这个函数是关闭定时器的HAL库函数。
2) 定时器中断处理函数
当定时器的计数到达ARR的值后,就会产生溢出中断,最终调用到中断完成回调函数,我们一般都是会改写这个函数,在这个函数里面执行相应逻辑。根据上面的配置,这个回调函数将500ms调用一次。void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef * htim)
3. STM32的定时器典型配置之PWM输出
(1)PWM占空比
什么是PWM呢,比如LCD背光就可以用PWM方式控制,当高电平时间比低电平时间长,那么肉眼感受到LCD亮的时间就比灭的时间长,如果继续减少低电平时间,甚至感受不到LCD有灭,那么通过这样的方式就可以实现LCD亮度控制。
一般来说PWM都是方波,那么高电平和低电平持续时间构成一个周期,高电平持续时间处于周期*100%,就是占空比,即Duty值。
(2)定时器比较值
一般比较值位于0到ARR重装载值之间,当定时器计数值处于0到比较值之间时,定时器的某个通道对应的GPIO输出高电平,如果计数值处于比较值到ARR重装载值之间,那么定时器的某个通道对应的GPIO输出低电平,由此可知通过改变比较值的大小就可以改变定时器的占空比。
(3)Cube配置
选中左侧相应定时器,选中右侧的Activated(如果只有后Activated就选中,如果是其他选项就选中Internal Clock即可),然后选中PWM Generation CH1。
参数那里PSC选择72-1,即计数频率是1MHz,即计数一次1us,ARR值为1000-1,即1000us响应一次中断,也就是1ms一次中断,中断频率就是1/0.1s=1000Hz。
1000Hz的频率肉眼是看不出来的,最后就是GPIO要选择对。
(4)代码编写
打开定时器PWM,HAL_TIM_WM_Start(&htimx,TIM_CHANNEL_2); 然后通过调用下面函数修改比较值,从而修改了占空比,从而实现亮度的控制。
__HAL_TIM_SetCompare(&htimx,TIM_CHANNEL_2,比较值);