本次实验利用开发板上的LD2、LD3、LD4所在的端口PB3、PB4、PB5输出同一频率、不同占空比的PWM波,使LD2、LD3、LD4呈现出不同的亮度。当然也可以让这三个LED呈现“呼吸”灯状态显示,输出固定占空比主要是方便对波型进行简单的定量分析。
从上图可以看到这三个端口可以被TIM2_CH2、TIM3_CH1、TIM3_CH2三个通道复用。TIM2、TIM3两个定时器都属“通用”定时器,但区别为TIM2为32位;TIM3为16位。下面是对这两个定时器更加具体的描述:
实验代码参考了官方DEMO。主要代码如下:
void TIM3_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //开启TIM3时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); //开启GPIOB时钟
GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_1);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_1);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5; //TIM3_CH1 TIM3_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/*定时器时钟频率 = 48MHz/psc = 48MHz/(47+1)=1MHz
定时时间 = 1MHz/arr = 1HMz/(999+1) = 1KHz = 0.001s = 1ms
*/
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 80K
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 不分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC1Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //CH1预装载使能
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //CH2预装载使能
TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIM3在ARR上的预装载寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIM1
}
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); //开启TIM2时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); //开启GPIOB时钟
GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_2); //开启PB3端口复用
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //TIM2_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 80K
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 不分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性低
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); //CH2预装载使能
TIM_ARRPreloadConfig(TIM2, ENABLE); //使能TIM2在ARR上的预装载寄存器
TIM_Cmd(TIM2, ENABLE); //使能TIM2
}
int main(void)
{
delay_init();
TIM2_PWM_Init(999,47);
TIM3_PWM_Init(999,47);
TIM3->CCR1 = 700;//PB4 LD4
TIM3->CCR2 = 400;//PB5 LD3
TIM2->CCR2 = 100;//PB3 LD2
while(1)
{
}
}
从上面的配置中可以看出,定时器时钟频率使用了48分频,即48MHz/(47+1)=1MHz,周期值为1000,这样在这三个输出通道上即可产生频率为1KHz的PWM波。TIM3两个通道定时器输出比较极性为“高”;TIM2为“低”,其它部分两个定时器配置一样。另外还要注意就是配置中别忘记打开输出端口的“复用”。
阅读手册中关于GPIO端口复用寄存器的描述:
其中对于端口复用功能高位寄存器(GPIOx_AFRH)(x = A..D)的描述中[AF7:AF0]是不是应该写成[AF15:AF8]?也可能是我理解有误。
下面是逻辑分析仪抓取的波型,实验结果符合代码配置要求。
PWM(TIM2 TIM3).rar
(257.74 KB)
|