STM32输出四路频率和占空比均可调PWM

一个项目需要使用PWM调制四路激光,要求四路PWM的频率和占空比均可调(频率1~50000Hz,占空比0~100%)。如果是频率固定,只是要求占空比可调的话,使用一个定时器四路输出通道即可,但该项目要求频率也可调,因此定时器的时钟频率和计数周期均需调整,就需要用到四个独立的定时器。

我项目中使用的单片机为STM32F103RCT6,设计使用四个通用定时器输出四路PWM,定时器及通道分别为TIM2_CH3、TIM3_CH4、TIM4_CH3、TIM5_CH2。定时器的程序如下(HAL库):

1、定时器GPIO外设配置

/**
  * @brief  定时器GPIO外设配置
  * @param  无
  * @retval 无
  */
static void TIMx_GPIO_Config(void) 
{
	GPIO_InitTypeDef GPIO_InitStruct;
 
	/* 通用定时器GPIO外设时钟使能 */
	
	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();
	
	/*TIM2_CH3功能引脚IO初始化*/
	GPIO_InitStruct.Pin = GPIO_PIN_2;	//引脚
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;	//模式为复用推挽输出
	GPIO_InitStruct.Pull = GPIO_PULLDOWN;	//下拉
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;	//高速
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);	//PA2初始化
	
	/*TIM3_CH4功能引脚IO初始化*/
	GPIO_InitStruct.Pin = GPIO_PIN_1;	//引脚
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);	//PB1初始化
	
	/*TIM4_CH3功能引脚IO初始化*/
	GPIO_InitStruct.Pin = GPIO_PIN_8;	//引脚
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);	//PB8初始化	
	
	/*TIM5_CH2功能引脚IO初始化*/
	GPIO_InitStruct.Pin = GPIO_PIN_1;	//引脚
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);	//PA1初始化	
	
}

2、定时器配置

TIM_HandleTypeDef  TIM2_TimeBaseStructure;
TIM_HandleTypeDef  TIM3_TimeBaseStructure;
TIM_HandleTypeDef  TIM4_TimeBaseStructure;
TIM_HandleTypeDef  TIM5_TimeBaseStructure;
static void TIM_PWMOUTPUT_Config(void)
{
	TIM_OC_InitTypeDef  TIM_OCInitStructure;  
	int tim_per=10000;//定时器周期
	
	/*使能定时器*/
	__HAL_RCC_TIM2_CLK_ENABLE();
	__HAL_RCC_TIM3_CLK_ENABLE();
	__HAL_RCC_TIM4_CLK_ENABLE();
	__HAL_RCC_TIM5_CLK_ENABLE();
	
	/*TIM2时基配置*/
	TIM2_TimeBaseStructure.Instance = TIM2;
	/* 累计 TIM_Period个后产生一个更新或者中断*/		
	//当定时器从0计数到10000,即为10000次,为一个定时周期(默认初始配置)
	TIM2_TimeBaseStructure.Init.Period = tim_per-1;
	// 通用控制定时器时钟源TIMxCLK = 72MHz 
	// 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=1MHz(默认初始配置)
	TIM2_TimeBaseStructure.Init.Prescaler = 72-1;	
	/*计数方式*/
	TIM2_TimeBaseStructure.Init.CounterMode = TIM_COUNTERMODE_UP;
	/*采样时钟分频,时钟分频因子 ,配置死区时间时需要用到*/
	TIM2_TimeBaseStructure.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
	/*初始化定时器*/
	HAL_TIM_Base_Init(&TIM2_TimeBaseStructure);
	
	/*TIM3时基配置*/
	TIM3_TimeBaseStructure.Instance = TIM3;
	TIM3_TimeBaseStructure.Init.Period = tim_per-1;
	TIM3_TimeBaseStructure.Init.Prescaler = 72-1;	
	TIM3_TimeBaseStructure.Init.CounterMode = TIM_COUNTERMODE_UP;
	TIM3_TimeBaseStructure.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
	HAL_TIM_Base_Init(&TIM3_TimeBaseStructure);
	
	/*TIM4时基配置*/
	TIM4_TimeBaseStructure.Instance = TIM4;
	TIM4_TimeBaseStructure.Init.Period = tim_per-1;
	TIM4_TimeBaseStructure.Init.Prescaler = 72-1;	
	TIM4_TimeBaseStructure.Init.CounterMode = TIM_COUNTERMODE_UP;
	TIM4_TimeBaseStructure.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
	HAL_TIM_Base_Init(&TIM4_TimeBaseStructure);
	
	/*TIM5时基配置*/
	TIM5_TimeBaseStructure.Instance = TIM5;
	TIM5_TimeBaseStructure.Init.Period = tim_per-1;
	TIM5_TimeBaseStructure.Init.Prescaler = 72-1;	
	TIM5_TimeBaseStructure.Init.CounterMode = TIM_COUNTERMODE_UP;
	TIM5_TimeBaseStructure.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
	HAL_TIM_Base_Init(&TIM5_TimeBaseStructure);
  
	/*PWM模式配置*/
	TIM_OCInitStructure.OCMode = TIM_OCMODE_PWM1;//配置为PWM模式1
	TIM_OCInitStructure.Pulse = tim_per;//默认占空比为100%
	TIM_OCInitStructure.OCFastMode = TIM_OCFAST_DISABLE;
	/*当定时器计数值小于CCR1_Val时为低电平,
	因为我的硬件上经过三极管反了一下,因此选择低电平,如直接输出可配置为高电平*/
	TIM_OCInitStructure.OCPolarity = TIM_OCPOLARITY_LOW;	
	
	/*配置PWM通道*/
	HAL_TIM_PWM_ConfigChannel(&TIM2_TimeBaseStructure, &TIM_OCInitStructure, TIM_CHANNEL_3);
	HAL_TIM_PWM_ConfigChannel(&TIM3_TimeBaseStructure, &TIM_OCInitStructure, TIM_CHANNEL_4);
	HAL_TIM_PWM_ConfigChannel(&TIM4_TimeBaseStructure, &TIM_OCInitStructure, TIM_CHANNEL_3);
	HAL_TIM_PWM_ConfigChannel(&TIM5_TimeBaseStructure, &TIM_OCInitStructure, TIM_CHANNEL_2);
	/*开始输出PWM*/
	HAL_TIM_PWM_Start(&TIM2_TimeBaseStructure,TIM_CHANNEL_3);
	HAL_TIM_PWM_Start(&TIM3_TimeBaseStructure,TIM_CHANNEL_4);
	HAL_TIM_PWM_Start(&TIM4_TimeBaseStructure,TIM_CHANNEL_3);
	HAL_TIM_PWM_Start(&TIM5_TimeBaseStructure,TIM_CHANNEL_2);	

}

