esp8266主控版本的结构更为简单,通过5V usb取电,由5v转固定3.3v版本的ams1117提供3.3v供电(esp8266),传感器采用主动模式,由esp8266主动询问并获取数据,由wifi连接送到服务器,而由于esp8266的IO接口限制(从性价比考虑,12F能以低廉的价格提供较多的IO,而相对地,如果IO数量要求不高,尤其是用于产品量产的情况下,可以采用01S型号,如果接口、Flash要求较高,可以不采用esp8266,而是考虑更高规格的esp32),LCD1602通过I2C转接板,和esp8266通信可以只占用两个接口。
ESP8266系列模组技术规格(01S和12F其实也只是5块钱和8块钱的区别):
项目用到的组件:
Arduino/ESP8266 QuickStart
开发环境:
esp8266和arduino都可以使用C/C++风格的Arduino IDE来进行开发,不同的是前者需要额外引入相关的开发板定义并下载类库。
资源:
arduino中文社区 https://www.arduino.cn/
wiki https://wiki.arduino.cn/
ide下载 https://www.arduino.cc/en/Main/Software
arduino开发板的开发比较简单,打开IDE直接就可以垒代码。
esp8266开发需要:
添加开发板定义,文件 -> 首选项 -> 附加开发板管理器网址中填入 http://arduino.esp8266.com/stable/package_esp8266com_index.json ;
工具 -> 开发板 -> 开发板管理器 -> 找到esp8266并下载安装(因为需要从github下载,所以速度会极慢,耐心等待,或者自行从网上搜索离线安装的方法吧);
待下载完成后,即可在 工具 -> 开发板 中找到新安装的esp8266。
esp8266的工作模式:
烧录模式:需要GPIO 0接地;
工作模式:需要GPIO 0与GND断开;
可以在GPIO 0与GND中间加一个拨片开关,方便快速切换;
RESET引脚接地建议使用触点开关,因为我手头没有,所以才用拨片开关。
LCD1602直连,需要用到LiquidCrystal库,较低版本的ide中默认不带,需要自行下载,操作方法是由工具菜单中的管理库菜单项打开库管理器,搜索LiquidCrystal后,下载安装,并在头部将库引入#include 。
LCD1602的I2C连接,需要用到LiquidCrystal_I2C库,使用方法同上,唯一不同的是库名为LiquidCrystal_I2C。
其它外设、功能所依赖的库的流程和上面一样,ide如果安装过,直接引入使用,如果没安装过,在库管理器中下载再引入使用。
void setup() { //开机运行的代码,只会运行一次}void loop() { //开机代码执行后,循环运行loop中的代码}
串口
串口分为硬串口和软串口;
软串口可以由任意IO接口定义而来,但是没有缓存,同时只能监听一个;
连线方式:开发板的TX/RX接外设的RX/TX,收发对调;
没有库依赖;
Serial.begin(9600);//定义串口波特率,默认格式为8N1Serial.print("A");//打印字符Serial.write(65);//打印ASCII码对应的字符while (Serial.available()) { int val = Serial.read(); //……}
WIFI
依赖ESP8266HTTPClient库;
#include WiFi.begin("ssid", "112233445566");//通过指定的wifi名和密码连接wifiwhile (WiFi.status() != WL_CONNECTED){ //检测到wifi连接未建立}String ip = WiFi.localIP();//获取wifi的IP
LCD1602和LCD1602_I2C
前者依赖LiquidCrystal库,后者依赖LiquidCrystal_I2C库;
连线方式:直连LCD1602模块采用4线或8线连接模式,I2C采用SCL/SDA两根线连接,前者适合IO宽裕的情况,需要占用6个引脚,后者只需要占用两个引脚。
只支持英文字库,也可以自定义点阵,但是1602每个字符只有5*8像素,显示复杂内容会很难分辨,因此有更复杂需求时应该选择更好的屏幕,用合适的设备做合适的事情。
#include <LiquidCrystal_I2C.h>LiquidCrystal_I2C lcd(0x27,16,2);//I2C地址0x27,16行,2列//模块地址是固定的,具体数值请参考说明书或厂商相关文档。 #include <LiquidCrystal.h>LiquidCrystal lcd(7, 6, 5, 4, 3, 2);//通过6个IO接口驱动屏幕//代表rs, en, d4, d5, d6, d7引脚lcd.init();//初始化lcd.clear();//清除屏幕lcd.print("ABCD123456");//输出内容lcd.backlight();//背光开启lcd.noBacklight();//背光关闭lcd.setCursor(x,y);//移动光标到x列y行
HTTPClient
依赖ESP8266HTTPClient库;
#include const char *headerKeys[] = {"tomorrow", "timestr", "light"};//一般API在返回复杂内容时,会用Json序列化结果,//用ResponseHeader的好处是无需让开发板省去//反序列化的过程。void weather(){ HTTPClient http; String req = "/Api/Weather"; http.begin("http://***.com", 83, req); http.collectHeaders(headerKeys, 3); //保存headerKeys数组中ResponseHeader http.addHeader("User-Agent", "ESP8266-12F", true); //设置httpRequestHeader http.GET(); String result=http.getString(); //获取http的结果 String disp=http.header("timestr"); lcd.print(disp); lcd.setCursor(0,1); lcd.print(result); String light=http.header("light"); if(light=="on"){ lcd.backlight(); }else{ lcd.noBacklight(); } delay(3000);//延迟3秒 lcd.clear(); lcd.setCursor(0,0); lcd.print("TOMORROW: "); lcd.setCursor(0,1); disp=http.header("tomorrow"); lcd.print(disp);}
甲醛传感器模块:
项目所用的是型号为wz-s的电化学气体传感器;
需要保存在无干扰环境里,否则会需要较长的时间进行校零(自动进行);
测试会被其它易挥发成分干扰;
传感器具有使用有效期;
不同传感器灵敏度不一样,电化学传感器灵敏度更高,而且很多传感器是污染物检测传感器冒充的。
参数:
输入电压:3.3v ~ 5v分辨率:0.001ppm串口:9600, 8N1设置主动模式:ff 01 78 40 00 00 00 00 47设置问答模式:ff 01 78 41 00 00 00 00 46请求数据命令:ff 01 86 00 00 00 00 00 79返回数据示例:ff 86 00 2A 00 00 00 20 30返回数据中包含两种单位的,按需选择。甲醛浓度换算关系:1ppm=1.228 mg/m3国家标准:室内甲醛浓度小于80μg/m3为合格
0 1 2 3 4 5 6 7 8 起始 命令 高位 低位 保留 保留 高位 低位 校验 0xFF 0x86 μg/m3 μg/m3 ppb ppb
#include #include #include LiquidCrystal_I2C lcd(0x27,16,2);int flag=0;int arr[9];int idx;bool light=false;const String host = "http://server.server.server";const char *headerKeys[] = {"tomorrow", "timestr", "light"};const int cmd0[]={0xff,0x01,0x78,0x41,0x00,0x00,0x00,0x00,0x46};const int cmd1[]={0xff,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};void setup() { Serial.begin(9600); lcd.init(); for (int i = 0; i < 9; i++) { arr[i] = -1; Serial.write(cmd0[i]); } flag=false; WiFi.begin("ssid", "12341234"); while (WiFi.status() != WL_CONNECTED) { lcd.clear(); lcd.print("WIFI Connecting."); if(flag){ lcd.backlight(); }else{ lcd.noBacklight(); } flag=(flag+1) % 3; delay(500); } lcd.backlight(); delay(3000);}void loop() { lcd.clear(); lcd.setCursor(0,0); flag = (flag + 1) % 3; switch(flag){ case 0: lcd.print("IP Address:"); lcd.setCursor(0,1); lcd.print(WiFi.localIP()); break; case 1: weather(); break; case 2: for(int i=0;i<9;i++){ Serial.write(cmd1[i]); } while (Serial.available()) { int val = Serial.read(); idx = idx + 1; arr[idx] = val; } HTTPClient http; idx = -1; String reqx = "/Api/Ch2o?value="; String para2 = String(arr[2] * 256 + arr[3]); String req = "/Api/Log?id="; //Log接口只用于服务器控制台打印 for (int i = 0; i < 9; i++) { req += String(arr[i]); req += ","; arr[i] = -1; } req += para2; reqx += para2; lcd.print("HCHO(ug/m3)"); lcd.setCursor(0,1); lcd.print(para2); lcd.print(" (VT<80)"); http.begin(host, 83, req); http.addHeader("User-Agent", "ESP8266", true); http.GET(); http.begin(host, 83, reqx); http.addHeader("User-Agent", "ESP8266", true); http.GET(); break; } delay(2000);}void weather(){ HTTPClient http; String req = "/Api/Weather"; //常用天气预报接口均为中文,为了免去esp8266进行解析, //在服务器上请求天气并返回格式化的结果 http.begin(host, 83, req); http.collectHeaders(headerKeys, 3); http.addHeader("User-Agent", "ESP8266-12F", true); http.GET(); String result=http.getString(); String disp=http.header("timestr");//天气接口调用时间 lcd.print(disp); lcd.setCursor(0,1); lcd.print(result); String light=http.header("light");//是否开灯 if(light=="on"){ lcd.backlight(); }else{ lcd.noBacklight(); } delay(3000); lcd.clear(); lcd.setCursor(0,0); lcd.print("TOMORROW: "); lcd.setCursor(0,1); disp=http.header("tomorrow");//明日天气 lcd.print(disp);}