MGJLN

Cyber ​​Palace Lamp - Decorative Lamp Based on ESP32-C3

 
Overview
更新日志
2024.01.25:最初开源改项目 Ver1.0
2024.05.18:上传模型文件,请注意遵守开源规则,不可商用
零、模型说明
目前模型仍存在一定问题,后续修正并上传模型。
存在的问题(2024.01.25):

模型尺寸过小,需要放大到150%进行打印;
装配主要采用过盈装配,尺寸偏松,需要缩小尺寸;
顶檐连接处装配可靠性较差,修改装配方式。

每台3D打印机的打印效果不尽相同,需要根据打印机打印效果修改尺寸。
一、效果展示
1.1 说明

使用FDM-3D打印该模型
顶檐、灯栅采用白色PETG耗材打印
角饰、角件、顶饰采用蓝色PLA耗材打印
灯座采用薄荷绿PC/ABS耗材打印
(个人感觉采用浅黄色、黄色、橙色等暖色耗材打印会好看点,但是我手头没有该类颜色耗材)

1.2 组成构件明细

顶饰 x1
EC11编码器 x1(焊接XH2.54-4P端子 Key1、KeyA、KeyB、GND,详见下文4.1)
灯檐1、灯檐2、灯檐3 各1
磁铁 x4(用于灯檐磁吸装配)
M3螺母 x4(用于灯檐磁吸装配)
角饰(灯角)x4
灯栅 x4(需要蒙纸 - 建议使用硫酸纸)
Light PCB x1
灯角(灯下角)x4
FPC 1.0x8P 反向 x1
Controleer PCB x1
M3x6螺丝 x4
M3土八螺母/铜嵌螺母 x4
聚合物电池(尺寸65x55x9.5mm PH2.0-2P端子)x1
灯座 x1

Figure1 实物图1(找不到硫酸纸用活页纸随便凑合了)
Figure2 实物图2
Figure3 实物爆炸图
二、硬件设计
2.0 设计思路
最初参照床头灯功能进行设计,需要具有:发光、带有电池与电源管理、能够方便开关与调节亮度并预留物联网功能。
本项目沿用自月球灯项目,对其进行大幅删改与适配。
各部分设计思路见下文:
2.1 MCU
为实现灯光控制、物联网等功能,采用ESP32-C3-MINI-N4作为控制器。
我永远喜欢乐鑫的USB JTAG,USB插上就能烧录是真滴爽
无需额外增加芯片,只需使用USB线与PC相连,即可进行烧录。
2.2 灯光
灯光部分位于独立的PCB上(板子Light)。
采用铝基板作为板材,保证长时间照明下灯珠不会严重过热,提升灯珠寿命。
发光分为两部分:白色与彩色。
Figure4 Lgiht-PCB

白色灯光

为了适配不同的应用场合,白色分别使用了两种色温的灯珠,能够组合得到不同色温的白色。
(由于我选用的型号没有封装库,故使用同一个3528封装LED代替,实际分别使用C2843808、C2843809)
采用4x4+4x4、串联驱动。
串联方案下,总线电流较小、每个灯珠间通过的电流相同,能够使灯珠发光亮度相近、寿命差别较小。

彩色灯光
要赛博怎么能少了R!G!B!
使用经典的WS2812b(5050封装)作为彩色灯光的照明来源。
采用4x3颗WS2812b作为彩色光源。

