(五)【STM32】TIM+PWM输出与捕获
PWM脉冲宽度调制,简称脉宽调制,指对脉冲宽度的控制,它是一种利用微控制器(MCU)的数字输出来对模拟电路进行控制的非常有效的技术。PWM信号由高电平和低电平交替组成,通过改变高电平时间(脉宽)与周期时间的比例(占空比)来调节输出信号的平均电压。占空比越高,平均电压越高,反之越低。
·
一.PWM信号的输出
1.1 PWM的定义及应用
PWM脉冲宽度调制,简称脉宽调制,指对脉冲宽度的控制,它是一种利用微控制器(MCU)的数字输出来对模拟电路进行控制的非常有效的技术。
PWM信号由高电平和低电平交替组成,通过改变高电平时间(脉宽)与周期时间的比例(占空比)来调节输出信号的平均电压。占空比越高,平均电压越高,反之越低。
1.2 关键参数
(1)频率(HZ)
信号周期的倒数,决定PWM的切换速度。
(2)占空比(%)
高电平时间与周期时间的比例。
占空比计算:占空比=Pulse/(ARR+1)*100%
(3)PWM的模式选择
PWM mode 1:向上计数,计数值小于CCR值输出高电平,计数值大于CCR时输出低电平,向下计数相反。
二. 实践
2.1输出
(1)输出频率为50HZ占空比为50%的波形(方波)



/* USER CODE BEGIN 2 */
__HAL_TIM_MOE_ENABLE(&htim1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
//HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
/* USER CODE END 2 */
(2)输出频率为50HZ~1KHZ占空比为50%的波形
STM32F103C8T6 没有内置 DAC,我们可以使用 PWM 输出配合低通滤波器来模拟斜波信号。
/* USER CODE BEGIN PV */
uint32_t current_freq = 50; //当前频率
uint32_t min_freq = 50; //最小频率
uint32_t max_freq = 1000; //最大频率
uint32_t freq_step = 10; //每次的频率变化量
uint32_t transition_delay = 50; //变化延时ms
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
__HAL_TIM_MOE_ENABLE(&htim1);//开启定时器1输出功能
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);//开启定时器1的PWM
//HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
/* USER CODE END 2 */
/* USER CODE BEGIN 3 */
uint32_t arr = (1000000 / current_freq) - 1; //计算重载值
if (arr > 65535) arr = 65535;
__HAL_TIM_SET_AUTORELOAD(&htim1, arr); //设置新的重载值
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, arr/2); //设置占空比为50%
HAL_Delay(transition_delay); //系统延时50ms,控制频率变化的速度
current_freq += freq_step; //当前频率增加freq_step(10)
if (current_freq > max_freq) //当频率超过max_freq(1000)时,赋值
{
current_freq = min_freq; //从最小频率重新开始
}
}
/* USER CODE END 3 */
(3)输出定频为50HZ占空比可调的一个波形
/* USER CODE BEGIN PV */
uint32_t current_duty = 50; //当前占空比
uint32_t min_duty = 0; //最小占空比
uint32_t max_duty = 100; //最大占空比
uint32_t duty_step = 5; //占空比调节步长
uint32_t transition_delay = 500; //占空比变化延迟时间
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
__HAL_TIM_SET_AUTORELOAD(&htim1, PWM_PERIOD - 1);
__HAL_TIM_MOE_ENABLE(&htim1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
/* USER CODE END 2 */
/* USER CODE BEGIN 3 */
uint32_t compare_val = (PWM_PERIOD * current_duty) / 100;//占空比百分比转换为定时器计数值
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, compare_val);//设置占空比
HAL_Delay(transition_delay); //延时
current_duty += duty_step; //改变占空比
if (current_duty > max_duty) //调整占空比
{
current_duty = min_duty;
}
}
/* USER CODE END 3 */
2.2捕获
(1)检测PWM的周期和频率
CubeMX




代码
/* USER CODE BEGIN PV */
uint16_t ccr1_cnt = 0; //第一次下降沿捕获时CCR值
uint16_t ccr2_cnt = 0; //第一次上升沿捕获时CCR值
uint16_t Period_cnt = 0; //
uint16_t Period_cnt1 =0; //发生计数器溢出事件次数
uint16_t Period_cnt2 = 0; //
uint16_t ic_flag = 0; //输入捕获标志
uint16_t end_flag = 0; //捕获结束标志
float frequency = 0; //频率
float duty_cycle = 0; //占空比
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1); //启动计时器2PWM输出
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1); //启动定时器3的输入捕获功能
/* USER CODE END 2 */
/* USER CODE BEGIN 3 */
HAL_Delay(500);
if(end_flag){
duty_cycle=(float)(Period_cnt1 * 65536 + ccr1_cnt + 1) * 100 /(Period_cnt2 * 65536 + ccr2_cnt + 1);
frequency=1000000 / (float)(Period_cnt2 * 65536 + ccr2_cnt + 1);
char buff[50];
sprintf(buff,"\r\n freq = %.2f Hz,duty = %.2f %%",frequency,duty_cycle);
HAL_UART_Transmit_IT(&huart1, (uint8_t*)buff, strlen(buff));
end_flag = 0;
}
}
/* USER CODE END 3 */
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){//定时器计数溢出回调
Period_cnt ++; //定时器计数溢出次数
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){ //定时器输入捕获回调
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1){ //是否是通道1
if(end_flag == 0){ //判断结束标志是不是0
switch(ic_flag){ //判断此时处于捕获第几阶段
case 0:
{ //第一次捕获到上升沿
__HAL_TIM_SET_COUNTER(&htim3,0); //定时器3计数设置为0
ccr1_cnt = 0; //参数设置0
ccr2_cnt =0;
Period_cnt = 0;
Period_cnt1 = 0;
Period_cnt2 = 0;
__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);
ic_flag = 1;
break;
}
case 1: //二阶段第一次捕获到下降沿
{
ccr1_cnt = __HAL_TIM_GET_COMPARE(&htim3,TIM_CHANNEL_1);
//获取CCR的值
Period_cnt1 = Period_cnt;
//获取计时器溢出次数1
__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);
//设置成上升沿捕获
ic_flag = 2;
break;
}
case 2: //阶段3 第二次捕获到上升沿
{
ccr2_cnt = __HAL_TIM_GET_COMPARE(&htim3,TIM_CHANNEL_1);
//获取CCR2
Period_cnt2 = Period_cnt;
//获取计时器溢出次数2
ic_flag = 0; //捕获设置为等待第一阶段
end_flag = 1;//完成一次捕获,将标志置1
break;
}
}
}
}
}
/* USER CODE END 4 */


更多推荐



所有评论(0)