arduino使用ESP8266和DHT11显示温湿度值

完整代码,最好修改下SERIAL_RX_BUFFER_SIZE 的大小为512。

#include 

#define DHT11_PIN (5)      //SCL引脚内部和ANALOG5相连,实际是PC5端口
byte dht11_dat[5];         //存储dht11的5字节数据

SoftwareSerial mySerial = SoftwareSerial(11, 12);

char ok[] = "OK";
char ipd[] = "+IPD,";
char rdy[] = "ready";
char GET[] = "GET /";
char SEND[] = ">";

int headlength;
char Header[]  = "HTTP/1.1 200 OK\r\n\
Server: nginx/1.10.3 (Ubuntu)\r\n\
Date: Wed, 08 Apr 2020 09:29:22 GMT\r\n\
Content-Type: text/plain\r\n\
Content-Length: 42\r\n\
Connection: keep-alive\r\n\
Last-Modified: Tue, 18 Sep 2018 03:55:48 GMT\r\n\
Accept-Ranges: bytes\r\n\
\r\n";

void setup()
{
  DDRC |= _BV(DHT11_PIN);   //Data Direction Register(数据方向寄存器)
  PORTC |= _BV(DHT11_PIN);  //数据寄存器


  mySerial.begin(9600);
  mySerial.println(F("start"));

  Serial.begin(115200);
  Serial.print(F("AT+RST\r\n"));
  if (waitForStr(rdy, 5000) == true)
    mySerial.println(F("ready ok"));

  Serial.println(F("ATE0"));           //disable echo
  if (waitForStr(ok, 1000) == true)
    mySerial.println(F("ATE0 ok"));

  Serial.println(F("AT+CWMODE=2"));    //station, AP is 3
  if (waitForStr(ok, 1000) == true)
    mySerial.println(F("AT+CWMODE=2 ok"));

  Serial.println(F("AT+CIPMUX=1"));
  if (waitForStr(ok, 1000) == true)
    mySerial.println(F("AT+CIPMUX=1 ok"));

  Serial.println(F("AT+CIPSERVER=1,8080"));
  if (waitForStr(ok, 1000) == true)
    mySerial.println(F("AT+CIPSERVER=1,8080 ok"));

  headlength = getStrLength(Header);
  byte ret = read_dht11();
  if (ret != 0)
  {
    mySerial.println("dht11 error!");
    return ;
  }
}

void loop()
{
  static char mux;                          //记录连接的通道号
  if (waitForStr(ipd, 1000) == true)        //有新的连接接入
  {
    mux = Serial.read();                    //ipd字符串下一个字节就是连接通道号
    if (waitForStr(GET, 1000) == true)      //有新的GET请求
    {
      //组建Body
      char Body[64];
      int bodylength = 0;
      sprintf(Body, "Current humdity = %2d.%1d%%\r\ntemperature=%2d.%1dC", dht11_dat[0], dht11_dat[1], dht11_dat[2], dht11_dat[3]);
      bodylength = getStrLength(Body);
      //调试串口打印 组建的数据的内容及长度
      //Header中的Content-Length必须设置成和这里的bodylength一样,否则浏览器不能正确解析,导致解析失败
      mySerial.println(Body);
      mySerial.print(F("Body length:"));
      mySerial.println(bodylength);
      //AT+CIPSEND=x,y 进入透传模式进行回复,x为通道号,y为要返回的数据长度
      Serial.print(F("AT+CIPSEND="));
      Serial.print(mux);
      Serial.print(",");
      Serial.println(headlength + bodylength);

      if (waitForStr(SEND, 1000) == true)   //出现'>'符号开始发送,发送头和体
      {
        Serial.print(Header);
        Serial.println(Body);
        if (waitForStr(ok, 10000) != true)    mySerial.println(F("send timeout"));

        //强制断开该连接
        Serial.print(F("AT+CIPCLOSE="));
        Serial.println(mux);
        if (waitForStr(ok, 1000) != true)     mySerial.println(F("close failed"));
      }
      else                                    mySerial.println(F("no >"));
    }
    else                                      mySerial.println(F("no GET"));
    return ;                                //为了保证WIFI模块的响应速度,响应成功后立即退出,重新进入loop进行下次响应,没有响应时才开始读传感器数据
  }
  else                                        mySerial.println(F("no connect"));

  delay(1000);                              //最快1s读一次传感器的数据
  byte ret = read_dht11();
  if (ret != 0)
  {
    mySerial.println("dht11 error!");
    return ;
  }
}






