温馨提示:本文不会重复之前提到的内容,如需查看,请参考附录
重点提炼:
引脚对应:
TIM3_CH1/TIM16_CH1——PB4——频率输出1
TIM2_CH1/TIM8_CH1——PA15——频率输出2
CubeMX设置:
将Combined Channels(结合渠道)设置为PWM Input on CH1模式
定时器基本参数:
- 预分频系数:Prescaler (PSC - 16 bits value)
- 定时器周期:Counter Period
定时器模式参数:
- 捕获极性:Polarity Selection (根据要读取的PWM波形选择,一般习惯是:如果PWM波以上跳沿开始那么CH1就设置为上跳沿有效)
打开对应的定时器中断。
MDK代码:
需要打开对应定时器、中断方式打开两个通道
HAL_TIM_Base_Start(&htim3);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);
中断服务函数名称:
void TIM3_IRQHandler(void)
读取比较寄存器的值:
__HAL_TIM_GET_COMPARE(定时器句柄地址, 通道号);
频率计算公式:
如果测量频率需要更精确,直接将预分频系数设置为0,这样定时器频率就等于APB1 Timer了。
读取的PWM波的频率 = 定时器频率/CH1读取的值
而:
定时器频率 = APB1 Timer/(预分频系数+1);
理论知识:
根据我介绍的操作,你可以学会读取PWM波方法,读取的原理参考以下文章PWM输入捕获(只使用一路定时器通道)_pwm捕获-CSDN博客
一、需求分析
本示例设计:读取PWM波的周期和脉宽,并显示在LCD上。LCD设置为蓝色背景,白色字符。
1、需要的外设资源分析:
- 读取PWM波:TIM3_CH1(PB4)
- LCD
2、外设具体分析:
查看原理图,和手册。
LCD部分见附录;
根据原理图,信号发生器(也就是开发板上的频率输出)有两个输出——PA15和PB4,如图:
利用CubeMX,发现引脚对应为:
TIM3_CH1/TIM16_CH1——PB4——频率输出1
TIM2_CH1/TIM8_CH1——PA15——频率输出2
所以,PB4可以用作TIM3的通道1,如图:
根据手册,输入捕获模式需要设置如下参数:
定时器基本参数:
- 预分频系数:Prescaler (PSC - 16 bits value)
- 定时器周期:Counter Period
定时器模式参数:
- 捕获极性:Polarity Selection (根据要读取的PWM波形选择,一般习惯是:如果PWM波以上跳沿开始那么CH1就设置为上跳沿有效)
3、软件分析:
要求分析:
使用TIM3_CH1捕获PWM信号,然后显示在LCD上。
二、软件配置
参考附录的内容,建立名为“PWM_In_Demo ”的项目,别忘记修改时钟配置。
按照分析配置引脚:
LCD部分见附录;
这里 TIM3 要先配置引脚,因为TIM3_CH1对应两个引脚,开发板上连接的是PB4。
然后选中TIM3,将Combined Channels(结合渠道)设置为PWM Input on CH1模式,如图:
然后配置 Parameter Settings :
- 为了看到明显改变,这里设置时钟频率为1万Hz。
- 读取PWM的定时器周期应该大于要读取的PWM波周期,默认情况下读取PWM的定时器周期设置的尽量大即可。所以这里把溢出周期为5000ms。
即:
- 预分频系数:Prescaler (PSC - 16 bits value) = 4999
- 定时器周期:Counter Period = 49999
- 捕获极性:将CH1的 Polarity Selection 设置为Rising Edge
- 其余保持默认
结果如图:
打开TIM3中断,使用默认优先级即可;
生成项目文件后,打开MDK;
导入LCD驱动程序;
三、代码编写
分析:
- 先在while循环前设置LCD的显示颜色,然后启动TIM3,以输入捕获模式中断启动CH1和CH2两个通道;
输入捕获模式中断启动CH1函数:
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1):
- 主循环体中不需要写代码,功能在中断服务函数里实现;
- 在 stm32g4xx_it.c 里用Find模式搜索TIM3,找到找到中断服务函数TIM3_IRQHandler;
- 在中断服务函数的第二个用户代码段里读取周期和脉宽,并显示在LCD上;
用到的函数:
中断服务函数名称:
void TIM3_IRQHandler(void)
读取比较寄存器的值:
__HAL_TIM_GET_COMPARE(定时器句柄地址, 通道号);
在MDK中编写代码:
在 main(void) 的 /* USER CODE BEGIN WHILE */ 代码段,编写以下代码:
/* USER CODE BEGIN WHILE */
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
LCD_Clear(Blue);
HAL_TIM_Base_Start(&htim3);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);
while (1)
{
/* USER CODE END WHILE */
在中断服务函数的 /* USER CODE BEGIN SysTick_IRQn 1 */代码段,编写以下代码:
/* USER CODE BEGIN TIM3_IRQn 1 */
uint16_t IC1_width = __HAL_TIM_GET_COMPARE(&htim3,TIM_CHANNEL_1);
uint16_t IC2_pluse = __HAL_TIM_GET_COMPARE(&htim3,TIM_CHANNEL_2);
if(IC1_width==0 || IC2_pluse==0)
return;
char str_width[20];
char str_pluse[20];
sprintf(str_width,"PWM width = %d",IC1_width);
sprintf(str_pluse,"PWM pluse = %d",IC2_pluse);
LCD_DisplayStringLine(Line3,str_width);
LCD_DisplayStringLine(Line5,str_pluse);
/* USER CODE END TIM3_IRQn 1 */
四、运行测试
编译、下载。
运行结果如下:
PWM_In_Deom实验结果
我们读取到了开发板上频率输出的周期和脉宽。
这里为了演示周期和脉宽的方便,设置的定时器频率太低了,不适合用来计算PWM波的频率。但是根据周期和定时器的配置,也可以粗略计算出频率,如果测量频率需要更精确,直接将预分频系数设置为0,这样定时器频率就等于APB1 Timer了。
频率计算公式:
读取的PWM波的频率 = 定时器频率/PWM波周期。
而:
定时器频率 = APB1 Timer/(预分频系数+1)