3、定时器初始化程序

在主程序内调用该函数进行定时器初始化配置。

/**
  * @brief  初始化控制通用定时器
  * @param  无
  * @retval 无
  */
void TIMx_Configuration(void)
{
	TIMx_GPIO_Config();
  
  TIM_PWMOUTPUT_Config();
}

4、PWM频率和占空比设置函数

可在其他功能函数中调用该函数进行四路PWM频率和占空比配置。

程序中的定时器时钟预分频和计数周期等参数计算参考自:STM32输出 PWM频率 占空比 连续可调~~

/**
  * @brief  设置PWM频率和占空比
  * @param  htim 定时器句柄结构体
  *			Channel 通道 TIM_CHANNEL_x x=1..4
  *			FQ 频率 1..50000(Hz)
  *			Duty 占空比 0..100(%)
  * @retval 无
  */
void TIMx_SetPWM_FQ_Duty(TIM_HandleTypeDef *htim,uint32_t Channel,uint32_t FQ,uint8_t Duty)
{
		
	uint32_t temp32;
	uint32_t uhTimerfrequency;
	uint16_t uhTimerPeriod;
	uint16_t uhTimerPrescaler;
	uint16_t uhTimerPulse;

	if (FQ >= 4000) 
	{
		uhTimerfrequency = FQ;  /* 定时器计时频率和PWM频率相等 */
		uhTimerPrescaler = 1;    /* 实际频率FQ较大时,TIMx设置分频为1(不分频)   */
	} 
	else 
	{
		uhTimerfrequency = 4000; /* 实际频率FQ较小时,和4000Hz的频率比较,看相差几倍 */
		uhTimerPrescaler = 4000 / FQ;  /* 实际频率和4000相差的倍数作为TIM2的分频设置值 */
		uhTimerfrequency = uhTimerPrescaler * FQ; /* TIMx分频后,计时周期变长,需要将uhTimerfrequency倍频  */
	}

	/* TIMx的周期要通过倍频uhTimerfrequency来计算,uhTimerPeriod = 72MHz / uhTimerfrequency */
	temp32 = SystemCoreClock / uhTimerfrequency;
	if (temp32 > 65535) temp32 = 65535;
	uhTimerPeriod = (uint16_t) temp32;

	if (Duty > 100) Duty = 100;
	uhTimerPulse = uhTimerPeriod * Duty / 100;

	
	__HAL_TIM_SET_PRESCALER(htim, uhTimerPrescaler-1);
	__HAL_TIM_SET_AUTORELOAD(htim, uhTimerPeriod-1);
	__HAL_TIM_SET_COMPARE(htim, Channel, uhTimerPulse);	

}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值