PWM即脉冲宽度调试,通过对周期内高低点平的所占时间长短(占空比)来调节GPIO的输出。
PWM的输出需要用到定时器。
配置步骤:
1、使能定时器时钟、GPIO时钟、复用时钟(若用到);
RCC_APBxPeriphClockCmd();
2、初始化GPIO
GPIO_Init();
3、映射定时器到复用的GPIO上
GPIO_PinRemapConfig();
4、初始化定时器
TIM_TimeBaseInit();
5、初始化定时器通道
TIM_OCxInit();
6、预加载定时器
TIM_OCxPreloadConfig();
7、使能定时器
TIM_Cmd();
8、不断改变OCRx值以达到更改占空比
TIM_SetComparex();
定时器初始化需要配置重装载值和预分频系数来控制PWM输出的周期
周期计算公式:Tout=(Period+1)(Prescaler+1)/Tclk
定时器初始化时需要配置的结构体成员变量及作用:
typedef struct
{
uint16_t TIM_Prescaler; //预分频系数 (主时钟分频)
uint16_t TIM_CounterMode; //计数模式 (向上对齐、向下对齐、中间对齐)
uint16_t TIM_Period; //重装载值 (定时器重新计时的值)
uint16_t TIM_ClockDivision; //时钟分频因子 (定时器时钟的再分频,一般设为TIM_CKD_DIV1)
uint8_t TIM_RepetitionCounter; //重复次数 (无需配置)
} TIM_TimeBaseInitTypeDef;
定时器通道初始化时需要配置的结构体成员变量及作用:
typedef struct
{
uint16_t TIM_OCPolarity; //输出极性(有效时输出高或者低)
uint16_t TIM_OCMode; //定时器通道模式(PWM模式或者Compare模式)
uint16_t TIM_OutputState; //是否使能
//以下PWM输出无需配置
uint16_t TIM_OutputNState; //是否使能(仅TIM1 和TIM8有效)
uint16_t TIM_Pulse; //直接操作寄存器控制输出波形
uint16_t TIM_OCNPolarity; //输出极性(有效时输出高或者低)(仅TIM1 和TIM8有效)
uint16_t TIM_OCIdleState; //设置空闲状态时的值(仅TIM1 和TIM8有效)
uint16_t TIM_OCNIdleState; //设置空闲状态时的值(仅TIM1 和TIM8有效)
} TIM_OCInitTypeDef;
改变CRR2值来调节占空比大小
TIM_SetComparex(TIMx,val);
参考代码:
int main(void)
{
u8 i=1;
u16 led0pwmval;
GPIO_InitTypeDef GPIO_InitStrue;
TIM_OCInitTypeDef TIM_OCInitStrue;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrue;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能TIM3和相关GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);// 使能GPIO复用时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);// 使能GPIOB时钟
GPIO_InitStrue.GPIO_Pin=GPIO_Pin_1; // TIM_CH4
GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP; // 复用推挽
GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz; //设置输出速度
GPIO_Init(GPIOB,&GPIO_InitStrue); //GPIO端口初始化设置
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);
//溢出时间Tout=(Period+1)(Prescaler+1)/Tclk 500ms
TIM_TimeBaseInitStrue.TIM_Period=4999; //设置自动重装载值(改变该值大小试试灯的亮度 ^_^)
TIM_TimeBaseInitStrue.TIM_Prescaler=7199; //预分频系数(时钟72MHz)
TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up; //计数器向上溢出
TIM_TimeBaseInitStrue.TIM_ClockDivision=TIM_CKD_DIV1; //时钟的分频因子
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStrue); //TIM3初始化设置(设置PWM的周期)
TIM_OCInitStrue.TIM_OCMode=TIM_OCMode_PWM2; // PWM模式2:CNT大于CCR时输出有效
TIM_OCInitStrue.TIM_OCPolarity=TIM_OCPolarity_High; // 设置极性-有效为高电平
TIM_OCInitStrue.TIM_OutputState=TIM_OutputState_Enable;// 输出使能
TIM_OC4Init(TIM3,&TIM_OCInitStrue); //TIM3的通道2PWM 模式设置
TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能预装载寄存器
TIM_Cmd(TIM3,ENABLE); //使能TIM3
while(1)
{
if(i)
led0pwmval++; // 由暗变亮
else
led0pwmval--; // 由亮变暗
if(led0pwmval==0)
i=1; // 已达到最亮,开始变暗
if(led0pwmval>50) // 将50改为其他值试试 ^_^
i=0; // 已达到最暗,开始变亮
TIM_SetCompare4(TIM3,led0pwmval); //改变比较值TIM3->CCR2达到调节占空比的效果
}
}
定时器TIM3重映像关系表(其他定时器映射表自己尝试查查吧TIM3重映像关系表^_^)
试试将GPIOB 1 不设置复用模式配置成PWM输出
最终软件仿真出的波形
---------------------------------------华丽分割--------------------------------------------
有小伙伴说软件仿真的波形不是500ms经过M君一番操作后发现可能是建立工程时设置的时钟晶振大小不是8MHz。
不妨将这里改一下再仿真看看呦。