【Arduino 动手做】使用 Nano 的综合环境监测系统

2025-07-291618
AI 快速预览详细 收起
这个项目使用Arduino Nano和多种传感器(如BME680、VEML680、BH1750和NEO 6M GPS)构建了一个综合环境监测系统。它可以实时显示温度、湿度、气压、空气质量指数、紫外线指数和光强度,并结合GPS数据提供当前位置信息。该项目解决了BME680代码运行时GPS值丢失的问题,确保了数据的准确性和可靠性。
使用 Nano 的环境监测系统,具有 GPS、BME680、VEML6070、MiCS-5524、BH1750、128x64 OLED 和 NeoPixels。

我创建这个设备是为了个人的。它最终将与带有 3.5 英寸 LCD 的 Raspberry Pi 配对,以显示雷达。最终产品将使我无论身在何处都能看到当前的天气状况,包括使用当前 GPS 数据的实时雷达。
它目前使用:
Arduino 纳米 (Rev3.0)
• Adafruit BME680(温度、湿度、气压和 AQI)
• Adafruit MiCS-5524 气体传感器(一氧化碳水平)
• Adafruit VEML6070(紫外线指数)
• BH1750(光强度)
• NEO 6M GPS(定位服务)
• OLED 单色 2.4 英寸 128x64 I2C(数值显示)
• Adafruit NeoPixel Stick(一目了然的显示屏)
它将显示温度、湿度、气压、空气质量指数(以 inHg 和 mb 为单位)空气质量指数、紫外线指数和光度;以及当前纬度/经度、高度、速度、航向和时间(UTC)。
Nano、BME680 和 CO 传感器目前安装在安装在塑料工艺容器中的 Adafruit Perma-Proto 四分之一尺寸板上。紫外线和勒克斯传感器安装在一块原型板上,并放置在设备内部的顶部。

我在代码中遇到了一个我还没有弄清楚的错误......似乎每当 BME680 代码运行时,高度、FIX、ACQUIRED 和 TRACKED 卫星的 GPS 值都会丢失。我还在努力弄清楚。
NeoPixels 以颜色编码格式显示当前值,通常遵循 NWS 格式。
• 0=温度水平(主观颜色)
• 1=压力读数(主观颜色)
• 2=湿度水平(主观颜色)
• 3= GPS 修复(绿色固定/红色无修复)
• 4=光强度(主观颜色)
• 5= 紫外线指数(遵循 NWS 指南)
• 6= 以 PPM 为单位的 CO 水平(主观颜色)
• 7=空气质素指数(遵循新创建指引)
我尝试将 NeoPixels 放在白标后面,图 1.1,但它太亮了。我最终在 NeoPixels 上放置了一条黑色电工胶带以扩散亮度,因此它们的外观,如图。

BME680 和 CO 传感器都安装在内部和接头上,而 UV 和 Lux 传感器安装在设备顶部的预备板上,并切出一块用于曝光,GPS 天线就坐在那里。
我的最后一步是在内部安装一个 5 毫米风扇,以使空气穿过内部传感器。

仅供参考,您可以使用 .96 英寸 128x64 IIC OLED 构建此项目,它将放置到位,无需任何代码修改。

【Arduino 动手做】使用 Nano 的综合环境监测系统图1

【Arduino 动手做】使用 Nano 的综合环境监测系统图2

【Arduino 动手做】使用 Nano 的综合环境监测系统图3

【Arduino 动手做】使用 Nano 的综合环境监测系统图5

【Arduino 动手做】使用 Nano 的综合环境监测系统图6

【Arduino 动手做】使用 Nano 的综合环境监测系统图4

【Arduino 动手做】使用 Nano 的综合环境监测系统图7

【Arduino 动手做】使用 Nano 的综合环境监测系统图8

【Arduino 动手做】使用 Nano 的综合环境监测系统图9

【Arduino 动手做】使用 Nano 的综合环境监测系统图10

