关于ESP8266的介绍我已经看到恶心了,相同的内容到处都是,没有几个有实际价值的适合新手刚刚入门的内容。博主经过亲身实验,在成功之后在这里记录一下。一来方便引导新手,二来方便大家交流学习,最重要的是我时间久了容易忘记内容,方便自己进行查找。目前仅仅是连接通过TCP连接访问服务器
在这里说一下,本文只是ESP8266简单的使用,没有过于详细的命令讲解关于命令可以查询相应的手册,或者网络资料非常多。我使用的是独立小模块ESP-01S,就是这种:
不是直接又控制芯片的ESP32。
这里是我购买的产品的公司的AT指令示例
能用到的代码我会尽量展示全。
1.硬件需求
如果仅仅是测试那只需要电脑和TTL电平转USB的转换器就好了,然后电脑打开串口调试助手,接线完成就可以实验了。如果没有合适的串口调试助可以点这个?
(恬不知耻地在这为自己宣传)
如果你想连接STM32,难么需要在单片机上留出一个USART,配置成115200波特率的8N1。部分模块需要增加一个使能管脚,如果你想也可以在为它留一个外部复位管脚(反正我是都没有,不过也有这个想法,但是资源不允许呀)。
2.操作流程
1.ESP8266 station模式的操作逻辑流程:
0.检查AT命令是不是能用
1.配置成Sation模式
2.连接到wifi
2.1可以查询一下自己的地址
3.连接到服务器
4.发送数据
5.如果是单链接模式,想更换服务器,先断开现在连接的
具体为啥要单链接:因为透传模式必须是单链接。
啥是透传模式:就是给啥转发啥,不管是数据还是命令。也就是说透传模式不会识别命令,具体怎么玩后面专门记录。

2.ESP8266 AP模式的操作逻辑流程
0.检查AT命令是不是能用
1.配置成AP模式
2.配置AP信息
2.1可以查询一下自己的地址
3.开启多连接(如果要开服务器的话,必须是多连接)
4.开启服务器和设置端口(一个命令)
5.等待接收数据

3.透传模式的进去和退出
配置透传模式需要几个命令:
建立好连接后:
设置成单链接模式(只能在单链接模式)
AT+CIPMUX=0
设置为透传模式
AT+CIPMODE=1
进入透传模式
AT+CIPSEND
具体时先建立连接在设置透传模式,还是先设置为透传模式在建立连接都可以。但是一定在进去透传模式命令发送前建立连接。在模块给你发完 ‘》’ 符号时就设置完成了。
然后就可以欢乐的传数据了,你发啥它转发啥。如果你在电脑上开了电脑的上的网络调试助手你可以看到模块给你发的内容:

