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