End-world Kit

想象一下有一天…

地球上爆发了核战争,毁灭性的攻击使得地表生灵涂炭,辐射超标,大量浮尘与有毒有害气体漂浮在大气中,强烈的紫外线照射…
这样的世界在许多科幻电影和游戏中都曾出现过,比如Fallout 4:

1e3H2V.jpg

1e3780.png

总之,这将是一个不太适合生存的世界,如果我们想要在这种环境生存下去,此时你需要的不仅仅是一部动力装甲,你更需要这个宝贝…(把头伸过来,我给你看个宝贝.jpg)

1e84sO.jpg

这就是我们本文要港的末世生存Kit_V1.0。

这是啥???

这是一个“基于Arduino电子平台的环境检测装置”

啊呸…这个学术腔我已经要听吐了(基于…的…)
我们干脆叫他末世生存Kit呗~
为什么叫Kit呢?因为很多电子套件都叫Kit,而这个项目其实可以做成套件的形式,因为它非常简单且有趣又实用还不失逼格( 虽然好像平时也没什么卵用… (小声bb)

整个项目用到了一些传感器模块,还有Arduino Nano,以及一些额外的USB接插件,锂电池座+电池充放电一体管理模块+开关,还有洞洞板(黄黄的像黄油一样的黄油板),M3铜柱,螺母,连接线!
主要元件如下:

VEML6070 - I2C通讯协议 - 数字紫外线强度传感器
SHT31 - I2C通讯协议 - 数字温湿度一体传感器
TEMT6000 - 模拟电压输出 - 模拟光强传感器
PMS7003 - UART通讯协议 - 攀藤的一体化颗粒物浓度检测传感器模块,提供串口通讯接口
MQ-135 - 模拟电压输出 - 有毒有害气体传感器,输出模拟电压信号
1.3 inch 132*64 OLED(蓝色) - SPI通讯协议

关于代码,就是调库!调库!再调库!(白嫖的快乐hhhhh)
我写的一份ino格式代码已经在 我的github 上了

关于元件的库,我也帮你找好了,在Github上都有,下载zip包导入到Arduino IDE的库就好了~

PMS Library(PMS7003传感器)
SHT3x(数字温湿度)
VEML6070(数字紫外线)
U8g2(OLED图形库)

如果你打算着手制作了,建议你先把各个传感器模块单独放在面包板上和Arduino联调进行一次测试哦~

这是检验元件是否好坏的第一步!

如果你不太会做这种测试,我建议你去 Adafruit的官网教程 学习一下√
所谓的测试就像这样:

VEML6070.jpg

等所有的模块都通过了测试(QC Pass!),你就可以着手设计电路连线怎样合理了,其实也没什么需要注意的,IIC协议是固定的2根信号线,UART端口我直接用了默认的下载口(我偷了个懒,因为这样连的话,下载程序时必须断开PMS7003传感器的连接,不然串口会冲突导致下载失败)
至于OLED,我买的SPI的版本,主控是SH1106,对应U8g2的初始化是这样的:

1
2
3
4
5
6
7
8
/*
代码不够闲话来凑
代码不够闲话来凑
代码不够闲话来凑
代码不够闲话来凑
代码不够闲话来凑
*/
U8G2_SH1106_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 7, /* dc=*/ 6, /* reset=*/ 5);

看代码可以看出,CS(片选) 连D7,DC(指令/数据选择) 连D6,RST(复位) 连D5。

我的测试代码我也在这里贴一遍吧~ 看完你就知道调库(白嫖)是多么的快乐了!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>

#include <U8g2lib.h>
#include "Adafruit_SHT31.h"
#include "Adafruit_VEML6070.h"
#include "PMS.h"

PMS pms(Serial);
PMS::DATA data;

Adafruit_SHT31 sht31 = Adafruit_SHT31();
Adafruit_VEML6070 uv = Adafruit_VEML6070();

U8G2_SH1106_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 7, /* dc=*/ 6, /* reset=*/ 5);

char i = 0;

const char s1[] PROGMEM = "End World Kit";
const char s2[] PROGMEM = ">-Temp: ";
const char s3[] PROGMEM = "*C";
const char s4[] PROGMEM = ">-Humidity: ";
const char s5[] PROGMEM = "%";
const char s6[] PROGMEM = ">-UV level: ";
const char s7[] PROGMEM = ">-Light LX: ";
const char s8[] PROGMEM = ">-PM2.5(ug/m^3): ";
const char s9[] PROGMEM = ">-PM10(ug/m^3): ";
const char s10[] PROGMEM = ">-PM1.0(ug/m^3): ";
const char s11[] PROGMEM = "No data response.";
const char *index[] = { s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11};

void _firstPage(void);
void _secondPage(void);
void _homePage(void);

void setup()
{
Serial.begin(9600); //init baudrate at 9600 to communicate with laser-gas sensor
uv.begin(VEML6070_HALF_T ); //Integration time sets to 62.5ms.
sht31.begin(0x45); // 0X45 OR 0X44
pms.passiveMode(); //set laser-gas sensor to passivemode
pms.wakeUp(); //wake up the laser-gas sensor
//u8g2.begin();

u8g2.begin();
u8g2.setPowerSave(0);
_homePage();
/*
u8g2.begin();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_helvB08_tf); //title Font.
u8g2.drawStr(30,8,"End World Kit");
u8g2.setFont(u8g2_font_t0_11_mf); // choose Internal font.
u8g2.sendBuffer();
*/

}

void loop()
{
_firstPage();
delay(2500);
_secondPage();
delay(2500);
}

