一、STM32定时器简介

STM32共有8个定时器,TIM1~TIM8。包括两个高级控制定时器,TIM1和TIM8;四个通用计时器,TIM2、TIM3、TIM4、TIM5;两个基本定时器,TIM6、TIM7。
其中除了TIM6和TIM7以外的其他定时器都可用来产生PWM输出。而每个高级控制定时器有7个通道,每个通用计时器也有4个通道,因此最多可以同时产生 30 路 PWM 输出。

二、此例简介

完成的功能:简单地使用多个定时器输出5路pwm
芯片:STM32F103RCT6
硬件:5个小灯,正点原子mini开发板

三、代码

1.main函数

int main(void)
 {
	  delay_init();            //延时函数初始化    	 
   
	  TIM2_PWM_Init(899,1);     //定时器2初始化
	  TIM3_PWM_Init(899,1);     //定时器3初始化
	  TIM4_PWM_Init(899,1);     //定时器4初始化
	  TIM5_PWM_Init(899,1);     //定时器5初始化

	 TIM_SetCompare3(TIM2,90);  //PA2,90%的亮度 
	 TIM_SetCompare4(TIM2,180);//PA3,80%的亮度
	 TIM_SetCompare2(TIM3,360); //PA7,60%的亮度
	 TIM_SetCompare1(TIM4,540);//PB6,40%的亮度
	 TIM_SetCompare2(TIM5,720);//PA1,20%的亮度
	 
	 delay_ms(100);

}

2.定时器初始化函数(以定时器二为例)

void TIM2_PWM_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  //使能定时器时钟2 
 	RCC_APB1PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  //使能GPIOA

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_2; //使能TIM2的CH3和CH4
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	TIM_TimeBaseStructure.TIM_Period = arr; //
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //一般设置为0
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数模式
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 

	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //脉冲宽度调制模式2
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_Pulse = 0; //CCR初始值
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //有效电平为高电平
	TIM_OC4Init(TIM2, &TIM_OCInitStructure);  //根据参数初始化TIM2的通道4
	TIM_OC3Init(TIM2, &TIM_OCInitStructure); //根据参数初始化TIM2的通道3

    TIM_CtrlPWMOutputs(TIM2,ENABLE);	//定时器2输出使能	

	TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);  //CH3预转载使能	
	TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);//CH4预转载使能
	
	TIM_ARRPreloadConfig(TIM2, ENABLE); //使能TIM2的ARR预装载寄存器

	TIM_Cmd(TIM2, ENABLE);  //使能TIM2
}

3.比较输出函数

void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3)
{
	assert_param(IS_TIM_LIST3_PERIPH(TIMx));//assert_param这个函数是用于检测传递给函数的参数是否是有效的参数
  	TIMx->CCR3 = Compare3; //将参数Compare3写入TIMx结构体中的成员CCR3
}

###########################################

注释:

1️⃣为什么执行TIM_SetCompare3(TIM2,90);输出的就是90%的亮度?

先解释一下PWM输出的频率,执行语句TIM2_PWM_Init(899,1);即把arr的值设置为899,psc设置为1(2分频),那么定时器输出PWM的频率为72MHz÷[(psc+1)×(arr+1)]=72MHz÷[(899+1)×(1+1)]=40000Hz,这个频率只要大于50Hz即可。因为大于50Hz时,人眼就感觉不到灯在闪烁。频率与亮度无关。

跟亮度有关的是脉冲宽度,在程序中,我们设置:

高电平为有效电平(TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;),

PWM模式为模式二(TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;),

向上计数模式(TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;),

CCR的值为90(TIM_SetCompare3(TIM2,90);),

CNT在0~899(ARR值)之间计数,当CNT>90(CCR值)时,输出高电平,此时高电平有效,故开始点亮LED。也就是说,只在0到90之间,LED灭,在90到900,LED亮,有效电平的脉冲宽度就为:(900-90)/900=90%,那么在高频率的闪烁中LED的亮度就为90% .

2️⃣PWM输出模式不只有上面的这种,可以很灵活

esp32有几个adc_脉冲宽度


这时候如果设置有效电平为高电平,那么输出的就是高电平;设置的电平是低电平,那么输出的就是低电平。

3️⃣几个小细节

我在使用多个定时器时,其初始化函数都是复制粘贴,但就犯了几个错误,找了几天😭

(1)TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Compare3)中的X是表示通道X,如果用的是通道3,那么就要写成TIM_SetCompare3.

(2)TIM_OCXInit(TIM2, &TIM_OCInitStructure);

TIM_OCXPreloadConfig(TIM2, TIM_OCPreload_Enable);

这两处也是,如果用的是通道3,那么就要写成TIM_OC3Init(TIM2, &TIM_OCInitStructure); 以及TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);.

四、调光效果

从左往右亮度分别为20%,40%,60%,80%,90%。

esp32有几个adc_脉冲宽度_02

五、附录

程序1、STM32定时器简单输出5路PWM,控制5个小灯呈现5种亮度