魔改Zippo打火机为番茄计时器
好久没写和开源硬件有关的内容了,绞尽脑汁想了半天,感觉还不如自己动手做个什么。拿出年初在Adafruit网站9.95美刀买的硬币大小的Arduino Gemma单片机琢磨了一会儿,觉得这个大小再加上颗3V纽扣电池,应该可以塞进我珍藏的一个Zippo打火机里,做个有趣的项目。
于是赶紧翻箱倒柜,把那个火机找了出来。说起来包爸也曾是个烟民,九几年白猴君回国探亲,送了我这个经典款的Zippo打火机。结婚后包爸就不再抽烟了,这个火机也束之高阁。一晃八九年过去,今天拿出来再次把玩,感觉机械部件运转灵活,声音清脆,闲放着真是可惜了。又回想了一会儿以前用这个火机打着火苗的情形,灵感有了:决定把火机内部储油的棉花取出,放Gemma和纽扣电池,灯芯换成LED,做成一个番茄工作法的计时器。
所谓番茄工作法,是一种旨在提高工作效率的方法,即每次只选择一个特定的工作项目,专注持续工作25分钟,休息5分钟,然后再工作25分钟,休息5分钟,以此循环……
所需材料
- Zippo打火机
- Gemma单片机
- 发光二极管LED
- 220欧姆电阻
- CR2032纽扣电池
- GPS-14B常闭磁控开关
- 小块磁铁
- 5类网线
- 电烙铁、焊锡、快干胶、剪线器等工具
电路图
代码
代码分为几个部分:
- 起始部分定义了一些常量和变量,currentTime和previousTime变量存储的是当前的时间(毫秒数),按理说应定义为unsigned long类型,否则一直增长下去(5天左右)会溢出。但是因为需要和常量workTime,restTime做除法,得出小于1的小数做判断,按Processing语言的限制,只能使用float类型。好在这个程序应该不会连续用这么长时间,就算是忘了关,纽扣电池也不见得能撑那么长久,所以倒不至于出问题;
- setup()定义了硬件配置;
- loop()是循环执行的主程序,在简短(0.5秒)间隔后,连续调用work()和rest()两个子程序;
- work()是工作时段,只要在workTime常量规定的时间内,就会执行让LED进行呼吸效果的闪烁;
- calculateBreathLength()将整个workTime平均分为5份,根据当前时间算出现在所处的位置,然后返回呼吸长度时间(秒数)。越接近(工作时段)结束时,呼吸频率越快(时间短);
- breath()是LED呼吸灯效果,接受变量l为参数进行调用,在此参数给定的秒数内,分十级亮度,逐渐明亮再逐渐熄灭;
- rest()是休息时间,在restTime常量规定的时间内,让LED闪亮;
- blink()让LED以固定亮度闪亮和熄灭。
代码如下:
const float workTime=1500000;
const float restTime=300000;
int ledPin=0;
const int breathInterval[5]={5, 4, 3, 2, 1};
float previousTime=0;
float currentTime;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop(){
delay(500);
work();
rest();
}
void work() {
//flash led for working time
currentTime=millis();
while((currentTime-previousTime)<=workTime) {
breath(calculateBreathLength());
currentTime=millis();
}
previousTime=currentTime;
}
void breath(int l) {
//led breath
int breathI=l*1000/2/10;
for (int i=0;i<=240;i=i+24) {
analogWrite(ledPin, i);
delay(breathI);
}
for (int i=240;i>=0;i=i-24) {
analogWrite(ledPin, i);
delay(breathI);
}
}
int calculateBreathLength() {
//calculate every breath's lasting seconds
float s=(currentTime-previousTime)/workTime;
int stage;
if (s>=0.8) {
stage=4;
} else {
if (s>=0.6) {
stage=3;
} else {
if (s>=0.4) {
stage=2;
} else {
if (s>=0.2) {
stage=1;
} else {
stage=0;
}
}
}
}
return breathInterval[stage];
}
void rest() {
//flash led for resting time
delay(500);
currentTime=millis();
while((currentTime-previousTime)<=restTime) {
blink();
currentTime=millis();
}
previousTime=currentTime;
}
void blink() {
//blink led
analogWrite(ledPin, 0);
delay(1000);
analogWrite(ledPin, 120);
delay(1000);
}
因为Gemma在Arduino IDE中无法使用串口监视器进行输出,程序一旦出问题,都没法输出一下变量进行debug。所以代码调试我是在旧的Arduino Duemilanove板上进行的,没问题后再重新编译传输到Gemma里。
硬件组装
- 打开Zippo火机,拆下吸收火机油的棉花、灯芯和底部防漏垫;
- 用一根网线截取合适长度,取出4根线穿过灯芯孔;
- 发光LED正极串联一个220欧姆的电阻,焊接一根露出来的网线,负极焊接另一根线。正极和电阻焊接的线在火机内部的一头接Gemma的D0口,负极引线的另一头接Gemma的GND口;
- 火机外另两根线焊接磁控开关,调整开关位置,贴着火机防风口围壁内侧固定好;
- 在火机上盖内侧,用快干胶垂直固定好一块小磁铁,注意上盖盖好时,磁极位置正好能对着刚才固定好的磁控开关;
- 磁控开关通向火机内部的线头分别接纽扣电池正极和Gemma的电源口;
- 纽扣电池负极引短线焊接在Gemma的GND口;
- Gemma和纽扣电池分别用小塑料口袋封装,确保绝缘,装入火机内部。
完成效果
就是这样,火机盖弹开后,常闭磁控开关会连通电源,为Gemma供电,程序开始运行。在25分钟工作时段内,LED会以呼吸灯形式闪亮,越接近工作时间结束,呼吸频率越快。
进入休息时段,LED以固定亮度亮1秒,暗1秒持续到此时段结束,然后再次进入工作时段。
火机盖盖上后,磁控开关断电,程序停止运行。
下一步打算给火机配个木头的底座,摆在桌面上,工作时使用,算是用新技术复活了一个老物件。
注:Zippo图片来自flickr