视频教程:https://www.bilibili.com/video/BV1dy4y1k7mv/
首先来看下今天要做的兔子灯挂件的样子

下图是电路部分需要的材料:

- 充放电板:充放电板+锂电池就是一个充电宝,既可以稳定的输出5v的电压,又可以安全的为锂电池充电。
- DigiSpark ATTINY85:主角芯片
- WS2812:信仰灯
- MicroUSB模块:可以通过MicroUSB给充电板提供5v的充电电压
- 10k电阻:做下拉电阻使用
- 锂电池:图片上是160毫安时的电池,制作的时候我换成了80毫安时的,更小一些。
- 面包板:用来固定元器件
- 轻触开关:用来切换灯光模式
安装驱动
目前驱动我只找到了windows版的,下载地址:https://github.com/digistump/DigistumpArduino/releases,如果下载不下来,可以到我的下载页面去下载:https://www.ubusy.net/download/,安装完成以后最好重启一下电脑。
配置开发环境
下面来安装开发工具,首先要安装 Arduino IDE,这部分内容在我之前将 Esp8266 的时候已经讲过了,可以看我之前写的 Esp8266 开发环境配置,链接:https://www.ubusy.net/2020/01/28/esp8266-1/
然后在开发板管理器(Board)里面装 DigiSpark 的开发工具链。首先要在设置(Preferences)里面添加下载地址:http://digistump.com/package_digistump_index.json,我已经安装了esp8266,所以直接换行写就行,然后去开发板管理器下载对应的工具链,安装digispark,请看下图:

安装完成以后需要选择对应的开发板,见下图:

选择好了 Digispark 后可以写一个空程序试一下,这里要注意这块开发板的上传和其他的板子不一样,首先需要拔下开发板,然后选择编译上传,只有在这个状态下插入开发板才能上传程序,注意上传状态只会保留60s,超时以后插上板子也没有用。看下图,按编译上传按钮,然后等待插板状态,见下图

然后插入开发板,系统会自动上传程序,完成后显示如下图,板卡上的程序也会进入执行状态。

DigiSpark
先看下Digispark的引脚图

Digispark 有5个gpio口,我这次选择了 P3 和 P4,千万不要选P5,看上面的图,P5还有个功能是RESET,会导致板子一直重启。下面来看一下接线图

