main函数
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "timer.h"
int main(void)
{
u16 led0pwmval=0;
u8 dir=1;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置NVIC中断分组2:2位抢占优先级,2位响应优先级
LED_Init(); //LED端口初始化
TIM3_PWM_Init(899,0); //不分频。PWM频率=72000000/900=80Khz
while(1)
{
delay_ms(10);
if(dir)led0pwmval++;
else led0pwmval--;
if(led0pwmval>300)dir=0;
if(led0pwmval==0)dir=1;
TIM_SetCompare2(TIM3,led0pwmval);
}
}
timer.c函数
#include "timer.h"
#include "led.h"
#include "usart.h"
//TIM3 PWM部分初始化
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{
//定义结构体变量
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
//使能定时器3时钟,使能GPIO外设和AFIO复用功能模块时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
//Timer3部分重映射 TIM3_CH2->PB5
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
//设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形 GPIOB.5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
//初始化TIM3
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
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的时间基数单位
//初始化TIM3 Channel2 PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC2
//使能TIM3在CCR2上的预装载寄存器
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
//使能TIM3
TIM_Cmd(TIM3, ENABLE);
}
代码解析
从死循环函数可以看出,我们将 led0pwmval 这个值设置为 PWM 比较值(低于这个值输出低电平,高于这个值输出高电平),也就是通过 led0pwmval 来控制 PWM 的占空比,然后控制 led0pwmval 的值从 0 变到 300,然后又从 300 变到 0,如此循环,因此 DS0 的亮度也会跟着从暗变到亮,然后又从亮变到暗。至于这里的值,我们为什么取 300,是因为 PWM 的输出占空比达到这个值的时候,我们的 LED 亮度变化就不大了(虽然最大值可以设置到 899),因此设计过大的值在这里是没必要的。至此,我们的软件设计就完成了。
对比延时函数实现的呼吸灯
前面写过一份关于呼吸灯的实现代码,那个是根据延时函数来实现的效果,利用灯的亮/灭时间的不同来控制显示灯的亮度。方法简单,但是实际项目过程中不可取,因为延时函数实现的呼吸灯会一直浪费CPU资源。而利用定时器产生PWM输出则可以节约CPU资源。
补充定时器PWM初始化时的模式设置和极性设置
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; 模式设置
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 极性设置
由此可知,(PWM2和High)以上代码设置含义为:当计数值CNT小于CCR比较值时为低电平0,当CNT大于CCR时为高电平。
通过改变PWM模式和极性即可改变PWM波形。