校园网络气象站的设计与实现

Posted 铁熊玩创客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了校园网络气象站的设计与实现相关的知识,希望对你有一定的参考价值。

0x01 项目背景

在很多学校里、景区里我们总能见到这样的气象信息大屏幕,能实时显示温度、湿度、气压等气象数据。相较于传统的气象百叶箱,这样的大屏幕气象站有更好的实时性、实用性和科技感,人们从很远处就能清楚地看到气象数据。作为一名创客老师,本着“自己动手,丰衣足食”的创客精神,就开始构思自己设计一个校园网络气象站。


0x02 项目分析

根据初步思路整理,我希望设计的是一面安装在校园大厅的气象信息墙,采集的气象数据为校园里的实时气象数据。考虑到整块大屏幕的成本较高,我准备使用多块小屏幕显示不同的气象数据的方式。为了提高项目整体的稳定性,为每块屏幕单独配物联网主控,利用 WiFi 实现气象数据的传输,同时也方便将气象数据上传到物联网平台供后期研究。

作为校园里使用的气象信息墙,最基础的显示信息应该有温度、湿度和气压等信息。为了引导学生保持安静,还可以增加检测噪音的功能,如果噪音值过高,还要额外提醒学生注意保持安静。另外,为了让学生能及时掌握上下课时间,还可以增加时钟功能,帮助学生更好地树立时间观念。

校园网络气象站设计构思图

气象数据检测模块以 WeMos D1 mini 为主控,连接 DHT11 温湿度传感器、BMP280 气压传感器和声音传感器,用于检测所需要的气象信息,将检测到的数据通过 Blynk 物联网平台发送到相应对的显示模块上。

温度显示模块以 WeMos D1 mini 为主控,用 2*4 点阵屏作为显示单元,将从气象数据检测模块接收到的温度数值显示在点阵屏上。湿度显示模块、噪声显示模块和气压显示模块也是同样的原理。

时钟显示模块以 WeMos D1 mini 为主控,用 2*8 点阵屏作为显示单元,直接从网络获取标准时间,无需手动调整时间。

0x03 硬件设计

为了保证气象信息墙的稳定性,避免出现因长期使用导致的导线接触不良等情况,传感器与主控的连接应该尽可能减少杜邦线的使用。因此,重新设计一块转接 PCB,用于焊接本项目中需要用到的各种传感器和模块。

该转接板用于显示模块时,转接板上只需要接 WeMos D1 mini 主控和 MAX7219 点阵屏幕。

而作为气象数据发送模块时,需要接 DHT11 温湿度传感器、BMP280 气压传感器、声音传感器和 WeMos D1 mini 主控。

综上需求,为转接板分配引脚如下:

模块模块引脚名主控引脚名
MAX7219 点阵屏CLKGPIO14

CSGPIO12

DINGPIO13
DHT11 温湿度传感器DATAGPIO2
RGB 灯带SIGGPIO15
噪音传感器RXGPIO12

TXGPIO13
BMP280SCLGPIO5

SDAGPIO4

借助于立创 EDA 设计软件,先设计转接板的原理图,并为各个传感器分配连接引脚。

电路原理图

根据原理图,生成 PCB,并调整各元器件布局。根据 MAX7219 点阵屏的尺寸,确定转接板上点阵屏接口位置,同时对应于点阵屏上的螺丝孔位,设计用于固定的四个螺丝孔。其他传感器根据其大小排布其位置。位置确认无误后,就可以对 PCB 进行布线了,对于新手而言,设计简单的电路板时可以直接使用软件自带的自动布线功能。自动布线虽然会存在一些问题,但是比较适合新手使用。

电路设计图

设计完成后,还可以直接看到电路板完成后平面和立体效果。也可以通过生成立体效果来检查各个元器件之间的安装距离,根据立体效果再对转接板做适当调整。

电路效果平面渲染图
电路效果立体渲染图

0x04 硬件焊接

设计好转接板后,通过嘉立创平台下单生产,等上几天后就能收到自己设计的转接板了。

转接板实物图

在 MAX7219 背面焊接 5P 排针,方便与转接板焊接,再安装 4 个用于固定的铜柱,铜柱位置与转接板上的螺丝孔位置对应。

点阵屏背面铜柱安装图

为转接板焊接排母和电源座,然后将其安装到点阵屏背后的铜柱上,装上 WeMos d1 mini 主控。这样就完成了一个显示模块的设计,利用同样的方法焊接 3 个显示模块,为不同的模块上传不同的程序,就能显示对应的气象数据了。

