一、STM32CubeMX配置
1.打开RCC时钟
选项 Master Clock Output 用来选择是否使能 MCO(PA8) 引脚时钟输出(冲突时会变红)
2.配置时钟
STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4
其中TIM1在APB2总线上,属于高级定时器,TIM2、3、4在APB1总线上,属于通用定时器
3.设置PWM的输出通道
PWM通道设置:
①Mode:
PWM模式1:无论是向上计数还是向下计数,只要CNT ⩽⩽CCRx,PWM输出高电平。
PWM模式2:无论是向上计数还是向下计数。只要CNT ⩽⩽CCRx,PWM输出低电平。
②Pulse:即初始的CCR值
类似于改占空比,例如Pulse=500,占空比则为 500/999(上图),占空比约为50%
③Output compare preload:输出比较值预加载
当使能此功能时,设置Pulse输出比较值时,该值不会立即生效,而是会等到当前PWM完成一个周期的输出后才把当前值设置至Pulse输出比较值的寄存器中。这样可以实现设置的平滑切换。不使能则是立即生效。这里建议使能该功能。
④Fast Mode:快速模式
⑤CH Polarity:通道极性,选择为高,若选择极性为低,则输出高低电平取反
4.PWM捕获配置
①Slave Mode(从机模式):可以在多种模式下与外部触发器同步
重置模式(输入出现上升沿时复位定时器计数并更新寄存器值)
门控模式(输入高电平时启动计数,输入低电平时停止计数,不重置寄存器)
触发模式(输入出现上升沿时启动计数,不能控制停止)。
②Trigger Source(触发源):如下图所示
③Clock Source(时钟源):一般使用内部时钟源即可。
④Channel x(第x通道):可以配置每个通道的功能
⑤One Pulse Mode(单脉冲模式):启用该功能时,当定时器计数值达到重装载值时停止计数。
⑥Input Capture Channel1 和 Input Capture Channel2设置:
Channel1选择上升沿捕获,储存的是CCR1的值,Channel2选择下降沿捕获,储存的是CCR2的值,由于是重置模式(输入出现上升沿时复位定时器计数并更新寄存器值),下降沿时计数器并不会清零。
⑦IC Selection:输入信号交叉,选择直通,不交叉(如下图所示)
⑧Prescaler Division Ratio:捕获预分频,选择不分频,每次信号都触发捕获
⑨Input Filter:滤波器参数,可以过滤信号抖动
5.使能所有用到的定时器
6.配置调试串口(非必要)
7.设置定时器优先级
因为用到多个定时器中断,需要设置中断优先级,具体需要自己判断
8.生成基本代码
二、编写主程序
个人认为在keil中更加简洁方便
以下是基于上述模板的示例代码
#include "my_main.h"
//TIM1输入捕获
u16 CCR1_1, CCR1_2, Duty1 = 0;
//TIM2输入捕获
u16 CCR2_1, CCR2_2, Duty2 = 0;
//TIM4输入捕获
u16 CCR4_1, CCR4_2, Duty4 = 0;
//TIM3输出PWM
u16 ARR3, Duty3_1, Duty3_2, Duty3_3, Duty3_4 = 0;
//串口
u8 UART_TX_Buffer[200] = "";
//我的初始化函数
void My_Init(void)
{
//TIM3输出PWM
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); //开启通道1输出
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2); //开启通道2输出
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3); //开启通道3输出
// HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4); //开启通道4输出
// 通过设置预分频器值设置PWM频率(CubeMX中已经配置了,但是可以在程序中再次修改)
__HAL_TIM_SET_PRESCALER(&htim3, 71); //72000000 Hz / (71 + 1) / (19999 + 1) = 50 Hz
__HAL_TIM_SET_AUTORELOAD(&htim3, 19999); //TIM3的ARR值
//TIM1输入捕获
HAL_TIM_IC_Start (&htim1, TIM_CHANNEL_1); //开启通道1输入捕获
HAL_TIM_IC_Start (&htim1, TIM_CHANNEL_2); //开启通道2输入捕获
//TIM2输入捕获
HAL_TIM_IC_Start (&htim2, TIM_CHANNEL_1); //开启通道1输入捕获
HAL_TIM_IC_Start (&htim2, TIM_CHANNEL_2); //开启通道2输入捕获
//TIM4输入捕获
HAL_TIM_IC_Start (&htim4, TIM_CHANNEL_1); //开启通道1输入捕获
HAL_TIM_IC_Start (&htim4, TIM_CHANNEL_2); //开启通道2输入捕获
}
//我的循环函数
void My_While(void)
{
// CCR2/CCR1 就是占空比
CCR1_1 = TIM1->CCR1;
CCR1_2 = TIM1->CCR2;
CCR2_1 = TIM2->CCR1;
CCR2_2 = TIM2->CCR2;
CCR4_1 = TIM4->CCR1;
CCR4_2 = TIM4->CCR2;
//为了便于计算(不出现浮点)
ARR3 = TIM3->ARR + 1;
Duty3_1 = CCR1_2 * ARR3 / CCR1_1; //输出TIM1捕获的PWM
Duty3_2 = CCR2_2 * ARR3 / CCR2_1; //输出TIM2捕获的PWM
Duty3_3 = CCR4_2 * ARR3 / CCR4_1; //输出TIM4捕获的PWM
// 确保TIM3的Duty在0到ARR3之间(无符号整数不可能小于0)
Duty3_1 = Duty3_1 > ARR3 ? ARR3 : Duty3_1;
Duty3_2 = Duty3_2 > ARR3 ? ARR3 : Duty3_2;
Duty3_3 = Duty3_3 > ARR3 ? ARR3 : Duty3_3;
//设置占空比
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, Duty3_1);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, Duty3_2);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, Duty3_3);
//使用串口观察数据
//计算占空比
Duty1 = (u16)((float)CCR1_2 / CCR1_1 * 100);
Duty2 = (u16)((float)CCR2_2 / CCR2_1 * 100);
Duty4 = (u16)((float)CCR4_2 / CCR4_1 * 100);
//使用串口输出到电脑
sprintf((char*)UART_TX_Buffer, "Duty1=%u%%;\nDuty2=%u%%;\nDuty4=%u%%;\nTIM3: ARR3=%u, Duty3_1=%u, Duty3_2=%u, Duty3_3=%u\n",
Duty1, Duty2, Duty4, ARR3, Duty3_1, Duty3_2, Duty3_3);
HAL_UART_Transmit(&huart2, (uint8_t*)UART_TX_Buffer, strlen((char*)UART_TX_Buffer), 200);
HAL_Delay(1000);
}
烧录到你的单片机中后,连接好电路,可以在电脑串口程序中看到捕获并输出的不同占空比的PWM波了。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/m0_70649291/article/details/144241039
|
共1人点赞
|