发现什么问题没?
–为啥我的AT命令也直接发出去了?!
在透传模式下无论你给ESP8266发啥,它都会无脑转出去,即使是命令(此刻的模块已经放飞自我,不受控制了)。如果想要重新可以获得控制权就需要向它发送退出透传命令。
–EXM?都说了它已经不听命令了,咋还说要发命令!垃圾博主,说的屁话,不看了!
大哥留步!这是一条非常特殊的命令!它长得就和人家不一样!
+++
你没看错,就是三个加号。在这里多说一句,所有的AT命令后面都要加回车换行就是C语言的转义字符 rn ,不然不识别。但是这里一!定!不!要!加!为啥? 因为人家就是不一样。
这里就要说到一个坑。退出透传命令必须要发送前有时间间隔,发送后有时间间隔,根据我实验,最短200ms即可(有些资料上写需要1s)。这里实验效果不明显,就不展示了,各位有兴趣可以自己亲自实验。
–既然透传模式设置和退出这么麻烦,那为什么要设置透传模式?
在发送大量数据,或者我们建立好连接后就需要反反复复发数据,而不会控制硬件设备的操作时,透传就体现除优越性了。至少可以减少每次发数据的命令。
4.C语言程序源码
扯了这么多,你是不是差点忘了你来是为了啥(别以为我不知道,这也是我曾经整个CSDN找资料的目的)。程序的逻辑和代码就在这里(使用的是Keil,所以代码注释在这里显示乱码,不要管,我另外有注释)。
理一下思路先:
1.我们需要控制串口收发命令。具体发送的是ASCLL码。
2.我们需要通过串口接收数据,接收的也是SACLL码。
3.我们要能识别什么时候模块发送完了。使用定时器计时,需要定义一个全局变量 ESP_RX_STATE 作为串口接收到数据的标志
4.接收完能够处理接收的结果(这里只讲返回数据识别)
1.配置串口
先配置一下USART2,具体配置方法不做多余解释,TXD-》PA2、RXD-》PA3。代码如下:
//宏定义
//ÍøÂç´®¿ÚʱÖÓ
#define ESP_RCC RCC_APB1Periph_USART2
//ÍøÂç´®¿Ú·¢ËͶ˿Ú
#define ESP_TX_PIN GPIO_Pin_2 //PA2
#define ESP_TX_GPIO GPIOA
//ÍøÂç´®¿Ú½ÓÊն˿Ú
#define ESP_RX_PIN GPIO_Pin_3 //PA3
#define ESP_RX_GPIO GPIOA
#define ESP_USART USART2
//wifi串口初始化 wifi´®¿Ú³õʼ»¯
void ESP_Usart_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //¿ªÆôGPIOAʱÖÓ
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //¿ªÆô¶Ë¿Ú¸´ÓÃʱÖÓ
RCC_APB1PeriphClockCmd(ESP_RCC, ENABLE); //¿ªÆôesp´®¿ÚʱÖÓ
USART_DeInit(ESP_USART); //¸´Î»esp´®¿Ú
//发送端口 ·¢ËͶ˿Ú
GPIO_InitStructure.GPIO_Pin = ESP_TX_PIN; //PA2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //¸´ÓÃÍÆÍìÊä³ö
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(ESP_TX_GPIO, &GPIO_InitStructure);
//接收端口 ½ÓÊն˿Ú
GPIO_InitStructure.GPIO_Pin = ESP_RX_PIN; //PA3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //¸´Óø¡¿ÕÊäÈë
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(ESP_RX_GPIO, &GPIO_InitStructure);
//ÅäÖô®¿Úģʽ
USART_DeInit(ESP_USART);
USART_InitStructure.USART_BaudRate = 115200; //ÉèÖò¨ÌØÂÊΪ115200bps
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //Êý¾ÝλΪ8λ
USART_InitStructure.USART_StopBits = USART_StopBits_1; //ֹͣλ1λ
USART_InitStructure.USART_Parity = USART_Parity_No; //ÎÞУÑéλ
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //·¢ËÍ¡¢½ÓÊÕģʽ´ò¿ª
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //ÎÞÓ²¼þ¿ØÖÆÁ÷¿Ø
USART_Init(ESP_USART, &USART_InitStructure); //´«ËÍÅäÖòÎÊý
USART_ClearFlag(ESP_USART, USART_FLAG_CTS); //Çå³ý·¢ËÍÍê³É±ê־λ
USART_Cmd(ESP_USART, ENABLE); //ʹÄÜ´®¿Ú1
USART_ITConfig(ESP_USART, USART_IT_RXNE, ENABLE); //¿ªÆô½ÓÊÕÖÐ¶Ï £¨1×Ö½ÚÒ»´ÎÖжϣ©
// USART_ITConfig(ESP_USART, USART_IT_IDLE, ENABLE); //¿ªÆô¿ÕÏÐÖжϣ¨8×Ö½ÚÒ»´ÎÖжϣ©
//ÉèÖÃNVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //ÉèÖô®¿Ú2ÖжÏ
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0; //ÇÀÕ¼ÓÅÏȼ¶
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //×ÓÓÅÏȼ¶Îª1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //ʹÄÜ
NVIC_Init(&NVIC_InitStructure);
printf(“## ESP_usart_config_over ##rn”);
}
2.配置定时器
还需要一个定时器,我是用的是TIM3,配置成10ms中断,并写中断函数
//定义一个全局变量用来指示是否接收到数据
//超过10ms没有收到数据认为接收结束,则ESP_RX_STATE增加1。即定时器中断就加1
u8 ESP_RX_STATE = 0; //³õʼ»¯ÒѽÓÊÕÊý¾ÝΪ0
//在头文件中声明外部变量,这样可以在其他C文件中调用
extern u8 ESP_RX_STATE; //½ÓÊÕÍê³É״̬
//定时器TIM3中断优先级配置¶¨Ê±Æ÷TIM3ÖжÏÓÅÏȼ¶ÅäÖÃ
void TIM3_NVIC_config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //ÉèÖÃ×éÓÅÏȼ¶
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //ÉèÖö¨Ê±Æ÷3ÖжÏÏß
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //ÉèÖÃÇÀÕ¼ÓÅÏȼ¶
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //ÉèÖÃ×ÓÓÅÏȼ¶2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //ʹÄÜIRQÖжÏ
NVIC_Init(&NVIC_InitStructure);
}
//定时器TIM3初始化,10ms¶¨Ê±Æ÷TIME3³õʼ»¯,10ms
void TIM3_init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //TIM3³õʼ»¯½á¹¹Ìå
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //¿ªÆôʱÖÓ
TIM_DeInit(TIM3); //½«ÍâÉèTIM3¼Ä´æÆ÷ÖØÉèΪȱʡֵ
TIM_TimeBaseStructure.TIM_Period = (2000-1); //×Ô¶¯ÖØ×°ÔؼĴæÆ÷Öµ
TIM_TimeBaseStructure.TIM_Prescaler =(3600-1); //ʱÖÓÔ¤·ÖƵÊý
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //²ÉÑù·ÖƵ£¬Ê¹¼ÆʱÆ÷¹¤×÷ƵÂÊΪ72MHz
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//ÏòÉϼÆÊýģʽ
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); //ÅäÖö¨Ê±Æ÷
TIM3_NVIC_config(); //ÅäÖÃTIM3ÖжÏÓÅÏȼ¶
TIM_ClearFlag(TIM3, TIM_FLAG_Update); //Çå³ý±ê־λ
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //ÖжÏÅäÖÃ
// TIM_Cmd(TIM3, ENABLE); //ʹÄܶ¨Ê±Æ÷TIM3
}
//TIM3中断函数TIM3ÖжϺ¯Êý
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //²úÉúÖжÏ
{
ESP_RX_STATE ++; //超过10ms,数据接收完毕,计数+1 ³¬¹ý10ms£¬Êý¾Ý½ÓÊÕÍê±Ï£¬¼ÆÊý+1
}
TIM_ClearITPendingBit(TIM3, TIM_FLAG_Update); // Çå³ýÖжϱêÖ¾
TIM_Cmd(TIM3, DISABLE); //¹Ø±ÕTIM3
}
3.准备接收缓冲区
在准备接收数据之前得先准备一个地方用来存储数据吧。我们为了简洁高效,使用循环队列作为数据接收的缓冲区
//宏定义缓冲队列最大存储上限
#define ESP_BUF_SIZE 1024 //ESP»º³åÇø×î´óÈÝÁ¿
//循环对列结构体
typedef struct
{
unsigned char buf[ESP_BUF_SIZE];
unsigned short int length;
unsigned short int fornt; //ESP¶ÓÁÐÍ·Ö¸Õë
unsigned short int rear; //ESP¶ÓÁÐβָÕë
}ESP_BufTypeDef; //¶¨ÒåESPÑ»·¶ÓÁлº³åÇø½á¹¹Ìå
//声明一个队列缓冲区,作为全局变量
ESP_BufTypeDef ESP_RX_BUF; //Wifi´®¿Ú½ÓÊÕ»º³åÇø
//在头文件中声明外部变量,这样可以在其他C文件中调用
extern ESP_BufTypeDef ESP_RX_BUF; //Wifi´®¿Ú½ÓÊÕ»º³åÇø
//接收缓冲区初始化ESP½ÓÊÕ»º³åÇø³õʼ»¯
void ESP_Rxbuf_Init(void)
{
int i ;
memset(ESP_RX_BUF.buf,0,sizeof(ESP_RX_BUF.buf)); //使用memset()函数需要包含头文件《string.h》
// for(i=0;i《 ESP_BUF_SIZE; i++)
// {
// ESP_RX_BUF.buf[i] = 0;
// }
ESP_RX_BUF.fornt = 0;
ESP_RX_BUF.length = 0;
ESP_RX_BUF.rear = 0;
ESP_RX_STATE = 0; //ÔÊÐí½ÓÊÕÊý¾Ý
}
到这里接收的数据存储位置也准备好了。
4.串口中断函数
可是定时器中断函数好了,存储位置准备好了,没有数据过来也是不行的呀。那就来写数据接收过程,即网络串口接收中断函数(USART2的中断函数):
//串口接收中断函数´®¿Ú½ÓÊÕÖжϺ¯Êý
void USART2_IRQHandler(void)
{
u8 rev_byte;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //Åж϶ȼĴæÆ÷ÊÇ·ñΪ·Ç¿Õ
{
rev_byte = USART_ReceiveData(USART2); //接收数据½ÓÊÕÊý¾Ý
if(ESP_RX_BUF.length 《= ESP_BUF_SIZE) //如果数据没有溢出Èç¹ûÊý¾ÝûÓÐÒç³ö
{
ESP_RX_BUF.buf[ESP_RX_BUF.rear] = rev_byte; //将数据存入缓冲区尾部½«Êý¾Ý´æÈëBUFF»º³åÇøβ²¿
ESP_RX_BUF.length ++; //缓冲区长度增加»º³åÇø³¤¶ÈÔö¼Ó
ESP_RX_BUF.rear = (ESP_RX_BUF.rear + 1) % ESP_BUF_SIZE; //尾指针+1,防止溢出,实现循环队列·ÀÖ¹Òç³ö
}
//这里的TIM3其实可以用宏定义,这样可以方便更改使用的定时器
TIM_SetCounter(TIM3,0); //定时器清空¼ÆÊýÆ÷Çå¿Õ
TIM_Cmd(TIM3,ENABLE); //使能定时器ʹÄܶ¨Ê±Æ÷
}
USART_ClearITPendingBit(USART2, USART_IT_RXNE); //清除标志Çå³ý±êÖ¾
}
如此,我们就可以将接收到的数据保存起来了。
5.读取缓冲队列函数
但是好像还是不行,只是保存起来,却不能使用,你说难不难受。
//读取ESP队列的数据¶ÁÈ¡espÊý¾Ý½ÓÊÕ¶ÓÁеÄÊý¾Ý
u8 ESP_Read_Quene_Data(ESP_BufTypeDef* Rx_buf)
{
u8 read_data_temp;
if(Rx_buf-》length == 0) //没有数据
{
read_data_temp = 0;
}
else
{
read_data_temp = Rx_buf-》buf[Rx_buf-》fornt]; //读出头指针所指的数据
Rx_buf-》fornt = (Rx_buf-》fornt + 1) % ESP_BUF_SIZE;//头指针增加
Rx_buf-》length --; //数据长度减少
}
return read_data_temp; //返回读取的结果
}
读取数据是不是很简单。
6.串口发送数据函数
既然可以接收和读取了,那怎么发送数据呢?这里就要使用到串口发送数据的方法了,如果回使用或者已经写好的可跳过:
/*-----------------------------------------
*串口发送字符串函数´®¿Ú·¢ËÍ×Ö·û´®º¯Êý
* USARTx Ö¸¶¨·¢Ë͵Ĵ®¿Ú
* *DataÖ¸¶¨´ý·¢Ë͵Ä×Ö·û´®
* 发送遇到字符串结束符‘ ’结束·¢ËÍÓöµ½×Ö·û´®½áÊø·û‘ ’½áÊø
-----------------------------------------*/
//这个函数讲真写的不是太好,有更好的大家可以修改
void USART_Send_String(USART_TypeDef* USARTx, u8 *Data, 。..)
{//使用变长参数,具体实现原理可百度
//·ÖÅäÄÚ´æ
va_list valist;
//ΪÊäÈëµÄ²ÎÊý³õʼ»¯
va_start(valist, Data);
while(*Data != ‘ ’)
{
USART_SendData(USARTx, *Data);
while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET); //µÈ´ý´®¿Ú·¢ËÍÍêÊý¾Ý
Data++;
}
//ÇåÀíΪvalist±£ÁôµÄÄÚ´æ
va_end(valist);
}
至此,我们的准备工作就算完成了,要真正开始操刀对ESP8266下手了。
7.读取回复信号函数
根据手册,我们可以知道,我们可以给ESP8266发送命令,然后它会回给我们相应的结果。我们也可以给它发数据,但是要先发相应的命令,然后跟着发送数据。所以我们先写发送命令函数,但是好像有个问题:发送完命令紧跟着是得到命令的结果,不然我们也不知道模块有没有执行。所以不要着急开始写CMD函数,先来写回复函数:
//讲真这是非常失败的函数,但是可以实现
//宏定义返回值
#define ACK_SUCCESS 1
#define ACK_DEFEAT 0
u8 ESP_Check_Ack(char *string) //¼ì²éÏàÓ¦»Ø¸´ÐźÅ
{
char *str_temp; //被检测的字符串的临时变量
u8 data_temp;
u8 rx_buff_temp[150]={0}; //临时存放接收到的数据ÁÙʱ´æ´¢½ÓÊÕµ½µÄÊý¾Ý
u8 pt_temp = 0; //rx_buff_temp的下标rx_buff_tempµÄϱê
u8 length_temp = 0; //临时数组的当前长度
str_temp = string;
if(ESP_RX_STATE 》 0) //Èç¹û½ÓÊÕÊý¾Ý½áÊø
{
//»ñÈ¡ÊÕµ½µÄ»Ø¸´ ÖÁÁÙʱÊý×飬±ãÓÚÅжÏ
do
{
if(length_temp 《 150)
{
data_temp = ESP_Read_Quene_Data(&ESP_RX_BUF);//从缓冲区读取一个值到数组
rx_buff_temp[pt_temp] = data_temp;
pt_temp ++; //下标向后移动一位
length_temp ++;
}
else
break; //³¬³ö´æ´¢ÉÏÏÞ£¬Ã»ÓÐÊÕµ½¡® ¡¯Ôò»áËÀÑ»·£¬Ìø³öµ±Ç°Ñ»·
}
while(data_temp != ‘ ’);
ESP_RX_STATE --; //读取完一个字符串,接收区计数减一¶ÁÈ¡ÍêÒ»¸ö½ÓÊÕµÄ×Ö·û´®£¬¼ÆÊý-1
}
//ÅжÏÊÇ·ñ·ûºÏÆÚÍûÐźÅ
if(strstr((const char *)rx_buff_temp, (const char *)str_temp ) != NULL) //检测到有想要的回复,就能得到不为空的地址
return ACK_SUCCESS; //返回成功Èç¹û·µ»ØµØÖ·²»Îª¿Õ£¬·µ»ØÓÐЧ
else
return ACK_DEFEAT; //如果没有,就是失败·ñÔò£¬·µ»Øʧ°Ü
}
8.发送命令函数
有检查回复信号的函数后就可以写命令函数了:
/*--------------------------------------------------
* ·¢ËÍÖ¸ÁϣÍûµÃµ½»Ø¸´
* *cmd 发送的命令
* *ack 希望得到的回复
* waittime 等待的时长
* ·µ»ØÖµ ACK_SUCCESS£¬·¢Ëͳɹ¦
* ACK_DEFEAT£¬·¢ËÍʧ°Ü
---------------------------------------------------*/
u8 ESP_Send_Cmd(char *cmd, char *ack, u16 waittime )
{//其实这里也可以写成边长参数的,而且会极大的方便后面发送命令,不过博主是写完功能了才学会的边长参数,后面我会在我程序中修改
USART_Send_String(ESP_USART, (u8 *)cmd); //直接使用发送字符串函数
while(waittime-- )
{
if(ESP_Check_Ack(ack) == ACK_SUCCESS)
{
return ACK_SUCCESS;
}
delay_ms(10); //每次等待10ms,所以waittime为20的时候,实际等待200ms
}
return ACK_DEFEAT;
}
是不是很简单。
9.发送数据函数
下面就是发送数据函数,之所以最后写,是因为发数据之前要发送一个命令,告诉ESP8266我要发数据了:
/*----------------------------------------------------
* ·¢ËÍÊý¾Ý¸øwifiÄ£¿é£¬
* *data为要发送的数据*dataΪ·¢Ë͵ÄÊý¾Ý
----------------------------------------------------*/
void ESP_Send_Data(u8 *data)
{
char cmdbuf_temp[32]; //整合命令使用的临时数组
unsigned short len; //发送数据的长度
len = sizeof(data);
sprintf(cmdbuf_temp,“AT+CIPSEND=%drn”, len);//格式化的命令写入命令字符串中,就是把长度加上°Ñ¸ñʽ»¯µÄÊý¾ÝдÈëij¸ö×Ö·û´®ÖÐ
if(ESP_Send_Cmd(cmdbuf_temp, “》”, 200) == ACK_SUCCESS) //检测接收数据是否包含‘》’¼ì²é½ÓÊÕÊý¾ÝÊÇ·ñΪ¡°》¡±
{
USART_Send_String(ESP_USART, data); //发送数据·¢ËÍÊý¾Ý
}
}
因为本篇写的是ESP8266连接服务器的方法,所以作为AP时候使用的接收数据解析IPD就不写了。至此,所有函数写完了。
10.连接TCP并发送数据演示
在使用的时候,先把ESP8266的端口配置初始化,缓冲区初始化。然后愉快的使用ESP_Send_Cmd函数发送命令,控制模块就好了。
这里我展示一个连接TCP并开启透传模式的过程。只是简单演示如何使用,在实际发送命令过程中返回失败还是很多的,所以要有容错,读者自己思考。
#define wifi_information “AT+CWJAP_DEF=”wifi名称“,”wifi密码“rn”
#define tcp_information “AT+CIPSTART=”TCP“,”TCP地址“,端口号rn”
if(ESP_Send_Cmd(“ATrn”,“OK”,20) == ACK_DEFEAT) //测试一下AT命令
{
delay_ms(50);
ESP_Send_Cmd(“+++”,“”,0); //Í˳ö͸´«Ä£Ê½
delay_ms(50);
}
ESP_Send_Cmd(“AT+CWMODE=1rn”,“OK”,20);//设置成Station模式
//一定要重启!!!
ESP_Send_Cmd(“AT+RSTrn”,“ready”,20);
delay_ms(1000); //一般1s就可以,也可以设置时间长一些
ESP_Rxbuf_Init(); //往往启动是时候模块会发版本信息,清空一下
printf(“Connecting to Wifi.rn”);
if(ESP_Send_Cmd(“AT+CWJAP_DEF?rn”,“No AP”,50) == ACK_SUCCESS) //返回没有连接AP·µ»ØûÓÐÁ¬½ÓAP
{
for(count_up = 0; count_up 《 5; count_up ++ ) //Ñ»·Á¬½Ó5´Î
{
if(ESP_Send_Cmd(wifi_information, “WIFI GOT IP”, 600) == ACK_SUCCESS) //如果连接成功Èç¹ûÁ¬½Ó³É¹¦
{
printf(“Have conntected.rn”);
break;
}else
{
printf(“Rejoin Wifi.rn”);
}
}
}
//此处可以添加如果重连5次都失败的处理方法
/*有时候遇到部分8266在链接TCP后不能进行单路链接设置*/
ESP_Send_Cmd(“AT+CIPMUX=0rn”,“OK”,15); //单路连接模式
ESP_Send_Cmd(tcp_information, “CONNECT”, 50); //连接到TCP
//这里其实就可以使用发送数据函数ESP_Send_Data开始发数据了
//ESP_Send_Data(“Hllow word!n”)
ESP_Send_Cmd(“AT+CIPMODE=1rn”,“OK”,20); //进去透传模式
ESP_Send_Cmd(“AT+CIPSENDrn”,“OK”,20); //进入透传模式
//透传模式直接使用串口发送函数即可
USART_Send_String(USART2, “Anything!”);
大功告成!
关于ESP8266的介绍我已经看到恶心了,相同的内容到处都是,没有几个有实际价值的适合新手刚刚入门的内容。博主经过亲身实验,在成功之后在这里记录一下。一来方便引导新手,二来方便大家交流学习,最重要的是我时间久了容易忘记内容,方便自己进行查找。目前仅仅是连接通过TCP连接访问服务器
在这里说一下,本文只是ESP8266简单的使用,没有过于详细的命令讲解关于命令可以查询相应的手册,或者网络资料非常多。我使用的是独立小模块ESP-01S,就是这种:
不是直接又控制芯片的ESP32。
这里是我购买的产品的公司的AT指令示例
能用到的代码我会尽量展示全。
1.硬件需求
如果仅仅是测试那只需要电脑和TTL电平转USB的转换器就好了,然后电脑打开串口调试助手,接线完成就可以实验了。如果没有合适的串口调试助可以点这个?
(恬不知耻地在这为自己宣传)
如果你想连接STM32,难么需要在单片机上留出一个USART,配置成115200波特率的8N1。部分模块需要增加一个使能管脚,如果你想也可以在为它留一个外部复位管脚(反正我是都没有,不过也有这个想法,但是资源不允许呀)。
2.操作流程
1.ESP8266 station模式的操作逻辑流程:
0.检查AT命令是不是能用
1.配置成Sation模式
2.连接到wifi
2.1可以查询一下自己的地址
3.连接到服务器
4.发送数据
5.如果是单链接模式,想更换服务器,先断开现在连接的
具体为啥要单链接:因为透传模式必须是单链接。
啥是透传模式:就是给啥转发啥,不管是数据还是命令。也就是说透传模式不会识别命令,具体怎么玩后面专门记录。