显示模块

而在焊接气象数据发送模块时稍许复杂一点,还需要将各个传感器焊接到转接板上。为发送模块上传程序后,该模块就会将气象数据发送给各个显示模块。

气象数据发送模块

0x05 程序编写

为了能实现各块 WeMos d1 mini 主控之间的数据通信,同时又能将温湿度数据发布到物联网平台,我采取使用 Blynk 物联网平台,实现数据的联通。利用 Blynk 的桥接功能,可以实现多块主控之间的数据传递。

因此,在开始编程之间,需要在 Blynk APP 中创建项目,并为该项目添加 5 个设备,不同的设备会有不同的授权码。

Blynk App项目设置

然后在该项目中添加 3 个显示组件用于显示温度、湿度和气压,再添加一个仪表组件显示声音分贝值。

Blynk App添加相关组件

5.1 分贝值的读取

普通的声音传感器检测到的只是声音响度的模拟值,无法直接转换成声音的分贝值。在这个项目中,我需要测出声音的分贝值,因此需要采用了一个分贝传感器。

该分贝传感器采用串口通信方式,以下为该模块的参数:

  • 串行波特率:115200,无校验位,1 位停止位;

  • 数据包格式:起始符+命令+数据+校验值,一帧数据包总长度为 6 字节;

  • 如:BB AA 01 7F 02 E7;

  • 起始符:BB AA,表示一帧的开始;

  • 命令:01,表示此帧为返回分贝值数据;

  • 数据:7F 02,表示检测到的分贝值为 63.9dB。低字节在前,高字节在后,且每单位为 0.1dB;

  • 校验值:E7,为 BB,AA,01,7F,02 的算术和校验值。

分贝传感器

据此说明,则可以通过串口读取到的数据计算出该传感器检测到的分贝数值。利用如下程序获取声音分贝值:

if (mySerial.available() > 0) 
    //获取噪声值
    if (mySerial.read() == 0xBB) 
      if (mySerial.read() == 0xAA) 
        if (mySerial.read() == 0x01) 
          Noise_L = mySerial.read();
          Noise_H = mySerial.read();
          Noise = (Noise_H * 256 + Noise_L) / 10.0;
        
      
    
  

利用该模块检测室内正常情况下的分贝值,一般室内相对安静的情况下,分贝值在 40dB 左右。

测试分贝值

5.2 气象数据发送模块程序

作为气象数据发送模块,首先需要为该模块网络,为了提高实用性,通过手机配网的方式让模块连接入网络,所以需要在初始化程序中将该模块设置为 AP 模式。

利用定时器函数,每隔 50 毫秒读取一次声音分贝值,每隔 1 秒读取温度、湿度和气压值,读取到数值后,将数值通过 blynk 桥接发送到各个显示模块。

/*
  气象数据发送端
*/
#define BLYNK_PRINT Serial
#define SEALEVELPRESSURE_HPA (1013.25)

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
#include <SoftwareSerial.h>
#include <WiFiManager.h>
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
#include <Wire.h>
#include <DHT.h>

#define SOUND_TX 13
#define SOUND_RX 12

SimpleTimer timer;

char temp_auth[] = "ql-7tUUaTYd3Hx1fl9LOvsl-RV4CCWDH";
char press_auth[] = "QwyARDcUsln_hNKOkMPLzkSHjvhEFmE8";
char bme_auth[] = "N0mnni2CNtITos-Jb4tm5rgwb-OldPOs";
char hum_auth[] = "0hN9wThrJrK8Ie_oy4OeDlxGBE2evnyR";
char sound_auth[] = "FlVPYSmNpCzJRBN3mzwQf9MHbkRBcgRr";

WidgetBridge bridge_temp(V0), bridge_press(V1), bridge_hum(V2), bridge_sound(V3);
Adafruit_BMP280 bmp;
DHT dht(2, 11);

float Noise, Noise_average, Noise_total, Temp, Hum, Pressure;
int Noise_H, Noise_L, i;

SoftwareSerial mySerial(SOUND_TX, SOUND_RX);

BLYNK_CONNECTED() 
  bridge_press.setAuthToken(press_auth);
  bridge_hum.setAuthToken(hum_auth);
  bridge_temp.setAuthToken(temp_auth);
  bridge_sound.setAuthToken(sound_auth);


