使用AT指令控制ESP8266 TCP单片机实现数据收发
目录
前言
ESP8266模式
AP 模式
station 模式
AP + station 共存模式
透传功能
透传需要先建立连接
无线网络参数
TCP连接参数
加密
UART 成帧机制
AT指令介绍
什么是AT指令?
AT指令类型
常用AT指令
ESP8266+TCP的AT指令示例
模块的客户端与服务器
模块的AP模式与Station模式
模块作为客户端 STA
模块作为服务器 STA
模块作为客户端 AP
模块作为服务器 AP
代码示例
模块为客户端STA
模块为客户端STA
前言
固件烧录
1.ESP8266 模块 AT(含MQTT)固件下载教程-CSDN博客
硬件接线(本篇代码基于2篇)
2.STM32通过串口发送AT命令控制ESP8266连接阿里云的代码-CSDN博客
主控芯片STM32f103c8t6,WIFI模块为ESP8266-01s
ESP8266模式
ESP8266 支持 softAP 模式,station 模式,softAP + station 共存模式三种。 利用 ESP8266 可以实现十分灵活的组网方式和网络拓扑。
AP 模式
AP:无线接入点,是一个无线网络的中心节点。通常使用的无线路由器就是一个无线接入点。
ESP8266 作为 AP,手机、电脑、用户设备、其他 ESP8266 station 接 口等均可以作为 station 连入ESP8266,组建成一个局域网。
station 模式
Station:即无线终端,是一个无线网络的终端。
ESP8266 作为 station,通过路由器(AP)连入 internet ,可向云端服务 器上传、下载数据。用户可随时使用移动终端(手机、笔记本等),通过云端监控 ESP8266 模块的状况,向 ESP8266 模块发送控制指令。
AP + station 共存模式
ESP8266 支持AP+station 共存的模式,用户设备、手机等可以作为 station 连入 ESP8266 的 softAP 接口,同时,可以控制 ESP8266 的 station 接口通过路由器(AP)连入 internet。
透传功能
透传,即透明传输功能。Host 通过 uart 将数据发给 ESP8266,ESP8266 再 通过无线网络将数据传出去;ESP8266 通过无线网络接收到的数据,同理通过 uart 传到Host。ESP8266 只负责将数据传到目标地址,不对数据进行处理,发送方和接收方的数据内容、长度完全一致,传输过程就好像透明一样。
透传需要先建立连接
无线网络参数
网络名称(SSID)
安全模式
密钥(password)
TCP连接参数
协议类型
连接类型 客户端(Client)或服务端(Server)
目的IP地址
目的端口
加密
ESP8266 支持多种无线网络加密方式
WEP (only station)
WPA-PSK/TKIP
WPA-PSK/AES
WPA2-PSK/TKIP
WPA2-PSK/AES
UART 成帧机制
ESP8266 判断 UART 传来的数据时间间隔,若时间间隔大于20ms,则认为一 帧结束;否则,一直接收数据到上限值2KB,认为一帧结束。ESP8266模块判断 UART 来的数据一帧结束后,通过WIFI接口将数据转发出去。 成帧时间间隔为20ms,一帧上限值为2KB。
AT指令介绍
什么是AT指令?
AT 指令(AT Commands)最早是由发明拨号调制解调器的贺氏公司为了控制拨号调制解调器而发明的控制协议。后来随着网络带宽的升级,速度很低的拨号调制解调器基本退出市场,但是 AT 指令被保留了下来。
在嵌入式开发中,经常是使用 AT 命令去控制各种通讯模块,比如 ESP8266 模块、4G 模块、GPRS 模块等等。一般就是主芯片通过硬件接口(比如串口、SPI)发送 AT 指令给通讯模块,模块接收到数据之后回应响应的数据。
AT指令类型
AT 指令分为四种类型:
类型 | 格式 | 功能 |
---|---|---|
测试指令 | AT + < X > = ? | 查询设置命令或内部程序设置的参数及其取值范围 |
查询指令 | AT + < X > ? | 返回参数的当前值 |
设置指令 | AT + < X > = < … > | 设置用户自定义的参数值 |
执行指令 | AT + < X > | 执行受模块内部程序控制的变参数不可变 |
AT 指令有近百条,但常用的就十几条,理解起来也非常简单,现在举例一些常用指令,并使用这些指令一步一步的通过 TCP 实现收发数据。
常用AT指令
AT指令 | 功能 |
---|---|
AT | 测试是否正常启动 |
AT+CWMODE=1 | 设置 STA 模式 |
AT+CWMODE=2 | 设置 AP 模式 |
AT+CWMODE=3 | 设置 AP+STA 模式 |
AT+RST | 重启生效 |
AT+CWSAP=”SSID”,”password”,1,4 | 设置 AP 参数:账号为SSID ,密码为password,通道号为 1,加密方式为:WPA_WPA2_PSK |
AT+CIPMUX=0 | 开启单连接 |
AT+CIPMUX=1 | 开启多连接 |
AT+CIPSERVER=1,8080 | 开启 SERVER 模式,设置端口为 8080 |
AT+CIPSTART=“TCP”,"192.168.X.XXX”,8080 |
建立 TCP 连接到”192.168.X.XXX”,8080 AT+CIPSTART="协议模式","服务端IP地址",端口号 |
AT+CIPSTART=“UDP”,“192.168.X.XXX”,8080 | 建立 UDP 连接到”192.168.X.XXX”,8080 |
AT+CIPCLOSE | 断开 TCP 连接 |
AT+CWQAP | 断开热点 |
AT+CIPSEND=n | 开始传输,n表示需要传输的字节数(单连接使用) |
AT+CIPSEND=0,n |
(多连接使用)AT+CIPSEND=<link ID>,<length> 向 ID0 发送 n 字节数据包,n的值自己定 |
AT+CIPMODE=0 | 普通传输模式 |
AT+CIPMODE=1 |
开启透传模式(仅⽀持 TCP 单连接和 UDP 固定通信对端的情况) |
AT+CIPSEND | 开始发送数据 |
AT+CIPMODE=0 | 退出透传 |
AT+CWJAP="SSID,“password” | 加入 WIFI 热点:SSID ,密码为:password |
AT+CIFSR | 查询 ESP8266 的 IP 地址 |
AT+CIPSTA? | 查询 ESP8266 的 IP 、网关地址和子网掩码 |
AT+RESTORE | 恢复出厂设置 |
注意:
透传模式传输时,如果连接断开,ESP8266 会不停尝试重连,此时单独输⼊ +++ 退出透传,则停⽌重连;普通传输模式则不会重连,提示连接断开。
AT+CIPSEND=0,n发送数据时。如果length大于实际发送的数据长度,则此次发送不发生,达到字节数再一起发送。如果length小于实际发送的长度,则此次发送length长度的数据,多余的数据截断丢失。发送的数据可以在接收端显示
ESP8266-01s模块恢复出厂设置后IP 地址为192.168.4.1
发送AT+CWMODE=1指令 IP 地址为0.0.0.0
sta模式下等待连上WIFI后又有新的IP地址
发送AT+CWMODE=2(或者3)IP 地址为192.168.4.1
连上服务器,客户端可与服务端通信,模块sta客户端与ap服务器接收格式:
+IPD,<数据长度>,<接收的数据>
模块发送AT+CIPMODE=1开启透传模式只接收数据,无包头(+IPD)和数据长度
AT+CIPSEND表示开始透传数据,+++停止透传数据,不改变AT+CIPMODE=1。
ESP8266+TCP的AT指令示例
模块的客户端与服务器
服务器:多连接;设置端口号 。
多连接不可用透传模式,需用 AT+CIPSEND=0,n 发送数据
客户端:单连接;设置连接的服务器IP及端口号
单连接可用透传模式,也可AT+CIPSEND=n发送数据
模块的AP模式与Station模式
AP模式:设置AP参数:SSID,password,通道数,加密方式
Station模式:设置路由器:SSID,password
这里的通道对应的就是不同的射频频率,如果同一空间内存在相同通道的 WIFI 信号,将会产生干扰,影响上网质量,因此可以设置通道来避免这种干扰
模块作为客户端 STA
AT+CWMODE=1 //设置模块 WIFI 模式为 STA 模式
AT+RST //重启模块生效
AT+CWJAP="k50","123456abc" //连接 WIFI热点,路由名字:k50,密码:123456abc
AT+CIPMUX=0 //设置单路连接模式
AT+CIPSTART="TCP","192.168.4.3",8080 //建立 TCP 连接到” 192.168.4.3”,8080
AT+CIPMODE=1 //开启透传模式
AT+CIPSEND //开始传输
+++ //(不加回车,只发一次),停止传输,仍为AT+CIPMODE=1
如果不退出透传,发出来的就算是 AT 指令,它也会被认为是普通字符串,直接透传给对方。
这里要注意服务端和模块要在同一个局域网才可以(即服务端和模块都连同一个WiFi)。
模块作为服务器 STA
AT+CWMODE=1 //设置模块 WIFI 模式为 STA 模式
AT+RST //重启模块生效
AT+CWJAP="k50","123456abc" //连接 WIFI热点,路由名字:k50,密码:123456abc
AT+CIPMUX=1 //开启多连接模式,即可以连接多个客户端
AT+CIPSERVER=1,8086 //开启服务器,端口号为 8086
AT+CIFSR //查询WiFi设备IP,用于客户端
AT+CIPSEND=0,5 //向 ID0 发送 5 字节的数据(多少个字符就对应输入多少,5则表示5个字符)
12345 //模块发送数据,在该模式下,每发一次数据之前都要发一次AT+CIPSEND=0,5指令才可以,接收端则不用每次都发,直接发数据即可。
进入客户端界面,正常连接成功是会提示连接成功的,如果没有,可以再次在电脑发送AT+CIPSERVER=1,8086指令就可以提示连接上了。
模块作为客户端 AP
AT+CWMODE=2 //设置模块 WIFI 模式为 AP 模式
AT+RST //重启模块生效
AT+CWSAP="ATK-ESP8266","12345678",1,4 //AP 参数:SSID 为 ATK-ESP8266,密码为 xxx,通道号为 1,加密方式为:WPA_WPA2_PSK
AT+CIPMUX=0 //开启单连接模式
AT+CIFSR //查询模块IP,与客户端建立连接时用到
AT+CIPSTART="TCP","192.168.xx.xxx",8086 //建立 TCP 连接到” 192.168.xx.xxx”,8088
AT+CIPMODE=1 //开启透传模式
AT+CIPSEND //开始传输
+++(不加回车,只发一次) //退出透传模式,发送一次即可(可以发+++后勾上发送新行再发AT测试是否退出透传模式)
模块作为服务器 AP
AT+CWMODE=2 //设置模块 WIFI 模式为 AP 模式
AT+RST //重启模块生效
AT+CWSAP="ATK-ESP8266","12345678",1,4 //AP 参数:SSID 为 ATK-ESP8266,密码为 xxx,通道号为 1,加密方式为:WPA_WPA2_PSK
AT+CIPMUX=1 //开启多连接模式,作为服务器最多支持5个客户端连接,id分配顺序是0-4
AT+CIPSERVER=1,8086 //开启 SERVER(服务器)模式,设置端口为 8086(自己定义)
AT+CIFSR //查询模块IP,与客户端建立连接时用到
AT+CIPSEND=0,5 //向 ID0 发送 5 字节数据包
12345 //模块发送数据,在该模式下,每发一次数据之前都要发一次AT+CIPSEND=0,5指令才可以,接收端则不用每次都发,直接发数据即可。
代码示例
AT指令函数(未测试)
uint8_t ESP8266_restore(void)
{
return ESP8266_SendCmd("AT+RESTORE\r\n", "ready");
}
uint8_t ESP8266_ate_config(uint8_t cfg)
{
switch (cfg) {
case 0:
return ESP8266_SendCmd("ATE0\r\n", "OK");
case 1:
return ESP8266_SendCmd("ATE1\r\n", "OK");
default:
return ESP8266_EINVAL;
}
}
char ip_buf[16];
uint8_t ESP8266_get_ip(char *buf)
{
char *p_start;
char *p_end;
if (ESP8266_SendCmd("AT+CIFSR\r\n", "STAIP") != REV_OK)
return REV_WAIT;
p_start = strstr((const char *)esp8266_buf, "\"");
p_end = strstr(p_start + 1, "\"");
*p_end = '\0';
sprintf(buf, "%s", p_start + 1);
return REV_OK;
}
UsartPrintf(USART_DEBUG,"ESP8266 IP: %s\r\n", ip_buf);
模块为客户端STA
宏定义+AT指令函数+ESP8266初始化
#define REV_OK 0 //接收完成标志位
#define REV_WAIT 1 //接受未完成标志位
#define ESP8266_EINVAL 2 //接收参数错误
#define ESP8266_STA_MODE 1
#define ESP8266_AP_MODE 2
#define ESP8266_STA_AP_MODE 3
#define WIFI_SSID "k50"
#define WIFI_PWD "123456abc"
#define TCP_SERVER_IP "192.168.0.105"
#define TCP_SERVER_PORT "8080"
uint8_t ESP8266_test_at(void)
{
return ESP8266_SendCmd("AT\r\n", "OK");
}
uint8_t ESP8266_set_mode(uint8_t mode)
{
switch (mode) {
case ESP8266_STA_MODE:
return ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK");
case ESP8266_AP_MODE:
return ESP8266_SendCmd("AT+CWMODE=2\r\n", "OK");
case ESP8266_STA_AP_MODE:
return ESP8266_SendCmd("AT+CWMODE=3\r\n", "OK");
default:
return ESP8266_EINVAL;
}
}
uint8_t ESP8266_reset(void)
{
return ESP8266_SendCmd("AT+RST\r\n", "OK");
}
uint8_t ESP8266_join_ap(char *ssid, char *pwd)
{
char cmd[64];
sprintf(cmd, "AT+CWJAP=\"%s\",\"%s\"\r\n", ssid, pwd);
return ESP8266_SendCmd(cmd, "WIFI GOT IP");
}
uint8_t ESP8266_single_connection(void)
{
return ESP8266_SendCmd("AT+CIPMUX=0\r\n", "OK");
}
uint8_t ESP8266_connect_tcp_server(char *server_ip, char *server_port)
{
char cmd[64];
sprintf(cmd, "AT+CIPSTART=\"TCP\",\"%s\",%s\r\n", server_ip, server_port);
return ESP8266_SendCmd(cmd, "CONNECT");
}
uint8_t ESP8266_enter_unvarnished(void)
{
uint8_t ret;
ret = ESP8266_SendCmd("AT+CIPMODE=1\r\n", "OK");
ret += ESP8266_SendCmd("AT+CIPSEND\r\n", ">");
if (ret == REV_OK)
return REV_OK;
else
return REV_WAIT;
}
uint8_t ESP8266_exit_unvarnished(void)
{
return ESP8266_SendCmd("+++", "");
}
uint8_t ESP8266_disconnect_tcp_server(void)
{
return ESP8266_SendCmd("AT+CIPCLOSE\r\n", "");
}
uint8_t ESP8266_Init(void)
{
ESP8266_Clear();
while(ESP8266_exit_unvarnished())
Delay_ms(500);
UsartPrintf(USART_DEBUG,"1.AT\r\n");
while(ESP8266_test_at())
Delay_ms(500);
UsartPrintf(USART_DEBUG,"2.RST\r\n");
while(ESP8266_reset())
Delay_ms(500);
while(ESP8266_disconnect_tcp_server())
Delay_ms(500);
UsartPrintf(USART_DEBUG,"3.CWMODE\r\n");
while(ESP8266_set_mode(ESP8266_STA_MODE))
Delay_ms(500);
UsartPrintf(USART_DEBUG,"4.AT+CIPMUX\r\n");
while(ESP8266_single_connection())
Delay_ms(500);
UsartPrintf(USART_DEBUG,"5.CWJAP\r\n");
while(ESP8266_join_ap(WIFI_SSID, WIFI_PWD))
Delay_ms(500);
UsartPrintf(USART_DEBUG,"6.CIPSTART\r\n");
while(ESP8266_connect_tcp_server(TCP_SERVER_IP, TCP_SERVER_PORT))
Delay_ms(500);
UsartPrintf(USART_DEBUG,"7.CIPMODE\r\n");
while(ESP8266_enter_unvarnished())
Delay_ms(500);
UsartPrintf(USART_DEBUG,"ESP8266_Init OK\r\n");
return REV_OK;
}
模块为客户端STA
宏定义+AT指令+ESP8266初始化+接收IPD数据
#define REV_OK 0 //接收完成标志位
#define REV_WAIT 1 //接受未完成标志位
#define ESP8266_EINVAL 2 //接收参数错误
#define ESP8266_STA_MODE 1
#define ESP8266_AP_MODE 2
#define ESP8266_STA_AP_MODE 3
#define WIFI_SSID "XAIOMI"
#define WIFI_PWD "123456abc"
//设置热点
uint8_t ESP8266_set_ap(char *ssid, char *pwd)
{
char cmd[64];
sprintf(cmd, "AT+CWSAP=\"%s\",\"%s\",5,3\r\n", ssid, pwd);
return ESP8266_SendCmd(cmd, "OK");
}
//设置多连接
uint8_t ESP8266_multi_connection(void)
{
return ESP8266_SendCmd("AT+CIPMUX=1\r\n", "OK");
}
//设置模式
uint8_t ESP8266_set_mode(uint8_t mode)
{
switch (mode) {
case ESP8266_STA_MODE:
return ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK");
case ESP8266_AP_MODE:
return ESP8266_SendCmd("AT+CWMODE=2\r\n", "OK");
case ESP8266_STA_AP_MODE:
return ESP8266_SendCmd("AT+CWMODE=3\r\n", "OK");
default:
return ESP8266_EINVAL;
}
}
//退出透传(不检验)
uint8_t ESP8266_exit_unvarnished(void)
{
return ESP8266_SendCmd("+++", "");
}
//设置服务器端口
uint8_t ESP8266_set_tcp_server()
{
char cmd[64];
sprintf(cmd, "AT+CIPSERVER=1,8080\r\n");
return ESP8266_SendCmd(cmd, "OK");
}
//AT测试
uint8_t ESP8266_test_at(void)
{
return ESP8266_SendCmd("AT\r\n", "OK");
}
断开服务器
uint8_t ESP8266_disconnect_tcp_server(void)
{
return ESP8266_SendCmd("AT+CIPCLOSE\r\n", "");
}
//RST复位
uint8_t ESP8266_reset(void)
{
return ESP8266_SendCmd("AT+RST\r\n", "OK");
}
ESP8266初始化
uint8_t ESP8266_Init(void)
{
ESP8266_Clear();
UsartPrintf(USART_DEBUG,"1.AT\r\n");
while(ESP8266_test_at())
Delay_ms(500);
UsartPrintf(USART_DEBUG,"2.CWMODE\r\n");
while(ESP8266_set_mode(ESP8266_AP_MODE))
Delay_ms(500);
UsartPrintf(USART_DEBUG,"3.RST\r\n");
while(ESP8266_reset())
Delay_ms(500);
UsartPrintf(USART_DEBUG,"4.AT+CIPMUX\r\n");
while(ESP8266_multi_connection())
Delay_ms(500);
UsartPrintf(USART_DEBUG,"5.CWJAP\r\n");
while(ESP8266_set_ap(WIFI_SSID, WIFI_PWD))
Delay_ms(500);
UsartPrintf(USART_DEBUG,"6.CIPSTART\r\n");
while(ESP8266_set_tcp_server())
Delay_ms(500);
UsartPrintf(USART_DEBUG,"ESP8266_Init OK\r\n");
return REV_OK;
}
//AT+CIPSEND多连接指定ID发送指定字长数据
char* tx_buf; //发送缓存区
uint8_t ESP8266_send_data(uint8_t ID ,uint8_t length)
{
char cmd[64];
char ret;
sprintf(cmd, "AT+CIPSEND=%d,%d\r\n",ID,length);
//UsartPrintf(USART_DEBUG,"cmd:%s\r\n",cmd);
ret = ESP8266_SendCmd(cmd, ">");
//UsartPrintf(USART_DEBUG,"1.ret:%d\r\n",ret);
ret += ESP8266_SendCmd(tx_buf,"OK");
//UsartPrintf(USART_DEBUG,"2.ret:%d\r\n",ret);
if (ret == REV_OK)
return REV_OK;
else
return REV_WAIT;
}
//AT+CIPSEND 主函数示例
if(ESP8266_send_data(0,strlen(tx_buf))!=REV_WAIT)
{
ESP8266_Clear();
}
else
{
UsartPrintf(USART_DEBUG,"SENDDATA ERROR!!!\r\n");
}//AT+CIPSEND
//该函数接收客户端IPD数据不稳定
/**
* @brief esp8266接收数据
* @param[in] none
* @retval 0-接收数据正常 1-接收数据异常或无数据
*/
uint8_t esp8266_receive_msg(void)
{
uint8_t retval =0;
int msg_len=0;
uint8_t msg_body[128] = {0};
if(receive_start == 1) //接收到数据,中断置1
{
do
{
receive_finish++; //等待串口接收不到数据后再延时5ms
Delay_ms(1);
}while(receive_finish < 5);
if(strstr((const char*)esp8266_buf,"+IPD"))//如果数据中有关键字
{
UsartPrintf(USART_DEBUG,"esp8266_buf:%s\r\n",esp8266_buf);
sscanf((const char *)esp8266_buf,"+IPD,0,%d:%s",&msg_len,msg_body);
UsartPrintf(USART_DEBUG,"len:%d,msg:%s\r\n",msg_len,msg_body);
if(strlen((const char*)msg_body)== msg_len)//校验数据
{
retval = 0;
}
else
{
retval = 1;
}
}
else
{
retval = 1;
}
}
else
{
retval = 1;
}
ESP8266_Clear();
return retval;
}
参考文档
2015050816423759wnte.pdf (dfrobot.com.cn)
参考文章
手把手教你玩转ESP8266(原理+驱动) – 良许Linux – 博客园 (cnblogs.com)
ESP8266 WIFI 模块和手机通信_esp8266wifi模块怎么连接手机-CSDN博客
作者:我不吃代码