实验内容
- 1s翻转LED灯
- 3s内实现LED灯的PWM效果,即3s实现由暗到亮到暗的变换
定时器背景
分为三类,包括高级控制定时器,通用定时器,基本定时器
基本定时器有TIM2和TIM5是32比特,TIM3和TIM4是16比特,也即比特位宽。
ARR,BSC,CCR
以向上计数为例,计数器持续计数,当计数到ARR满载的时候会溢出,发生程序中断,然后中断时去点亮LED灯。
可以设置阈值CCR,CCR将计数分为两个区域,即计数值小于CCR和大于CCR的情况。通过改变CCR阈值的位置可以改变脉宽,也即高低电平宽度。
图 1 ARR和CCR作用可视化
实验步骤
实验步骤基于0.5s翻转LED灯和6s内实现LED灯的PWM效果,即6s内实现暗-亮-暗变化
基础配置:
SYS中Debug设定为JTAG(4 pins),时钟配置同往常实验,正常时钟配置。
Timers选择TIM3,Clock Source选择打开Internal Clock,如果对PA6有操纵就要去开通道引脚但现在不需要。
正点原子例程中main.c中TIM3_Int_Init(5000-1, 8400-1); 逗号前为ARR设定,逗号后为PSC设定,-1是因为从0开始计数,但分别仍为5000和8400个值。则在参数设定中的Counter Settings中配置Prescaler (PSC)为8400,Counter Period (ARR)为5000并且选择向上计数模式,选择没有分频,使能自动重装载auto-reload preload,使能自动重装载的作用为如果计数值超过ARR产生中断后要把ARR数值移到寄存器中(在我的的理解为计数值归0重新计数)才能在溢出后重新进入下一个定时周期的计数。
因为要在中断点灯,设置打开中断,在NVIC中打开TIM3 global interrupt。
打开PF10引脚作为LED0,点灯,maximum output speed设置为Medium。
【标准库vs HAL库:HAL库要使能外设或使能外设中断;写中断服务函数,在HAL库里中断服务函数省掉了获取标志位和清除标志位的工作然后直接跳进Callback函数】
在tim.c中开启中断函数:HAL_TIM_Base_Start_IT(&htim3); 该函数可以去头文件找,在Drivers中STM32F4xx_HAL_Driver底层驱动库中Inc(头文件)中打开stm32f4xx_hal_tim.h,在右侧有函数的框总结了所有函数变量名,函数都在头文件中定义。
图 2 头文件中的宏变量和函数定义
然后要写中断的代码,打开stm32f4xx_it.c,找到void TIM3_IRQHandler(void),定位到callback 函数,加入如下代码。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin); }
该工程挂载在APB1时钟,其为42MHz。
图 3 APB1时钟
因为APB1分频不等于1,所以根据图4,if (APBx presc = 1x1 else x2)得,定时器时钟需要x2,为42MHzx2 = 84MHz。
图 4 APB外设时钟使能
频率=84M/8400,工作频率为84M,分频系数为8400,时间=8400/84M=0.1ms,0.1ms代表着为了计数到5000,一个单位时间为0.1ms,则ARR代表的溢出时间界限为0.1msx5000=500ms。
ARR不可以无限大,阈值受限于CNT(比特位宽),CNT有16bit和32bit,最高能计数到216或232。
达成实验1目的方式
ARR设置为10000或分频系数PSC为16800。
PWM背景
通过捕获/比较1寄存器CH1改变占空比。
PWM脉宽调制,PF9挂载在TIM14,通过TIM14外设控制实现PWM。定时器由4个通道变为2两个通道。
基础配置:
激活TIM14,Channel1选择PWM Generation CH1,TIM14_PWM_Init(500-1, 84-1); 其他设置同上。
通过PWM模式和极性设定CCR左右的高低电平。
PWM模式可以设定CCR值两侧的有效与无效,PWM模式1对应CNT<CCR 区域有效;PWM模式2对应CNT>CCR区域有效。
CCER中的CC1P极性可以设定有效与无效分别对应的高低电平:为0时,有效为高电平,为1时,有效为低电平。
在该实验中,设定最终效果为CNT>CCR时为高电平,即配置PWM模式为1并选择CH Polarity为Low。还要使能输出比较。
在tim.c中void MX_TIM14_Init(void)里使能HAL_TIM_PWM_Start(&htim14, TIM_CHANNEL_1);用于开外设的功能。
编写主函数,在main.c中用SetCompare函数不断更新迭代CCR数值从而实现PWM,_HAL_TIM_SetCompare(&htim14, TIM_CHANNEL_1, led0pwmval); CCR数值对应led0pwmval。
在main.c里编写如下代码:
HAL_Delay(4.5);
if(dir)led0pwmval++;
else led0pwmval--;
if(led0pwmval>300)dir=0;
if(led0pwmval==0)dir=1;
__HAL_TIM_SetCompare(&htim14, TIM_CHANNEL_1, led0pwmval);
定义局部变量
uint16_t led0pwmval=0;
uint8_t dir=1;
6s的计算如下:
T=1/8=84(PSC)/84M=1/1Ms=1μs
500x1μs=500μs=0.5ms, CCR为300,即暗到亮要300个周期即300个0.5μs,暗亮暗有600周期,即300ms,变化太快人眼难以捕捉,所以给了delay10ms,,(10+0.5)x600=6300ms。
达成实验2目的方式
改变delay为HAL_Delay(4.5)。
结果
D2灯1s翻转一次;D1灯3s内实现PWM效果,即3s实现由暗到亮到暗的变换。图5和图6拍摄时间上相差1s。
图 5 D2灯灭,D1灯变暗
图 6 D2灯亮,D1灯变暗