void Get_Data() 
  if (mySerial.available() > 0) 
    //获取噪声值
    if (mySerial.read() == 0xBB) 
      if (mySerial.read() == 0xAA) 
        if (mySerial.read() == 0x01) 
          Noise_L = mySerial.read();
          Noise_H = mySerial.read();
          Noise = (Noise_H * 256 + Noise_L) / 10.0;
        
      
    
  

  i++;
  Noise_total +=  Noise;

  if (i == 20) 
    i = 0;
    Noise_average = Noise_total / 20;//计算1秒内的平均噪声值
    Noise_total = 0;
    //读取并发送温度、湿度、气压值
    Hum = dht.readHumidity();
    Pressure = bmp.readPressure();
    Temp = bmp.readTemperature();
    bridge_press.virtualWrite(V0, Pressure);
    bridge_hum.virtualWrite(V0, Hum);
    bridge_temp.virtualWrite(V0, Temp);
    bridge_sound.virtualWrite(V0, Noise_average*0.75);
    Serial.println(Noise_average*0.75);
  


void setup() 
  Serial.begin(9600);
  mySerial.begin(115200);
  WiFiManager wifiManager;
  if (!wifiManager.autoConnect("Weather Station")) 
    //设置模块在未联网状态下进入AP模式,等待联网
    Serial.println("failed to connect and hit timeout");
    delay(3000);
    ESP.reset();
    delay(5000);
  
  bmp.begin(0x76);
  dht.begin();
  Blynk.config(bme_auth, "blynk.mixly.org", 8080);
  timer.setInterval(50L, Get_Data);//每隔1s,运行Get_Data函数


void loop() 
  timer.run();
  Blynk.run();

5.3 模块配网

为了便于模块在不同 WiFi 环境下使用,我程序中没有将连接的 WiFi 信息固定,而是采用 AP 配网的方式进行。上传程序后,打开串口监视器,可以发现模块进入了 AP 配网模式,在该模式下,模块会成为一个无线接入点,会发出一个 WiFi 信号,如该模块发出的 WiFi 信号名称为 Weather Station。

模块进入AP配网模式

用手机搜索该名称的 WiFi 信号,并接入到该信号,然后手机会自动跳转到网络配置界面,选择 Configure WiFi,然后会扫描出附近可用的 WiFi 信号,选择我们常用的信号并输入密码,稍等片刻后,该模块就可以连接到指定的 WiFi 上。利用同样的方法,为后面每一个模块连接到 WiFi 上,保证每一个模块都可以正确连接到网络。

为各模块配置网络

气象数据发送模块连接到网络后,就可以在 Blynk App 中查询到相关气象数据,在 App 中设置了不同的组件来呈现不同的数据,还可以通过 Super Chart 组件呈现出一段时间内气象数据的变化情况。

Blynk APP端查看气象数据

5.4 设计显示字体

为了提高数值的辨识度,需要重新设计点阵屏显示的数字字体,根据屏幕尺寸,设计两种尺寸的字体。

用大字体作为温湿度数值的整数部分和时钟模块的小时分钟显示,用小字体作为温湿度数值的小数部分和时钟模块的秒钟显示。

大字体占用 8*16 的点阵空间,小字体占用 5*8 的点阵空间。记录每个字的点阵分布,设计字体文件,方便显示模块调用字体。字体显示效果如下图:

点阵屏字体设计效果图

5.5 显示模块程序

作为显示模块,主要负责从发送端接收到显示数据,然后将数值在屏幕上显示出来。模块联网后,先对点阵屏进行初始化设置,然后通 Blynk 虚拟管脚接收数值。由于各个模块的授权码不同,所以各个模块接收到的数值也不相同。温度显示模块接收到的是温度值,湿度显示模块接收到的湿度值。

#define BLYNK_PRINT Serial
#define CSPin 12

#include <Wire.h>
#include <WiFiManager.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
#include <BlynkSimpleEsp8266.h>
#include "Tiny5pt7A.h"
#include "FreeMono12pt7b.h"

char hum_auth[] = "0hN9wThrJrK8Ie_oy4OeDlxGBE2evnyR";
float Hum;

Max72xxPanel myMatrix = Max72xxPanel(CSPin, 4, 2);

BLYNK_WRITE(V0) 
  //通过虚拟管脚接收湿度数值
  Hum = param.asFloat();
  myMatrix.fillScreen(0);
  myMatrix.setCursor(60, 6);
  myMatrix.setFont(&FreeMono12pt7b);
  //用大字体显示湿度值的整数部分
  myMatrix.print(int(Hum));
  myMatrix.setFont(&Tiny5pt7A);
  //用小字体显示湿度值的小数部分
  myMatrix.print(int(Hum * 10) % 10);
  myMatrix.write();