这里充电板所有的GND都是连通的,可以任意使用。电源通过usb模块给充电板供电,电池接在充电板的BAT上充电,充放电板在没有外接电源的情况下可以把电池升压到5v输出,有外接电源的时候一边输出一边给电池充电,充满了会自动断电,电池没电了也会自动断电。充放电板上的灯显示剩余电量。充电板上有个小按钮,在外接电源的时候没有用,不外接电源的时候按一下打开输出,按两下停止输出。
编码
这些工作都准备好了以后就可以开始编码了,代码原理在之前的Esp8266里面已经讲过了,这里直接贴代码,代码里面的说明也很全了。复制黏贴后直接就可以使用。需要注意的地方是刷写程序的时候必须把电池的电断掉,就是按两下充放电板上的按钮,否则无法刷写成功
下面的代码功能是通过微动开关控制灯的模式,我这里写了5种模式,分别是呼吸灯1,呼吸灯2,双闪,惊悚1,惊悚2,大家可以对着代码看看。另外还有个stop模式是为了在充电的情况下把灯关掉的。
// 首先,引入库文件
#include <Adafruit_NeoPixel.h>
// 定义一个led模块
// 参数1:这个模块有几个led 像素
// 参数2:使用哪一个gpio口输出
// 参数3:模式,一般ws2812都是 NEO_GRB + NEO_KHZ800,其他模式的模块可以参考手册
Adafruit_NeoPixel led = Adafruit_NeoPixel(1, PB3, NEO_GRB + NEO_KHZ800);
// 模式的个数
const uint8_t mode_count = 6;
// 当前模式
uint8_t state = 0;
// 当前帧数,每次循环会将frame + 1
uint32_t frame = 0;
// 初始化
void setup() {
pinMode(PB3,OUTPUT); // P3 为灯的输出口
pinMode(PB4,INPUT); // P4 为微动开关的输入口
led.begin(); // 打开led
led.setBrightness(150); // 设置led的亮度为150,最大为255
frame = 0; // 初始化当前帧数为0
}
// 按键检测函数
bool CheckButton() {
// button_state 用于检测按键的按下和抬起的状态,每一次按下和抬起改变一次模式
static bool button_state = false;
// 如果按键是没有按下状态,设置为按下状态并且将状态+1
if (digitalRead(PB4) == HIGH && button_state == false) {
button_state = true;
state++;
state %= mode_count; // 状态循环
} else if (digitalRead(PB4) == LOW && button_state == true) {
button_state = false; // 回复状态按键为抬起状态
}
}
// 三角函数是弧度制,这里提供一个角度转弧度的函数
float Deg2Rad(uint32_t deg) {
return deg / 180.0f * 3.1415926;
}
// 关闭灯,做这个功能为了充电时可以设置到这个模式让灯可以不亮
void Stop() {
led.setPixelColor(0, led.Color(0, 0, 0));
led.show();
}
// 呼吸灯函数,参数是跳帧,默认为2
// 使用sin周期函数,但是由于不要负值用了fabs,因此周期是180
void Breath(uint32_t skip_frame = 2) {
// 初始化灯的颜色
static uint8_t r = rand() % 256;
static uint8_t g = rand() % 256;
static uint8_t b = rand() % 256;
// 每180帧换一次颜色
if ((frame % 180) == 0) {
r = rand() % 256;
g = rand() % 256;
b = rand() % 256;
}
// 第 2n 个周期关灯,让呼吸灯不要常亮,模拟呼吸效果
if ((frame % 360) > 180) {
Stop();
// 这里的跳帧为了控制灯熄灭的时间。
//用跳帧不用delay是因为delay会让按钮输入无法检测到
frame += skip_frame;
} else {
// 通过sin函数设置灯的颜色
float c = fabs(sin(Deg2Rad(frame))) ;
led.setPixelColor(0, led.Color(c * r, c * g, c * b));
led.show();
}
}
// 第二种呼吸灯模式
void Breath2(){
// 这里调用Breath函数,并设置跳帧为8帧,缩短呼吸时间
Breath(8);
}
// 双闪模式
void Blink() {
uint32_t f = frame % 20;
// 周期为20帧,在20帧里,第0,1帧和第4,5帧随机闪一个颜色,其余时间关灯
if (f < 2 || (f >= 4 && f <= 5)) {
led.setPixelColor(0, led.Color(rand() % 255, rand() % 255, rand() % 255));
led.show();
} else {
led.setPixelColor(0, led.Color(0, 0, 0));
led.show();
}
}
// 惊悚灯
void Thriller(uint8_t adjust = 0) {
// 通过adjust参数随机决定灯是否要闪烁
bool effect = (rand() % 8) <= adjust;
// 随机一个颜色,其余时间关灯
if (effect) {
led.setPixelColor(0, led.Color(rand() % 255, rand() % 255, rand() % 255));
led.show();
} else {
led.setPixelColor(0, led.Color(0, 0, 0));
led.show();
}
}
// 惊悚灯升级版,这里的目的是为了让灯在亮和暗的时间相对集中
void Thriller2() {
// pause参数为了让灯有更多的机会连续熄灭
static uint8_t pause = 0;
// 如果pause大于0,就让灯强制熄灭
if (pause > 0){
pause--;
Stop();
return;
}
// 这里随机一个亮度,然后调用Horrify(6),让灯连续亮
led.setBrightness(rand() % 256);
Thriller(6);
// 这里判断是否要暂停亮灯
if (rand() % 4 == 0 && pause == 0) {
pause = rand() % 32;
}
}
// 循环函数,每帧调用
void loop() {
// 首先恢复亮度为150,因为惊悚灯2会改变亮度
led.setBrightness(150);
// 设置灯运行状态
switch(state) {
case 0:
Breath(); break;
case 1:
Breath2(); break;
case 2:
Blink(); break;
case 3:
Thriller(); break;
case 4:
Thriller2(); break;
case 5:
Stop(); break;
}
// 按键检测
CheckButton();
// 延迟50ms,控制帧率为每秒100帧
delay(50);
frame++;
}
看下效果,走线不算合理,如果觉得充电板上的灯影响效果,也可以找东西把它遮起来。

3D打印
最后的模型是3D打印出来的,等模型的改的好一点我会放在下载页面给大家下载的。
在兔子眼睛和嘴巴镂空的部分贴一层无纺布作为柔光的效果

效果
来看下兔子灯挂件的最终效果。

下面是南瓜灯的最终效果。
