4.4.8 农场温湿控系统#

4.4.8.1 简介#

本教程介绍如何使用温湿度传感器、风扇模块、智能语音模块和LCD1602模块,构建一个智能温湿度控制系统。

该系统的温湿度传感器能够测量环境温度和湿度,并根据需求控制风扇降温。当温度超过设定阈值时,系统会自动开启风扇,将环境温度降至设定值以下。系统的 LCD1602 显示屏显示当前温度和湿度值。同时,我们对着智能语音模块发出类似的“当前温度是多少”和“当前湿度是多少”等命令词,智能语音模块接收到相应命令词后语音播报当前温度和当前湿度的百分数值。该系统能够实现自动调节环境温湿度的功能,对于需要控制环境温湿度的项目具有很好的应用价值。

Img

这个应用场景需要通过单线通信来获取XHT11温湿度传感器的数据,并将温度和湿度数值显示在LCD1602显示屏上。还能语音播报检测到的当前温度和当前湿度,同时,当温度或湿度超过设定的阈值时,风扇模块会开启,用来降低温度以保护农场里的动植物。这种模块的优点是安装容易,且功能强大。它不仅可以通过PWM调节速度,还能够通过单线通信来传输数据。总的来说,这个应用场景是一个非常实用的解决方案,可以帮助农场主人监测和控制农场的环境,提高农业生产效率。