2.3 LED驱动
由于采用串联LED方案,对驱动电压的要求较高。
因此,需要输出电压范围较大、最高电压较高的方案。需选用升压型/升降压型LED驱动器。
白色照明分别由冷白、暖白两路LED组成,每路16颗LED串联。
通过查阅手册,可知每颗灯珠最大正向电压为3.2V、额定电流20mA。
因此额定驱动电压为3.2x16=51.2V(灯珠串联),需要能够升压至51.2V以上的驱动器。
额定电流20mA,一般驱动器都能满足该要求。
综上所述,需要选择升压型/升降压型、最大电压大于51.2V(还需留出一定冗余空间)的LED驱动方案。
通过比较,采用双路LGS63042 LED驱动器分别驱动暖白、冷白两路白色LED。驱动电路如下图所示:
Figure5 LED驱动电路
通过查阅3528 LED灯珠的手册,可知LED灯珠的正向电流为20mA。
依照Figure4中表格将Rsence设置为10Ω,设定满载输出电流为20mA。
LGS63042 LED驱动器支持PWM调光,可以通过向EN引脚输入PWM波对LED亮度进行调节。
2.4 电源管理
电源管理方案沿用月球灯项目的相关设计。
2.5 人机交互
在人机交互方面,本项目采用了EC11编码器。EC11编码器带有一个正交编码器和一个非自锁式轻触开关。
编码器可以实现数值调节、模式调节等功能;轻触开关可以通过按键复用分别执行单击、双击、长按任务。
通过将以上交互任务进行组合,可以实现丰富的人机交互。
三、软件设计
根据以上硬件设计,系统整体框架如下图所示:
Figure6 系统框架
当前实现的功能较为简单,主要实现了整体的亮度调节、WS2812b灯珠的调色。
后续会进一步实现自动配网、物联网以及更流畅的灯控等功能。
也有大佬在我的另一个项目里提到WLED,等我了解一下考虑要不要移植。
3.1 系统的刷新
设置一个定时器,并设定Tsms为刷新周期,每一个Ts周期刷新一次灯珠发光状态(LED1、LED2亮度;LED3色相、亮度)。
3.2 WS2812b灯珠驱动
与月球灯项目相似,本项目使用FastLED库实现了WS2812b灯珠的驱动。
目前主要实现了色彩控制与亮度控制:


色彩控制
WS2812b的色彩基于HSV色彩模型进行控制。
每一种颜色都是由色相(Hue,简H),饱和度(Saturation,简S)和色明度(Value,简V)所表示的。
默认饱和度、明度都设置为255,通过控制色相改变色彩。
自定义了一种HSV颜色CHSV myHSVcolor(hVal,sVal,vVal);,通过myHSVcolor.h+=x(x指数值)改变色相。
最后通过FastLED.show();函数刷新WS2812b的发光状态。


亮度控制
设置了一个unsigned char变量Light3Level,用于存储亮度数值。
通过FastLED.setBrightness(Light3Level);设置存储的亮度数值。
最后通过FastLED.show();函数刷新WS2812b的发光状态。


3.3 白色灯珠驱动
白色LED通过LGS63042驱动电路进行驱动,可以通过PWM进行调光。
使用analogWrite(LED1,Light1Level);函数设定对驱动芯片EN引脚输入PWM波的占空比,范围0~255。
3.4 EC11编码器
EC11编码器分为正交编码器相关程序设计和轻触开关程序设计。
人机交互逻辑如下:
Figure7 人机交互逻辑


正交编码器(旋钮):
正交编码器的交互通过Encoder库实现。
首先通过编码器两个引脚注册编码器Encoder Enc(KEYB, KEYA);。
设置一个初始位置后,通过Encoder库Enc.read();读取新的位置newPosition,
将新的位置与旧的位置oldPosition比较,并做对应数值增减。


轻触开关(按键):
轻触开关的交互通过OneButton库实现。
如Figure7所示,按键分为单击、双击、长按三个功能,并分别复用任务。


四、模型装配
构成见1.2 组成构件明细。


角饰、灯角、灯檐、灯栅、灯座的装配:
模型主要采用过盈装配。角饰、灯角带有V型槽,可以卡入灯栅;灯檐带有榫卯;灯座带有槽恰好可以卡入灯角。


角饰-灯檐的装配:
灯檐与角饰见采用磁吸进行连接组合,需要在角饰内埋入M3螺母、顶檐1埋入Φ6x3mm磁铁。


灯角-Lgiht PCB、灯座-Controler PCB的装配:
灯座与灯角需要埋入土八螺母/铜嵌螺母,用于M3螺纹配合,以固定Controler、Light两块PCB。(见Figure10、Figure11)


顶饰-灯檐3-EC11编码器的装配:
EC11编码器带有螺纹,通过配套的螺母将EC11编码器固定在顶檐3上;
EC11编码器旋钮杆恰好可以塞入顶饰孔中,保留一定距离用于EC11上轻触开关的键程。(见Figure12)


顶饰EC11编码器的接线焊接:
将正交编码器的公共端、轻触开关其中一段与EC11编码器底部铁片焊接在一起。
焊接四根线,分别为KeyA、KeyB、Key1、GND。
正交编码器另外两端分别焊接KeyA、KeyB;
EC11编码器固定脚(任一)焊接GND;
轻触开关另一端焊接Key1。


