刚刚实现PWM控制LED亮度,急急忙忙总结一下.
还望斧正.
第一步-了解什么是PWM脉冲宽度调制
什么是脉冲宽度调制
通过TIM快速开关电源改变占空比.
通过改变占空比改变平均电压.
1556684804542.png就是通过一个值改变一个周期内高低电平所占的宽度.
这个值存放在CCR中,也就是捕获寄存器中.
我们可以控制某个引脚输出高电平点亮LED灯,但是也只是点亮LED灯.
通过PWM我们便可以来控制灯的亮度,高电平在一个周期内所占的越大,灯便越亮,反之高电平越小灯便越暗.
开发板资源
1556684883785.png我使用的是STM32F407ZGT6野火的霸天虎开发板.
在这里我选择了PB15通道2(CH2).
第二步-输出捕获代码
初始化GPIO引脚复用
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/*开启相关的GPIO外设时钟*/
RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOB, ENABLE);
/* 定时器通道引脚复用 */
GPIO_PinAFConfig(GPIOB,GPIO_PinSource15,GPIO_AF_TIM12);
/* 定时器通道引脚配置 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
这一部分代码写的是将PB15引脚复用,推挽输出,不上拉也不下拉.
初始化中断优先级
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
// 设置中断来源
NVIC_InitStructure.NVIC_IRQChannel =TIM8_BRK_TIM12_IRQn;
// 设置抢占优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
// 设置子优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
这一部分主要是设置中断来源,抢占优先级和子优先级.
初始化TIM定时器基础
clip_image001.pngvoid TIM_Base_Config(unsigned int psc,unsigned int arr)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 开启TIMx_CLK,x[2,3,4,5,12,13,14]
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM12, ENABLE);
/* 累计 TIM_Period个后产生一个更新或者中断*/
//当定时器从0计数到8399,即为8400次,为一个定时周期
TIM_TimeBaseStructure.TIM_Period = arr-1;
// 通用控制定时器时钟源TIMxCLK = HCLK/2=84MHz
// 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=100KHz
TIM_TimeBaseStructure.TIM_Prescaler =psc-1;
// 采样时钟分频
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
// 计数方式
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
// 初始化定时器TIMx, x[2,3,4,5,12,13,14]
TIM_TimeBaseInit(TIM12, &TIM_TimeBaseStructure);
}
这一部分为配置TIM12的基础部分.
两个参数分别为
计数
TIM_TimeBaseStructure.TIM_Period = arr-1;
分频
TIM_TimeBaseStructure.TIM_Prescaler =psc-1;
初始化PWM模式
clip_image001-1556695815462.pngvoid TIM_PWM_Config(void)
{
/*PWM模式配置*/
TIM_OCInitTypeDef TIM_OCInitStructure;
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//配置为PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 2800-1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//当定时器计数值小于CCR1_Val时为高电平
TIM_OC2Init(TIM12, &TIM_OCInitStructure); //使能通道2
/*使能通道2重载*/
TIM_OC2PreloadConfig(TIM12, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM12, ENABLE); //使能TIM重载寄存器ARR
// 开启计数器中断
TIM_ITConfig(TIM12,TIM_IT_Update,ENABLE);
// 使能定时器
TIM_Cmd(TIM12, ENABLE);
}
这里要注意几个地方,一个是使能通道2初始化,一个是使能通道2重载.
如果说使用的是CH1(通道1),那么只需要将函数修改为通道1即可.
例:
TIM_OC1Init(TIM12, &TIM_OCInitStructure); //使能通道2
/*使能通道2重载*/
TIM_OC1PreloadConfig(TIM12, TIM_OCPreload_Enable);
中断服务函数
void TIM8_BRK_TIM12_IRQHandler(void)
{
if(TIM_GetITStatus(TIM12,TIM_IT_Update))
{
TIM12->CCR2=100;
TIM_ClearITPendingBit(TIM12,TIM_IT_Update);
}
}
CCR2就是(CH2)通道2的捕获寄存器,通过修改CCR2的值.
注意:如果说引脚持续输出高电平,
没有低电平的切换的话大多是因为CCR的值高出了周期,
修改下计数分频或者修改CCR的值都可.
网友评论