4.4.8.2 接线图#

  • XHT11温湿度传感器的S引脚连接到io17

  • 电机模块的IN-连接到io18,IN+连接到io19

  • 智能语音模块的TXD引脚连接到io5,RXD引脚连接到io23

  • LCD1602模块连接到 BUS I2C(SDA连接(SDA:IO21)、SCL连接(SCL:IO22)

⚠️ 特别注意:智慧农场已经组装好了,这里不需要把XHT11温湿度传感器、电机模块、LCD1602模块和智能语音模块拆下来又重新组装和接线,这里再次提供接线图,是为了方便您编写代码!

Img

4.4.8.3 代码流程图#

Img

4.4.8.4 实验代码#

代码文件在Arduino_代码文件夹中,代码文件为4_4_8_Tem-Hum-Control-System,如下图所示:

Img

鼠标双击4_4_8_Tem-Hum-Control-System.ino即可在Arduino IDE中打开。

⚠️ 注意:代码中的条件阈值可以根据实际情况自行设置。

/*
 * 文件名 : Temperature-Humidity-Control-System
 * 功能   : 结合XHT11温湿度传感器,语音控制模块和电机模块模拟农场温湿控风扇系统
 * 编译IDE:ARDUINO 2.3.6
 * 作者   : https://www.keyesrobot.cn/
*/

//导入相关库文件
#include <SoftwareSerial.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <dht11.h>

// 定义引脚常量
const int RX_PIN = 23; // 引脚 GPIO23 为 RX
const int TX_PIN = 5; // 引脚 GPIO5 为 TX
const int DHT11PIN = 17; // 温湿度传感器的引脚
const int MotorPin1 = 19; // (IN+)
const int MotorPin2 = 18; // (IN-)

// 定义变量
volatile int yuyin;
volatile int Temperature;
volatile int Humidity;

LiquidCrystal_I2C lcd(0x27,16,2); // 定义LCD地址和行列

SoftwareSerial mySerial(RX_PIN, TX_PIN); // 定义软件串口引脚(RX, TX)

dht11 DHT11; // 初始化dht11

// 串口发送消息最大长度
#define UART_SEND_MAX      32
#define UART_MSG_HEAD_LEN  2
#define UART_MSG_FOOT_LEN  2

// 串口发送消息号
#define U_MSG_bozhensgshu      1
#define U_MSG_boxiaoshu      2
#define U_MSG_bobao1      3
#define U_MSG_bobao2      4
#define U_MSG_bobao3      5
#define U_MSG_bobao4      6
#define U_MSG_bobao5      7
#define U_MSG_bobao6      8
#define U_MSG_bobao7      9
#define U_MSG_bobao8      10
#define U_MSG_bobao9      11
#define U_MSG_bobao10      12
#define U_MSG_bobao11      13
#define U_MSG_bobao12      14
#define U_MSG_bobao13      15
#define U_MSG_bobao14      16
#define U_MSG_bobao15      17
#define U_MSG_bobao16      18
#define U_MSG_bobao17      19
#define U_MSG_bobao18      20

// 串口消息参数类型
typedef union {
  double d_double;
  int d_int;
  unsigned char d_ucs[8];
  char d_char;
  unsigned char d_uchar;
  unsigned long d_long;
  short d_short;
  float d_float;}uart_param_t;

// 串口发送函数实现
void _uart_send_impl(unsigned char* buff, int len) {
  // TODO: 调用项目实际的串口发送函数
  for(int i=0;i<len;i++){
    mySerial.write (*buff++);
  }
}

// 串口通信消息尾
const unsigned char g_uart_send_foot[] = {
  0x55, 0xaa
};

// 十六位整数转32位整数
void _int16_to_int32(uart_param_t* param) {
  if (sizeof(int) >= 4)
    return;
  unsigned long value = param->d_long;
  unsigned long sign = (value >> 15) & 1;
  unsigned long v = value;
  if (sign)
    v = 0xFFFF0000 | value;
  uart_param_t p;  p.d_long = v;
  param->d_ucs[0] = p.d_ucs[0];
  param->d_ucs[1] = p.d_ucs[1];
  param->d_ucs[2] = p.d_ucs[2];
  param->d_ucs[3] = p.d_ucs[3];
}

// 浮点数转双精度
void _float_to_double(uart_param_t* param) {
  if (sizeof(int) >= 4)
    return;
  unsigned long value = param->d_long;
  unsigned long sign = value >> 31;
  unsigned long M = value & 0x007FFFFF;
  unsigned long e =  ((value >> 23 ) & 0xFF) - 127 + 1023;
  uart_param_t p0, p1;
  p1.d_long = ((sign & 1) << 31) | ((e & 0x7FF) << 20) | (M >> 3);
  param->d_ucs[0] = p0.d_ucs[0];
  param->d_ucs[1] = p0.d_ucs[1];
  param->d_ucs[2] = p0.d_ucs[2];
  param->d_ucs[3] = p0.d_ucs[3];
  param->d_ucs[4] = p1.d_ucs[0];
  param->d_ucs[5] = p1.d_ucs[1];
  param->d_ucs[6] = p1.d_ucs[2];
  param->d_ucs[7] = p1.d_ucs[3];
}

// 串口通信消息头
const unsigned char g_uart_send_head[] = {
  0xaa, 0x55
};

// 播报函数1
void _uart_bobao1() {
  uart_param_t param;
    int i = 0;
    unsigned char buff[UART_SEND_MAX] = {0};
    for (i = 0; i < UART_MSG_HEAD_LEN; i++) {
        buff[i + 0] = g_uart_send_head[i];
    }
    buff[2] = U_MSG_bobao1;
    for (i = 0; i < UART_MSG_FOOT_LEN; i++) {
        buff[i + 3] = g_uart_send_foot[i];
    }
    _uart_send_impl(buff, 5);
}

// 播报整数
void _uart_bozhensgshu(int zhengshu) {
  uart_param_t param;
    int i = 0;
    unsigned char buff[UART_SEND_MAX] = {0};
    for (i = 0; i < UART_MSG_HEAD_LEN; i++) {
        buff[i + 0] = g_uart_send_head[i];
    }
    buff[2] = U_MSG_bozhensgshu;
    param.d_int = zhengshu;
    _int16_to_int32(&param);
    buff[3] = param.d_ucs[0];
    buff[4] = param.d_ucs[1];
    buff[5] = 0;
    buff[6] = 0;
    for (i = 0; i < UART_MSG_FOOT_LEN; i++) {
        buff[i + 7] = g_uart_send_foot[i];
    }
    _uart_send_impl(buff, 9);
}

// 播报函数2
void _uart_bobao2() {
  uart_param_t param;
    int i = 0;
    unsigned char buff[UART_SEND_MAX] = {0};
    for (i = 0; i < UART_MSG_HEAD_LEN; i++) {
        buff[i + 0] = g_uart_send_head[i];
    }
    buff[2] = U_MSG_bobao2;
    for (i = 0; i < UART_MSG_FOOT_LEN; i++) {
        buff[i + 3] = g_uart_send_foot[i];
    }
    _uart_send_impl(buff, 5);
}

// 播报函数4
void _uart_bobao4() {
  uart_param_t param;
    int i = 0;
    unsigned char buff[UART_SEND_MAX] = {0};
    for (i = 0; i < UART_MSG_HEAD_LEN; i++) {
        buff[i + 0] = g_uart_send_head[i];
    }
    buff[2] = U_MSG_bobao4;
    for (i = 0; i < UART_MSG_FOOT_LEN; i++) {
        buff[i + 3] = g_uart_send_foot[i];
    }
    _uart_send_impl(buff, 5);
}

void setup(){
   mySerial.begin(9600); // 软件串口(与外设通信)
   Serial.begin(9600); // 硬件串口(与电脑通信)
   pinMode(MotorPin1,OUTPUT); // 设置IN+引脚为输出模式
   pinMode(MotorPin2,OUTPUT); // 设置IN-引脚为输出模式
   yuyin = 0; // 定义变量yuyin初始值为0
   Temperature = 0; // 定义变量Temperature初始值为0
   Humidity = 0; // 定义变量Humidity初始值为0
   Wire.begin(21,22); // 打开LCD通信引脚
   lcd.init(); // 初始化LCD
   lcd.backlight(); // 打开LCD背光
   lcd.display(); // 打开LCD显示
   lcd.clear(); // LCD清屏
}

void loop(){
   //获取温湿度数据
   int chk = DHT11.read(DHT11PIN); 
   Temperature = DHT11.temperature;
   Humidity = DHT11.humidity;
   // 在LCD对应位置显示温度相关信息
   lcd.setCursor(0, 0);
   lcd.print(String("Temp(C):") + String(Temperature));
   // 在LCD对应位置显示湿度相关信息
   lcd.setCursor(0, 1);
   lcd.print(String("Hum(%RH):") + String(Humidity));

   if (mySerial.available() > 0) { // 接收语音控制模块的外设数据(命令参数)
     yuyin = mySerial.read(); // 将接收到的外设数据(命令参数)进行赋值 
     Serial.println(yuyin); // 串口打印收到的外设数据(命令参数) 
     if (yuyin == 47) { // 进行判断,接收到的外设数据(命令参数)为47,检测温度并且进行语音播报
        yuyin = 0;
        delay(2000);
        _uart_bobao1();
        delay(2000);
        _uart_bozhensgshu(Temperature);
        delay(2000);
        _uart_bobao2();
        delay(2000);
     }
     if (yuyin == 48) { // 进行判断,接收到的外设数据(命令参数)为48,检测湿度并且进行语音播报
        yuyin = 0;
        delay(2000);
        _uart_bobao4();
        delay(2000);
        _uart_bozhensgshu(Humidity);
        delay(2000);
     }
   }
   if (Temperature >= 28 || Humidity > 70) { // 进行判断,温度大于等于48或湿度大于70
     //风扇转动
     analogWrite(MotorPin1, 70);
     analogWrite(MotorPin2, 0);
   } else { // 否则,风扇停止 
     delay(3000);
     analogWrite(MotorPin1, 0);
     analogWrite(MotorPin2, 0);
     delay(200);
   }
   delay(500);
   lcd.clear(); // 清除LCD显示
}

4.4.8.5 实验结果#

按照接线图接好线,外接电源,选择好正确的开发板板型(ESP32 Dev Module)和 适当的串口端口(COMxx),然后单击按钮Img上传代码。上传代码成功后,LCD1602显示屏实时显示XHT11传感器检测到环境中的湿度值和温度值。当空气温度大于等于28℃或空气湿度大于70%RH时,风扇模块会开启,进行散热降湿,当空气温度小于28℃且空气湿度小于等于70%RH时,风扇模块会关闭(风扇为模拟散热,散热效果一般),达到农场自动控温控湿效果,节省能源。

对着智能语音模块上的麦克风,使用唤醒词 “你好,小智” 或 “小智小智” 来唤醒智能语音模块,同时喇叭播放回复语 “有什么可以帮到您”。

智能语音模块唤醒后,对着麦克风说:“当前温度是多少” 或 “当前温度多少” 等命令词时,接着语音播报 “正在为您读取温度” + “当前温度为” + “XHT11温湿度传感器检测到的温度值” + “度”。

对着麦克风说:“当前湿度是多少” 或 “当前湿度多少” 等命令词时,接着语音播报 “正在为您读取湿度” + “当前湿度为百分之” + “XHT11温湿度传感器检测到的湿度值”。

Img