void _firstPage(void)
{
u8g2.clearDisplay();
u8g2.setFont(u8g2_font_helvB08_tf);
float temp = sht31.readTemperature();
float humidity = sht31.readHumidity();
do {
u8g2.setCursor(30, 8);
u8g2.print((class __FlashStringHelper *) index[0]);

if (! isnan(temp))
{ // check if 'is not a number'
u8g2.setCursor(0, 24);
u8g2.print((class __FlashStringHelper *) index[1]);
u8g2.print(temp);
u8g2.print((class __FlashStringHelper *) index[2]);
}
if (! isnan(humidity))
{ // check if 'is not a number'
u8g2.setCursor(0, 40);
u8g2.print((class __FlashStringHelper *) index[3]);
u8g2.print(humidity);
u8g2.print((class __FlashStringHelper *) index[4]);
}
u8g2.setCursor(0, 56);
u8g2.print((class __FlashStringHelper *) index[5]);
u8g2.print(uv.readUV());
} while (u8g2.nextPage());
}

void _secondPage(void)
{
u8g2.setFont(u8g2_font_helvB08_tf );
unsigned int lx = 0, anr = 0;
for (i = 0; i < 16; i++)
{
anr = analogRead(A6);
lx = lx + anr;
anr = 0;
delay(5);
}
lx = lx / 16;


do {
u8g2.clearDisplay();
u8g2.setCursor(0, 10);
u8g2.print((class __FlashStringHelper *) index[6]);
u8g2.print(lx);
lx = 0;
pms.requestRead();
if (pms.readUntil(data))
{
u8g2.setCursor(0, 24);
u8g2.print((class __FlashStringHelper *) index[7]);
u8g2.print(data.PM_AE_UG_2_5);
u8g2.setCursor(0, 38);
u8g2.print((class __FlashStringHelper *) index[8]);
u8g2.print(data.PM_AE_UG_10_0);
u8g2.setCursor(0, 52);
u8g2.print((class __FlashStringHelper *) index[9]);
u8g2.print(data.PM_AE_UG_1_0);
}
else
{
u8g2.setCursor(0, 40);
u8g2.print((class __FlashStringHelper *) index[10]);
}
} while ( u8g2.nextPage() );

}

void _homePage(void)
{
u8g2.clearDisplay();
u8g2.setFont(u8g2_font_helvB08_tf);
do
{
//u8g2.setFont(u8g2_font_helvB08_tf); // choose Internal font.
u8g2.setCursor(30, 8);
u8g2.print(F("End world Kit"));
u8g2.setCursor(0, 20);
u8g2.print(F("Test & developed by "));
u8g2.setCursor(0, 32);
u8g2.print(F("Floydfish.In case of "));
u8g2.setCursor(0, 44);
u8g2.print(F("extreme conditions."));
u8g2.setCursor(0, 56);
u8g2.print(F("detect everything around."));
} while ( u8g2.nextPage() );

delay(3000);

}

我唯一的代码量就是写GUI,因为数据项太多,小小的13264屏幕放不下,所以我分了2页显示,对应的刷新函数为_firstPage()和_secondPage(),以及上电初始化页面_homePage()。

其实U8g2库对于Arduino Nano来说过于臃肿了…我这个程序占用了80%多的代码存储空间,几乎塞满,在我优化前它一度占到了90%多…于是我刚开始还写了一遍U8X8的版本,但是我发现u8x8没有我中意的字体,所以又换了回来233

Assemble

首先把几个小传感器和OLED和接口都焊好,走好线,像这样:

1e8hQK.jpg

接着,把PMS7003和MQ-135固定在另一块板子上,焊好线引好接口:

1e82J1.jpg

我把这第二块板子叫做"颗粒物DLC"23333
因为它就像拓展组件一样,可以堆很多额外的传感器来增强功能。
(这就是它叫V1.0的原因之一~)

然后,全部连接好,烧录程序,开始调试。

1e8RRx.jpg

这是最初的调试代码,只用了一个页面来显示数据。

侧面

1e8Wz6.jpg

屁股翻过来看看

1e8giR.jpg

Final!

1e84sO.jpg

Enjoy!(装逼)

什么?我费尽千辛万苦做出来个炫酷玩意儿还不许我装装逼了?

这个项目本来就是 好 van ♂ 的
想怎样使用都看你自己啦。
在这里放一些我自己玩的图片

在电梯里,我开启了开关,电池充放电管理模块上的电压指示红色LED在电梯上形成一道猩红色的光带 (异闻带)

某CNPP同学说这是"鲨红了眼"

1e85LD.jpg

在某个 Lab Stay Night,我饿了…
于是我出门买烤冷面,路上我用它测量了一下晚上10点长安区的气温(好冷鸭.jpg)
可以看到,-3度,湿度58.22%…

1e8oee.jpg

END!

后记

其实我最后放弃了使用MQ-135。。。
因为我发现这东西耗电太大了,因为它的工作原理依赖电热丝,不仅耗电,发热还会干扰到上面的温湿度传感器正常采集数据(怪我的机械设计布局没考虑周全),所以你在代码中是看不到这个传感器的采集的~

然后。。V2.0版本,我预计会加入简单的盖革计数管,测量环境本底辐射,有条件再加入联网功能,可以查询气象站API并跟自己的数据比对。

我还想加入一些奇怪的传感器,比如氧气浓度和二氧化碳,气压,海拔,电子罗盘,陀螺仪等。(好像有点太多了)(主要还是传感器太贵了,咱买不起啊orz)

还想换一个大一些的显示器,做一个更好看的GUI~!(我希望实现曲线记录显示)

这个坑先挖在这,什么时候填呢…有空再说!