1、准备开发板
开发板功能区分布图
开发板俯视图
2、ESP8266简介
????ESP8266 WIFI模块内置TCP/IP网络协议,模块支持三种网络模式,AP、STA和AP+STA模式,AP模式:模块作为WIFI热点,等待其他设备的连接,进行局域网的通信,STA模式:模块作为客户端通过路由器连接外网,和服务器进行通信,AP+STA模式:两种模式共存,可以进行任意切换。另外,模块支持AT指令操作,使用PC端或者单片机TTL串口配置简单的指令即可实现,这也是选择这款模块的一个原因。
什么是AT指令?
ESP8266开发常用的AT指令
基础AT指令 | |
---|
命令 | 描述 | AT | 测试AT启动 | AT+RST | 重启模块 | AT+GMR | 查看版本信息 |
WIFI功能AT指令 | |
---|
命令 | 描述 | AT+CWMODE | 选择WIFI应用模式 | AT+CWJAP | 加入AP | AT+CWLAP | 列出当前可用AP | AT+CWQAP | 退出与AP的连接 | AT+CWSAP | 设置AP模式下的参数 | AT+CWLIF | 查看已接入设备的IP |
TCP/IP 工具箱 AT 指令 | |
---|
命令 | 描述 | AT+CIPSTATUS | 获得连接状态 | AT+CIPSTART | 建立TCP连接或注册UDP | AT+CIPSEND | 发送数据 | AT+CIPCLOSE | 关闭TCP或UDP | AT+CIFSR | 获取本地IP地址 | AT+CIPMUX | 启动多连接 | AT+CIPSERVER | 配置为服务器 | AT+CIPMODE | 设置模块传输模式 | AT+CIPSTO | 设置服务器超时时间 |
3、在MDK中编写代码
????在写代码之前我们要了解的编程思维:高内聚、低耦合,简单来说就是:把一些东西放在一边,另一些东西放在另一边,然后划定边界,就是一种“分类”的思想,一个模块实现一个功能,功能之间相互联系。并且我们可以用I/O模型来管理我们的设备,在计算机系统中I/O就是输入(Input)和输出(Output)的意思,用来控制计算机的数据流动包括程序、硬件。
ESP8266基础函数 | |
---|
函数 | 描述 | ESP8266_IO_Delay | ESP8266模块延时 | ESP8266_IO_Reset | 对ESP8266进行硬件重启 | ESP8266_IO_Send | ESP8266模块所在的串口发送数据 | ESP8266_IO_WaitRecive | 对ESP8266是否接收到数据进行判断 | ESP8266_IO_ClearRecive | 清除ESP8266模块所在的串口的缓存 |
ESP8266功能函数 | |
---|
ESP8266_SendCmd | 对ESP8266发送命令,并将ESP8266返回的数据进行检索 | ESP8266_SendData | ESP8266向服务器发送数据 | ESP8266_Net_Mode_Choose | 选择ESP8266模块的工作模式 | ESP8266_JoinAP | ESP8266模块连接外部WiFi | ESP8266_CIPAP | 设置模块的 AP IP | ESP8266_BuildAP | WF-ESP8266模块创建WiFi热点 | ESP8266_Enable_MultipleId | ESP8266模块启动多连接 | ESP8266_Link_Server | ESP8266模块连接外部服务器 | ESP8266_StartOrShutServer | ESP8266模块开启或关闭服务器模式 | ESP8266_Inquire_ApIp | 获取 F-ESP8266 的 AP IP | ESP8266_UnvarnishSend | 配置ESP8266模块进入透传发送 | ESP8266_Get_LinkStatus | ESP8266 的连接状态,较适合单端口时使用 | ESP8266_GetIPD | 对ESP8266返回的数据进行检索,并将处理好的数据返回 |
在ESP8266.h中编写以下代码
#ifndef __ESP8266_H_
#define __ESP8266_H_
#include "sys.h"
#define ESP8266_USART LPUART1
#define USART_DEBUG USART1
#ifndef ESP8266_OK
#define ESP8266_OK 0
#endif
#ifndef ESP8266_NOK
#define ESP8266_NOK 1
#endif
#define ESP8266_RETTYPE unsigned char
typedef enum
{
STA,
AP,
STA_AP
}ENUM_Net_ModeTypeDef;
typedef enum{
enumTCP,
enumUDP,
} ENUM_NetPro_TypeDef;
typedef enum{
Multiple_ID_0 = 0,
Multiple_ID_1 = 1,
Multiple_ID_2 = 2,
Multiple_ID_3 = 3,
Multiple_ID_4 = 4,
Single_ID_0 = 5,
} ENUM_ID_NO_TypeDef;
typedef enum{
OPEN = 0,
WEP = 1,
WPA_PSK = 2,
WPA2_PSK = 3,
WPA_WPA2_PSK = 4,
} ENUM_AP_PsdMode_TypeDef;
#define User_ESP8266_BulitApSsid "PRECHIN"
#define User_ESP8266_BulitApEcn OPEN
#define User_ESP8266_BulitApPwd "prechin"
#define User_ESP8266_TCPServer_IP "192.168.1.119"
#define User_ESP8266_TCPServer_PORT "8080"
#define User_ESP8266_TCPServer_OverTime "1800"
#define TCPAGREEMENT enumTCP
typedef struct _NET_DEVICE_INFO
{
USART_INFO_STRUCT* netIOInfo;
char staName[20];
char staPass[20];
char staIPAddress[20];
char staPort[20];
unsigned short err : 2;
unsigned short netWork : 1;
unsigned short initStep : 4;
unsigned short dataType : 4;
unsigned short reverse : 6;
} NET_DEVICE_INFO;
extern NET_DEVICE_INFO netDeviceInfo;
void ESP8266_IO_Delay(uint32_t time);
void ESP8266_IO_Send(uint8_t *str,uint32_t strlen );
ESP8266_RETTYPE ESP8266_IO_WaitRecive(void);
void ESP8266_IO_ClearRecive(void);
void ESP8266_IO_Reset(void);
ESP8266_RETTYPE ESP8266_SendCmd(char *cmd, char *res1,char *res2,uint32_t timeOut);
ESP8266_RETTYPE ESP8266_SendData(FunctionalState enumEnUnvarnishTx,unsigned char *data, unsigned short len,ENUM_ID_NO_TypeDef ucId);
ESP8266_RETTYPE ESP8266_Net_Mode_Choose(ENUM_Net_ModeTypeDef enumMode);
ESP8266_RETTYPE ESP8266_JoinAP( char * pSSID, char * pPassWord );
ESP8266_RETTYPE ESP8266_CIPAP ( char * pApIp );
ESP8266_RETTYPE ESP8266_BuildAP ( char * pSSID, char * pPassWord, ENUM_AP_PsdMode_TypeDef enunPsdMode );
ESP8266_RETTYPE ESP8266_Enable_MultipleId (FunctionalState enumEnUnvarnishTx );
ESP8266_RETTYPE ESP8266_Link_Server(ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id);
ESP8266_RETTYPE ESP8266_StartOrShutServer ( FunctionalState enumMode, char * pPortNum, char * pTimeOver );
ESP8266_RETTYPE ESP8266_Inquire_ApIp ( char * pApIp, uint8_t ucArrayLength );
ESP8266_RETTYPE ESP8266_UnvarnishSend ( void );
ESP8266_RETTYPE ESP8266_Get_LinkStatus ( void );
unsigned char *ESP8266_GetIPD(FunctionalState enumEnUnvarnishTx,unsigned short timeOut);
ESP8266_RETTYPE NET_DEVICE_Init(void);
#endif
在ESP8266.c编写以下代码
NET_DEVICE_INFO netDeviceInfo = {
&lpuart1Info,
"M5GM",
"18022100@MMKJ",
"192.168.0.100",
"7437",
0, 0, 0, 0,
};
void ESP8266_IO_Delay(uint32_t time)
{
#if SYSTEM_SUPPORT_OS
rt_thread_mdelay(time);
#else
delay_ms(time);
#endif
}
void ESP8266_IO_Send(uint8_t *str,uint32_t strlen )
{
USART_SendBuf(ESP8266_USART,str,strlen);
}
ESP8266_RETTYPE ESP8266_IO_WaitRecive(void)
{
if(netDeviceInfo.netIOInfo->InfBit.dataLen == 0)
return ESP8266_NOK;
if(netDeviceInfo.netIOInfo->InfBit.dataLen == netDeviceInfo.netIOInfo->dataLenPre)
{
netDeviceInfo.netIOInfo->rxBuf[netDeviceInfo.netIOInfo->InfBit.dataLen] = '\0';
netDeviceInfo.netIOInfo->dataLenPre = netDeviceInfo.netIOInfo->InfBit.dataLen;
netDeviceInfo.netIOInfo->InfBit.dataLen = 0;
return ESP8266_OK;
}
netDeviceInfo.netIOInfo->dataLenPre = netDeviceInfo.netIOInfo->InfBit.dataLen;
return ESP8266_NOK;
}
void ESP8266_IO_ClearRecive(void)
{
netDeviceInfo.netIOInfo->InfBit.dataLen = 0;
memset(netDeviceInfo.netIOInfo->rxBuf, 0, sizeof(netDeviceInfo.netIOInfo->rxBuf));
}
void ESP8266_IO_Reset(void)
{
UsartPrintf(USART_DEBUG, "Tips: NET_DEVICE_Reset\r\n");
}
ESP8266_RETTYPE ESP8266_SendCmd(char *cmd, char *res1,char *res2,uint32_t timeOut)
{
ESP8266_RETTYPE ucExecRes = ESP8266_NOK;
ESP8266_IO_ClearRecive();
UsartPrintf(USART_DEBUG,"Tips: %s\r\n",cmd);
ESP8266_IO_Send((unsigned char *)cmd, strlen((const char *)cmd));
while(timeOut--)
{
if(ESP8266_IO_WaitRecive() == ESP8266_OK)
{
if(*res1 != 0 && *res2 != 0)
{
if(((bool)strstr((const char *)netDeviceInfo.netIOInfo->rxBuf, res1))||
((bool)strstr((const char *)netDeviceInfo.netIOInfo->rxBuf, res2)))
{
ucExecRes = ESP8266_OK;
break;
}
}
else if(*res1 != 0)
{
if((bool)strstr((const char *)netDeviceInfo.netIOInfo->rxBuf, res1))
{
ucExecRes = ESP8266_OK;
break;
}
}
else
{
if((bool)strstr((const char *)netDeviceInfo.netIOInfo->rxBuf, res2))
{
ucExecRes = ESP8266_OK;
break;
}
}
}
ESP8266_IO_Delay(1);
}
return ucExecRes;
}
unsigned char *ESP8266_GetIPD(FunctionalState enumEnUnvarnishTx,unsigned short timeOut)
{
char *ptrIPD;
do
{
if(ESP8266_IO_WaitRecive() == ESP8266_OK)
{
if(enumEnUnvarnishTx == DISABLE)
{
ptrIPD = strstr((char *)netDeviceInfo.netIOInfo->rxBuf, "IPD,");
if(ptrIPD == NULL)
{
}
else
{
ptrIPD = strchr(ptrIPD, ':');
if(ptrIPD != NULL)
{
ptrIPD++;
return (unsigned char *)(ptrIPD);
}
else
return NULL;
}
}
else
{
return netDeviceInfo.netIOInfo->rxBuf;
}
}
ESP8266_IO_Delay(20);
} while(timeOut--);
return NULL;
}
ESP8266_RETTYPE ESP8266_SendData(FunctionalState enumEnUnvarnishTx,unsigned char *data, unsigned short len,ENUM_ID_NO_TypeDef ucId)
{
char cmdBuf[30];
ESP8266_RETTYPE ucExecRes = ESP8266_NOK;
if( enumEnUnvarnishTx )
{
ESP8266_IO_Send(data, len);
ucExecRes = ESP8266_OK;
}
else
{
if ( ucId < 5 )
sprintf ( cmdBuf, "AT+CIPSEND=%d,%d\r\n", ucId, len );
else
sprintf ( cmdBuf, "AT+CIPSEND=%d\r\n", len );
ucExecRes = ESP8266_SendCmd ( cmdBuf, "> ", 0, 4000 );
if(ucExecRes == ESP8266_OK)
{
USART_SendBuf(USART_DEBUG,data,len);
ESP8266_IO_Send(data,len);
}
}
return ucExecRes;
}
ESP8266_RETTYPE ESP8266_Net_Mode_Choose(ENUM_Net_ModeTypeDef enumMode)
{
switch ( enumMode )
{
case STA:
return ESP8266_SendCmd ( "AT+CWMODE=1\r\n", "OK", "no change", 2500 );
case AP:
return ESP8266_SendCmd ( "AT+CWMODE=2\r\n", "OK", "no change", 2500 );
case STA_AP:
return ESP8266_SendCmd ( "AT+CWMODE=3\r\n", "OK", "no change", 2500 );
default:
return ESP8266_NOK;
}
}
ESP8266_RETTYPE ESP8266_JoinAP( char * pSSID, char * pPassWord )
{
char cmdBuf [120];
sprintf ( cmdBuf, "AT+CWJAP=\"%s\",\"%s\"\r\n", pSSID, pPassWord );
return ESP8266_SendCmd( cmdBuf, "OK", NULL, 5000 );
}
ESP8266_RETTYPE ESP8266_CIPAP ( char * pApIp )
{
char cmdBuf [ 30 ];
sprintf ( cmdBuf, "AT+CIPAP=\"%s\"\r\n", pApIp );
if ( ESP8266_SendCmd ( cmdBuf, "OK", 0, 5000 ) == ESP8266_OK)
return ESP8266_OK;
else
return ESP8266_NOK;
}
ESP8266_RETTYPE ESP8266_BuildAP ( char * pSSID, char * pPassWord, ENUM_AP_PsdMode_TypeDef enunPsdMode )
{
char cmdBuf [120];
sprintf ( cmdBuf, "AT+CWSAP=\"%s\",\"%s\",1,%d\r\n", pSSID, pPassWord, enunPsdMode );
return ESP8266_SendCmd ( cmdBuf, "OK", 0, 1000 );
}
ESP8266_RETTYPE ESP8266_Enable_MultipleId (FunctionalState enumEnUnvarnishTx )
{
char cStr [20];
sprintf ( cStr, "AT+CIPMUX=%d\r\n", ( enumEnUnvarnishTx ? 1 : 0 ) );
return ESP8266_SendCmd ( cStr, "OK", 0, 500 );
}
ESP8266_RETTYPE ESP8266_Link_Server(ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id)
{
char cStr [100] = { 0 }, cmdBuf [120];
switch ( enumE )
{
case enumTCP:
sprintf ( cStr, "\"%s\",\"%s\",%s\r\n", "TCP", ip, ComNum );
break;
case enumUDP:
sprintf ( cStr, "\"%s\",\"%s\",%s\r\n", "UDP", ip, ComNum );
break;
default:
break;
}
if ( id < 5 )
sprintf ( cmdBuf, "AT+CIPSTART=%d,%s\r\n", id, cStr);
else
sprintf ( cmdBuf, "AT+CIPSTART=%s\r\n", cStr );
return ESP8266_SendCmd ( cmdBuf, "OK", "ALREAY CONNECT", 4000 );
}
ESP8266_RETTYPE ESP8266_StartOrShutServer ( FunctionalState enumMode, char * pPortNum, char * pTimeOver )
{
char cmdBuf1 [120], cmdBuf2 [120];
if ( enumMode )
{
sprintf ( cmdBuf1, "AT+CIPSERVER=%d,%s\r\n", 1, pPortNum );
sprintf ( cmdBuf2, "AT+CIPSTO=%s\r\n", pTimeOver );
return ( ESP8266_SendCmd ( cmdBuf1, "OK", 0, 500 ) &&
ESP8266_SendCmd ( cmdBuf2, "OK", 0, 500 ) );
}
else
{
sprintf ( cmdBuf1, "AT+CIPSERVER=%d,%s\r\n", 0, pPortNum );
return ESP8266_SendCmd ( cmdBuf1, "OK", 0, 500 );
}
}
ESP8266_RETTYPE ESP8266_Inquire_ApIp ( char * pApIp, uint8_t ucArrayLength )
{
char uc;
char * pCh;
if(!ESP8266_SendCmd ( "AT+CIFSR\r\n", "OK", 0, 500 ))
{
pCh = strstr ( (char*)netDeviceInfo.netIOInfo->rxBuf, "APIP,\"" );
if ( pCh )
pCh += 6;
else
return ESP8266_NOK;
for ( uc = 0; uc < ucArrayLength; uc ++ )
{
pApIp [ uc ] = * ( pCh + uc);
if ( pApIp [ uc ] == '\"' )
{
pApIp [ uc ] = '\0';
break;
}
}
}
return ESP8266_OK;
}
ESP8266_RETTYPE ESP8266_UnvarnishSend ( void )
{
if (!ESP8266_SendCmd ( "AT+CIPMODE=1\r\n", "OK", 0, 500 ))
return ESP8266_NOK;
return
ESP8266_SendCmd( "AT+CIPSEND\r\n", "OK", ">", 500 );
}
ESP8266_RETTYPE ESP8266_Get_LinkStatus ( void )
{
if (ESP8266_SendCmd( "AT+CIPSTATUS\r\n", "STATUS:", NULL, 1000 ) == ESP8266_OK)
{
UsartPrintf(USART_DEBUG,"netDeviceInfo.netIOInfo->rxBuf:%s\r\n",netDeviceInfo.netIOInfo->rxBuf);
if ( strstr ( (char*)netDeviceInfo.netIOInfo->rxBuf, "STATUS:2\r\n" ) )
{
UsartPrintf(USART_DEBUG, "ESP8266 Got IP\r\n");
return 2;
}
else if ( strstr ( (char*)netDeviceInfo.netIOInfo->rxBuf, "STATUS:3\r\n" ) )
{
UsartPrintf(USART_DEBUG, "ESP8266 Connect OK\r\n");
return 3;
}
else if ( strstr ( (char*)netDeviceInfo.netIOInfo->rxBuf, "STATUS:4\r\n" ) )
{
UsartPrintf(USART_DEBUG, "ESP8266 Lost Connect\r\n");
return 4;
}
}
UsartPrintf(USART_DEBUG, "ESP8266 TimeOut\r\n");
return ESP8266_NOK;
}
ESP8266_RETTYPE NET_DEVICE_LinkServer_Init(void)
{
unsigned char errCount = 0, errType = 0;
switch(netDeviceInfo.initStep)
{
case 0:
if(ESP8266_Net_Mode_Choose(STA) == ESP8266_OK)
netDeviceInfo.initStep++;
break;
case 1:
if(ESP8266_Enable_MultipleId(DISABLE) == ESP8266_OK)
netDeviceInfo.initStep++;
break;
case 2:
if(ESP8266_JoinAP(netDeviceInfo.staName,netDeviceInfo.staPass) == ESP8266_OK)
netDeviceInfo.initStep++;
break;
case 3:
if(ESP8266_Link_Server(enumTCP,netDeviceInfo.staIPAddress,netDeviceInfo.staPort,Single_ID_0) == ESP8266_OK)
netDeviceInfo.initStep++;
break;
default:
netDeviceInfo.netWork = 1;
errType = 3;
break;
}
return errType;
}
ESP8266_RETTYPE NET_DEVICE_Init(void)
{
netDeviceInfo.err = NET_DEVICE_LinkServer_Init();
if(netDeviceInfo.err == 1)
{
UsartPrintf(USART_DEBUG, "Wifi info Error,Use USART2 -> 8266\r\n");
return ESP8266_NOK;
}
else if(netDeviceInfo.err == 2)
{
UsartPrintf(USART_DEBUG, "PT info Error,Use APP -> 8266\r\n");
return ESP8266_NOK;
}
else if(netDeviceInfo.err == 3)
{
UsartPrintf(USART_DEBUG, "Tips: NET_DEVICE STA OK\r\n");
ESP8266_IO_Delay(500);
return ESP8266_OK;
}
else
return ESP8266_NOK;
}
在main.c中添加以下代码
ESP8266_RETTYPE netStatus = ESP8266_NOK;
unsigned char netErrCount = 0;
在main.c下的main函数加入以下代码
unsigned char* dataPtr = NULL;
uint32_t send_time = 0;
ESP8266_RETTYPE ucExecRes = ESP8266_NOK;
USART_Interupt_Enable();
TIM_Interupt_Enable();
while (1)
{
if(!netDeviceInfo.netWork)
{
if(NET_DEVICE_Init() == ESP8266_OK)
{
printf("连接服务器成功\r\n");
}
}
if(netDeviceInfo.netWork)
{
dataPtr = ESP8266_GetIPD(DISABLE,0);
if(dataPtr != NULL)
{
printf("dataPtr:%s\r\n",dataPtr);
if(strstr((char*)dataPtr,"OpenLED"))
{
printf("LED点亮\r\n");
LED_Set(LED_ON);
}
if(strstr((char*)dataPtr,"CloseLED"))
{
printf("LED熄灭\r\n");
LED_Set(LED_OFF);
}
}
}
if(time2Count - send_time >= 10000)
{
send_time = time2Count;
if(netDeviceInfo.netWork)
{
ucExecRes = ESP8266_SendData(DISABLE,"hello world",strlen("hello world"),Single_ID_0);
if(ucExecRes != ESP8266_OK)
{
printf("网络可能断开了\r\n");
netErrCount++;
if(netErrCount >= 3)
{
netStatus = ESP8266_Get_LinkStatus();
if(netStatus == 4)
{
netErrCount = 0;
netDeviceInfo.netWork = 0;
netDeviceInfo.initStep = 0;
}
}
}
else
{
netErrCount = 0;
}
}
}
}
4、实验现象
实现的功能 |
---|
1、上电自动连接WIFI | 2、成功连接WIFI后自动连接TCP服务器 | 3、成功连接TCP服务器后自动发送数据给服务器 | 4、TCP服务器下发OpenLED指令会点亮LED,下发CloseLED会熄灭LED灯 | 5、当服务器连接断开的时候,会自动进行重新连接服务器,并重新发送数据 |
|