/*---------------------------------------------------------------------------------------------------------------*/

//获取数据长度函数
int getStrLength(char* str) {
  int i = 0;
  while (str[i] != '\0') {
    i++;
  }
  return i;
}

//从串口中等待字符串str,超时时间为timeout ms
bool waitForStr(char* str, long timeout) {
  long intime = millis();
  int i = 0, j = 0, cur = 0, index = 0;
  int len = getStrLength(str);
  bool ret = true;
  char* temp = new char(len);
  while (str[i] != '\0') {
    while (j - cur < len) {
      if (timeout > 0)
        if (millis() - intime > timeout) {
          ret = false;
          goto OUT;
        }
      if (Serial.available()) {
        index = j % len;
        temp[index] = Serial.read();
        j++;
      }
    }
    index = (cur + i) % len;
    if (str[i] == temp[index])
      i++;
    else
      i = 0, cur++;
  }
OUT:
  delete temp;
  return ret;
}



/*---------------------------------------------------------------------------------------------------------------*/

/*
  从DHT11中读取一个byte的数据
*/
byte read_dht11_dat()
{
  byte i = 0;
  byte result = 0;
  for (i = 0; i < 8; i++) {

    while (!(PINC & _BV(DHT11_PIN))); // wait for 50us          //#define _BV(bit) (1 << (bit))
    delayMicroseconds(30);

    if (PINC & _BV(DHT11_PIN))
      result |= (1 << (7 - i));
    while ((PINC & _BV(DHT11_PIN))); // wait '1' finish
  }
  return result;
}

/*
  从DHT11中读取一次数据
*/
int read_dht11()
{
  byte dht11_in;        //存储当前端口读取的值
  byte i;
  // start condition
  // 1. pull-down i/o pin from 18ms
  PORTC &= ~_BV(DHT11_PIN); //拉低
  delay(18);
  PORTC |= _BV(DHT11_PIN);  //拉高
  delayMicroseconds(40);

  DDRC &= ~_BV(DHT11_PIN);
  delayMicroseconds(40);

  dht11_in = PINC & _BV(DHT11_PIN);

  if (dht11_in) {
    //Serial.println("dht11 start condition 1 not met");
    return 1;
  }
  delayMicroseconds(80);

  dht11_in = PINC & _BV(DHT11_PIN);

  if (!dht11_in) {
    //Serial.println("dht11 start condition 2 not met");
    return 2;
  }
  delayMicroseconds(80);
  // now ready for data reception
  for (i = 0; i < 5; i++)
    dht11_dat[i] = read_dht11_dat();

  DDRC |= _BV(DHT11_PIN);
  PORTC |= _BV(DHT11_PIN);

  byte dht11_check_sum = dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3];
  // check check_sum
  if (dht11_dat[4] != dht11_check_sum)
  {
    //Serial.println("DHT11 checksum error");
    return 3;
  }
  return 0;
}

实物连线如图,IIC接口连接的是DHT11传感器,实际信号连接的是A5接口(PC5);
软件串口连接的是D11和D12;
白色USB线只用于供电,未使用板载的USB2TTL功能,实际的硬件串口接入了ESP8266的WIFI模块;
板子上的系统供电开关拨至3V3处;


手机访问显示效果:
arduino使用ESP8266和DHT11显示温湿度值_第1张图片
软件串口看到的日志:
arduino使用ESP8266和DHT11显示温湿度值_第2张图片
注意白色USB线的串口是COM4,用于程序的下载,软件串口使用了USB2TTL模块,显示的是串口5,打开串口监视器的时候需要使用串口5才能正确的显示。
arduino使用ESP8266和DHT11显示温湿度值_第3张图片

下面是添加了oled屏幕的代码:

#include 
#include "U8glib.h"

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0); // I2C / TWI

#define DHT11_PIN (3)      //SCL引脚内部和ANALOG5相连,实际是PC5端口
byte dht11_dat[5];         //存储dht11的5字节数据

