资讯详情

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

2286f22a66d1973b3eefc86116018402.png

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 点阵屏 CLK GPIO14
CS GPIO12
DIN GPIO13
DHT11 温湿度传感器 DATA GPIO2
RGB 灯带 SIG GPIO15
噪音传感器 RX GPIO12
TX GPIO13
BMP280 SCL GPIO5
SDA GPIO4

借助于立创 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 E;

  • 起始符: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 结束语

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


点个支持一下吧 ↓↓↓

标签: oy054s传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台