void setup() 
  Serial.begin(115200);
  WiFiManager wifiManager;
  //对MAX7219点阵屏初始化设置
  myMatrix.setIntensity(15);
  myMatrix.fillScreen(LOW);
  for (int i = 0; i < 8; i++) 
    myMatrix.setRotation(i, 1);
  
    
  for (int 4 = 0; i < 8; i++) 
    myMatrix.setPosition(i, i - 4, 1);
  
    
  myMatrix.setCursor(5, 0);
  myMatrix.print("Hum");
  myMatrix.write();
  if (!wifiManager.autoConnect("Hum")) 
    //设置模块在未联网状态下进入AP模式,等待联网
    Serial.println("failed to connect and hit timeout");
    delay(3000);
    ESP.reset();
    delay(5000);
  

  Blynk.config(hum_auth, "blynk.mixly.org", 8080);


void loop() 
  Blynk.run();

以上是湿度显示模块程序,温度显示模块、气压显示模块等其他模块,只需要修改授权码即可。

各显示模块上传程序后,就可以通过网络从气象数据发送端获取到对应的气象数据,模块上显示效果如下图所示。

温度、湿度、气压显示效果

5.6 彩虹灯带模块

彩虹灯带在在正常情况下会不断变换颜色,为校园网络气象站增加一抹绚丽的色彩。但是当检测到的噪音超过一定数值时,彩虹灯带会先变黄色;如果噪音持续变大,彩虹灯带会变成红色,提醒附近的学生要保持安静。

彩虹灯带效果图
#define BLYNK_PRINT Serial
#define RGBPin 15
#define NUMPIXELS 150

#include <Wire.h>
#include <WiFiManager.h>
#include <SimpleTimer.h>
#include <BlynkSimpleEsp8266.h>
#include <Adafruit_NeoPixel.h>

SimpleTimer timer;

char sound_auth[] = "FlVPYSmNpCzJRBN3mzwQf9MHbkRBcgRr";
float Noise;
int YELLOW_TIME, RED_TIME,hue;

Adafruit_NeoPixel rgb_display = Adafruit_NeoPixel(NUMPIXELS, RGBPin, NEO_GRB + NEO_KHZ800);

BLYNK_WRITE(V0) 
  Noise = param.asFloat();
  Serial.println(Noise);
  if (Noise > 75)
    RED_TIME = 6;
  else if (Noise > 65)
    YELLOW_TIME = 6;


void rainbow() 
  for (int i = 0; i <= NUMPIXELS; i ++ ) 
    for (int j = 0; j <= NUMPIXELS; j++ ) 
      hue = (i + j) % (NUMPIXELS+1) * (65536/NUMPIXELS);//计算每一盏灯的颜色值
      rgb_display.setPixelColor(j , rgb_display.ColorHSV(hue, 255, 255));
    
    rgb_display.show();
    delay(5);
  


void DisplayTime() 
  if (RED_TIME)
  
    for (int j = 0; j <= NUMPIXELS; j ++)
      rgb_display.setPixelColor(j, 0xff0000);//全部亮红色
    rgb_display.show();
    RED_TIME--;
  
  else if (YELLOW_TIME)
  
    for (int j = 0; j <= NUMPIXELS; j ++)
      rgb_display.setPixelColor(j, 0xffff00);//全部亮黄色
    rgb_display.show();
    YELLOW_TIME--;
  
  else
    rainbow();


void setup() 
  Serial.begin(115200);
  WiFiManager wifiManager;
  rgb_display.begin();
  if (!wifiManager.autoConnect("RGB")) 
    Serial.println("failed to connect and hit timeout");
    delay(3000);
    ESP.reset();
    delay(5000);
  
  Serial.println("local ip");
  Serial.println(WiFi.localIP());
  Blynk.config(sound_auth, "blynk.mixly.org", 8080);
  timer.setInterval(1550L, DisplayTime);


void loop() 
  timer.run();
  Blynk.run();

0x06 时间显示模块

校园里的很多时钟都是采用传统的时钟,传统的时钟经常会出现因电池损耗而渐渐变得不准时,需要人工去重新调整时间。而我们发现,手机上的时钟却可以一直都很准时,从来不用担心因没电而导致不准时。这是因为现在的手机都可以连接到互联网上,而网络上有提供标准授时的时间服务器。

