前言

我是一个写代码的程序员,这几个月接触了一下物联网,这几天做了一个esp8266配合土壤湿度传感器的玩意,写个帖子来记录一番。

成品

硬件清单:

  • NodeMCU (esp8266 wifi 模块)

  • 土壤湿度传感器

  • DHT11 温湿度传感器

  • OLED液晶屏

    NodeMCU
    土壤湿度传感器
    DHT11 温湿度传感器
    OLED液晶屏

    这些在某宝都可以买到,总的下来也就30块左右吧。剩下的杜邦线,面包板这些就不说了,玩这个都需要的。
    这里说一下NodeMCU就是基于esp8266进行的二次封装,集成了硬件、软件,也就是不需要自己刷固件了。推荐小白进行开发 ESP8266与NodeMCU的区别和开发方式

软件清单:

  • arduino IDE

Arduino IDE安装esp8266 SDK

正式流程

nodeMcu 连接显示屏

这里直接把最难的一步放到最前面。因为我将我这块屏连上nodeMcu就花了好几天。

我这块屏是1.8寸的OLED液晶屏,采用ST7735S驱动。

一开始我用淘宝卖家提供的库进行连接,十分不好用,文档都是英文的,网上百度也没有教程。于是我找到了网上用的最多的一个TFT库:TFT_eSPI,这个库兼容许多驱动,下面就用这个库进行操作。GitHub:TFT_eSPI

下载TFT_eSPI库

首先去GitHub上下载TFT_eSPI,放到Arduino IDE的libraries文件夹下,一般在文档\Arduino\libraries

编辑用户需要的驱动

这一步非常重要,来到TFT_eSPI文件加下找到User_Setup.h这个文件,打开编辑。

选择自己显示屏的驱动

找到你的显示屏驱动,然后取消注释。我这里用的ST7735S,但是只有ST7735,就将就着用了,目前没发现问题。

屏幕分辨率

找到屏幕所适合的分辨率,WIDTH宽,HIGHT高。取消注释

接线

接线这一步也是非常的重要,困扰了我好几天。因为我的显示屏引脚和网上的不太一样,实验了很久。

按照上面的内容,将NodeMCU和显示屏进行连接。

这边说一下,有的小伙伴买到的显示屏或许没有SDI/MOSI,其实对应的就是SDA,名字不一样而已。还有SDO/MISO对应SCL,RESET也就是RST。有的还有一个BL,可以不用连。

接下来进TFT_eSPI\examples文件夹,根据分辨率在前三个文件夹进行选择,找到里面的TFT_Rainbow测试案例,进行刷入,测试显示屏是否连接成功。

注:当显示屏和nodemcu连接上并通电时,应该是白色的,说明正负极接对了。

测试程序显示完全后,搁置一旁,进行下面的操作。

连接DHT11温湿度传感器

加载DHT驱动库

  • 在arduino中的工具-管理库中搜索DHT

  • 找到DHT sensor library,选择安装即可。

在传感器上,有三个脚,分别是+、out、-,分别是正极、输入、负极,正负极随便连接nodemcu上的GND和3V3即可,out我这边连接的是D2。

代码

所需的代码(这里只是介绍代码功能,完整代码见末尾):

#include "DHT.h"  

#define DHTPIN 8
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

void setup() {
Serial.begin(9600);
dht.begin();
}

void loop() {
delay(2000);
float h = dht.readHumidity(); // 获取湿度
float t = dht.readTemperature(); // 获取温度
Serial.print("Humidity: ");
Serial.println(h);
Serial.print("Temperature: ");
Serial.print(t);
Serial.println(" ℃ ");
}

打开串口监视器

串口输出

连接土壤湿度传感器

土壤湿度传感器有两种,黑色的是四线制的(4个引脚),有数字信号和模拟信号两种输出;红色款是三线制,只有模拟信号。我用的是四线制的。

中间小的叫比较器

先将土壤湿度传感器和比较器相连,正负相连。如上图。

然后比较器的GND和VCC分别连接nodemcu的GND和vcc(3v3),AO连nodemcu上的A0,DO因为用不到,所以不连。

下面的是测试程序:

