一、原件清单

  • esp8266 node-mcu*1
  • ssd1302 oled显示屏*1
  • dht11温湿度传感器*1
  • bmp280气压传感器*1
  • 风速传感器(淘宝店铺:风速传感器的店铺)
  • 2pin接线端子*1
  • 杜邦线 若干

二、硬件连接

连线图.png
连线图

NodeMCU ssd1306 dht11 BMP280 风速传感器
D0 SCL
D1 SCL
D2 SDA
D3
D4 S
D5 SDO
D6 CSB
D7 SDA
A0 棕色信号线
PS:各个模块的VCC和GNG端口皆并联在由NodeMCU引出的3v3和gnd上,风速传感器的蓝色线为gnd线,连接在NodeMCU的GND端口上

三、原理框图

农业气象监测站原理图.png

通过wifi的方式来将数据传回手机。


四、程序代码

废话少说直接上代码

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
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
#include <dht11.h>//引入DHT11库
#include "SSD1306Wire.h"
#define BLINKER_WIFI
#include <Blinker.h>

#define temNumber "num-gpc"
#define humNumber "num-ia5"
#define windNumber "num-zb4"
#define AirNumber "num-3zw"

char auth[] = "c2b25ef0c332";
char ssid[] = "皇室家族Family";
char pswd[] = "sunlisunrusunxu@";

BlinkerNumber Tem(temNumber);
BlinkerNumber Hum(humNumber);
BlinkerNumber Wind(windNumber);
BlinkerNumber Air(AirNumber);

dht11 DHT11;//定义传感器类型
#define DHT11PIN 2//定义传感器连接引脚。此处的PIN2在NodeMcu8266开发板上对应的引脚是D4
const int I2C_ADDR = 0x3c; // oled屏幕的I2c地址
#define SDA_PIN 4 // SDA引脚,默认gpio4(D2)
#define SCL_PIN 5 // SCL引脚,默认gpio5(D1)

#define BMP_SCK 16
#define BMP_MISO 14
#define BMP_MOSI 13
#define BMP_CS 12 //气压传感器引脚定义

SSD1306Wire oled(I2C_ADDR, SDA_PIN, SCL_PIN);
Adafruit_BMP280 bmp(BMP_CS, BMP_MOSI, BMP_MISO, BMP_SCK);
String number[]={"0","1","2","3","4","5","6","7","8","9"};
static const uint8_t text[][32]={
0x10,0x04,0x60,0x04,0x02,0x7E,0x8C,0x01,0x00,0x40,0x00,0x7E,0xFE,0x42,0x92,0x42,0x92,0x7E,0x92,0x42,0x92,0x7E,0x92,0x42,0xFE,0x42,0x00,0x7E,0x00,0x40,0x00,0x00,/*"温",0*/
0x00,0x40,0x00,0x30,0xFC,0x8F,0x24,0x80,0x24,0x84,0x24,0x4C,0xFC,0x55,0x25,0x25,0x26,0x25,0x24,0x25,0xFC,0x55,0x24,0x4C,0x24,0x80,0x24,0x80,0x04,0x80,0x00,0x00,/*"度",1*/
0x10,0x04,0x60,0x04,0x02,0x7E,0x8C,0x01,0x00,0x44,0xFE,0x48,0x92,0x50,0x92,0x7F,0x92,0x40,0x92,0x40,0x92,0x7F,0x92,0x50,0xFE,0x48,0x00,0x44,0x00,0x40,0x00,0x00,/*"湿",2*/
0x00,0x40,0x00,0x30,0xFC,0x8F,0x24,0x80,0x24,0x84,0x24,0x4C,0xFC,0x55,0x25,0x25,0x26,0x25,0x24,0x25,0xFC,0x55,0x24,0x4C,0x24,0x80,0x24,0x80,0x04,0x80,0x00,0x00,/*"度",3*/
0x00,0x80,0x00,0x60,0xFE,0x1F,0x02,0x00,0x12,0x20,0x22,0x10,0xC2,0x0C,0x02,0x03,0xC2,0x0C,0x32,0x30,0x02,0x00,0xFE,0x0F,0x00,0x30,0x00,0x40,0x00,0xF8,0x00,0x00,/*"风",4*/
0x40,0x00,0x40,0x40,0x42,0x20,0xCC,0x1F,0x00,0x20,0x04,0x48,0xF4,0x44,0x94,0x42,0x94,0x41,0xFF,0x5F,0x94,0x41,0x94,0x42,0xF4,0x44,0x04,0x48,0x00,0x40,0x00,0x00,/*"速",5*/
0x20,0x00,0x10,0x00,0x4C,0x00,0x47,0x00,0x54,0x00,0x54,0x00,0x54,0x00,0x54,0x00,0x54,0x00,0x54,0x00,0x54,0x00,0xD4,0x0F,0x04,0x30,0x04,0x40,0x00,0xF0,0x00,0x00,/*"气",6*/
0x00,0x80,0x00,0x60,0xFE,0x1F,0x02,0x40,0x82,0x40,0x82,0x40,0x82,0x40,0x82,0x40,0xFA,0x7F,0x82,0x40,0x82,0x40,0x82,0x44,0x82,0x58,0x82,0x40,0x02,0x40,0x00,0x00,/*"压",7*/
};