提供标准授时的服务器叫 NTP 服务器,我们可以通过 WeMos D1 mini 主控去连接该服务器,然后获取到最新的时间,通过点阵屏显示出来。

#define CSPin 12

#include <TimeLib.h>
#include <WiFiManager.h>
#include <NtpClientLib.h>
#include <SimpleTimer.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
#include "FreeMono12pt7b.h"
#include "Tiny5pt7A.h"

SimpleTimer timer;

int8_t timeZone = 8;//设置时区
const PROGMEM char *ntpServer = "ntp1.aliyun.com";//设置时间服务器

Max72xxPanel myMatrix = Max72xxPanel(CSPin, 8, 2);

void DisplayTime()  //显示内容
  String currentTime = "" ;
  String colon = (NTP.getTimeSecond() % 2 == 0) ? ":" : " ";//每隔1秒显示冒号
  currentTime += (NTP.getTimeHour24() < 10) ? "0" + String(NTP.getTimeHour24()) : String(NTP.getTimeHour24());
  currentTime += colon;
  currentTime += (NTP.getTimeMinute() < 10) ? "0" + String(NTP.getTimeMinute()) : String(NTP.getTimeMinute());
  myMatrix.fillScreen(LOW);
  myMatrix.setCursor(60, 6);
  myMatrix.setFont(&FreeMono12pt7b);
  myMatrix.print(currentTime);//显示 时:分 
  myMatrix.setFont(&Tiny5pt7A);
  myMatrix.print((NTP.getTimeSecond() < 10) ? "0" + String(NTP.getTimeSecond()) : String(NTP.getTimeSecond()));
  //显示 秒
  myMatrix.write();


void setup() 
  Serial.begin(9600);
  WiFiManager wifiManager;
  myMatrix.setIntensity(15);
  myMatrix.fillScreen(LOW);
  for (int i = 0; i < 16; i++) 
    myMatrix.setRotation(i, 1);
   
  myMatrix.setCursor(4, 0);
  myMatrix.print("Clock");
  myMatrix.write();
  if (!wifiManager.autoConnect("Clock")) 
    Serial.println("failed to connect and hit timeout");
    delay(3000);
    ESP.reset();
    delay(5000);
  
  Serial.println("local ip");
  Serial.println(WiFi.localIP());
  NTP.setInterval (600);//设置与NTP时间服务器同步时间间隔
  NTP.setNTPTimeout (1500);
  NTP.begin (ntpServer, timeZone, false);
  timer.setInterval(1000L, DisplayTime);//每隔1s,运行Display函数


void loop() 
  timer.run();

为时间显示模块配置网络后就能显示正确的时间了。

时间模块显示效果

0x07 外观设计与安装

校园网络气象墙以将一棵树作为主体的造型,将各个显示模块安装在不同位置的树叶上,实现各个气象数据的显示。

校园网络气象墙效果图

将设计图制作成实体模型,树叶部分选取材质需要有一定的透光性,这样可以将显示模块直接装在内部,点阵屏的光亮正好可以透出来,光线会变得更柔和。彩虹灯带沿着草坪轮廓粘贴安装,从左侧引线到达电源箱。

气象站的各个模块采用 5V 供电,每个显示模块需要 1-1.5A 左右的电流,其中时间显示模块需要 2A 左右的电流,灯带需要 2A 左右的电流,因此整个作品大概需要 8A 左右的电流。为了保证电源有足够的冗余,给整个作品提供的电源需要 5V 10A 以上。将电源模块隐藏在左侧盒子中,预留一定的空隙,保持空气流通,避免电源模块温度过高。

气象检测模块的安装位置要选择通风性好,避免高温的位置,由于每一块点阵屏都会有发热的情况,不可以将气象检测模块安装到树叶内部。

校园网络气象墙实际效果

0x08 结束语

当整个作品完成后,可以为校园里的同学们提供实时的温湿度情况和时间显示。帮助学生更好地了解温湿度情况和时间,同时通过噪音检测功能可以很好的提醒学生要在课间保持安静。


欢迎转发朋友圈。如需转载,请注明出处和原作者。

点个在看支持一下吧 ↓↓↓

以上是关于校园网络气象站的设计与实现的主要内容,如果未能解决你的问题,请参考以下文章

校园网络气象站的设计与实现

校园网络气象站的设计与实现

基于OMAPL138+FPGA射频直接采样气象传真接收机的设计与实现

基于树莓派的微型气象站设计与开发

Python气象数据处理与绘图(18):泰勒图

Python高级应用程序设计任务要求