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