ARDUINO UNO跟ESP8266结合
电路
程序
1. 第一步——ARDUINO引用软串口库
基本的只引用软串口
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX 配置10、11为软串口
带有各种检测的
#include <SoftwareSerial.h>
// 软串口
SoftwareSerial WIFISerial(6, 7); // RX, TX交叉接线
#define OK "OK"
#define SENDOK "SEND OK"
#define WIFIPIN 4 //配网按键,按住2秒配网
bool WIFIPINAvailable = true;// 配网按钮是否可用
bool wifiLinked = false;// WIFI是否连接上AP
bool serverLinked = false;// 服务器是否连接
unsigned long lastTime;
2. 第二步——初始化
void setup() {
pinMode(WIFIPIN, INPUT);
// 硬件串口 initialize serial for debugging
Serial.begin(115200);
while (!Serial) {}
// 软串口 initialize serial for ESP module
WIFISerial.begin(57600);
// WIFISerial.println("AT+UART_DEF=57600,8,1,0,0");//解决乱码
// delay(1000);
while (!WIFISerial) {}
WIFISerial.listen();// 开始监听
Serial.println(F("---setup start---"));
// 查询网络连接状态,等待wifi连网几秒
bool _link = false;
int _i = 0;
bgnwifi:
for (int i = 0; i < 3; i++) {
// STATUS 2:获得 IP ,3:已连接,4:断开连接,5:未连接到 WiFi
if (doCMD(F("AT+CIPSTATUS"), F("STATUS:2|STATUS:3"), 3000)) {
_link = true;
break;
}
delay(1000);
}
if (!_link && _i == 0) {
doCMD(F("AT+RST"), F("ready"), 3000);// 重启wifi模块
delay(4000);// 等待连接
_i++;
goto bgnwifi;
}
if (!_link) {
smartConfig();// 启动一键配网
}else {
wifiLinked = true;
}
lastTime = millis();
Serial.println(F("---setup end---"));
}
3. 第三步——开始使用LOOP函数
- 简单 直接在arduino IDE中的串口监视器中进行AT指令的发送
void loop() // run over and over
{
if (mySerial.available())
Serial.write(mySerial.read());
if (Serial.available())
mySerial.write(Serial.read());
}
- 复杂 使用一些封装的函数,然后再进行loop 的使用
找到的一个封装公共函数–飘易封装的公共函数
// 执行AT指令
// cmd AT指令,返回值包含flag则true(2个以|分割),timeout超时时间ms(200的整数倍)
bool doCMD(String cmd, String flag, long timeout) {
String str = "";
WIFISerial.println(cmd); //发送AT指令
delay(300);
flag.toLowerCase();// 小写
// 限期时间
long deadline = millis() + timeout;
while (millis() < deadline)
{
str = "";
while (WIFISerial.available()) {
str += (char)WIFISerial.read();
delay(2);
}
if (str != "") {
Serial.println(str);// 打印输出
str.toLowerCase();// 小写
// 判断 flag 是否需要切割,以 | 切割,逻辑或关系
String flag1 = "", flag2 = "";
int commaPosition = flag.indexOf('|');
if (commaPosition > -1)
{
flag1 = flag.substring(0, commaPosition);
flag2 = flag.substring(commaPosition + 1, flag.length());
}
if (flag1 != "" && flag2 != "") {
if (str.indexOf(flag1) > -1 || str.indexOf(flag2) > -1 ) {
return true;
}
}
if (str.indexOf(flag) > -1) {
return true;
}
}
delay(100);
}
return false;
}
// 一键配网 smartconfig
void smartConfig() {
// 启动smartconfig之前,先停止一下,以避免上次未复位
doCMD(F("AT+CWSTOPSMART"), OK, 3000);
// SmartConfig 仅支持在 ESP8266 单 station 模式下调用
if (!doCMD(F("AT+CWMODE_DEF=1"), OK, 3000)) {}
// 上电自动连接AP
if (!doCMD(F("AT+CWAUTOCONN=1"), OK, 3000)) {}
// 启动smartconfig,支持ESP-Touch和Airkiss智能配网
// 在 SmartConfig 过程中请勿执行其他指令
Serial.println(F("~~ Start SmartConfig ~~"));
bool res = doCMD(F("AT+CWSTARTSMART=3"), F("WIFI GOT IP"), 60000);// 60秒超时
if (res) {
wifiLinked = true;
Serial.println(F("SmartConfig OK"));
} else {
wifiLinked = false;
Serial.println(F("SmartConfig Fail"));
}
doCMD(F("AT+CWSTOPSMART"), OK, 3000);// 无论配网是否成功,都释放快连所占的内存
}
// 连接TCP服务器
bool connectTcp() {
bool linkOk = true;
//连接服务器
String s(F("AT+CIPSTART=\"TCP\",\"tcp.x.com\",9960"));// 字符串存入FLASH
if (!doCMD(s, F("OK|CONNECTED"), 3000)) {
linkOk = false;
}
if (linkOk) {
// 登录,也是心跳包,1分钟内必须上报一次,如有其他定时上报,则可不使用本心跳包
s = F("{\"method\": \"update\",\"gatewayNo\": \"01\",\"userkey\": \"123\"}&^!");// 字符串存入FLASH
doCMD("AT+CIPSEND=" + String(s.length()), ">", 3000);
if (!doCMD(s, SENDOK, 3000)) {
linkOk = false;
}
}
if (!linkOk) {
Serial.println(F("!!SERVER NOT CONNECTED!!"));
} else {
}
serverLinked = linkOk;
return linkOk;
}
实例
执行的业务逻辑是:每50秒为一个循环,在每个循环的第5秒上报传感器的温度和湿度值给云端。当用户按下wifi配网按钮时,wifi模组进入一键配网流程重新设置wifi的ssid和密码信息。
set up 函数参考上面的,这里直接给出loop函数
void loop() {
String info = "";
// 定时上报给服务器 - TCP长连接
if (millis() - lastTime == 5000) {
// 判断wifi是否连接上
if (!wifiLinked) {
Serial.println(F("!!WIFI NOT CONNECTED!!"));
} else {
//连接TCP服务器
if (!serverLinked) {
connectTcp();//连接TCP服务器
} else {
// 上报传感器值 - 定时上报,可代替心跳包(1分钟内1次)
String temp = String(random(10, 40));// 模拟温度
String humi = String(random(40, 90));// 模拟湿度
if (true) {
String s1(F("{\"method\": \"upload\",\"data\":[{\"Name\":\"temp\",\"Value\":\""));// 字符串存入FLASH
String s2(F("\"},{\"Name\":\"humi\",\"Value\":\""));// 字符串存入FLASH
String s3(F("\"}]}&^!"));// 字符串存入FLASH
info = s1 + temp + s2 + humi + s3;
Serial.println(info);
doCMD("AT+CIPSEND=" + String(info.length()), ">", 3000);
if (!doCMD(info, SENDOK, 3000)) {
serverLinked = false;
} else {
}
}
}
}
}
// 恢复计时,云端限制提交频率不能低于20秒
if (millis() - lastTime >= 50000) {
lastTime = millis();
}
// 读取WIFI配网按钮是否接通
boolean val = digitalRead(WIFIPIN);
if (val && WIFIPINAvailable) {
WIFIPINAvailable = false;
Serial.println(F("WIFIPIN pressed"));
smartConfig();// 启动一键配网
WIFIPINAvailable = true;
}
// PC串口转发给wifi软串口
while (Serial.available()) {
WIFISerial.write(Serial.read());
}
// wifi软串口发送过来的信息
String str = "";
while (WIFISerial.available()) {
str = str + (char)WIFISerial.read();
}
if (str != "") {
Serial.println(str);
}
}