ESP8266与MCU通信

前段时间学习了ESP8266的AT指令集,现在通过AT指令初始化ESP8266+串口通信的方式,完成WLAN下的信息交换,比如手机、PC、其他MCU与STC89 C51的通信等等。其中踩了不少的坑,特此记录一下。ESP8266小模块系列常见的就下面几种:ESP-01S比ESP-01多了两颗小料并增强了天线的强度,其他的是一样的,完全通用!
下面是其管脚图与外形尺寸图,如果PCB背板也有图的话那么直接根据背板的上的图也是OK的:
AT测试+服务模式配置
通过USB转TTL模块把ESP8266模块和电脑连接起来 ,下面是我是使用的USB转TTL,专门用于ESP8266 WIFI模块的调试工具,购买链接 https://detail.1688.com/offer/548614288547.html :
连接好后,就准备用电脑用串口调试助手向ESP8266发送AT指令即可,调试助手可使用XCOMV2,非常好用。 设置好串口调试助手的串口和波特率,ESP8266默认波特率为115200,把串口调试助手的波特率调为115200,并且 勾选左下角的发送新行。 在输入框中输入 AT 然后点击发送:
如果AT测试指令返回OK,就是没问题的,如果未返回,那么需要刷入官方原厂固件才可以继续使用。
由于ESP 8266这种小模块通常只是作为其他设备与MCU的沟通媒介,所以配置成服务器模式进行数据交互就OK了, 按照以下顺序向模块发送AT指令:
-> 下面的指令配置一次就够了,断电重连配置的信息也不会改变
1、AT+RST 复位命令,复位成功后ESP8266会返回一堆乱码,这时候就说明ESP8266配置成功了
2、AT+CWMODE=2 服务器/热点模式
3、AT+CWSAP=“esp8266”,“0123456789”,11,3 设置WIFI热点属性,名称,密码,通道号, 加密方式
4、AT+RST 配置完 AT+CWMODE要重启模块使配置生效
-> 下面的指令每次重启模块之后都要配置一遍
5、AT+CIPMUX=1 设置为多连接模式
6、AT+CIPSERVER=1,8080 其中1代表建立服务器,只能选1,端口号没有固定值,可随意修改。
按照上述顺序配置完之后就可以用手机进行连接,使用网络调试助手 https://img.zouchanglin.cn/b0c1c79fd9c5f1bbb51da68a317e8398.apk ,如果手机发现WIFI并且输入密码成功连接了,就证明上面的配置成功了。打开手机网络调试助手,把协议类型设置为"TCP Client", IP地址设置为用 AT+CIFSR 指令查询到的ESP8266的IP(一般为192.168.4.1),端口号就是前面设置的端口号。
手机要连接好ESP8266的WIFI,如果可以连接上,并且串口调试助手收到了手机端发来的数据,那么就说明配置都是OK的,现在基本的手机和ESP8266通信已经完成了。
调整波特率,与C51匹配
上面的配置只是电脑和ESP8266的连接,确保ESP8266运行正常,现在要进行单片机和ESP8266的连接了。因为51单片机通讯的波特率达不到115200,所以最好选择9600即可,所以ESP8266要与单片机进行连接通讯,就要先用电脑把ESP8266的波特率设置为9600;
AT+CIOBAUD=9600 该指令就可以设置ESP8266波特率为9600了,AT+RST重启一下ESP8266。
注意不要忘记把电脑串口调试助手的波特率也改为9600,不然电脑连接ESP8266就会出现错误。
AT+CIPMUX=1与AT+CIPSERVER=1,8080这两条指令每次重启模块之后都要配置一遍,因此,这两条指令让MCU去发送即可,每次MCU重启之后都会自动发动这两条指令进行ESP8266的初始化操作。
C51如何指定波特率呢?其实可以自己计算,也可以通过软件直接计算:
/**
* @brief 串口初始化,9600bps@11.0592MHz
* @param 无
* @retval 无
*/
void UART_Init(void) //9600bps@11.0592MHz
{
PCON |= 0x80; //使能波特率倍速位SMOD
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xFA; //设定定时初值
TH1 = 0xFA; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
EA=1;
ES=1;
}
/**
* @brief 串口发送一个字节数据
* @param Byte 要发送的一个字节数据
* @retval 无
*/
void UART_SendByte(unsigned char Byte)
{
SBUF=Byte;
while(TI==0);
TI=0;
}
先测试发送一个字符或者字符串,如果成功,那就说明单片机设置的9600bps发送数据是没问题的。
其实这种思路很重要,每做一部,先看看这一步是否存在问题,这样能缩小问题的范围,不至于最终调试的时候才发现出了BUG,不知道从何找起,单元测试就是这个道理。
MCU与ESP8266接线
串口接线其实非常简单,ESP8266的VCC、GND、TXD、RXD接入C51的3.3V、GND、RXD(P30)、TXD(P31)即可。
需要注意的是,在C51的P31和P30口在接入ESP8266时,烧录程序会有问题,在烧录程序的时候应该将串口移除才可以。
另外ESP8266的CH_PD口应该也接3.3V:

