STM32F103单片机PWM功能实现

x33g5p2x  于2021-10-14 转载在 其他  
字(3.7k)|赞(0)|评价(0)|浏览(453)

PWM模式也叫脉冲宽度调制模式,它可以产生一个频率和占空比可调的方波。由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。在硬件电路中,PWM波产生通常是由一个三角波和参考值送入比较器中,然后比较器输出的就是PWM波。

V1是三角波发生器,幅度为5V,频率为1K,V2是直流源,电压为3V,将这两个波形送入到比较器中,然后比较器输出的就是PWM波。输出波形如下:

当V1的电压值大于V2时,比较器输出高电平。当V1电压值小于V2时,比较器输出的就是低电平。改变V2的值,就可以改变占空比。

在单片机中寄存器ARR的值就相当于V1的值,CCR的值就相当于V2的值。当ARR和CCR寄存器的值设置好之后,计时器在计数的过程中计数器值就会实时和这两个值比较,当计数器值小于CCR时,输出低电平,当计数器值大于CCR值时,输出高电平。当计数器的值等于ARR时,计数器就会清零。

在设置PWM计数模式的时候,一般有三种模式,向上计数模式、向下计数模式、中央对齐模式。

向上计数模式:指的是计数器从0开始递增计数,当计数值等于ARR时,计数器清0,然后从0开始重新递增计数。

向下计数模式:指的是计数器从ARR开始递减计数,当计数值等于0时,计数器值重新设置为ARR,然后从ARR开始重新递减计数。

中央对齐模式:指的是计数器0开始递增计数,当计数值等于ARR时,计时器开始递减计数。当计数器值减到0时,又开始递增计数。

一般情况下用的比较多的就是向上计数模式,因为这种模式比较简单,理解起来也更容易一点。下面就通过代码来实现PWM的输出功能。

void TIM3_PWM_Init(u16 arr, u16 psc)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);							//使能定时器3时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);	//使能GPIO和AFIO复用功能模块时钟

    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);	//Timer3部分重映射 TIM3_CH2(PA7)--->PB5 TIM3_CH1(PA6)-->PB4

    //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形 GPIOB.5
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    //初始化TIM3
    TIM_TimeBaseInitStructure.TIM_Period = arr;
    TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
    //初始化TIM3_CH2 PWM 模式
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC2Init(TIM3, &TIM_OCInitStructure);
    //使能TIM3在CCR2上的预装载寄存器
    TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
    //使能TIM3
    TIM_Cmd(TIM3, ENABLE);
}
void TIM1_PWM_Init(u16 arr, u16 psc)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_OCInitTypeDef TIM_OCInitSturcture;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    TIM_TimeBaseInitStructure.TIM_Period = arr;
    TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);

    TIM_OCInitSturcture.TIM_OCMode = TIM_OCMode_PWM2;
    TIM_OCInitSturcture.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitSturcture.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC1Init(TIM1, &TIM_OCInitSturcture);

	
    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);

    TIM_Cmd(TIM1, ENABLE);				//使能计数器
    TIM_CtrlPWMOutputs(TIM1,ENABLE);	//主输出使能
}

这里通过两个定时器输出2路PWM波。使用的计数模式都为向上计数模式。PWM模式为PWM2模式。

接下来在主程序中设置PWM的频率和占空比。

int main(void)
{
    u16 led_pwm_val=0;
    u8 dir=1;
    delay_init();       //延时函数初始化
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    LED_Init();
    TIM3_PWM_Init(899,0);	//不分频。PWM频率=72000000/900=80Khz
    TIM1_PWM_Init(899,0);
    while(1)
    {
		delay_ms(10);
		if(dir) led_pwm_val++;
		else led_pwm_val--;
		
		if(led_pwm_val>300) dir=0;
		if(led_pwm_val==0) dir=1;
		TIM_SetCompare2(TIM3,led_pwm_val);
		TIM_SetCompare1(TIM1,led_pwm_val);
    }
}

在主函数中向初始化函数中传递两个参数,第一个参数是设置ARR值,第二个参数是设置时钟的分频系数。这里设置的ARR值为900,系统会自动给设置的值加1(因为ARR的值至少为1),所以设置值为899时,系统真正写入ARR寄存器的值是899+1,然后时钟分频系数设置为0,也就是默认时钟频率72MHz不分频。这样PWM的频率就为系统时钟除以自动装载的值。设置的PWM频率为 72MHz/900=80K。

要改变占空比时通过TIM_SetCompare()函数来设置,这个函数内部设置的就是CCR寄存器的值。
代码中设置的是CCR的值从0增加到300,然后又减到0。将PWM的输出端口接上一个LED灯,就可看到这个LED灯从亮到灭慢慢变化,实现了类似于呼吸灯的效果。

相关文章