2.ESP8266 AP模式的操作逻辑流程
0.检查AT命令是不是能用
1.配置成AP模式
2.配置AP信息
2.1可以查询一下自己的地址
3.开启多连接(如果要开服务器的话,必须是多连接)
4.开启服务器和设置端口(一个命令)
5.等待接收数据

3.透传模式的进去和退出
配置透传模式需要几个命令:
建立好连接后:
设置成单链接模式(只能在单链接模式)
AT+CIPMUX=0
设置为透传模式
AT+CIPMODE=1
进入透传模式
AT+CIPSEND
具体时先建立连接在设置透传模式,还是先设置为透传模式在建立连接都可以。但是一定在进去透传模式命令发送前建立连接。在模块给你发完 ‘》’ 符号时就设置完成了。
然后就可以欢乐的传数据了,你发啥它转发啥。如果你在电脑上开了电脑的上的网络调试助手你可以看到模块给你发的内容:

发现什么问题没?
–为啥我的AT命令也直接发出去了?!
在透传模式下无论你给ESP8266发啥,它都会无脑转出去,即使是命令(此刻的模块已经放飞自我,不受控制了)。如果想要重新可以获得控制权就需要向它发送退出透传命令。
–EXM?都说了它已经不听命令了,咋还说要发命令!垃圾博主,说的屁话,不看了!
大哥留步!这是一条非常特殊的命令!它长得就和人家不一样!
+++
你没看错,就是三个加号。在这里多说一句,所有的AT命令后面都要加回车换行就是C语言的转义字符 rn ,不然不识别。但是这里一!定!不!要!加!为啥? 因为人家就是不一样。
这里就要说到一个坑。退出透传命令必须要发送前有时间间隔,发送后有时间间隔,根据我实验,最短200ms即可(有些资料上写需要1s)。这里实验效果不明显,就不展示了,各位有兴趣可以自己亲自实验。
–既然透传模式设置和退出这么麻烦,那为什么要设置透传模式?
在发送大量数据,或者我们建立好连接后就需要反反复复发数据,而不会控制硬件设备的操作时,透传就体现除优越性了。至少可以减少每次发数据的命令。
4.C语言程序源码
扯了这么多,你是不是差点忘了你来是为了啥(别以为我不知道,这也是我曾经整个CSDN找资料的目的)。程序的逻辑和代码就在这里(使用的是Keil,所以代码注释在这里显示乱码,不要管,我另外有注释)。
理一下思路先:
1.我们需要控制串口收发命令。具体发送的是ASCLL码。
2.我们需要通过串口接收数据,接收的也是SACLL码。
3.我们要能识别什么时候模块发送完了。使用定时器计时,需要定义一个全局变量 ESP_RX_STATE 作为串口接收到数据的标志
4.接收完能够处理接收的结果(这里只讲返回数据识别)
1.配置串口
先配置一下USART2,具体配置方法不做多余解释,TXD-》PA2、RXD-》PA3。代码如下:
//宏定义
//ÍøÂç´®¿ÚʱÖÓ
#define ESP_RCC RCC_APB1Periph_USART2
//ÍøÂç´®¿Ú·¢ËͶ˿Ú
#define ESP_TX_PIN GPIO_Pin_2 //PA2
#define ESP_TX_GPIO GPIOA
//ÍøÂç´®¿Ú½ÓÊն˿Ú
#define ESP_RX_PIN GPIO_Pin_3 //PA3
#define ESP_RX_GPIO GPIOA
#define ESP_USART USART2
//wifi串口初始化 wifi´®¿Ú³õʼ»¯
void ESP_Usart_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //¿ªÆôGPIOAʱÖÓ
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //¿ªÆô¶Ë¿Ú¸´ÓÃʱÖÓ
RCC_APB1PeriphClockCmd(ESP_RCC, ENABLE); //¿ªÆôesp´®¿ÚʱÖÓ
USART_DeInit(ESP_USART); //¸´Î»esp´®¿Ú
//发送端口 ·¢ËͶ˿Ú
GPIO_InitStructure.GPIO_Pin = ESP_TX_PIN; //PA2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //¸´ÓÃÍÆÍìÊä³ö
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(ESP_TX_GPIO, &GPIO_InitStructure);
//接收端口 ½ÓÊն˿Ú
GPIO_InitStructure.GPIO_Pin = ESP_RX_PIN; //PA3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //¸´Óø¡¿ÕÊäÈë
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(ESP_RX_GPIO, &GPIO_InitStructure);
//ÅäÖô®¿Úģʽ
USART_DeInit(ESP_USART);
USART_InitStructure.USART_BaudRate = 115200; //ÉèÖò¨ÌØÂÊΪ115200bps
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //Êý¾ÝλΪ8λ
USART_InitStructure.USART_StopBits = USART_StopBits_1; //ֹͣλ1λ
USART_InitStructure.USART_Parity = USART_Parity_No; //ÎÞУÑéλ
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //·¢ËÍ¡¢½ÓÊÕģʽ´ò¿ª
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //ÎÞÓ²¼þ¿ØÖÆÁ÷¿Ø
USART_Init(ESP_USART, &USART_InitStructure); //´«ËÍÅäÖòÎÊý
USART_ClearFlag(ESP_USART, USART_FLAG_CTS); //Çå³ý·¢ËÍÍê³É±ê־λ
USART_Cmd(ESP_USART, ENABLE); //ʹÄÜ´®¿Ú1
USART_ITConfig(ESP_USART, USART_IT_RXNE, ENABLE); //¿ªÆô½ÓÊÕÖÐ¶Ï £¨1×Ö½ÚÒ»´ÎÖжϣ©
// USART_ITConfig(ESP_USART, USART_IT_IDLE, ENABLE); //¿ªÆô¿ÕÏÐÖжϣ¨8×Ö½ÚÒ»´ÎÖжϣ©
//ÉèÖÃNVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //ÉèÖô®¿Ú2ÖжÏ
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0; //ÇÀÕ¼ÓÅÏȼ¶
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //×ÓÓÅÏȼ¶Îª1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //ʹÄÜ
NVIC_Init(&NVIC_InitStructure);
printf(“## ESP_usart_config_over ##rn”);
}
2.配置定时器
还需要一个定时器,我是用的是TIM3,配置成10ms中断,并写中断函数
//定义一个全局变量用来指示是否接收到数据
//超过10ms没有收到数据认为接收结束,则ESP_RX_STATE增加1。即定时器中断就加1
u8 ESP_RX_STATE = 0; //³õʼ»¯ÒѽÓÊÕÊý¾ÝΪ0
//在头文件中声明外部变量,这样可以在其他C文件中调用
extern u8 ESP_RX_STATE; //½ÓÊÕÍê³É״̬
//定时器TIM3中断优先级配置¶¨Ê±Æ÷TIM3ÖжÏÓÅÏȼ¶ÅäÖÃ
void TIM3_NVIC_config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //ÉèÖÃ×éÓÅÏȼ¶
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //ÉèÖö¨Ê±Æ÷3ÖжÏÏß
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //ÉèÖÃÇÀÕ¼ÓÅÏȼ¶
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //ÉèÖÃ×ÓÓÅÏȼ¶2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //ʹÄÜIRQÖжÏ
NVIC_Init(&NVIC_InitStructure);
}
//定时器TIM3初始化,10ms¶¨Ê±Æ÷TIME3³õʼ»¯,10ms
void TIM3_init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //TIM3³õʼ»¯½á¹¹Ìå
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //¿ªÆôʱÖÓ
TIM_DeInit(TIM3); //½«ÍâÉèTIM3¼Ä´æÆ÷ÖØÉèΪȱʡֵ
TIM_TimeBaseStructure.TIM_Period = (2000-1); //×Ô¶¯ÖØ×°ÔؼĴæÆ÷Öµ
TIM_TimeBaseStructure.TIM_Prescaler =(3600-1); //ʱÖÓÔ¤·ÖƵÊý
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //²ÉÑù·ÖƵ£¬Ê¹¼ÆʱÆ÷¹¤×÷ƵÂÊΪ72MHz
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//ÏòÉϼÆÊýģʽ
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); //ÅäÖö¨Ê±Æ÷
TIM3_NVIC_config(); //ÅäÖÃTIM3ÖжÏÓÅÏȼ¶
TIM_ClearFlag(TIM3, TIM_FLAG_Update); //Çå³ý±ê־λ
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //ÖжÏÅäÖÃ
// TIM_Cmd(TIM3, ENABLE); //ʹÄܶ¨Ê±Æ÷TIM3
}
//TIM3中断函数TIM3ÖжϺ¯Êý
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //²úÉúÖжÏ
{
ESP_RX_STATE ++; //超过10ms,数据接收完毕,计数+1 ³¬¹ý10ms£¬Êý¾Ý½ÓÊÕÍê±Ï£¬¼ÆÊý+1
}
TIM_ClearITPendingBit(TIM3, TIM_FLAG_Update); // Çå³ýÖжϱêÖ¾
TIM_Cmd(TIM3, DISABLE); //¹Ø±ÕTIM3
}
3.准备接收缓冲区
在准备接收数据之前得先准备一个地方用来存储数据吧。我们为了简洁高效,使用循环队列作为数据接收的缓冲区
//宏定义缓冲队列最大存储上限
#define ESP_BUF_SIZE 1024 //ESP»º³åÇø×î´óÈÝÁ¿
//循环对列结构体
typedef struct
{
unsigned char buf[ESP_BUF_SIZE];
unsigned short int length;
unsigned short int fornt; //ESP¶ÓÁÐÍ·Ö¸Õë
unsigned short int rear; //ESP¶ÓÁÐβָÕë
}ESP_BufTypeDef; //¶¨ÒåESPÑ»·¶ÓÁлº³åÇø½á¹¹Ìå
//声明一个队列缓冲区,作为全局变量
ESP_BufTypeDef ESP_RX_BUF; //Wifi´®¿Ú½ÓÊÕ»º³åÇø
//在头文件中声明外部变量,这样可以在其他C文件中调用
extern ESP_BufTypeDef ESP_RX_BUF; //Wifi´®¿Ú½ÓÊÕ»º³åÇø
//接收缓冲区初始化ESP½ÓÊÕ»º³åÇø³õʼ»¯
void ESP_Rxbuf_Init(void)
{
int i ;
memset(ESP_RX_BUF.buf,0,sizeof(ESP_RX_BUF.buf)); //使用memset()函数需要包含头文件《string.h》
// for(i=0;i《 ESP_BUF_SIZE; i++)
// {
// ESP_RX_BUF.buf[i] = 0;
// }
ESP_RX_BUF.fornt = 0;
ESP_RX_BUF.length = 0;
ESP_RX_BUF.rear = 0;
ESP_RX_STATE = 0; //ÔÊÐí½ÓÊÕÊý¾Ý
}
到这里接收的数据存储位置也准备好了。
4.串口中断函数
可是定时器中断函数好了,存储位置准备好了,没有数据过来也是不行的呀。那就来写数据接收过程,即网络串口接收中断函数(USART2的中断函数):
//串口接收中断函数´®¿Ú½ÓÊÕÖжϺ¯Êý
void USART2_IRQHandler(void)
{
u8 rev_byte;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //Åж϶ȼĴæÆ÷ÊÇ·ñΪ·Ç¿Õ
{
rev_byte = USART_ReceiveData(USART2); //接收数据½ÓÊÕÊý¾Ý
if(ESP_RX_BUF.length 《= ESP_BUF_SIZE) //如果数据没有溢出Èç¹ûÊý¾ÝûÓÐÒç³ö
{
ESP_RX_BUF.buf[ESP_RX_BUF.rear] = rev_byte; //将数据存入缓冲区尾部½«Êý¾Ý´æÈëBUFF»º³åÇøβ²¿
ESP_RX_BUF.length ++; //缓冲区长度增加»º³åÇø³¤¶ÈÔö¼Ó
ESP_RX_BUF.rear = (ESP_RX_BUF.rear + 1) % ESP_BUF_SIZE; //尾指针+1,防止溢出,实现循环队列·ÀÖ¹Òç³ö
}
//这里的TIM3其实可以用宏定义,这样可以方便更改使用的定时器
TIM_SetCounter(TIM3,0); //定时器清空¼ÆÊýÆ÷Çå¿Õ
TIM_Cmd(TIM3,ENABLE); //使能定时器ʹÄܶ¨Ê±Æ÷
}
USART_ClearITPendingBit(USART2, USART_IT_RXNE); //清除标志Çå³ý±êÖ¾
}
如此,我们就可以将接收到的数据保存起来了。
5.读取缓冲队列函数
但是好像还是不行,只是保存起来,却不能使用,你说难不难受。
//读取ESP队列的数据¶ÁÈ¡espÊý¾Ý½ÓÊÕ¶ÓÁеÄÊý¾Ý
u8 ESP_Read_Quene_Data(ESP_BufTypeDef* Rx_buf)
{
u8 read_data_temp;
if(Rx_buf-》length == 0) //没有数据
{
read_data_temp = 0;
}
else
{
read_data_temp = Rx_buf-》buf[Rx_buf-》fornt]; //读出头指针所指的数据
Rx_buf-》fornt = (Rx_buf-》fornt + 1) % ESP_BUF_SIZE;//头指针增加
Rx_buf-》length --; //数据长度减少
}
return read_data_temp; //返回读取的结果
}
读取数据是不是很简单。
6.串口发送数据函数
既然可以接收和读取了,那怎么发送数据呢?这里就要使用到串口发送数据的方法了,如果回使用或者已经写好的可跳过:
/*-----------------------------------------
*串口发送字符串函数´®¿Ú·¢ËÍ×Ö·û´®º¯Êý
* USARTx Ö¸¶¨·¢Ë͵Ĵ®¿Ú
* *DataÖ¸¶¨´ý·¢Ë͵Ä×Ö·û´®
* 发送遇到字符串结束符‘ ’结束·¢ËÍÓöµ½×Ö·û´®½áÊø·û‘ ’½áÊø
-----------------------------------------*/
//这个函数讲真写的不是太好,有更好的大家可以修改
void USART_Send_String(USART_TypeDef* USARTx, u8 *Data, 。..)
{//使用变长参数,具体实现原理可百度
//·ÖÅäÄÚ´æ
va_list valist;
//ΪÊäÈëµÄ²ÎÊý³õʼ»¯
va_start(valist, Data);
while(*Data != ‘ ’)
{
USART_SendData(USARTx, *Data);
while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET); //µÈ´ý´®¿Ú·¢ËÍÍêÊý¾Ý
Data++;
}
//ÇåÀíΪvalist±£ÁôµÄÄÚ´æ
va_end(valist);
}
至此,我们的准备工作就算完成了,要真正开始操刀对ESP8266下手了。
7.读取回复信号函数
根据手册,我们可以知道,我们可以给ESP8266发送命令,然后它会回给我们相应的结果。我们也可以给它发数据,但是要先发相应的命令,然后跟着发送数据。所以我们先写发送命令函数,但是好像有个问题:发送完命令紧跟着是得到命令的结果,不然我们也不知道模块有没有执行。所以不要着急开始写CMD函数,先来写回复函数:
//讲真这是非常失败的函数,但是可以实现
//宏定义返回值
#define ACK_SUCCESS 1
#define ACK_DEFEAT 0
u8 ESP_Check_Ack(char *string) //¼ì²éÏàÓ¦»Ø¸´ÐźÅ
{
char *str_temp; //被检测的字符串的临时变量
u8 data_temp;
u8 rx_buff_temp[150]={0}; //临时存放接收到的数据ÁÙʱ´æ´¢½ÓÊÕµ½µÄÊý¾Ý
u8 pt_temp = 0; //rx_buff_temp的下标rx_buff_tempµÄϱê
u8 length_temp = 0; //临时数组的当前长度
str_temp = string;
if(ESP_RX_STATE 》 0) //Èç¹û½ÓÊÕÊý¾Ý½áÊø
{
//»ñÈ¡ÊÕµ½µÄ»Ø¸´ ÖÁÁÙʱÊý×飬±ãÓÚÅжÏ
do
{
if(length_temp 《 150)
{
data_temp = ESP_Read_Quene_Data(&ESP_RX_BUF);//从缓冲区读取一个值到数组
rx_buff_temp[pt_temp] = data_temp;
pt_temp ++; //下标向后移动一位
length_temp ++;
}
else
break; //³¬³ö´æ´¢ÉÏÏÞ£¬Ã»ÓÐÊÕµ½¡® ¡¯Ôò»áËÀÑ»·£¬Ìø³öµ±Ç°Ñ»·
}
while(data_temp != ‘ ’);
ESP_RX_STATE --; //读取完一个字符串,接收区计数减一¶ÁÈ¡ÍêÒ»¸ö½ÓÊÕµÄ×Ö·û´®£¬¼ÆÊý-1
}
//ÅжÏÊÇ·ñ·ûºÏÆÚÍûÐźÅ
if(strstr((const char *)rx_buff_temp, (const char *)str_temp ) != NULL) //检测到有想要的回复,就能得到不为空的地址
return ACK_SUCCESS; //返回成功Èç¹û·µ»ØµØÖ·²»Îª¿Õ£¬·µ»ØÓÐЧ
else
return ACK_DEFEAT; //如果没有,就是失败·ñÔò£¬·µ»Øʧ°Ü
}
8.发送命令函数
有检查回复信号的函数后就可以写命令函数了:
/*--------------------------------------------------
* ·¢ËÍÖ¸ÁϣÍûµÃµ½»Ø¸´
* *cmd 发送的命令
* *ack 希望得到的回复
* waittime 等待的时长
* ·µ»ØÖµ ACK_SUCCESS£¬·¢Ëͳɹ¦
* ACK_DEFEAT£¬·¢ËÍʧ°Ü
---------------------------------------------------*/
u8 ESP_Send_Cmd(char *cmd, char *ack, u16 waittime )
{//其实这里也可以写成边长参数的,而且会极大的方便后面发送命令,不过博主是写完功能了才学会的边长参数,后面我会在我程序中修改
USART_Send_String(ESP_USART, (u8 *)cmd); //直接使用发送字符串函数
while(waittime-- )
{
if(ESP_Check_Ack(ack) == ACK_SUCCESS)
{
return ACK_SUCCESS;
}
delay_ms(10); //每次等待10ms,所以waittime为20的时候,实际等待200ms
}
return ACK_DEFEAT;
}
是不是很简单。
9.发送数据函数
下面就是发送数据函数,之所以最后写,是因为发数据之前要发送一个命令,告诉ESP8266我要发数据了:
/*----------------------------------------------------
* ·¢ËÍÊý¾Ý¸øwifiÄ£¿é£¬
* *data为要发送的数据*dataΪ·¢Ë͵ÄÊý¾Ý
----------------------------------------------------*/
void ESP_Send_Data(u8 *data)
{
char cmdbuf_temp[32]; //整合命令使用的临时数组
unsigned short len; //发送数据的长度
len = sizeof(data);
sprintf(cmdbuf_temp,“AT+CIPSEND=%drn”, len);//格式化的命令写入命令字符串中,就是把长度加上°Ñ¸ñʽ»¯µÄÊý¾ÝдÈëij¸ö×Ö·û´®ÖÐ
if(ESP_Send_Cmd(cmdbuf_temp, “》”, 200) == ACK_SUCCESS) //检测接收数据是否包含‘》’¼ì²é½ÓÊÕÊý¾ÝÊÇ·ñΪ¡°》¡±
{
USART_Send_String(ESP_USART, data); //发送数据·¢ËÍÊý¾Ý
}
}
因为本篇写的是ESP8266连接服务器的方法,所以作为AP时候使用的接收数据解析IPD就不写了。至此,所有函数写完了。
10.连接TCP并发送数据演示
在使用的时候,先把ESP8266的端口配置初始化,缓冲区初始化。然后愉快的使用ESP_Send_Cmd函数发送命令,控制模块就好了。
这里我展示一个连接TCP并开启透传模式的过程。只是简单演示如何使用,在实际发送命令过程中返回失败还是很多的,所以要有容错,读者自己思考。
#define wifi_information “AT+CWJAP_DEF=”wifi名称“,”wifi密码“rn”
#define tcp_information “AT+CIPSTART=”TCP“,”TCP地址“,端口号rn”
if(ESP_Send_Cmd(“ATrn”,“OK”,20) == ACK_DEFEAT) //测试一下AT命令
{
delay_ms(50);
ESP_Send_Cmd(“+++”,“”,0); //Í˳ö͸´«Ä£Ê½
delay_ms(50);
}
ESP_Send_Cmd(“AT+CWMODE=1rn”,“OK”,20);//设置成Station模式
//一定要重启!!!
ESP_Send_Cmd(“AT+RSTrn”,“ready”,20);
delay_ms(1000); //一般1s就可以,也可以设置时间长一些
ESP_Rxbuf_Init(); //往往启动是时候模块会发版本信息,清空一下
printf(“Connecting to Wifi.rn”);
if(ESP_Send_Cmd(“AT+CWJAP_DEF?rn”,“No AP”,50) == ACK_SUCCESS) //返回没有连接AP·µ»ØûÓÐÁ¬½ÓAP
{
for(count_up = 0; count_up 《 5; count_up ++ ) //Ñ»·Á¬½Ó5´Î
{
if(ESP_Send_Cmd(wifi_information, “WIFI GOT IP”, 600) == ACK_SUCCESS) //如果连接成功Èç¹ûÁ¬½Ó³É¹¦
{
printf(“Have conntected.rn”);
break;
}else
{
printf(“Rejoin Wifi.rn”);
}
}
}
//此处可以添加如果重连5次都失败的处理方法
/*有时候遇到部分8266在链接TCP后不能进行单路链接设置*/
ESP_Send_Cmd(“AT+CIPMUX=0rn”,“OK”,15); //单路连接模式
ESP_Send_Cmd(tcp_information, “CONNECT”, 50); //连接到TCP
//这里其实就可以使用发送数据函数ESP_Send_Data开始发数据了
//ESP_Send_Data(“Hllow word!n”)
ESP_Send_Cmd(“AT+CIPMODE=1rn”,“OK”,20); //进去透传模式
ESP_Send_Cmd(“AT+CIPSENDrn”,“OK”,20); //进入透传模式
//透传模式直接使用串口发送函数即可
USART_Send_String(USART2, “Anything!”);
大功告成!
举报