STM32 PWM实现呼吸灯

STM32 PWM控制呼吸灯程序(脉冲宽度调制)

PWM工作原理


ARR:自动预装载寄存器
CNT:自动装载计数器
CRR:比较器
图解:在一个周期t2内,随着计数器(CNT)值的不断增加,取任一时刻t1,CNT的值与CCR的值进行比较,如果CNT>CCR,则选择t1-t2时间段为有效电平(具体根据选择的PWM模式来确定)

通过不断改变比较器里的值来与定时计数器的值作比较来实现脉冲宽度的调制,具体结合PWM的模式选择向上溢出还是向下溢出

几个关键词解释:
更新:当计数器里面的值溢出(上溢或下溢)之后(如果设中断的话会触发标志位置一进中断),计数器会重置重新计数`
占空比:对于呼吸灯而言,即在一个周期内,高电平持续的时间(此处为有效电平,如果高电平有效)

代码部分及详解

注意:配置led灯,包括时钟开关,复用功能等等,关于定时器的配置网上都有成片的代码,我用的STM32 F103ZET6,将PF6用作呼吸灯,用的是TIM2定时器,主要是在PF6上没有默认的TIM2的通道,只能引入一个引脚PA0并输入可调制的脉冲宽度,然后将一根杜邦线将PF6引脚和PA0引脚相连就OK了,当时在这纠结了好久,思维定势,总是对PF6进行操作
最后main函数的两个while循环功能就是不断地改变比较器里面的值(这个方法也是在网上找的,只要达到这个功能就行),延时函数不可忽略,最好用库函数我是自己写的,如果没有延时函数的话效果看不见或者是不明显,还有注意不需要点灯代码Setbits()
注:代码仅仅针对PWM,定时器方面没做解释,所以很简单,很容易帮助理解脉冲宽度调制

void delay(int v)
{
	for( i = 1000;i>0;i--)
		for( j = 1000;j > 1000;j--);
}
void LED_Config(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOA,ENABLE);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
	
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void Timer_Init(void)
{
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        TIM_OCInitTypeDef TIM_OCInitStructure;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //打开定时器时钟
        
        //定时器2 设置 360分频 1KHz 向上计数
        TIM_DeInit(TIM2);
        TIM_TimeBaseStructure.TIM_Period =199;//
        TIM_TimeBaseStructure.TIM_Prescaler =359; //360分频 即为200KHz,16位的值,最大65536
        TIM_TimeBaseStructure.TIM_ClockDivision =0x00; //时钟分频系数,不分频
        TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //初始化定时器

        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //主定时器TIM2为PWM1模式
        TIM_OCInitStructure.TIM_OutputState =TIM_OutputState_Enable;//使能输出比较状态
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
        //ch1 配置项
        TIM_OCInitStructure.TIM_Pulse = 5;
        TIM_OC1Init(TIM2, & TIM_OCInitStructure); //ch1占空比75%
        TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能的预装载寄存器

        TIM_ClearFlag(TIM2, TIM_IT_CC1);
        TIM_Cmd(TIM2,ENABLE); //使能定时器2
}
int main()
{
	u16 i;
	LED_Config();
	Timer_Init();
	while (1) 
	{
		i = 0; //i置为0
		
		while (i <= 300) 
		{
			delay(1000);
			//delay_ms(10);
			TIM_SetCompare1(TIM2, i);
			i++;
		}
		
		i = 300; //i置为300
		
		while (i > 0) 
		{
			//delay_ms(10);
			delay(1000);
			TIM_SetCompare1(TIM2, i);
			i--;
		}
	}

}