
3路LED 23kHz高频PWM驱动
简介
46.875KHz 高频PWM无极调光,结构简单,不伤眼,但是有拍摄需求的请注意。
简介:46.875KHz 高频PWM无极调光,结构简单,不伤眼,但是有拍摄需求的请注意。开源协议
:GPL 3.0
(未经作者授权,禁止转载)描述
2024年7月4日20点57分 更新
1.修复了部分型号LDO上电概率损坏的问题。
************************************************************************************
构成简单,用了两三年了,因太简单了没想着开源,不过本着能给更多人方便,现公开。
高频PWM驱动,利用STC8G1K08A(0.9元左右)单片机的硬件PWM控制,无极调光。
“根据GB/T31831-2015规范,在频率为9Hz至3125Hz时,波动深度高于f*0.08/2.5%,就可能会对人体造成影响。 而LCD显示器的LED背光的波动率一般都为100%,所以,就算在全黑环境中使用PWM调光的LCD显示器,只要显示器LED背光的PWM频率超过3125Hz,频闪就不会对身体造成任何影响,不用担心伤眼问题。”
单片机24Mhz时钟下,4分频,256位,最终调光频率 24E6/4/256 = 23KHz,超出人耳听觉范围。
可自行修改代码,实现更高频率和PWM分辨率。
请注意,本PWM虽然不伤眼,但是相机一类数码产品对闪烁敏感。
如果您有拍摄需求,请谨慎(本人小米10 LineageOS20 拍摄无闪烁)
3路PWM,可以控制3路灯光,注意是PWM直驱,注意电压,可以是12V,24V或者其他,但是LDO线性降压芯片 和 NMOS耐压要支持,同时直驱的LED也要相同耐压,建议使用线性灯灯条,用了两三年没有出过问题。
只适配灯条(线性灯),恒流LED不要使用!!
3路LED,每路LED 3个亮度档位,每个档位单独无极调光。
默认 1档最暗 2档中等 3档最亮。
按住调节亮度。亮度信息 总电源断电(非关闭LED) 消失,恢复默认亮度。
STC8G1K08A 1个 要有A 24MHz时钟
LDO线性降压 1个 注意耐压
TO-252 NMOS 3个(本工程AOD4184)
XH2.54 3套
0.1uf 10uf 各2个
1K电阻 3个
作为唯一光源时,拍摄无闪烁
文件列表有编译后的hex文件,直接烧录就好。
以下是源码,几年前写的,水平不行,勿喷:
#include // 此处STC8G.h 文件可以从STC烧录软件中获得,保存在源码同目录下
#include
#define uchar unsigned char
#define uint unsigned int
#define PWM_DUTY 255 //定义PWM的周期,数值为时钟周期数
#define PWM_CHANGE 1 //定义PWM一次改变的数值,暂时只能1,目前代码没有判断是否加减过头的判断,后续需要完善
#define PWM_DUTY_MAX PWM_DUTY-10 //限制PWM输出的最大占空比,也就是最小亮度
#define PWM_DUTY_MIN 0 //限制PWM输出的最小占空比,也就是最大亮度
#define SWITCH_TIME 6000 //开关变换等待时间,用来防抖
#define DELAY_TIME 15000 //亮度调节速度,越小越快
//#def ine FOSC 24000000UL
//#define BRT (65536 - FOSC / 115200 / 4)
// 默认24MHz,可增加频率,如果要用串口,则需要注意
// PWM输出引脚需要设置PCA的引脚,在3.1.1 章节
// 默认 PCA_PWM0 P32 PCA_PWM1 P33 PCA_PWM2 P54
// 24E6/2/256 = 46.875KHz
// 24E6/4/256 = 23.437KHz(默认)
sbit key_1 = P3^0;
sbit key_2 = P3^1;
sbit key_3 = P5^5;
uint pwm_duty1[4],pwm_duty2[4],pwm_duty3[4]; //三个占空比数组
uchar pwm_duty1_sub = 0,pwm_duty2_sub = 0,pwm_duty3_sub = 0; //占空比数组下标,0-2对应上面数组,3为关灯
bit switch_sta1 = 0,switch_sta2 = 0,switch_sta3 = 0; //按住调节增加或者减少,0减少,1增加
//10位PWMPCA初始化
void PCA_Init()
{
CCON=0x00; //关闭PCA计数器,清除相关标志位
CMOD=0x0A; //PCA时钟源为系统时钟,0x08系统时钟,0x02系统时钟/2,0x0A /4 ( 默认 ) ,0x0C /6 , 0x0E /8 , 0x00 /12 , 0x04 定时器0溢出时间, 0x06 外部时钟
CL =0x00; //计数器清零
CH =0x00;
/*------------------------PWM0部分-----------------------------*/
CCAPM0 = 0x40; //失能PCA模块0_PWM输出
CCAP0L=0X00; //捕获比较寄存器低8位,比较值
CCAP0H=0X00; //捕获比较寄存器高8位,重装值
PCA_PWM0=0x00; //10位PWM输出 0xC0,8位为 0x00
CCAPM0=0x42; //使能PCA模块0_PWM输出
/*------------------------PWM1部分-----------------------------*/
CCAPM1 = 0x40; //失能PCA模块1_PWM输出
CCAP1L=0X00; //捕获比较寄存器低8位,比较值
CCAP1H=0X00; //捕获比较寄存器高8位,重装值
PCA_PWM1=0x00; //10位PWM输出 0xC0,8位为 0x00
CCAPM1=0x42; //使能PCA模块1_PWM输出
/*------------------------PWM2部分-----------------------------*/
CCAPM2 = 0x40; //失能PCA模块2_PWM输出
CCAP2L=0X00; //捕获比较寄存器低8位,比较值
CCAP2H=0X00; //捕获比较寄存器高8位,重装值
PCA_PWM2=0x00; //10位PWM输出 0xC0,8位为 0x00
CCAPM2=0x42; //使能PCA模块2_PWM输出
//CCON|= 1<<6; //启动计数器
CR = 1; //启动计数器
}
//设置脉冲宽度,设置的是低电平宽度,比如 PWM_DUTY/4,则高电平75%低电平25%
void PWM0_Set_Duty(uint Duty)
{
//注意:在更新 10 位 PWM 的重载值时,必须先写高两位 XCCAPnH[1:0],再写低 8 位 CCAPnH[7:0]。
//================= 8 位 代码
CCAP0L = Duty;
CCAP0H = Duty;
//================= 8 位 代码
}
//设置脉冲宽度,设置的是低电平宽度,比如 PWM_DUTY/4,则高电平75%低电平25%
void PWM1_Set_Duty(uint Duty)
{
//注意:在更新 10 位 PWM 的重载值时,必须先写高两位 XCCAPnH[1:0],再写低 8 位 CCAPnH[7:0]。
//================= 8 位 代码
CCAP1L = Duty;
CCAP1H = Duty;
//================= 8 位 代码
//CCAPM1 = 0x42; //使能PCA模块0_PWM输出
}
//设置脉冲宽度,设置的是低电平宽度,比如 PWM_DUTY/4,则高电平75%低电平25%
void PWM2_Set_Duty(uint Duty)
{
//注意:在更新 10 位 PWM 的重载值时,必须先写高两位 XCCAPnH[1:0],再写低 8 位 CCAPnH[7:0]。
//================= 8 位 代码
CCAP2L = Duty;
CCAP2H = Duty;
//================= 8 位 代码
//CCAPM2 = 0x42; //使能PCA模块0_PWM输出
}
void main()
{
uint wait_time11 = 0,wait_time12 = 0; // key_1 计时用
uint wait_time21 = 0,wait_time22 = 0; // key_2 计时用
uint wait_time31 = 0,wait_time32 = 0; // key_3 计时用
P5M1 = 0x00; //P5.4设置为推挽输出
P5M0 = 0x10;
P3M1 = 0x00; //P3.2,P3.3 为推挽输出
P3M0 = 0x0C;
key_1 = 1,key_2 = 1,key_3 = 1;
pwm_duty1[0] = PWM_DUTY_MAX,pwm_duty1[1] = PWM_DUTY/2,pwm_duty1[2] = PWM_DUTY_MIN;
pwm_duty2[0] = PWM_DUTY_MAX,pwm_duty2[1] = PWM_DUTY/2,pwm_duty2[2] = PWM_DUTY_MIN;
pwm_duty3[0] = PWM_DUTY_MAX,pwm_duty3[1] = PWM_DUTY/2,pwm_duty3[2] = PWM_DUTY_MIN;
pwm_duty1_sub = 3,pwm_duty2_sub = 3,pwm_duty3_sub = 3; //占空比数组下标,3为关
PCA_Init();
//PWM0_Set_Duty(pwm_duty1[0]);
//PWM1_Set_Duty(pwm_duty2[0]);
//PWM2_Set_Duty(pwm_duty2[0]);
PWM0_Set_Duty(PWM_DUTY);
CCAPM0 = 0x40; //失能PCA模块0_PWM输出
P32 = 0;
PWM1_Set_Duty(PWM_DUTY);
CCAPM1 = 0x40; //失能PCA模块1_PWM输出
P33 = 0;
PWM2_Set_Duty(PWM_DUTY);
CCAPM2 = 0x40; //失能PCA模块2_PWM输出
P54 = 0;
while(1)
{
if(key_1 == 0)
{
wait_time11++;
if(wait_time11 >= 65535)
wait_time12++;
if(wait_time12 >= 5)
{
uint wait_time = 0;
wait_time11 = 0;
wait_time12 = 0;
switch_sta1 == 1 ? (switch_sta1 = 0):(switch_sta1 = 1);
//+ 开始了按住
while(key_1 == 0 && pwm_duty1_sub < 3)
{
wait_time++;
if(wait_time >= DELAY_TIME)
{
wait_time = 0;
if(switch_sta1 == 1)//增加
{
if(pwm_duty1[pwm_duty1_sub] > 0)
pwm_duty1[pwm_duty1_sub]--;
}else{ //减少
if(pwm_duty1[pwm_duty1_sub] < PWM_DUTY_MAX)
pwm_duty1[pwm_duty1_sub]++;
}
PWM0_Set_Duty(pwm_duty1[pwm_duty1_sub]);
}
}
}
}else if(wait_time11 > SWITCH_TIME && wait_time12 < 5)
{
//+ 短按一次
wait_time11 = 0;
wait_time12 = 0;
pwm_duty1_sub++;
if(pwm_duty1_sub > 3)
pwm_duty1_sub = 0;
if(pwm_duty1_sub < 3)
{
CCAPM0 = 0x42; //使能PCA模块0_PWM输出
PWM0_Set_Duty(pwm_duty1[pwm_duty1_sub]);
}else{
PWM0_Set_Duty(PWM_DUTY);
CCAPM0 = 0x40; //失能PCA模块0_PWM输出
P32 = 0;
}
/*
SBUF=pwm_duty1_sub;//将接收到的数据放入到发送寄存器
while(!TI);
TI = 0;
SBUF=pwm_duty1[pwm_duty1_sub];//将接收到的数据放入到发送寄存器
while(!TI);
TI = 0;
*/
}else{
wait_time11 = 0;
wait_time12 = 0;
}
if(key_2 == 0)
{
wait_time21++;
if(wait_time21 >= 65535)
wait_time22++;
if(wait_time22 >= 5)
{
uint wait_time = 0;
wait_time21 = 0;
wait_time22 = 0;
switch_sta2 == 1 ? (switch_sta2 = 0):(switch_sta2 = 1);
//+ 开始了按住
while(key_2 == 0 && pwm_duty2_sub < 3)
{
wait_time++;
if(wait_time >= DELAY_TIME)
{
wait_time = 0;
if(switch_sta2 == 1)//增加
{
if(pwm_duty2[pwm_duty2_sub] > 0)
pwm_duty2[pwm_duty2_sub]--;
}else{ //减少
if(pwm_duty2[pwm_duty2_sub] < PWM_DUTY_MAX)
pwm_duty2[pwm_duty2_sub]++;
}
PWM1_Set_Duty(pwm_duty2[pwm_duty2_sub]);
}
}
}
}else if(wait_time21 > SWITCH_TIME && wait_time22 < 5)
{
//+ 短按一次
wait_time21 = 0;
wait_time22 = 0;
pwm_duty2_sub++;
if(pwm_duty2_sub > 3)
pwm_duty2_sub = 0;
if(pwm_duty2_sub < 3)
{
CCAPM1 = 0x42; //使能PCA模块1_PWM输出
PWM1_Set_Duty(pwm_duty2[pwm_duty2_sub]);
}else{
PWM1_Set_Duty(PWM_DUTY);
CCAPM1 = 0x40; //失能PCA模块1_PWM输出
P33 = 0;
}
/*
SBUF=pwm_duty2_sub;//将接收到的数据放入到发送寄存器
while(!TI);
TI = 0;
SBUF=pwm_duty1[pwm_duty2_sub];//将接收到的数据放入到发送寄存器
while(!TI);
TI = 0;
*/
}else{
wait_time21 = 0;
wait_time22 = 0;
}
if(key_3 == 0)
{
wait_time31++;
if(wait_time31 >= 65535)
wait_time32++;
if(wait_time32 >= 5)
{
uint wait_time = 0;
wait_time31 = 0;
wait_time32 = 0;
switch_sta3 == 1 ? (switch_sta3 = 0):(switch_sta3 = 1);
//+ 开始了按住
while(key_3 == 0 && pwm_duty3_sub < 3)
{
wait_time++;
if(wait_time >= DELAY_TIME)
{
wait_time = 0;
if(switch_sta3 == 1)//增加
{
if(pwm_duty3[pwm_duty3_sub] > 0)
pwm_duty3[pwm_duty3_sub]--;
}else{ //减少
if(pwm_duty3[pwm_duty3_sub] < PWM_DUTY_MAX)
pwm_duty3[pwm_duty3_sub]++;
}
PWM2_Set_Duty(pwm_duty3[pwm_duty3_sub]);
}
}
}
}else if(wait_time31 > SWITCH_TIME && wait_time32 < 5)
{
//+ 短按一次
wait_time31 = 0;
wait_time32 = 0;
pwm_duty3_sub++;
if(pwm_duty3_sub > 3)
pwm_duty3_sub = 0;
if(pwm_duty3_sub < 3)
{
CCAPM2 = 0x42; //使能PCA模块2_PWM输出
PWM2_Set_Duty(pwm_duty3[pwm_duty3_sub]);
}else{
PWM2_Set_Duty(PWM_DUTY);
CCAPM2 = 0x40; //失能PCA模块2_PWM输出
P54 = 0;
}
}else{
wait_time31 = 0;
wait_time32 = 0;
}
}
}
设计图
BOM
ID | Name | Designator | Footprint | Quantity |
---|---|---|---|---|
1 | 0.1uF | C1,C2 | C0603 | 2 |
2 | 10uF | C3,C4 | C0603 | 2 |
3 | LED 3 mos | Q1 | TO-252-2_L6.6-W6.1-P4.57-LS9.9-BR-CW | 1 |
4 | LED 2 mos | Q2 | TO-252-2_L6.6-W6.1-P4.57-LS9.9-BR-CW | 1 |
5 | LED 1 mos | Q3 | TO-252-2_L6.6-W6.1-P4.57-LS9.9-BR-CW | 1 |

评论