SoftwareSerial mySerial = SoftwareSerial(11, 12);


char ok[] = "OK";
char ipd[] = "+IPD,";
char rdy[] = "ready";
char GET[] = "GET /";
char SEND[] = ">";

int headlength;
char Header[] = "HTTP/1.1 200 OK\r\n\
Server: nginx/1.10.3 (Ubuntu)\r\n\
Date: Wed, 08 Apr 2020 09:29:22 GMT\r\n\
Content-Type: text/plain\r\n\
Content-Length: 42\r\n\
Connection: keep-alive\r\n\
Last-Modified: Tue, 18 Sep 2018 03:55:48 GMT\r\n\
Accept-Ranges: bytes\r\n\
\r\n";

void setup()
{
  DDRC |= _BV(DHT11_PIN);   //Data Direction Register(数据方向寄存器)
  PORTC |= _BV(DHT11_PIN);  //数据寄存器

  oled_init();

  mySerial.begin(9600);
  mySerial.println(F("start"));

  Serial.begin(115200);
  Serial.print(F("AT+RST\r\n"));
  if (waitForStr(rdy, 5000) == true)
    mySerial.println(F("ready ok"));

  Serial.println(F("ATE0"));           //disable echo
  if (waitForStr(ok, 1000) == true)
    mySerial.println(F("ATE0 ok"));

  Serial.println(F("AT+CWMODE=2"));    //station, AP is 3
  if (waitForStr(ok, 1000) == true)
    mySerial.println(F("AT+CWMODE=2 ok"));

  Serial.println(F("AT+CIPMUX=1"));
  if (waitForStr(ok, 1000) == true)
    mySerial.println(F("AT+CIPMUX=1 ok"));

  Serial.println(F("AT+CIPSERVER=1,8080"));
  if (waitForStr(ok, 1000) == true)
    mySerial.println(F("AT+CIPSERVER=1,8080 ok"));

  headlength = getStrLength(Header);
  delay(1000);                              //垃圾DHT11模块开机必须等待1s才能用
  byte ret = read_dht11();
  if (ret != 0)
  {
    mySerial.println(F("dht11 error!"));
    return ;
  }
}

void loop()
{
  oled_show();
  static char mux;                          //记录连接的通道号
  if (waitForStr(ipd, 1000) == true)        //有新的连接接入
  {
    mux = Serial.read();                    //ipd字符串下一个字节就是连接通道号
    if (waitForStr(GET, 1000) == true)      //有新的GET请求
    {
      //组建Body
      char Body[64];
      int bodylength = 0;
      sprintf(Body, "Current humdity = %2d.%1d%%\r\ntemperature=%2d.%1dC", dht11_dat[0], dht11_dat[1], dht11_dat[2], dht11_dat[3]);
      bodylength = getStrLength(Body);
      //调试串口打印 组建的数据的内容及长度
      //Header中的Content-Length必须设置成和这里的bodylength一样,否则浏览器不能正确解析,导致解析失败
      mySerial.println(Body);
      mySerial.print(F("Body length:"));
      mySerial.println(bodylength);
      //AT+CIPSEND=x,y 进入透传模式进行回复,x为通道号,y为要返回的数据长度
      Serial.print(F("AT+CIPSEND="));
      Serial.print(mux);
      Serial.print(",");
      Serial.println(headlength + bodylength);

      if (waitForStr(SEND, 1000) == true)   //出现'>'符号开始发送,发送头和体
      {
        Serial.print(Header);
        Serial.println(Body);
        if (waitForStr(ok, 10000) != true)    mySerial.println(F("send timeout"));

        //强制断开该连接
        Serial.print(F("AT+CIPCLOSE="));
        Serial.println(mux);
        if (waitForStr(ok, 1000) != true)     mySerial.println(F("close failed"));
      }
      else                                    mySerial.println(F("no >"));
    }
    else                                      mySerial.println(F("no GET"));
    return ;                                //为了保证WIFI模块的响应速度,响应成功后立即退出,重新进入loop进行下次响应,没有响应时才开始读传感器数据
  }
  else                                        mySerial.println(F("no connect"));

  delay(1000);                              //最快1s读一次传感器的数据
  byte ret = read_dht11();
  if (ret != 0)
  {
    mySerial.println("dht11 error!");
    return ;
  }
}

