PWM 实现调光

您所在的位置:网站首页 灯光调节器怎么安装 PWM 实现调光

PWM 实现调光

2024-07-15 15:42| 来源: 网络整理| 查看: 265

PWM 实现调光 一、项目效果 预期(没有相关经验)

在这里插入图片描述

达到的目的(是实际能做到的)

通过 PWM 驱动扩展板上的冷光 LED 和暖光 LED, 并通过红外遥控器调节占空比来实现调节色温和调节亮度的功能。 这里也可以使用普通的,调节普通的led灯珠的亮度

使用 CH+/-键设置灯光的色温使用+/-键设置灯光亮度使用 EQ 键控制灯光开启或者关闭 (是基于成功做出,遥控器的实验)通过串口打印此时的亮度和色温百分比 二、原理说明 调光原理

学习物联网最经典的案例就是实现一款智能灯, 用户可以对其进行色温、亮度、颜色(下一章讲解)的控制, 色温就是指灯光的颜色是偏白(冷光源) 还是偏黄(暖光源) , 单位是K(开尔文),色温值越高光源颜色就越白反之色温越低,光源颜色就越黄。 通常使用冷光灯和暖光灯配合的方式,通过调节各自的亮度来实现色温的任意调节。

调节灯光亮度的原理就是通过 PWM 的占空比来设置灯光亮暗, 调节灯光色温则是在当前亮度值(占空比)基础上再次进行比例的分配 在这里插入图片描述 这便是调光原理

硬件连接

开发板上使用的冷光灯色温为 6000K,暖光灯为 3000K, 上图这种情况下对应的色温值为 3900K,另外为了保证色温恒定在固定值,通常亮度不能设置为 0, 而是有一个保底的最小值,比如 10%。 还需要注意的是,为了大家方便理解今后不使用 K 作为色温单位, 而是像亮度那样使用百分比值,范围 0-100,值越大,灯光越白

开发板上的两颗高亮 LED 分别是暖光 LED 和冷光 LED 在这里插入图片描述 其中使用这两个引脚(PA15和PB5)的注意点 PA15上电后,该引脚默认是 JTAG 的 JTDI, 因此需要将其引脚重映射为 TIM2 的通道 1, PB3 上电默认功能是 JTAG 的 JTDO,所以也需要 PB3 重映射为 TIM2 的通道 1, 这两个引脚的功能映射图 在这里插入图片描述

配置定时器 2 的通道 1/2 作为 PWM 输出的步骤 重映射 TIM2 的 1/2 通道到 PA15 和 PB3 引脚,并初始化为复用输出初始化定时器,主要是设置定时器周期和重装载寄存器分别初始化定时器 2 的输出比较通道 1/2 总结

难点就在于将亮度和色温值最终转换为占空比的计算公式上。

程序说明 灯光初始化函数 /** * 功能:初始灯光 * 参数: * brightness:初始化亮度 10-100 * colortemp:初始化色温 0-100 * 返回值:None */ void initLight(u8 brightness,u8 colortemp) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE); GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //禁止JTAG保留SWD GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); //设置JTAG为定时器2部分映射,只使用SWD模式 /*设置冷光灯*/ 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); /*设置暖光灯*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); setLight(brightness,colortemp); }

结合代码来理解这句话 灯光初始化函数实现了复用功能重映射, 并初始化冷光灯和暖光灯的控制引脚为复用输出。