#define AO  A0  // 数字信号 连 A0 
#define DO 16 // 模拟信号 连 D0

void setup()
{
pinMode(AO, INPUT);
pinMode(DO, INPUT);
Serial.begin(9600);
}

void loop()
{
Serial.print("AO=");
Serial.print(analogRead(A0)); // 获取数字信号
Serial.print("|DO=");
Serial.println(digitalRead(DO)); // 获取模拟信号
delay(1000);
}

将信息显示在屏幕上

如果你的DHT传感器和土壤湿度传感器的测试程序都通过的话,就可以进行下面的操作了。

这里介绍几个屏幕操作代码:

// 初始化彩屏
tft.init();
//设置屏幕颜色为黑色
tft.fillScreen(TFT_BLACK);
// 设置屏幕旋转 180 度
tft.setRotation(2);
// 设置 4 号字体
tft.setTextFont(4);
//设置文本颜色为绿色
tft.setTextColor(TFT_GREEN);
//设置文字起始位置(从左上角开始为0,0)
tft.setCursor(x, y);
//在屏幕上打印文本
tft.print("输出文本");

文字取模

因为屏幕不支持汉字,所以要想显示汉字,必须像画图一下在屏幕上一笔一笔的显示出啦。所以需要对汉字进行取模。

这里用到的取模工具:字模提取V2.2

使用方法:
  1. 在文字输入区输入汉字

  2. 输入完成后按ctrl+enter

  3. 左边点击取模方式

  4. 选择C51格式

  5. 在点阵生成区显示对应的十六进制数

  6. 每个汉字对应两行十六进制,复制保存。

    //这边解释一下这行代码:

    //在屏幕上打印一个汉字。
    tft.drawBitmap(x, y, 汉字变量名, 汉字的长, 汉字的宽, 汉字的颜色);

    准备好后,附上我完整的代码:

#include <SPI.h>
#include <DHT.h>
#include <TFT_eSPI.h>

TFT_eSPI tft = TFT_eSPI();
#define AO A0 //定义A0为土壤湿度传感器AO脚
#define DO 16 // DO没有用到,可以不写

#define DHTPIN 4 //D2 对应DHT的out脚
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

//下面的是汉字取模的定义变量,一个汉字一个变量。
//土
static const unsigned char PROGMEM str_1[] =
{
0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x3F,0xF8,0x01,0x00,
0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xFF,0xFE,0x00,0x00
};
//壤
static const unsigned char PROGMEM str_2[] =
{
0x20,0x40,0x27,0xFC,0x20,0x00,0x23,0xB8,0xF2,0xA8,0x23,0xB8,0x21,0x10,0x27,0xFC,
0x21,0x10,0x27,0xFC,0x31,0x10,0xEF,0xFE,0x41,0x28,0x03,0x10,0x0D,0x48,0x01,0x86
};
//湿
static const unsigned char PROGMEM str_3[] =
{
0x00,0x00,0x27,0xF8,0x14,0x08,0x14,0x08,0x87,0xF8,0x44,0x08,0x44,0x08,0x17,0xF8,
0x11,0x20,0x21,0x20,0xE9,0x24,0x25,0x28,0x23,0x30,0x21,0x20,0x2F,0xFE,0x00,0x00
};
//度
static const unsigned char PROGMEM str_4[] =
{
0x01,0x00,0x00,0x80,0x3F,0xFE,0x22,0x20,0x22,0x20,0x3F,0xFC,0x22,0x20,0x22,0x20,
0x23,0xE0,0x20,0x00,0x2F,0xF0,0x24,0x10,0x42,0x20,0x41,0xC0,0x86,0x30,0x38,0x0E
};
//室
static const unsigned char PROGMEM str_5[] =
{
0x02,0x00,0x01,0x00,0x7F,0xFE,0x40,0x02,0x80,0x04,0x3F,0xF8,0x04,0x00,0x08,0x20,
0x1F,0xF0,0x01,0x10,0x01,0x00,0x3F,0xF8,0x01,0x00,0x01,0x00,0xFF,0xFE,0x00,0x00
};
//内
static const unsigned char PROGMEM str_6[] =
{
0x01,0x00,0x01,0x00,0x01,0x00,0x7F,0xFC,0x41,0x04,0x41,0x04,0x41,0x04,0x42,0x84,
0x42,0x44,0x44,0x24,0x48,0x14,0x50,0x14,0x40,0x04,0x40,0x04,0x40,0x14,0x40,0x08
};
//温
static const unsigned char PROGMEM str_7[] =
{
0x00,0x00,0x23,0xF8,0x12,0x08,0x12,0x08,0x83,0xF8,0x42,0x08,0x42,0x08,0x13,0xF8,
0x10,0x00,0x27,0xFC,0xE4,0xA4,0x24,0xA4,0x24,0xA4,0x24,0xA4,0x2F,0xFE,0x00,0x00
};
//:
static const unsigned char PROGMEM str_8[] =
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00
};
//℃
static const unsigned char PROGMEM str_9[] =
{
0x60,0x00,0x91,0xF4,0x96,0x0C,0x6C,0x04,0x08,0x04,0x18,0x00,0x18,0x00,0x18,0x00,
0x18,0x00,0x18,0x00,0x18,0x00,0x08,0x00,0x0C,0x04,0x06,0x08,0x01,0xF0,0x00,0x00
};