创作许可协议

本项目采用 None(不开放任何权利,保留所有权利) 进行许可。

评论(2)
驴友花雕
驴友花雕
作者
【Arduino 动手做】使用 Nano 的综合环境监测系统
项目链接:https://www.hackster.io/PyreMage/an-environmental-monitoring-tool-2ebf0a
项目作者:柴堆法师
项目视频 :https://www.youtube.com/watch?v=jhZbnQCLt0w
项目代码:https://www.hackster.io/code_files/213798/download

驴友花雕
驴友花雕
作者
项目代码
[code]#include
#include
#include
#include
#include
#include "Adafruit_BME680.h"
#include "Adafruit_VEML6070.h"
#include
#define PIN 12
#define NUMPIXELS 8
int delayval = 50;
static NMEAGPS gps;
static gps_fix fix;
Adafruit_BME680 bme;
BH1750 lightMeter;
Adafruit_VEML6070 uv = Adafruit_VEML6070();
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
void setup() {
pixels.begin();
gpsPort.begin(9600);
bme.begin();
lightMeter.begin();
uv.begin(VEML6070_1_T);
//Serial.begin(9600);
u8x8.begin();
u8x8.setFont(u8x8_font_chroma48medium8_r);
u8x8.clearDisplay();
delay(10);
u8x8.drawString(4,3,"LocAware");
u8x8.drawString(3,4,"by PyreMage");
u8x8.drawString(6,5,"v4.0");
delay(1500);
u8x8.clearDisplay();
u8x8.drawString(0,0," Acquiring Fix");
u8x8.inverse();
u8x8.drawString(0, 1, "T");//Temp
u8x8.drawString(8, 1, "P");//Pressure
u8x8.drawString(0, 2, "H");//Humidity
u8x8.drawString(8, 2, "P");//Pressure
u8x8.drawString(0, 3, "L");//Lux
u8x8.drawString(8, 3, "UVI");//UV index
u8x8.drawString(0, 4, "CO");//CO Gas
u8x8.drawString(8, 4, "AQI");//AQI
u8x8.drawString(0, 5, "Sp");//Speed
u8x8.drawString(11, 5, "Hd");//Heading
u8x8.drawString(0, 6, "A");//Altitude
u8x8.drawString(0, 7, "F");//Fix
u8x8.drawString(3, 7, "T");//Tracking
u8x8.drawString(6, 7, "A");//Acquired
u8x8.drawString(10, 7, "U");//UTC Time
u8x8.noInverse();
/*
Neopixels definition
0=Temp
1=Pressure
2=Humidity
4=Lux
3=GPS Fix
5=UVI
6=CO
7=AQI
*/
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
for(int i=0;ipixels.setPixelColor(i, pixels.Color(0,255,0));
pixels.show();
delay(delayval);}
for(int i=0;ipixels.setPixelColor(i, pixels.Color(0,0,0));
pixels.show();
delay(delayval);}
}
void loop() {
uint16_t lux = lightMeter.readLightLevel();
char tmpchar[4];
int bmetmp=(bme.readTemperature() * 9/5 + 32-10);
dtostrf((bme.readTemperature() * 9/5 + 32-10), 3, 2, tmpchar);
if (bmetmp>100){pixels.setPixelColor(1, pixels.Color(255,0,0));//red
pixels.show();}else
if (bmetmp>90 && bmetmp<99){pixels.setPixelColor(0, pixels.Color(255,125,0));//orange
pixels.show();}else
if (bmetmp>80 && bmetmp<89){pixels.setPixelColor(0, pixels.Color(255,255,0));//yellow
pixels.show();}else
if (bmetmp>70 && bmetmp<79){pixels.setPixelColor(0, pixels.Color(0,255,125));//turquiose
pixels.show();}else
if (bmetmp>60 && bmetmp<69){pixels.setPixelColor(0, pixels.Color(0,255,0));//green
pixels.show();}else
if (bmetmp<59){pixels.setPixelColor(0, pixels.Color(0,0,255));//blue
pixels.show();}else
if (bmetmp<1){pixels.setPixelColor(0, pixels.Color(0,0,0));pixels.show();}//off
u8x8.drawString(1, 1, tmpchar);
u8x8.drawString(6, 1, "F");
delay(10);
char prschar[4];
dtostrf((bme.readPressure()/3365.3*1+.15), 3, 2, prschar);
u8x8.drawString(9, 1, prschar);
u8x8.drawString(14, 1, "Hg");
char prs2char[4];
dtostrf(bme.readPressure()*.01+12, 4, 2, prs2char);
int bmeprs=(bme.readPressure()*.01+12);
dtostrf((bme.readTemperature() * 9/5 + 32-10), 3, 2, tmpchar);
if (bmeprs>1020){pixels.setPixelColor(1, pixels.Color(255,125,0));//orange
pixels.show();}else
if (bmeprs>1010 && bmeprs<1019){pixels.setPixelColor(1, pixels.Color(0,255,0));//green
pixels.show();}else
if (bmeprs>1000 && bmeprs<1009){pixels.setPixelColor(1, pixels.Color(0,255,125));//turquiose
pixels.show();}else
if (bmeprs>990 && bmeprs<9999){pixels.setPixelColor(1, pixels.Color(255,125,0));//orange
pixels.show();}else
if (bmeprs>970 && bmeprs<989){pixels.setPixelColor(1, pixels.Color(255,255,0));//yellow
pixels.show();}else
if (bmeprs<969){pixels.setPixelColor(1, pixels.Color(255,0,0));//red
pixels.show();}else
if (bmeprs<1){pixels.setPixelColor(1, pixels.Color(0,0,0));pixels.show();}//off
u8x8.drawString(9, 2, prs2char);
//u8x8.drawString(14, 1, "mB");
char humchar[4];
int bmehum=(bme.readHumidity()+14.5);
dtostrf(bme.readHumidity()+14.5, 3, 2, humchar);
if (bmehum>100){pixels.setPixelColor(2, pixels.Color(255,0,0));//red
pixels.show();}else
if (bmehum>90 && bmehum<99){pixels.setPixelColor(2, pixels.Color(255,125,0));//orange
pixels.show();}else
if (bmehum>80 && bmehum<89){pixels.setPixelColor(2, pixels.Color(255,255,0));//yellow
pixels.show();}else
if (bmehum>70 && bmehum<79){pixels.setPixelColor(2, pixels.Color(0,0,255));//blue
pixels.show();}else
if (bmehum>60 && bmehum<69){pixels.setPixelColor(2, pixels.Color(0,255,125));//turquiose
pixels.show();}else
if (bmehum<59){pixels.setPixelColor(2, pixels.Color(0,255,0));//green
pixels.show();}else
if (bmehum<1){pixels.setPixelColor(2, pixels.Color(0,0,0));pixels.show();}//off
u8x8.drawString(1, 2, humchar);
u8x8.drawString(6, 2, "%");
char luxchar[5];
dtostrf(lux, 5, 0, luxchar);
//Serial.println(luxchar);
if (lux>34001){pixels.setPixelColor(4, pixels.Color(255,0,0));//red
pixels.show();}else
if (lux>20001 && lux<34000){pixels.setPixelColor(4, pixels.Color(255,125,0));//orange
pixels.show();}else
if (lux>10001 && lux<20000){pixels.setPixelColor(4, pixels.Color(255,255,0));//yellow
pixels.show();}else
if (lux>5001 && lux<10000){pixels.setPixelColor(4, pixels.Color(0,0,255));//blue
pixels.show();}else
if (lux>2000 && lux<5000){pixels.setPixelColor(4, pixels.Color(0,255,125));//turquiose
pixels.show();}else
if (lux<2000){pixels.setPixelColor(4, pixels.Color(0,255,0));//green
pixels.show();}else
if (lux<1){pixels.setPixelColor(4, pixels.Color(0,0,0));pixels.show();}//off
u8x8.drawString(1, 3, " ");
u8x8.drawString(1, 3, luxchar);
char uvchar[4];
uv.readUV();
if (uv.readUV()>2055) {u8x8.drawString(11, 3, " ");u8x8.drawString(11, 3, "Extre");
pixels.setPixelColor(5, pixels.Color(255,0,0));//red
pixels.show();}else
if (uv.readUV()>1494 && uv.readUV()<2054) {u8x8.drawString(11, 3, " ");u8x8.drawString(11, 3, "VHigh");
pixels.setPixelColor(5, pixels.Color(255,125,0));//orange
pixels.show();}else
if (uv.readUV()>1121 && uv.readUV()<1493) {u8x8.drawString(11, 3, " ");u8x8.drawString(11, 3, "High");
pixels.setPixelColor(5, pixels.Color(255,255,0));//yellow
pixels.show();}else
if (uv.readUV()>561 && uv.readUV()<1120) {u8x8.drawString(11, 3, " ");u8x8.drawString(11, 3, "Moder");
pixels.setPixelColor(5, pixels.Color(0,0,255));//blue
pixels.show();}else
if (uv.readUV()<560) {u8x8.drawString(11, 3, " ");u8x8.drawString(11, 3, "Low");
pixels.setPixelColor(5, pixels.Color(0,255,0));//green
pixels.show();}else
if (uv.readUV()<1){pixels.setPixelColor(5, pixels.Color(0,0,0));pixels.show();}//off
char vocchar[5];
dtostrf(bme.gas_resistance, 5, 0, vocchar);
if (bme.gas_resistance>140901) {u8x8.drawString(11, 4, " ");u8x8.drawString(11, 4, "Good");
pixels.setPixelColor(7, pixels.Color(0,255,0));//green
pixels.show();}else
if (bme.gas_resistance>75001 && bme.gas_resistance<140900) {u8x8.drawString(11, 4, " ");u8x8.drawString(11, 4, "Moder");
pixels.setPixelColor(7, pixels.Color(0,255,125));//turquiose
pixels.show();}else
if (bme.gas_resistance>37400 && bme.gas_resistance<75000) {u8x8.drawString(11, 4, " ");u8x8.drawString(11, 4, "USG");
pixels.setPixelColor(7, pixels.Color(0,0,255));//blue
pixels.show();}else
if (bme.gas_resistance>18770 && bme.gas_resistance<37399) {u8x8.drawString(11, 4, " ");u8x8.drawString(11, 4, "Unhlt");
pixels.setPixelColor(7, pixels.Color(255,0,255));//magenta
pixels.show();}else
if (bme.gas_resistance>9001 && bme.gas_resistance<18771) {u8x8.drawString(11, 4, " ");u8x8.drawString(11, 4, "VUnhl");
pixels.setPixelColor(7, pixels.Color(225,125,0));//orange
pixels.show();}else
if (bme.gas_resistance>8371 && bme.gas_resistance<9000) {u8x8.drawString(11, 4, " ");u8x8.drawString(11, 4, "Hazar");
pixels.setPixelColor(7, pixels.Color(255,0,0));//red
pixels.show();}else
if (bme.gas_resistance<8370) {u8x8.drawString(11, 4, " ");u8x8.drawString(11, 4, "Vacat");
pixels.setPixelColor(7, pixels.Color(255,0,0));//red
pixels.show();}else
if (bme.gas_resistance<1){pixels.setPixelColor(7, pixels.Color(0,0,0));pixels.show();}//off
char gaschar[4];
int reading = analogRead(A0);
dtostrf(reading, 3, 0, gaschar);
u8x8.drawString(2, 4, gaschar);
u8x8.drawString(5, 4, "PPM");
//Serial.println(reading);
if (reading>1000){pixels.setPixelColor(6, pixels.Color(255,0,0));pixels.show();}//red
if (reading>501 && reading<999){pixels.setPixelColor(6, pixels.Color(225,125,0));pixels.show();}else//orange
if (reading>151 && reading<500){pixels.setPixelColor(6, pixels.Color(255,255,0));pixels.show();}else//yellow
if (reading>71 && reading<150){pixels.setPixelColor(6, pixels.Color(0,0,255));pixels.show();}else//blue
if (reading>1 && reading<70){pixels.setPixelColor(6, pixels.Color(0,255,0));pixels.show();}else//green
if (reading<1){pixels.setPixelColor(6, pixels.Color(0,0,0));pixels.show();}//off
GPSloop();
}
static void GPSloop()
{
pixels.setPixelColor(3, pixels.Color(255,0,0));pixels.show();//red
while (gps.available( gpsPort )) {
pixels.setPixelColor(3, pixels.Color(0,255,0));pixels.show();//green
GetGPS();
}
}
static void GetGPS()
{
fix = gps.read();
int totalSatellites, trackedSatellites;
totalSatellites = gps.sat_count;
for (uint8_t w = 0; w < totalSatellites; w++) {
if (gps.satellites[w].tracked) {
trackedSatellites++;
}
}
enum {BufSizeTracked = 3}; //Space for 2 characters + NULL
char trackedchar[BufSizeTracked];
snprintf (trackedchar, BufSizeTracked, "%d", trackedSatellites);
u8x8.drawString(4, 7, " ");
u8x8.drawString(4, 7, trackedchar);
enum {BufSizeTotal = 3};
char availchar[BufSizeTotal];
snprintf (availchar, BufSizeTotal, "%d", totalSatellites);
u8x8.drawString(7, 7, " ");
u8x8.drawString(8, 7, availchar);
if (fix.valid.time) {
enum {BufSizeTime = 3};
int hour = fix.dateTime.hours;
int minute = fix.dateTime.minutes;
char hourchar[BufSizeTime];
char minutechar[BufSizeTime];
snprintf (hourchar, BufSizeTime, "%d", hour);
snprintf (minutechar, BufSizeTime, "%d", minute);
if ( hour < 10 )
{
snprintf (hourchar, BufSizeTime, "%02d", hour);
}
if ( minute < 10 )
{
snprintf (minutechar, BufSizeTime, "%02d", minute);
}
u8x8.drawString(11, 7, hourchar);
u8x8.drawString(13, 7, ":");
u8x8.drawString(14, 7, minutechar);
}
char latchar[7]; // Buffer big enough for 4-character float
dtostrf(fix.latitude(), 3, 4, latchar);
u8x8.drawString(0, 0, " ");
u8x8.drawString(0, 0, latchar);
char longchar[7];
dtostrf(fix.longitude(), 3, 4, longchar);
u8x8.drawString(8, 0, longchar);
char altchar[5]; // Buffer big enough for 4-character float
dtostrf((fix.altitude()*3.28084), 3, 2, altchar);
u8x8.drawString(1, 6, " ");
u8x8.drawString(1, 6, altchar);
u8x8.drawString(7, 6, "ft");
char headchar[3];
dtostrf (fix.heading(), 3, 0, headchar);
if (headchar<10){u8x8.drawString(12, 5, "00");u8x8.drawString(14, 5, headchar);}else
if (headchar<99){u8x8.drawString(12, 5, "0");u8x8.drawString(13, 5, headchar);}else
u8x8.drawString(12, 5, headchar);
char spdchar[4];
dtostrf((fix.speed_kph()*0.621371), 2, 2, spdchar);
u8x8.drawString(2, 5, spdchar);
u8x8.drawString(7, 5, "Mph");
char satchar2[3];
dtostrf(fix.satellites, 2, 0, satchar2);
u8x8.drawString(1, 7, " ");
u8x8.drawString(1, 7, satchar2);
}[/code]
- 没有更多了 -