创作者:KanameAimu | 更新日期:2024-05-09 | 在线时长:146天
西安天气
简介
本项目是一个基于Arduino和NRF24L01的环境监测硬件。
能实时获取当前气温,气压,光照,湿度,降水,PM2.5值,以及自身的电池电量,使用2.4G模块传到网关节点,再由节点上传到云。
节点本身不接受信息,仅以40s的间隔采集并发送数据。
硬件构成
主控:Arduino Pro Mini(5V/16MHz)
通信:NRF24L01+
气温:BMP180(0.01) DS18B20(0.50)
气压:BMP180(0.01)
光照:GY-30(IC为BH1750FVI)
湿度:DHT11(1)
降水:PCB 雨滴模块(他的编号是YL-83)
PM2.5:GP2Y1010AU0F
供电:18650一节
关于节电
由于设备处于阳台的位置,因此有线供电较为麻烦,太阳能供电也麻烦,所以采用可更换的18650锂电池供电;
电池供电方案显然要考虑能耗问题,因此有通信选择的问题:有esp01(WiFi)和NRF24L01(2.4G)可供选择。
ESP8266是耗电模块(工作:80mA(264mW),最高:200mA(660mW)),而NRF24L01+工作电流只有11.3mA(TX,0dbm)和13.5mA(RX),掉电模式电流仅为900nA,显然是一个比较好的选择。
一个合理的选择是设备用NRF将数据发送到室内的节点,这个节点再将数据传到云。室内节点可以使用电源供电,不存在能耗问题。
Promini和3v3和雨滴模块上都有LED,这些也很耗电(每个10到20mA),因此全部焊掉。
空气质量之前采用的是MQ135,但是这个东西由于要电热,非常耗电。资料上提到加热功率居然有900mW(!)。于是用低功耗的粉尘模块替换之。
为减小工作电流以获得尽可能长的工作时间,设备绝大多数时间进入睡眠模式(使用LowPower库),利用watchdog周期性醒来发送数据,然后立刻回到睡眠模式。
nrf24l01模块也需要同时睡眠和醒来,使用Mirf库里的powerDown()命令。
这样设计的待机电流:9.6mA(36mW),工作电流31mA(120mW),一节3000mAh的电池能工作12天左右。
电路设计
用EasyEDA画了下原理图,先在面包板上搭建了实验电路,再焊到一块5x7cm的洞洞板上。所有模块都采用可更换式的设计,同时保证布局尽可能紧凑。
由于雨滴模块和光照模块都要安装在阳台边,因此预留了接口。使用的时候用线连接出去。
EasyEDA链接:https://easyeda.com/KanameAimu/WeatherStation-e9dae2dacdea4157baf0bea2717fbf6c
原理图
成品图
室内节点
室内节点使用了一个ArduinoProMini+NRF24L01用于接收NRF链路数据并处理,以及一个Wemos D1用来提供WiFi通信。二者之间用I2C总线实现通信。由于工作电压不同,中间使用一个txs0108e模块做电平转换。
基本的功能是存储转发,还有一些附加的功能,例如在1602上显示收到的数据等。
Wemos D1是一个Arduino兼容的ESP8266开发板,可以直接使用Arduino IDE和很多的库,非常方便。这里用来从promini拿数据并上传到bigiot。
外形设计
接下来就是3D打印个盒子来安装电路板和固定传感器。模型设计使用OpenSCAD,生成STL切片后打印。
盒子
上面的部分用来固定18650电池盒,左下用来固定GP2Y1010传感器,右下用来固定DHT11模块。悬空的地方设计了支撑方便打印。
盒盖
采用卡扣式设计,将DHT11线,下载口和BMP180口留了出来。
完成后如图。
成品图
软件设计
设备需要采集数据并放入缓冲区,用nrf模块发送,然后再用LowPower.powerDown。
电池电压数据在传感器工作前采集一次,传感器工作后再采集一次取平均。
DS18B20是备用温度计。BMP180出问题后才使用,实际硬件可以不用。
另外注意ArduinoProMini(ATMega328P-AU)的int是16位,float=double=32位,要注意数据包和32位系统的兼容性。
数据包格式:
字节 | 类型 | 数据 |
0 | byte | 设备ID |
1 | byte | 包ID |
2 | uint16_t | 电池电压 |
4 | uint16_t | 雨滴传感器电压 |
6 | float | 粉尘传感器电压 |
10 | uint16_t | 光照数值 |
12 | float | 气压 |
16 | float | 气温 |
20 | byte | 湿度 |
21~31 | 保留 |
代码摘要:
void loop() {
char data[Mirf.payload];
data[0] = device_id;
data[1] = packet_id;
packet_id++;
int battery_value_1 = analogRead(PIN_BatteryVoltage);
int rain_value = analogRead(PIN_RAIN_SENSOR);
data[4] = *(((byte *)&rain_value)+0);
data[5] = *(((byte *)&rain_value)+1);
float dust_volt = getSharpDustSensorVoltage();
data[6] = *(((byte *)&dust_volt)+0);
data[7] = *(((byte *)&dust_volt)+1);
data[8] = *(((byte *)&dust_volt)+2);
data[9] = *(((byte *)&dust_volt)+3);
unsigned int brightness_val = (unsigned int)getGY30Reading();
data[10] = *(((byte *)&brightness_val)+0);
data[11] = *(((byte *)&brightness_val)+1);
float pres,temp;
if(!getBMP180Readings(&pres, &temp))
{
pres = 0;
temp = getDS18B20Temp();
}
data[12] = *(((byte *)&pres)+0);
data[13] = *(((byte *)&pres)+1);
data[14] = *(((byte *)&pres)+2);
data[15] = *(((byte *)&pres)+3);
data[16] = *(((byte *)&temp)+0);
data[17] = *(((byte *)&temp)+1);
data[18] = *(((byte *)&temp)+2);
data[19] = *(((byte *)&temp)+3);
data[20] = getDHT11Humidity();
int battery_value_2 = analogRead(PIN_BatteryVoltage);
int battery_value = (battery_value_1 + battery_value_2) / 2;
data[2] = *(((byte *)&battery_value)+0);
data[3] = *(((byte *)&battery_value)+1);
for(int i=21;i<32;i++)
{
data[i] = 0;
}
Mirf.setTADDR((byte *)"iotc1");
Mirf.send(data);
while(Mirf.isSending());
Mirf.powerDown();
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
全部代码和设计文件可以在我的GitHub上找到:https://github.com/KanameAimu/WeatherStation
此文章欢迎转载,转载请注明作者和原始链接。
2016-11-28
查了下ESP8266的功耗。DeepSleep有10mA(33mW),有个待机模式似乎是0.9uA,不过问题是8266只有1个ADC,本项目至少需要2个。
而且不想用那么多WiFi设备连路由器,个人认为还是控制中心这种设计比较好。各设备用nrf构成局域网。
8266的3.3v电压也是个问题,因为GP2Y要5v,还有dht11什么的东西,还是用arduino比较方便。
2019-10-9
数据包装其实可以用union解决。理论上可以用三极管给模块供电,可以进一步降低功耗。
还是不想拿8266当节点。可能是怕麻烦吧。
近期打算画个pcb来整合器件和接口。