MCU:零知开源开发板
wifi模块:ESP-12F
开发工具:零知实验室
功能:通过串口连接零知实验室开发板与esp-12f wifi模块,实现联网:本示例使用AP指令开发方式,开启一个热点并设置为TCP服务器模式,程序运行后就可以被其他wifi功能的终端连接上进行网络通信
我们把esp8266连接到零知开发板的Serial1的引脚上(注意RX和TX交叉连接)
零知-标准板 <-------------> ESP8266打开零知开发工具,在【示例】中选择如下选项:
/**************************************************************************************
* 文件: \esp8266-wifi-test(AP模式下建立TCP服务器)\AP_TCP_Server.ino
* 作者:零知实验室
* -^^- 零知开源,让电子制作变得更简单! -^^-
* 时间: 2019-11-20 19:01:29
* 说明: 使用ESP8266建立TCP服务器示例
****************************************************************************************/
#include "esp8266.h"
#include <HardwareSerial.h>
#define ssid "ESP8266-TCP服务器" //在这里设置你的热点名称
#define password "12345678" //在这里设置你的热点密码
#define serverPort 8081 // 开启的端口号
Esp8266 wifi; //创建实例
#define serialDebug Serial
#define serialEsp Serial1
void setup()
{
delay(8000); //等待一段时间,以便查看串口的调试信息
serialDebug.begin(115200); //设置调试串口波特率,启动调试串口
serialEsp.begin(115200); //设置ESP串口波特率,启动ESP传输串口
wifi.begin(&serialEsp, &serialDebug); ///Serial串行用于与esp8266模块通信,serialDebug用于打印调试消息
if (wifi.enableAP(ssid, password))
{
wifi.debugPrintln("AP成功开启!");
}
if (wifi.setMultiConnect())
{
wifi.debugPrintln("开启多连接模式成功!");
}
if (wifi.openTCPServer(serverPort, 180))
{
wifi.debugPrintln("开启TCP服务器成功!");
}
wifi.debugPrintln("服务器IP:" + wifi.getIP() + " 端口:" + String(serverPort));
}
void loop()
{
int state = wifi.getState(); //根据WiFi状态进入以下操作
switch (state)
{
case WIFI_NEW_MESSAGE: //从客户端接收到了新的信息,打印
wifi.debugPrintln(String(wifi.getWorkingID()) + ":" + wifi.getMessage()); // 调试
wifi.sendMessage(wifi.getWorkingID(), wifi.getMessage()); // 把接收到的信息发送回给客户端
wifi.setState(WIFI_IDLE);
break;
case WIFI_CLOSED: //如果连接口已关闭
wifi.debugPrintln(String(wifi.getFailConnectID()) + ":连接关闭!");
wifi.setState(WIFI_IDLE);
break;
case WIFI_IDLE:
{
int state = wifi.checkMessage();
wifi.setState(state);
break;
}
case WIFI_CLIENT_ON: //客户端连接成功,WiFi发出问候字符串信息
wifi.sendMessage(wifi.getWorkingID(), "from ESP8266: Hello, www.lingzhilab.com");
wifi.setState(WIFI_IDLE);
break;
}
}
#include "esp8266.h"
Esp8266::Esp8266() {
this->workingState = WIFI_IDLE;
this->wifiMode = WIFI_MODE_STATION;
this->isDebug = false;
}
void Esp8266::begin(Stream *serial){
this->serial=serial;
}
void Esp8266::begin(Stream *serial, Stream *serialDebug){
this->serial = serial;
this->serialDebug = serialDebug;
this->isDebug = true;
}
bool Esp8266::connectAP(String ssid, String password) {
unsigned long timeout = 20000;
unsigned long t_start = 0;
int buf[10];
char index=0;
if (checkMode()!=WIFI_MODE_AP){
this->wifiMode = WIFI_MODE_STATION;
}
else {
if (setMode(WIFI_MODE_STATION))
this->wifiMode = WIFI_MODE_STATION;
else {
if (this->isDebug) {
debugPrintln("set mode to station false!");
}
return false;
}
}
clearBuf();
this->serial->println("AT+CWJAP=""+ssid+"",""+password+""");
t_start = millis();
while ((millis()-t_start) < timeout) {
while (available()>0) {
buf[index] = read();
if (buf[index]=='K' && buf[(index+9)%10]=='O') {
return true;
}
if (buf[index]=='L' && buf[(index+9)%10]=='I' && buf[(index+8)%10]=='A' && buf[(index+7)%10]=='F') {
return false;
}
index++;
if (index==10)
index = 0;
}
}
if (this->isDebug) {
debugPrintln("connect AP timeout");
}
return false;
}
int Esp8266::available() {
return this->serial->available();
}
void Esp8266::write(String str) {
this->serial->println(str);
flush(); /*wait the data send ok, clear send_buf*/
}
bool Esp8266::checkEsp8266() {
bool isOK=false;
clearBuf();
write("AT");
delay(200);
isOK = this->serial->findUntil("AT", "\r\n");
if (true == isOK) {
return true;
} else {
return false;
}
}
/*clear rx_buf*/
void Esp8266::clearBuf() {
while(available() > 0)
read();
}
int Esp8266::read() {
return this->serial->read();
}
String Esp8266::readData() {
unsigned long timeout = 100;
unsigned long t = millis();
String data = "";
while(millis() - t < timeout) {
if(available() > 0) {
char r = serial->read();
data += r;
t = millis();
}
}
return data;
}
bool Esp8266::setMode(char mode) {
clearBuf();
write("AT+CWMODE="+String(mode));
delay(200);
String str = readData();
if (str.indexOf("no change") > 0)
return true;
else {
if (resetEsp8266()) {
this->wifiMode = mode;
return true;
}
else {
return false;
}
}
}
/*clear send_buf*/
void Esp8266::flush() {
this->serial->flush();
}
char Esp8266::checkMode() {
clearBuf();
write("AT+CWMODE?");
delay(200);
String str = readData();
// Serial.println(str);
if (str.indexOf('1') > 0 )
return '1';
else if (str.indexOf('2') > 0)
return '2';
else if (str.indexOf('3') > 0)
return '3';
else
return '0';
}
bool Esp8266::resetEsp8266() {
unsigned long timeout = 7000;
unsigned long t_start = 0;
int buf[10];
char index=0;
clearBuf();
write("AT+RST");
t_start = millis();
while ((millis()-t_start) < timeout) {
while (available()>0) {
buf[index] = read();
if (buf[index]=='y' && buf[(index+9)%10]=='d' && buf[(index+8)%10]=='a' && buf[(index+7)%10]=='e' && buf[(index+6)%10]=='r') {
return true;
}
index++;
if (index==10)
index = 0;
}
}
if (this->isDebug) {
debugPrintln("rest esp8266 timeout");
}
return false;
}
void Esp8266::debugPrintln(String str) {
this->serialDebug->println(str);
}
bool Esp8266::setMux(int flag) {
String str;
clearBuf();
write("AT+CIPMUX="+String(flag));
delay(100);
str = readData();
if (str.indexOf("OK")>0 || str.indexOf("link is builded")>0)
return true;
else
return false;
}
bool Esp8266::setSingleConnect() {
this->connectID = 0;
this->multiFlag = false;
return setMux(0);
}
bool Esp8266::setMultiConnect() {
this->connectID = 0;
this->multiFlag = true;
return setMux(1);
}
bool Esp8266::connectTCPServer(String serverIP, String serverPort) {
unsigned long timeout = 5000;
unsigned long t_start = 0;
unsigned char buf[10];
unsigned char index=0;
clearBuf();
if (!this->multiFlag) {
write("AT+CIPSTART="TCP","" + serverIP + ""," + serverPort);
t_start = millis();
while((millis())-t_start < timeout) {
while(available()) {
buf[index] = read();
if (buf[index]=='T' && buf[(index+9)%10]=='C' && buf[(index+8)%10]=='E' && buf[(index+7)%10]=='N'
&& buf[(index+6)%10]=='N' && buf[(index+5)%10]=='O' && buf[(index+4)%10]=='C') {
return true;
}
index++;
if (index==10)
index = 0;
}
}
if (this->isDebug) {
debugPrintln("connectTCPServer timeout");
}
return false;
} else {
write("AT+CIPSTART="+ String(this->connectID) + ","TCP","" + serverIP + ""," + serverPort);
t_start = millis();
while((millis())-t_start < timeout) {
while(available()) {
buf[index] = read();
if (buf[index]=='T' && buf[(index+9)%10]=='C' && buf[(index+8)%10]=='E' && buf[(index+7)%10]=='N'
&& buf[(index+6)%10]=='N' && buf[(index+5)%10]=='O' && buf[(index+4)%10]=='C') {
this->connectID++;
return true;
}
index++;
if (index==10)
index = 0;
}
}
if (this->isDebug) {
debugPrintln("connectTCPServer timeout");
}
return false;
}
}
int Esp8266::getState() {
return this->workingState;
}
void Esp8266::setState(int state) {
this->workingState = state;
}
int Esp8266::checkMessage() {
String tmp="";
tmp = readData();
if (tmp!="") {
if (tmp.substring(2, 6) == "+IPD") {
if (!(this->multiFlag)) {
int index = tmp.indexOf(":");
int length = tmp.substring(7, index+1).toInt();
this->message = tmp.substring(index+1, index+length+1);
return WIFI_NEW_MESSAGE;
} else {
int id = 0, length=0, index=0;
id = tmp.substring(7, 8).toInt();
index = tmp.indexOf(":");
length = tmp.substring(9, index+1).toInt();
this->workingID = id;
this->message = tmp.substring(index+1, index+length+1);
return WIFI_NEW_MESSAGE;
}
} else if (tmp.substring(0,6) == "CLOSED" || (tmp.charAt(1)==',' && tmp.substring(2,8)=="CLOSED")) {
if (!(this->multiFlag)) {
return WIFI_CLOSED;
} else {
this->failConnectID = tmp.charAt(0)-'0';
return WIFI_CLOSED;
}
} else if (tmp.substring(1,9) == ",CONNECT") {
int index = tmp.charAt(0)-'0';
this->workingID = index;
return WIFI_CLIENT_ON;
} else if (this->isPureDataMode) {
this->message = tmp;
return WIFI_NEW_MESSAGE;
} else {
return WIFI_IDLE;
}
} else {
return this->workingState;
}
}
String Esp8266::getMessage() {
return this->message;
}
bool Esp8266::sendMessage(String str) {
if (this->isPureDataMode) {
this->serial->print(str);
} else {
String tmp = "";
int index = 0;
int len = 0;
len = str.length();
write("AT+CIPSEND="+String(len));
delay(20);
this->serial->print(str);
tmp = readData();
index = tmp.length();
if (tmp.substring(index-9, index-2) == "SEND OK") {
return true;
} else {
return false;
}
}
}
bool Esp8266::sendMessage(int index, String str) {
String tmp = "";
int i = 0;
int len = 0;
len = str.length();
write("AT+CIPSEND="+String(index)+","+String(len));
delay(20);
this->serial->print(str);
tmp = readData();
i = tmp.length();
if (tmp.substring(i-9, i-2) == "SEND OK") {
return true;
} else {
return false;
}
}
int Esp8266::getWorkingID() {
return this->workingID;
}
int Esp8266::getFailConnectID() {
return this->failConnectID;
}
bool Esp8266::openTCPServer(int port, int timeout) {
if (setMux(1)) {
String str="";
write("AT+CIPSERVER=1,"+String(port));
str = readData();
if (str.indexOf("OK")) {
write("AT+CIPSTO="+String(timeout));
str = readData();
if (str.indexOf("OK")) {
return true;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
bool Esp8266::enableAP(String ssid, String password) {
if (setMode(WIFI_MODE_AP)) {
write("AT+CWSAP=""+ssid+"",""+password+"","+String(10)+String(',')+String(4));
String tmp;
delay(200);
tmp = readData();
if (tmp.indexOf("OK")>0) {
return true;
} else {
return false;
}
}
}
String Esp8266::getIP() {
write("AT+CIFSR");
String tmp = readData();
if (this->wifiMode == WIFI_MODE_STATION) {
int index1 = tmp.indexOf("STAIP");
int index2 = tmp.indexOf("+CIFSR:STAMAC");
this->staIP = tmp.substring(index1+7, index2-3);
return this->staIP;
} else {
int index1 = tmp.indexOf("APIP");
int index2 = tmp.indexOf("+CIFSR:APMAC");
this->apIP = tmp.substring(index1+6, index2-3);
return this->apIP;
}
}
bool Esp8266::setPureDataMode() {
write("AT+CIPMODE=1");
String tmp = readData();
if (tmp.indexOf("OK")>0) {
write("AT+CIPSEND");
this->isPureDataMode = true;
return true;
} else
return false;
}
#ifndef _ESP8266_H_
#define _ESP8266_H_
#include <Arduino.h>
#include <Stream.h>
#include <avr/pgmspace.h>
#include <IPAddress.h>
#define WIFI_IDLE 1
#define WIFI_NEW_MESSAGE 2
#define WIFI_CLOSED 3
#define WIFI_CLIENT_ON 4
#define WIFI_MODE_STATION '1'
#define WIFI_MODE_AP '2'
#define WIFI_MODE_BOTH '3'
class Esp8266
{
public:
Esp8266();
void begin(Stream *serial);
void begin(Stream *serial,Stream *serialDebug);
void comSend();
bool connectAP(String ssid, String password);
bool checkEsp8266();
bool resetEsp8266();
void debugPrintln(String str);
bool setSingleConnect();
bool setMultiConnect();
bool connectTCPServer(String serverIP, String serverPort);
int checkMessage();
String getMessage();
void setState(int state);
int getState();
bool sendMessage(String str);
bool sendMessage(int index, String str);
int getWorkingID();
int getFailConnectID();
bool openTCPServer(int port, int timeout);
bool enableAP(String ssid, String password);
String getIP();
bool setPureDataMode();
private:
int available();
void write(String str);
void clearBuf();
int read();
String readData();
void flush();
bool setMode(char mode);
char checkMode();
bool setMux(int flag);
private:
Stream *serial;
Stream *serialDebug;
int connectID;
int workingID;
int failConnectID;
bool multiFlag;
int workingState;
<font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> 字符串消息; </font></font>
<font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> char wifiMode; </font></font>
<font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> String staIP; </font></font>
<font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> String apIP; </font></font>
<font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> bool isDebug; </font></font>
<font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> bool是PureDataMode; </font></font>
<font style="vertical-align: inherit;"><font style="vertical-align: inherit;">}; </font></font>
<font style="vertical-align: inherit;"><font style="vertical-align: inherit;">#万一</font></font>
程序烧写到开发板后,打开零知Lab开发工具的串口监视器,选择波特率为115200,就可以看到如下所示:
可以看到网络功能开启成功的信息,以及服务器开放的ip和端口号。
在手机上打开网络设置界面,可以看到esp8266的热点信息,如下
再打开手机上的网络调试助手工具,再到TCP客户端项目中选择增加,填写正确的ip和端口,如下
然后连接成功后会显示如下:
可以看到从esp8266 wifi模块发送过来的信息,在发送框中发送信息,就可以在串口监视器中看到从手机上发过来的信息,如下:
这就实现了STM32与手机之间通过无线网络的TCP协议的通信
将该文件解压后放到IDE安装目录的stm32duino文件夹下面的stm32examples中【13.wifi】目录中,在开发工具中的示例13下面就可以从示例中看到该工程示例。