一.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 */

 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