本次实验使用的是蓝桥杯嵌入式大赛的指定开发板,STM32G431R8T6。
下面为 CubeMX 和代码部分
CubeMX
选择对应引脚,配置为定时器模式,设置通道一路为“Input Captu direct mode”(输入捕获直接模式用于读取周期)、一路为“Input Captu inindirect mode”(输入捕获间接模式用于计算占空比)。
预分频(PSC)设置为(时钟频率-1)以便于计算。
自动重装初值默认不变。
通道一设置为“Rising Edge”上升沿捕获、通道二设置为“Falling Edge”下降沿捕获。
生成代码。
pwm.c
#include "pwm.h"
/* 用于输入捕获 */
uint32_t tim2_val1, tim2_val2, tim3_val1, tim3_val2; /* 保存两路通道读取的值 */
uint32_t tim2_freq, tim3_freq; /* 保存两路PWM的频率 */
float tim2_duty, tim3_duty; /* 保存两路PWM的占空比*/
/* PWM捕获,占空比频率 (定时器输入捕获回调函数)
* 参数:定时器
*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2)
{
/* 捕获到上升沿 */
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
tim2_val1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); /* 读取通道一,上升沿的值 一个完整的周期 */
tim2_val2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2); /* 读取通道二,下降沿的值 一个周期中的高电平 */
__HAL_TIM_SetCounter(htim, 0); /* 清零定时器中的值,继续读取下一周期的脉冲 */
/* 捕获到的频率 = 时钟频率 / 预分频值 / 捕获的值(从0开始直到上升沿产生读的数值) */
tim2_freq = (80000000 / 80) / tim2_val1;
/* 捕获的占空比 = 高电平的时间 / 低电平的时间 * 100 */
tim2_duty = ((float)tim2_val2 / tim2_val1) * 100;
HAL_TIM_IC_Start(htim, TIM_CHANNEL_1);
HAL_TIM_IC_Start(htim, TIM_CHANNEL_1);
}
}
else if(htim->Instance == TIM3)
{
/* 捕获到上升沿 */
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
tim3_val1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); /* 读取通道一,上升沿的值 一个完整的周期 */
tim3_val2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2); /* 读取通道二,下降沿的值 一个周期中的高电平 */
__HAL_TIM_SetCounter(htim, 0); /* 清零定时器中的值,继续读取下一周期的脉冲 */
/* 捕获到的频率 = 时钟频率 / 预分频值 / 捕获的值(从0开始直到上升沿产生读的数值) */
tim3_freq = (80000000 / 80) / tim3_val1;
/* 捕获的占空比 = 高电平的时间 / 低电平的时间 * 100 */
tim3_duty = ((float)tim3_val2 / tim3_val1) * 100;
HAL_TIM_IC_Start(htim, TIM_CHANNEL_1);
HAL_TIM_IC_Start(htim, TIM_CHANNEL_1);
}
}
}
pwm.h
#ifndef __PWM_H_
#define __PWM_H_
#include "main.h"
/* 用于输入捕获 */
extern uint32_t tim2_val1, tim2_val2, tim3_val1, tim3_val2; /* 保存两路通道读取的值 */
extern uint32_t tim2_freq, tim3_freq; /* 保存两路PWM的频率 */
extern float tim2_duty, tim3_duty; /* 保存两路PWM的占空比*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);
#endif
主函数功能验证部分
sprintf(lcd_string, "R39 freq %d ",tim3_freq);
LCD_DisplayStringLine(Line1, (unsigned char *)lcd_string);
sprintf(lcd_string, "R39 duty %.3f ",tim3_duty);
LCD_DisplayStringLine(Line2, (unsigned char *)lcd_string);
sprintf(lcd_string, "R40 freq %d ",tim2_freq);
LCD_DisplayStringLine(Line3, (unsigned char *)lcd_string);
sprintf(lcd_string, "R40 duty %.3f ",tim2_duty);
LCD_DisplayStringLine(Line4, (unsigned char *)lcd_string);
注意在 main 函数开始时,我们还需要使能 PWM输入捕获中断使能:
/* 开启定时器2,3输入捕获中断 */
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_2);