void setup(void) {
dht.begin();
pinMode(AO, INPUT);
pinMode(DO, INPUT);
Serial.begin(115200);
// 初始化彩屏
tft.init();
tft.fillScreen(TFT_BLACK);
// 设置屏幕旋转 180 度 屏幕旋转是因为我的屏幕是立着的。根据自己需要。1是90度
tft.setRotation(2);
// 设置 4 号字体,绿色文本颜色
tft.setTextFont(4);
tft.setTextColor(TFT_GREEN);
}

void loop() {
//模拟信号
double value = analogRead(AO);
value = 100-(value / 1024 *100);//模拟信号在湿度为0时是1024,随湿度增加数字降低。这边进行转换成正向的百分比。

//获取DHT的空气湿度和温度
float h = dht.readHumidity();
float t = dht.readTemperature();

//设置文字颜色的绿色
tft.setTextColor(TFT_GREEN);
//设置屏幕颜色为黑色
tft.fillScreen(TFT_BLACK);
tft.drawBitmap(0, 0, str_1, 16, 16, TFT_GREEN);//土
tft.drawBitmap(20, 0, str_2, 16, 16, TFT_GREEN);//壤
tft.drawBitmap(40, 0, str_3, 16, 16, TFT_GREEN);//湿
tft.drawBitmap(60, 0, str_4, 16, 16, TFT_GREEN);//度
tft.drawBitmap(80, 0, str_8, 16, 16, TFT_GREEN);//:
//输出土壤湿度的值
tft.setCursor(0, 20);
tft.print(value);
tft.println("%");

tft.setTextColor(TFT_RED);
//室内湿度: 的五个汉字
tft.drawBitmap(0, 50, str_5, 16, 16, TFT_RED);
tft.drawBitmap(20, 50, str_6, 16, 16, TFT_RED);
tft.drawBitmap(40, 50, str_3, 16, 16, TFT_RED);
tft.drawBitmap(60, 50, str_4, 16, 16, TFT_RED);
tft.drawBitmap(80, 50, str_8, 16, 16, TFT_RED);

tft.setCursor(0, 70);
tft.print(h);
tft.println("%");

tft.setTextColor(TFT_YELLOW);
//室内温度
tft.drawBitmap(0, 100, str_5, 16, 16, TFT_YELLOW);
tft.drawBitmap(20, 100, str_6, 16, 16, TFT_YELLOW);
tft.drawBitmap(40, 100, str_7, 16, 16, TFT_YELLOW);
tft.drawBitmap(60, 100, str_4, 16, 16, TFT_YELLOW);
tft.drawBitmap(80, 100, str_8, 16, 16, TFT_YELLOW);

tft.setCursor(0, 120);
tft.print(t);
tft.drawBitmap(70, 124, str_9, 16, 16, TFT_YELLOW);

//延迟1秒刷新数据
delay(1000);
}