/*---------------------------------------------------------------------------------------------------------------*/
void oled_init(void) {
  // flip screen, if required
  // u8g.setRot180();

  // set SPI backup if required
  //u8g.setHardwareBackup(u8g_backup_avr_spi);

  // assign default color value
  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
    u8g.setColorIndex(255);     // white
  }
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
    u8g.setColorIndex(3);         // max intensity
  }
  else if ( u8g.getMode() == U8G_MODE_BW ) {
    u8g.setColorIndex(1);         // pixel on
  }
  else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255, 255, 255);
  }
}

void oled_show()
{
  u8g.firstPage();
  do {
    draw();
  } while ( u8g.nextPage() );
}

void draw(void) {
  // graphic commands to redraw the complete screen should be placed here
  u8g.setFont(u8g_font_unifont);
  char ss[16];
  sprintf(ss, "humi = %2d.%1d%%", dht11_dat[0], dht11_dat[1]);
  u8g.drawStr( 0, 12, ss);
  sprintf(ss, "temp = %2d.%1dC", dht11_dat[2], dht11_dat[3]);
  u8g.drawStr(0, 23, ss);
}


/*---------------------------------------------------------------------------------------------------------------*/

//获取数据长度函数
int getStrLength(char* str) {
  int i = 0;
  while (str[i] != '\0') {
    i++;
  }
  return i;
}

//从串口中等待字符串str,超时时间为timeout ms
bool waitForStr(char* str, long timeout) {
  long intime = millis();
  int i = 0, j = 0, cur = 0, index = 0;
  int len = getStrLength(str);
  bool ret = true;
  char* temp = new char(len);
  while (str[i] != '\0') {
    while (j - cur < len) {
      if (timeout > 0)
        if (millis() - intime > timeout) {
          ret = false;
          goto OUT;
        }
      if (Serial.available()) {
        index = j % len;
        temp[index] = Serial.read();
        j++;
      }
    }
    index = (cur + i) % len;
    if (str[i] == temp[index])
      i++;
    else
      i = 0, cur++;
  }
OUT:
  delete temp;
  return ret;
}



/*---------------------------------------------------------------------------------------------------------------*/

/*
  从DHT11中读取一个byte的数据
*/
byte read_dht11_dat()
{
  byte i = 0;
  byte result = 0;
  for (i = 0; i < 8; i++) {

    while (!(PINC & _BV(DHT11_PIN))); // wait for 50us          //#define _BV(bit) (1 << (bit))
    delayMicroseconds(30);

    if (PINC & _BV(DHT11_PIN))
      result |= (1 << (7 - i));
    while ((PINC & _BV(DHT11_PIN))); // wait '1' finish
  }
  return result;
}

/*
  从DHT11中读取一次数据
*/
int read_dht11()
{
  byte dht11_in;        //存储当前端口读取的值
  byte i;
  // start condition
  // 1. pull-down i/o pin from 18ms
  PORTC &= ~_BV(DHT11_PIN); //拉低
  delay(18);
  PORTC |= _BV(DHT11_PIN);  //拉高
  delayMicroseconds(40);

  DDRC &= ~_BV(DHT11_PIN);
  delayMicroseconds(40);

  dht11_in = PINC & _BV(DHT11_PIN);

  if (dht11_in) {
    //Serial.println("dht11 start condition 1 not met");
    return 1;
  }
  delayMicroseconds(80);

  dht11_in = PINC & _BV(DHT11_PIN);

  if (!dht11_in) {
    //Serial.println("dht11 start condition 2 not met");
    return 2;
  }
  delayMicroseconds(80);
  // now ready for data reception
  for (i = 0; i < 5; i++)
    dht11_dat[i] = read_dht11_dat();

  DDRC |= _BV(DHT11_PIN);
  PORTC |= _BV(DHT11_PIN);

  byte dht11_check_sum = dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3];
  // check check_sum
  if (dht11_dat[4] != dht11_check_sum)
  {
    //Serial.println("DHT11 checksum error");
    return 3;
  }
  return 0;
}

使用前必须添加u8glib库:
arduino使用ESP8266和DHT11显示温湿度值_第4张图片

你可能感兴趣的:(arduino)