float wind=0.0;
float wind_value=0.0;

void setup()
{
Serial.begin(9600);//设置波特率为115200

Blinker.begin(auth, ssid, pswd);

oled.init(); //初始化
oled.flipScreenVertically(); // 设置屏幕翻转
oled.setContrast(255); // 设置屏幕亮度
drawRect(); // 测试屏幕显示
oled.clear(); oled.display(); // 清除屏幕

}

/********************###主函数###********************/
void loop()
{
Blinker.run();
bmp.begin();
Serial.println("\n");
DHT11.read(DHT11PIN); //更新传感器所有信息
delay(500);//每0.5秒打印一次

int sensorValue = analogRead(A0);
float wind = sensorValue * (5.0 / 1024.0);
wind_value=100*wind-4.39;

oled.setFont(ArialMT_Plain_16); // 设置字体
oled.clear();
oled.drawFastImage(4 + 16*0, 0, 16, 16, text[0]);
oled.drawFastImage(4 + 16*1, 0, 16, 16, text[1]);
oled.drawFastImage(18 + 16*3, 0, 16, 16, text[2]);
oled.drawFastImage(18 + 16*4, 0, 16, 16, text[3]);
oled.drawFastImage(4 + 16*0, 19, 16, 16, text[4]);
oled.drawFastImage(4 + 16*1, 19, 16, 16, text[5]);
oled.drawFastImage(4 + 16*0, 19*2, 16, 16, text[6]);
oled.drawFastImage(4 + 16*1, 19*2, 16, 16, text[7]);
oled.drawString(4 + 16*2, 0, ":"+number[DHT11.temperature/10]+number[DHT11.temperature%10]);
oled.drawString(18 + 16*5, 0, ":"+number[DHT11.humidity/10]+number[DHT11.humidity%10]);
oled.drawString(4 + 16*2, 19, ":"+number[(int)wind_value/100]+number[(int)wind_value/10%10]+number[(int)wind_value%10]+"."+number[((int)(wind_value*100))/10%10]+number[((int)(wind_value*100))%10]+"km/h");
pressuCheck();
oled.display();

Tem.print(DHT11.temperature);
Hum.print(DHT11.humidity);
Wind.print(wind_value);

}
void drawRect(void) {
for (int16_t i=0; i<oled.getHeight()/2; i+=2) {
oled.drawRect(i, i, oled.getWidth()-2*i, oled.getHeight()-2*i);
oled.display();
delay(50);
}
}
void pressuCheck()
{
float Pressure=0.0;
int Pressure1,Pressure2,Pressure3,Pressure4,Pressure5,Pressure6,Pressure7,Pressure8;
Pressure=bmp.readPressure();

//由于气压的位数比较多,因此单独储存便于分类
Pressure1=(int)Pressure/100000;
Pressure2=(int)Pressure/10000%10;
Pressure3=(int)Pressure/1000%10;
Pressure4=(int)Pressure/100%10;
Pressure5=(int)Pressure/10%10;
Pressure6=(int)Pressure%10;
Pressure7=((int)(Pressure*100))/10%10;
Pressure8=((int)(Pressure*100))%10;
oled.drawString(4 + 16*2, 19*2, ":"+number[Pressure1]+number[Pressure2]+number[Pressure3]+number[Pressure4]+number[Pressure5]+number[Pressure6]+"."+number[Pressure7]+number[Pressure8]+"P");

Air.print(Pressure);
}

注意事项:

  • 代码中的中文汉字用到了一个叫 image.pngPCtoLCD2002 的软件,这个软件可以很方便的将汉字转化成对应的字形码来输出,这里用的是16*16的字宽字长。
  • 在文章末尾的名叫pressuCheck()的子函数,之所以把这段单独写出来而不是写在loop函数里面去处理,不是因为笔者的代码习惯,而是必须这样不可。因为ESP8266芯片的内存有限,笔者一开始非常畅快的在loop函数中大写特写,结果虽然编译没有问题,但是上传到单片机上的时候,设备一直死机重启,害的笔者一开始还以为焊接的时候动到单片机的Rst引脚了,最后才反应过来是内存溢出的问题,把全局变量改为了局部变量之后,内存溢出问题得以解决。
  • 老生常谈,NodeMCU只支持3.3V电压,过高的电压可能会损坏芯片。
  • 连接手机的app使用的是电灯科技的接口,一方面租用服务器很贵,对于这种学习性质的设计来说有些划不来,另一方面则是考虑到开发时间的问题,如果转向Android开发则会使得开发的重心偏移,关于Android我有计划在以后的博客中编写
  • 最后,esp8266这块芯片真的很好用,使用Arduino的库真的省去了大量的重复造轮子的时间,如果转而用51
    系列单片机开发代码量起码是这个的五倍。不过如果是用来学习嵌入式,我想51还是更好的选择,因为他更能让人深刻的理解嵌入开发。

五、实物图

实物图1.jpg
实物图2.jpg
实物图3.jpg

六、结束

这次的设计总的来说是数据的采集和发送,逻辑上并不困难,学习各个传感器的引脚定义可能花费了一点时间,但也并不属于很复杂的项目,今后有机会想做一些更有挑战性的东西。