文章目录
一、定时器计数控制LED
使用STM32F103的 Tim2~Tim5其一定时器的某一个通道pin(与GPIOx管脚复用,见下图),连接一个LED,用定时器计数方式,控制LED以2s的频率周期性地亮-灭。
1.1、创建项目
再设置一个输出管脚控制LED灯的亮灭。这里设置的是A4。最后按照之前的配置,生成程序即可。
1.2、代码添加
- 首先需要开启定时器中断
- 添加中断回调处理函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
static uint32_t time_cnt = 0;
if(htim->Instance == TIM2){
if(++time_cnt >= 400){
time_cnt = 0;
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_4);
}
}
}
1.3、实现效果
二、定时器pwm模式呼吸灯
采用定时器pwm模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整到一个满意效果。使用Keil虚拟示波器,观察 pwm输出波形。
2.1、设计思路
- 第一步:定义初始化占空比Duty值为0
- 第二步:如果占空比值小于200,则步进10,延迟60ms,一直循环,直到占空比值为200
- 第三步:如果占空比值为200,则步进-10,延迟60ms,一直循环知道占空比值为0,又回到第2步。
一个PWM信号周期为20ms,因为STM32F103C8T6的时钟频率为72MHZ,故可以PSC为7199,ARR为200。这样单个脉冲周期为200/[72*10^6/(7199+1)]=0.02s即20ms
2.2、项目创建
改成72MHZ
最后生成这个项目即可
2.3、代码添加
- 开启PWM
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
- while循环控制pwm占空比
while (1)
{
/* USER CODE END WHILE */
while(Duty < 200){
HAL_Delay(60);
Duty = Duty + 10;
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, Duty);
}
while(Duty > 0){
HAL_Delay(60);
Duty = Duty - 10;
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, Duty);
}
/* USER CODE BEGIN 3 */
}
2.4、示波器观察
通过示波器可以看到占空比逐渐在变化,这一段是从0一直到200。因为使用了延迟函数,延迟同一占空比60ms,一个脉冲周期为20ms,所以会重复三次相同脉冲,步进值为10。60*20=1200ms,为从0到200的时间。
这段是从200到0,会持续1200ms的时间。所以总共一个呼吸下来会话2.4s的时间。
2.5、效果
人眼看的时候,这确实是一个呼吸灯,但使用手机录制视频时就会出现闪烁的情况,这是为什么?闪烁的频率太慢了。如何解决?增大闪烁的频率,即减小一个脉冲的周期。所以可以减小分频系数,或者减少计数值。
- 将分频系数改为71,实际数值会加1,此时计算每个脉冲周期为0.2ms,示波器如下:
效果如下:
- 改变计数值
此时的一个脉冲周期为2ms。示波器如下:
效果如下:
三、串口显示周期脉宽
采用定时器的另外一个通道,编程采集上面的pwm输出信号,获得其周期和脉宽,并重定向输出到串口显示。
3.1、创建项目
设置TIM1通道1为输入捕获并开启输入捕获中断
设置TIM2为PWM输出
3.2、代码
- 输入捕获回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
if(htim->Instance == TIM1) //ÅжϷ¢Éú²¶»ñÖжϵĶ¨Ê±Æ÷
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) //Åжϲ¶»ñ·¢ÉúͨµÀ
{
if(CapIndex == 0){
CapVal1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
printf("CapVal1: %d\r\n",CapVal1);
CapIndex = 1;
}else if(CapIndex == 1){
CapVal2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
printf("CapVal2: %d\r\n",CapVal2);
HAL_TIM_IC_Stop(htim, TIM_CHANNEL_1);
CapIndex = 0;
MeasureFlag = 1;
}else{
Error_Handler();
}
}
}
}
- while
while (1)
{
/* USER CODE END WHILE */
if(MeasureFlag == 1){
if(CapVal1>=CapVal2){
Diff = CapVal2-CapVal1;
}else{
Diff = ((10000-CapVal1)+CapVal2);
}
printf("Period is:%.4fms\r\n",Diff/1.0);
MeasureFlag = 0;
HAL_Delay(1000);
HAL_TIM_IC_Start(&htim1, TIM_CHANNEL_1);
}
//printf("Period is:%.4fms\r\n",Diff/1.0);
/* USER CODE BEGIN 3 */
}
3.3、运行效果
四、总结
经过本次实验,发现并没有很熟练的掌握定时器板块,有一部分实验没有做成功,比如输入捕获这里,还需要后续进一步完善,暂时没有找到原因。但呼吸灯以及定时控制亮灭都成功完成,对定时器有了初步的了解,以及如何控制PWM。