Figure8 三维模型
Figure9 三维模型爆炸图
Figure10 灯座-控制器图1
Figure11 灯座-控制器图2
Figure12 灯檐3-EC11编码器
五、更多图片
Figure13 灯座正面(Type-C输入接口与充电指示灯)
Figure14 灯座背面(EN复位按键-需要使用顶针)
Figure15 灯顶(灯饰作为EC11键帽,能够旋转与按下)
附录
I.源代码
#include
#include
#include
#include

// 引脚设置
#define LED1 0
#define LED2 1
#define KEY1 5
#define KEYA 6
#define KEYB 7

// 参数设置
// #define freq 500
// #define resolution 8
#define Ts 50
#define NUM_LEDS 12
#define DATA_PIN 10
#define LED_TYPE WS2812
#define COLOR_ORDER GRB

boolean WorkStatus=0;
unsigned char ModeStatus=0;
unsigned char Light1Level=0;
unsigned char Light2Level=0;
unsigned char Light3Level=0;
unsigned char hVal=0;
unsigned char sVal=255;
unsigned char vVal=255;

// Fastled
CRGB leds[NUM_LEDS];

CHSV myHSVcolor(hVal,sVal,vVal);

// Encoder
Encoder Enc(KEYB, KEYA);
long oldPosition=-999;
long newPosition=0;

void EncoderRead(){
newPosition = Enc.read();
if(newPosition != oldPosition){
if(newPosition > oldPosition){
//LED1
if(Light1Level>=255){
Light1Level=255;
}
else{
Light1Level++;
}
//LED2
if(Light2Level>=255){
Light2Level=255;
}
else{
Light2Level++;
}
//LED3
if(Light3Level>=255){
Light3Level=255;
}
else{
Light3Level++;
}
}
else{
//LED1
if(Light1Level<=0){
Light1Level=0;
}
else{
Light1Level--;
}
//LED2
if(Light2Level<=0){
Light2Level=0;
}
else{
Light2Level--;
}
//LED3
if(Light3Level<=0){
Light3Level=0;
}
else{
Light3Level--;
}
}
oldPosition=newPosition;
}
}

// OneButton
OneButton button1(KEY1, true);

void Button1Click(){
Light1Level=0;
Light2Level=0;
Light3Level=0;
}

void Button1DoubleClick(){
myHSVcolor.h+=8;
fill_solid(leds, NUM_LEDS, myHSVcolor);
}

void Button1LongPress(){
Light1Level=255;
Light2Level=255;
Light3Level=255;
}

// LED
void LED1Flash(){
analogWrite(LED1,Light1Level);
}

void LED2Flash(){
analogWrite(LED2,Light2Level);
}

void LED3Flash(){
FastLED.setBrightness(Light3Level);
}

// 定时器设置
hw_timer_t * timer1 = NULL; // 定时器1 采样、上传、控制刷新

unsigned char level=0;
void IRAM_ATTR onTimer1(){
// analogWrite(LED1,level);
// analogWrite(LED2,level);
// level+=16;
LED1Flash();
LED2Flash();
LED3Flash();
}

void setup() {
// put your setup code here, to run once:

// Serial port initialization
//Serial.begin(115200);

// Pin initialization
pinMode(LED1,OUTPUT);
pinMode(LED2,OUTPUT);

// OneButton
button1.attachClick(Button1Click);
button1.attachDoubleClick(Button1DoubleClick);
button1.attachLongPressStart(Button1LongPress);

// FastLED
FastLED.addLeds(leds, NUM_LEDS);
FastLED.setBrightness(128);

// Timer initialization
// Timer1
timer1 = timerBegin(1,80,true); // Initialize timer - use timer1
timerAttachInterrupt(timer1,onTimer1,true); // Bind timer interrupt service function
timerAlarmWrite(timer1,Ts*1000,true); // Set the interrupt interval to the sampling period:
`timerAlarmEnable(timer1);` // Start the timer.
} `

void loop() {
` // Put your main code here, to run repeatedly: `
button1.tick();
FastLED.show();

EncoderRead();
` }
参考设计图片
×
 
 
Search Datasheet?

Supported by EEWorld Datasheet

Forum More
Update:2026-03-28 06:11:17

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
community

Robot
development
community

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号