程序编写
UART.h与UART.c
// -------------------------- UART.h --------------------------------
#ifndef __UART_H__
#define __UART_H__
void UART_Init();
void UART_SendByte(unsigned char Byte);
void UART_SendString(unsigned char *str);
#endif //!__UART_H__
// ---------------------------- UART.c ------------------------------
#include <REGX51.H>
/**
* @brief 串口初始化,4800bps@12.000MHz
* @param 无
* @retval 无
*/
void UART_Init(void) //9600bps@11.0592MHz
{
PCON |= 0x80; //使能波特率倍速位SMOD
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xFA; //设定定时初值
TH1 = 0xFA; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
EA=1;
ES=1;
}
/**
* @brief 串口发送一个字节数据
* @param Byte 要发送的一个字节数据
* @retval 无
*/
void UART_SendByte(unsigned char Byte)
{
SBUF=Byte;
while(TI==0);
TI=0;
}
/**
* @brief 串口发送一个字符串数据
* @param str 要发送的字符串指针
* @retval 无
*/
void UART_SendString(unsigned char *str)
{
char *tmp = str;
while(*tmp!='\0')
{
UART_SendByte(*tmp);
tmp++;
}
}
/*串口中断函数模板
void UART_Routine() interrupt 4
{
if(RI==1)
{
RI=0;
}
}
*/
main.c
#include <REGX51.H>
#include <INTRINS.H>
#include <STRING.H>
#include "UART.h"
#include "LCD1602.h"
unsigned char i = 0;
unsigned char flag = 0;
unsigned char receive[20] = {0};
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 22;
j = 3;
k = 227;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
// 初始化ESP8266
void Connect_Init()
{
char *mux="AT+CIPMUX=1\r\n";
char *server="AT+CIPSERVER=1,8080\r\n";
Delay500ms();
UART_SendString(mux);
Delay500ms();
UART_SendString(server);
}
// 收到数据触发中断
void UART_Routine() interrupt 4
{
char res;
res=SBUF; //取出接受到的数据
RI=0; //清除接受中断标志位
if(res==':'||i>0) //i是全局变量
{
receive[i]=res; //receive数组也是全局变量
i++;
if(res=='\n')
{
LCD_ShowNum(2,1,flag++,3);
LCD_ShowString(2,5,receive);
i=0;
//添加对收到信息的处理代码
memset(receive,0,50);
}
}
}
void main()
{
LCD_Init();
UART_Init();
Connect_Init();
LCD_ShowString(1,1,"server ready");
while(1)
{
}
}
其中LCD的代码和之前的LCD1602一模一样,接下来手机连接WIFI,打开网络调试助手,发送信息OK!
最终效果
整个过程中需要注意的点:
1、波特率一定要一致,不要超出MCU支持的最高波特率,一般为9600即可;
2、确保8266模块时正常工作的,接入MCU之前一定要通过USB转TTL在PC上测试;
3、确保MCU串口发送数据没有问题,通过串口调试助手验证;
4、某些开发板由于引脚冲突,可能导致程序异常,这个时候换个最小系统板试试;
5、8266接入MCU后,如果需要烧录MCU,先将8266连接线断开再烧录;
补充:MCU如何回发数据
其实,对于数据回发来说,只需要使用 AT+CIPSEND=“0,30” 即可,其中0时客户端ID,30是数据长度,下面是我封装的ESP8266模块:
// ------------------------ ESP8266.h -------------------------------
#ifndef __ESP8266_H__
#define __ESP8266_H__
void ESP8266_Connect_Init();
void ESP8266_SendString(char *clientId, char *str, char *length);
#endif //!__ESP8266_H__
// ------------------------ ESP8266.c -------------------------------
#include "Delay.h"
#include "UART.h"
#include "LCD1602.h"
// 初始化ESP8266
void ESP8266_Connect_Init()
{
char *muxCmd="AT+CIPMUX=1\r\n";
char *serverCmd="AT+CIPSERVER=1,8080\r\n";
Delay(200);
UART_SendString(muxCmd);
Delay(200);
UART_SendString(serverCmd);
}
// 发送到客户端,客户端ID,内容,内容长度
void ESP8266_SendString(char *clientId, char *str, char *length)
{
// 串口发送数据传出指令, 如AT+CIPSEND=0,10
UART_SendString("AT+CIPSEND=");
UART_SendString(clientId);
UART_SendString(",");
UART_SendString(length);
UART_SendString("\r\n");
Delay(100);
UART_SendString(str);
Delay(20);
}
在main.c中直接调用即可:
#include <REGX51.H>
#include <INTRINS.H>
#include <STRING.H>
#include "UART.h"
#include "LCD1602.h"
#include "Delay.h"
#include "ESP8266.h"
unsigned char i = 0;
unsigned char flag = 0;
unsigned char receive[50] = {'\0'};
// 收到数据触发中断
void UART_Routine() interrupt 4
{
char res;
res=SBUF;
RI=0;
if(res=='+'||i>0)
{
receive[i]=res;
i++;
if(res=='\n')
{
LCD_ShowNum(2,1,flag++,3);
LCD_ShowString(2,4,receive);
// 收到后做出响应【可选】,参数为客户端ID、内容、长度,注意都是字符串表示形式
ESP8266_SendString("0", "ABC12345678", "11");
i=0;
//添加对收到信息的处理代码
memset(receive,0,50);
}
}
}
void main()
{
LCD_Init();
UART_Init();
ESP8266_Connect_Init();
LCD_ShowString(1,1,"success");
while(1)
{
}
}
完整工程代码见 : Wifi模块 – ESP8266