设置灯光函数 /** * 功能:设置灯光亮度和色温 * 参数: * brightness:亮度 10-100 * colortemp:色温 0-100 * 返回值:None */ void setLight(u8 brightness,u8 colortemp) { /** * 无论是亮度还是色温,最终都体现在LED的亮度上 * LED最终的亮度计算公式为:满占空比(重装载值) * 亮度百分比 * 色温百分比 * 并且要保证冷光和暖光的色温比值之和为100% * */ TIM_SetCompare1(TIM2,getPeriod(TIM2)*brightness/100*colortemp/100); //设置冷光 对应PA15 TIM2_CH1 TIM_SetCompare2(TIM2,getPeriod(TIM2)*brightness/100*(100-colortemp)/100); //设置暖光 对应PB3 TIM2_CH2 }

为了方便理解, 没有把占空比计算公式进行合并。 我们通过 TIM_setCompare1()和 TIM_setCompare2()函数 对定时器 2 的捕获/比较寄存器 1/2 赋值来改变 PWM 占空比, 传入函数的第二个参数就是亮度-色温的计算公式, 在公式中先获取了重装载寄存器中的值(满占空比对应的计数值), 然后乘上亮度的百分比得到我们想要的亮度,最后在此基础上又将亮度值乘上色温百分比, 这里要注意,冷/暖光的色温比值之和是 100%, 这就保证了无论亮度值是多少,最终呈现出来的色温是不受影响的。

PWM 初始化函数

初始化定时器2输出比较通道1来生成PWM 对应冷光

/** * 功能:初始化定时器2输出比较通道1来生成PWM 对应冷光 * 参数: * duty:设置PWM输出的占空比 * 返回值:None */ void initTIM2OC1(u16 duty) { TIM_OCInitTypeDef TIM_OCInitStructure; //定义输出比较初始化结构体 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //设置PWM1模式 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能 TIM_OCInitStructure.TIM_Pulse = duty; //设置捕获比较寄存器的值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //设置有效电平为高电平 TIM_OC1Init(TIM2, &TIM_OCInitStructure); //生效初始化设置 TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能输出比较预装载,即更改完输入捕获寄存器的值要等到更新事件发生才生效,该行加不加无所谓 }

初始化定时器2输出比较通道2来生成PWM 对应暖光

/** * 功能:初始化定时器2输出比较通道2来生成PWM 对应暖光 * 参数: * duty:设置PWM输出的占空比 * 返回值:None */ void initTIM2OC2(u16 duty) { TIM_OCInitTypeDef TIM_OCInitStructure; //定义输出比较初始化结构体 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //设置PWM1模式 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能 TIM_OCInitStructure.TIM_Pulse = duty; //设置捕获比较寄存器的值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //设置有效电平为高电平 TIM_OC2Init(TIM2, &TIM_OCInitStructure); //生效初始化设置 TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能输出比较预装载,即更改完输入捕获寄存器的值要等到更新事件发生才生效,该行加不加无所谓 } 主函数 int main(void) { u8 light_power = 1; //默认开机 s8 brightness = 100; //亮度 s8 colortemp = 50; //色温 /*初始化各外设*/ initSysTick(); initLED(); initUART(); initNVIC(NVIC_PriorityGroup_2); /*初始化NEC*/ initNEC(); /*定时器4时钟周期10us,中断周期200ms,使能更新中断和捕获通道3中断*/ initTIMx(TIM4,719,19999,TIM_IT_Update|TIM_IT_CC3,ENABLE); /*设置下降沿触发捕获*/ initTIM4IC3(TIM_ICPolarity_Falling); /*设置定时器2时钟为10us,1KHz*/ initTIMx(TIM2,719,99,TIM_IT_Update,DISABLE); initTIM2OC1(50); initTIM2OC2(50); /*亮度10%,色温50%*/ initLight(100,50); while(1) { if(NEC_DataStructure.CmdCode_H == 0x45) //CH-键按下 { NEC_DataStructure.CmdCode_H = 0; //清除键值 colortemp -= 10; if(colortemp100) { colortemp = 100; } setLight(brightness,colortemp); }else if(NEC_DataStructure.CmdCode_H == 0x07) //-键按下 { NEC_DataStructure.CmdCode_H = 0; //清除键值 brightness -= 10; if(brightness100) { brightness = 100; } setLight(brightness,colortemp); }else if(NEC_DataStructure.CmdCode_H == 0x09) //EQ键按下 { NEC_DataStructure.CmdCode_H = 0; //清除键值 light_power = !light_power; //开关机状态取反 if(light_power == 0) { setLight(0,0); //关灯 }else { setLight(brightness,colortemp); //开灯 } }else { } printf("brightness is :%d%%\n",brightness); printf("color temperature is :%d%%\n",colortemp); toggleLED(); Delay_ms(100); } }

代码很长,主要实现的是 定时器 2 设置的时钟周期为 10us,则 1KHz(1ms)需要计数 100 个。 然后初始化 PWM 并设置灯光开机默认最大亮度,色温 50%。 在用户逻辑循环中不断的判断此时红外键值,并根据键值做出相应的灯光控制动作。

最终效果

在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3