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/com.network.debug.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如何指定波特率呢?其实可以自己计算,也可以通过软件直接计算:

 1/**
 2  * @brief  串口初始化,9600bps@11.0592MHz
 3  * @param  无
 4  * @retval 无
 5  */
 6void UART_Init(void)		//9600bps@11.0592MHz
 7{
 8	PCON |= 0x80;		//使能波特率倍速位SMOD
 9	SCON = 0x50;		//8位数据,可变波特率
10	
11	TMOD &= 0x0F;		//清除定时器1模式位
12	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
13	TL1 = 0xFA;		//设定定时初值
14	TH1 = 0xFA;		//设定定时器重装值
15	ET1 = 0;		//禁止定时器1中断
16	TR1 = 1;		//启动定时器1
17	
18	EA=1;
19	ES=1;
20}
21
22/**
23  * @brief  串口发送一个字节数据
24  * @param  Byte 要发送的一个字节数据
25  * @retval 无
26  */
27void UART_SendByte(unsigned char Byte)
28{
29	SBUF=Byte;
30	while(TI==0);
31	TI=0;
32}

先测试发送一个字符或者字符串,如果成功,那就说明单片机设置的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

 1// -------------------------- UART.h --------------------------------
 2#ifndef __UART_H__
 3#define __UART_H__
 4
 5void UART_Init();
 6void UART_SendByte(unsigned char Byte);
 7void UART_SendString(unsigned char *str);
 8
 9#endif //!__UART_H__
10
11
12// ---------------------------- UART.c ------------------------------
13#include <REGX51.H>
14
15/**
16  * @brief  串口初始化,4800bps@12.000MHz
17  * @param  无
18  * @retval 无
19  */
20void UART_Init(void)		//9600bps@11.0592MHz
21{
22	PCON |= 0x80;		//使能波特率倍速位SMOD
23	SCON = 0x50;		//8位数据,可变波特率
24	
25	TMOD &= 0x0F;		//清除定时器1模式位
26	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
27	TL1 = 0xFA;		//设定定时初值
28	TH1 = 0xFA;		//设定定时器重装值
29	ET1 = 0;		//禁止定时器1中断
30	TR1 = 1;		//启动定时器1
31	
32	EA=1;
33	ES=1;
34}
35
36/**
37  * @brief  串口发送一个字节数据
38  * @param  Byte 要发送的一个字节数据
39  * @retval 无
40  */
41void UART_SendByte(unsigned char Byte)
42{
43	SBUF=Byte;
44	while(TI==0);
45	TI=0;
46}
47
48/**
49  * @brief  串口发送一个字符串数据
50  * @param  str 要发送的字符串指针
51  * @retval 无
52  */
53void UART_SendString(unsigned char *str)
54{
55	char *tmp = str;
56	while(*tmp!='\0')
57    {
58        UART_SendByte(*tmp);
59        tmp++;
60    }
61}
62
63/*串口中断函数模板
64void UART_Routine() interrupt 4
65{
66	if(RI==1)
67	{
68		
69		RI=0;
70	}
71}
72*/

main.c

 1#include <REGX51.H>
 2#include <INTRINS.H>
 3#include <STRING.H>
 4
 5#include "UART.h"
 6#include "LCD1602.h"
 7
 8unsigned char i = 0;
 9unsigned char flag = 0;
10unsigned char receive[20] = {0};
11	
12void Delay500ms() //@11.0592MHz
13{
14	unsigned char i, j, k;
15
16	_nop_();
17	_nop_();
18	i = 22;
19	j = 3;
20	k = 227;
21	do
22	{
23		do
24		{
25			while (--k);
26		} while (--j);
27	} while (--i);
28}
29
30
31// 初始化ESP8266
32void Connect_Init()
33{
34    char *mux="AT+CIPMUX=1\r\n";
35    char *server="AT+CIPSERVER=1,8080\r\n";
36	
37	Delay500ms();
38    UART_SendString(mux);
39	Delay500ms();
40    UART_SendString(server);
41}
42
43// 收到数据触发中断
44void UART_Routine() interrupt 4
45{
46    char res;
47    res=SBUF;         //取出接受到的数据
48    RI=0;              //清除接受中断标志位
49    if(res==':'||i>0)    //i是全局变量
50    {
51        receive[i]=res;   //receive数组也是全局变量
52        i++;
53        if(res=='\n')
54        {
55			LCD_ShowNum(2,1,flag++,3);
56			LCD_ShowString(2,5,receive);
57            i=0;
58            //添加对收到信息的处理代码
59            memset(receive,0,50);
60        }
61    }
62}
63
64void main()
65{
66	LCD_Init();
67	UART_Init();
68	Connect_Init();
69	LCD_ShowString(1,1,"server ready");
70	while(1)
71	{
72		
73	}
74}

其中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模块:

 1// ------------------------ ESP8266.h -------------------------------
 2#ifndef __ESP8266_H__
 3#define __ESP8266_H__
 4
 5
 6void ESP8266_Connect_Init();
 7
 8
 9void ESP8266_SendString(char *clientId, char *str, char *length);
10
11#endif //!__ESP8266_H__
12
13
14// ------------------------ ESP8266.c -------------------------------
15#include "Delay.h"
16#include "UART.h"
17#include "LCD1602.h"
18
19// 初始化ESP8266
20void ESP8266_Connect_Init()
21{
22    char *muxCmd="AT+CIPMUX=1\r\n";
23    char *serverCmd="AT+CIPSERVER=1,8080\r\n";
24	
25	Delay(200);
26    UART_SendString(muxCmd);
27	Delay(200);
28    UART_SendString(serverCmd);
29}
30
31// 发送到客户端,客户端ID,内容,内容长度
32void ESP8266_SendString(char *clientId, char *str, char *length)
33{	
34	// 串口发送数据传出指令, 如AT+CIPSEND=0,10
35	UART_SendString("AT+CIPSEND=");
36	UART_SendString(clientId);
37	UART_SendString(",");
38	UART_SendString(length);
39	UART_SendString("\r\n");
40	Delay(100);
41	UART_SendString(str);
42	Delay(20);
43}

在main.c中直接调用即可:

 1#include <REGX51.H>
 2#include <INTRINS.H>
 3#include <STRING.H>
 4
 5#include "UART.h"
 6#include "LCD1602.h"
 7#include "Delay.h"
 8#include "ESP8266.h"
 9
10unsigned char i = 0;
11unsigned char flag = 0;
12unsigned char receive[50] = {'\0'};
13
14
15// 收到数据触发中断
16void UART_Routine() interrupt 4
17{
18    char res;
19    res=SBUF;
20    RI=0;
21    if(res=='+'||i>0)
22    {
23        receive[i]=res;
24        i++;
25        if(res=='\n')
26        {
27			LCD_ShowNum(2,1,flag++,3);
28			LCD_ShowString(2,4,receive);
29			// 收到后做出响应【可选】,参数为客户端ID、内容、长度,注意都是字符串表示形式
30			ESP8266_SendString("0", "ABC12345678", "11");
31            i=0;
32            //添加对收到信息的处理代码
33            memset(receive,0,50);
34        }
35    }
36}
37
38void main()
39{
40	LCD_Init();
41	UART_Init();
42	ESP8266_Connect_Init();
43	LCD_ShowString(1,1,"success");
44	while(1)
45	{
46		
47	}
48}

完整工程代码见 : Wifi模块 – ESP8266