#include "esp8266.h" volatile uint8_t ucTcpClosedFlag = 0; char cStr [ 1500 ] = { 0 }; struct SerialFrame_t xSerialFrameRecord = { 0 }; /** * @brief vEsp8266GpioConfig * @note ESP8266模块连接引脚配置函数,该函数被vEsp8266Init调用。 * @param 无 * @retval 无 */ void vEsp8266GpioConfig ( void ) { /* 定义一个GPIO_InitTypeDef类型的结构体 */ GPIO_InitTypeDef GPIO_InitStructure; /* 配置 CH_PD 引脚*/ RCC_APB2PeriphClockCmd ( macESP8266_CH_PD_CLK, ENABLE ); GPIO_InitStructure.GPIO_Pin = macESP8266_CH_PD_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init ( macESP8266_CH_PD_PORT, & GPIO_InitStructure ); /* 配置 RST 引脚*/ RCC_APB2PeriphClockCmd ( macESP8266_RST_CLK, ENABLE ); GPIO_InitStructure.GPIO_Pin = macESP8266_RST_PIN; GPIO_Init ( macESP8266_RST_PORT, & GPIO_InitStructure ); } /** * @brief vEsp8266Rst * @note 调用这个函数,就可以重启ESP8266模块,该函数被vEsp8266AtTest调用。 * @param 无 * @retval 无 */ void vEsp8266Rst ( void ) { #if 0 bEsp8266Command ( "AT+RST", "OK", "ready", 2500 ); #else macESP8266_RST_LOW_LEVEL(); vDelayMs ( 500 ); macESP8266_RST_HIGH_LEVEL(); #endif } /** * @brief bEsp8266Command * @note 对ESP8266模块发送AT指令,并等待响应。该函数被外部调用。 * @param pcCmd:待发送的指令 * @param pcReply1,pcReply2:期待的响应,为NULL表不需响应,两者为或逻辑关系。 * @param ulWaittime:等待响应的时间 * @retval true:指令发送成功 * @retval false:指令发送失败 */ bool bEsp8266Command ( char * pcCmd, char * pcAck1, char * pcAck2, uint32_t ulWaittime ) { xSerialFrameRecord .Bits_t .usFrameLength = 0; //从新开始接收新的数据包 vUsartPrintf ( USART2, "%s\r\n", pcCmd ); if ( ( pcAck1 == 0 ) && ( pcAck2 == 0 ) ) //不需要接收数据 return true; vDelayMs( ulWaittime ); //延时 xSerialFrameRecord .cSerialReceivedBuffer [ xSerialFrameRecord .Bits_t .usFrameLength ] = '\0'; if ( ( pcAck1 != 0 ) && ( pcAck2 != 0 ) ) return ( ( bool ) strstr ( xSerialFrameRecord .cSerialReceivedBuffer, pcAck1 ) || ( bool ) strstr ( xSerialFrameRecord .cSerialReceivedBuffer, pcAck2 ) ); else if ( pcAck1 != 0 ) return ( ( bool ) strstr ( xSerialFrameRecord .cSerialReceivedBuffer, pcAck1 ) ); else return ( ( bool ) strstr ( xSerialFrameRecord .cSerialReceivedBuffer, pcAck2 ) ); } /** * @brief vEsp8266AtTest * @note 对ESP8266模块进行AT测试启动,该函数被外部调用。 * @param 无 * @retval 无 */ void vEsp8266AtTest ( void ) { char count=0; macESP8266_RST_HIGH_LEVEL(); vDelayMs( 1000 ); while ( count < 10 ) { if( bEsp8266Command ( "AT", "OK", NULL, 500 ) ) return; vEsp8266Rst(); ++ count; } } /** * @brief bEsp8266NetModeChoose * @note 选择ESP8266模块的工作模式,该函数被外部调用。 * @param xMode,工作模式 * @retval 1,选择成功 * @retval 0,选择失败 */ bool bEsp8266NetModeChoose ( eNetMode_t xMode ) { switch ( xMode ) { case STA: return bEsp8266Command ( "AT+CWMODE=1", "OK", "no change", 2500 ); case AP: return bEsp8266Command ( "AT+CWMODE=2", "OK", "no change", 2500 ); case STA_AP: return bEsp8266Command ( "AT+CWMODE=3", "OK", "no change", 2500 ); default: return false; } } /** * @brief bEsp8266JoinAp * @note ESP8266模块连接外部WiFi,该函数被外部调用。 * @param pcSsid,WiFi名称字符串 * @param pcPassWord,WiFi密码字符串 * @retval 1,连接成功 * @retval 0,连接失败 */ bool bEsp8266JoinAp ( char * pcSsid, char * pcPassWord ) { char cCmd [120]; sprintf ( cCmd, "AT+CWJAP=\"%s\",\"%s\"", pcSsid, pcPassWord ); return bEsp8266Command ( cCmd, "OK", NULL, 5000 ); } /** * @brief bEsp8266MqttInit * @note ESP8266模块MQTT初始化,该函数被外部调用。 * @param pcMqttUserName,MQTT用户名字符串 * @param pcMqttPassword,MQTT密码字符串 * @param pcMqttClientId,MQTT客户端ID字符串 * @param pcMqttServerIp,MQTT服务器IP地址字符串 * @param usMqttServerPort,MQTT服务器端口号 * @retval 1,初始化成功 * @retval 0,初始化失败 */ bool bEsp8266MqttInit ( char * pcMqttUserName, char * pcMqttPassword, char * pcMqttClientId, char * pcMqttServerIp, uint16_t usMqttServerPort, char * pcMqttSubscribeTopic ) { char cCmd[512] = {0}; /* 1. 配置MQTT用户信息 */ snprintf(cCmd, sizeof(cCmd), "AT+MQTTUSERCFG=0,1,\"NULL\",\"%s\",\"%s\",0,0,\"\"", pcMqttUserName, pcMqttPassword); if (!bEsp8266Command(cCmd, "OK", NULL, 2000)) return false; /* 2. 设置客户端ID */ memset(cCmd, 0, sizeof(cCmd)); snprintf(cCmd, sizeof(cCmd), "AT+MQTTCLIENTID=0,\"%s\"", pcMqttClientId); if (!bEsp8266Command(cCmd, "OK", NULL, 2000)) return false; /* 3. 连接到MQTT服务器 */ memset(cCmd, 0, sizeof(cCmd)); snprintf(cCmd, sizeof(cCmd), "AT+MQTTCONN=0,\"%s\",%u,1", pcMqttServerIp, usMqttServerPort); if (!bEsp8266Command(cCmd, "OK", NULL, 5000) && !bEsp8266Command(cCmd, "+MQTTCONN", NULL, 5000)) return false; /* 4. 订阅主题 */ memset(cCmd, 0, sizeof(cCmd)); snprintf(cCmd, sizeof(cCmd), "AT+MQTTSUB=0,\"%s\",1", pcMqttSubscribeTopic); if (!bEsp8266Command(cCmd, "OK", NULL, 2000)) return false; return true; } /** * @brief bEsp8266BuildAp * @note ESP8266模块创建AP热点,该函数被外部调用。 * @param pcSsid,AP名称字符串 * @param pcPassWord,AP密码字符串 * @param xPsdMode,AP加密方式 * @retval 1,创建成功 * @retval 0,创建失败 */ bool bEsp8266BuildAp ( char * pcSsid, char * pcPassWord, eApPsdMode_t xPsdMode ) { char cCmd [120]; sprintf ( cCmd, "AT+CWSAP=\"%s\",\"%s\",1,%d", pcSsid, pcPassWord, xPsdMode ); return bEsp8266Command ( cCmd, "OK", 0, 1000 ); } /** * @brief bEsp8266EnableMultipleId * @note ESP8266模块使能/禁止多连接,该函数被外部调用。 * @param xEnumEnUnvarnishTx,ENABLE:使能多连接;DISABLE:禁止多连接 * @retval 1,操作成功 * @retval 0,操作失败 */ bool bEsp8266EnableMultipleId ( FunctionalState xEnumEnUnvarnishTx ) { return bEsp8266Command ( "AT+CIPMUX=%d", "OK", 0, 500 ); } /** * @brief bEsp8266LinkServer * @note ESP8266模块连接服务器,该函数被外部调用。 * @param xNetProtocol,连接协议类型 * @param pcIp,服务器IP地址字符串 * @param pcComNum,服务器端口号字符串 * @param xId,连接ID号 * @retval 1,连接成功 * @retval 0,连接失败 */ bool bEsp8266LinkServer ( eNetPro_t xNetProtocol, char * pcIp, char * pcComNum, eIdNo_t xId) { char cStr [100] = { 0 }, cCmd [120]; switch ( xNetProtocol ) { case enumTCP: sprintf ( cStr, "\"%s\",\"%s\",%s", "TCP", pcIp, pcComNum ); break; case enumUDP: sprintf ( cStr, "\"%s\",\"%s\",%s", "UDP", pcIp, pcComNum ); break; default: break; } if ( xId < 5 ) sprintf ( cCmd, "AT+CIPSTART=%d,%s", xId, cStr); else sprintf ( cCmd, "AT+CIPSTART=%s", cStr ); return bEsp8266Command ( cCmd, "OK", "ALREADY CONNECT", 4000 ); } /** * @brief bEsp8266StartOrShutServer * @note ESP8266模块启动/关闭服务器,该函数被外部调用。 * @param xMode,ENABLE:启动服务器;DISABLE:关闭服务器 * @param pcPortNum,服务器端口号字符串 * @param pcTimeOver,服务器超时时间字符串 * @retval 1,操作成功 * @retval 0,操作失败 */ bool bEsp8266StartOrShutServer ( FunctionalState xMode, char * pcPortNum, char * pcTimeOver ) { char cCmd1 [120], cCmd2 [120]; if ( xMode ) { sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 1, pcPortNum ); sprintf ( cCmd2, "AT+CIPSTO=%s", pcTimeOver ); return ( bEsp8266Command ( cCmd1, "OK", 0, 500 ) && bEsp8266Command ( cCmd2, "OK", 0, 500 ) ); } else { sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 0, pcPortNum ); return bEsp8266Command ( cCmd1, "OK", 0, 500 ); } } /** * @brief ucEsp8266GetLinkStatus * @note 获取ESP8266的连接状态,该函数被外部调用。 * @param 无 * @retval 0,未连接 * @retval 2,已连接至AP但未连接服务器 * @retval 3,已连接至AP且已连接服务器 * @retval 4,连接断开 */ uint8_t ucEsp8266GetLinkStatus ( void ) { if ( bEsp8266Command ( "AT+CIPSTATUS", "OK", 0, 500 ) ) { if ( strstr ( xSerialFrameRecord .cSerialReceivedBuffer, "STATUS:2\r\n" ) ) return 2; else if ( strstr ( xSerialFrameRecord .cSerialReceivedBuffer, "STATUS:3\r\n" ) ) return 3; else if ( strstr ( xSerialFrameRecord .cSerialReceivedBuffer, "STATUS:4\r\n" ) ) return 4; } return 0; } /** * @brief ucEsp8266GetIdLinkStatus * @note 获取ESP8266的各ID连接状态,该函数被外部调用。 * @param 无 * @retval 各ID连接状态,位0~4分别表示ID0~ID4的连接状态,1表示已连接,0表示未连接 */ uint8_t ucEsp8266GetIdLinkStatus ( void ) { uint8_t ucIdLinkStatus = 0x00; if ( bEsp8266Command ( "AT+CIPSTATUS", "OK", 0, 500 ) ) { if ( strstr ( xSerialFrameRecord .cSerialReceivedBuffer, "+CIPSTATUS:0," ) ) ucIdLinkStatus |= 0x01; else ucIdLinkStatus &= ~ 0x01; if ( strstr ( xSerialFrameRecord .cSerialReceivedBuffer, "+CIPSTATUS:1," ) ) ucIdLinkStatus |= 0x02; else ucIdLinkStatus &= ~ 0x02; if ( strstr ( xSerialFrameRecord .cSerialReceivedBuffer, "+CIPSTATUS:2," ) ) ucIdLinkStatus |= 0x04; else ucIdLinkStatus &= ~ 0x04; if ( strstr ( xSerialFrameRecord .cSerialReceivedBuffer, "+CIPSTATUS:3," ) ) ucIdLinkStatus |= 0x08; else ucIdLinkStatus &= ~ 0x08; if ( strstr ( xSerialFrameRecord .cSerialReceivedBuffer, "+CIPSTATUS:4," ) ) ucIdLinkStatus |= 0x10; else ucIdLinkStatus &= ~ 0x10; } return ucIdLinkStatus; } /** * @brief ucEsp8266InquireApIp * @note 获取ESP8266的AP IP,该函数被外部调用。 * @param pcApIp,存放 AP IP 的数组的首地址 * @param ucArrayLength,存放 AP IP 的数组的长度 * @retval 0,获取失败 * @retval 1,获取成功 */ uint8_t ucEsp8266InquireApIp ( char * pcApIp, uint8_t ucArrayLength ) { char uc; char * pCh; bEsp8266Command ( "AT+CIFSR", "OK", 0, 500 ); pCh = strstr ( xSerialFrameRecord .cSerialReceivedBuffer, "APIP,\"" ); if ( pCh ) pCh += 6; else return 0; for ( uc = 0; uc < ucArrayLength; uc ++ ) { pcApIp [ uc ] = * ( pCh + uc); if ( pcApIp [ uc ] == '\"' ) { pcApIp [ uc ] = '\0'; break; } } return 1; } /** * @brief bEsp8266UnvarnishSend * @note 配置ESP8266模块进入透传模式,该函数被外部调用。 * @param 无 * @retval 1,配置成功 * @retval 0,配置失败 */ bool bEsp8266UnvarnishSend ( void ) { return bEsp8266Command ( "AT+CIPMODE=1", "OK", 0, 500 ); } /** * @brief vEsp8266ExitUnvarnishSend * @note 使ESP8266模块退出透传模式,该函数被外部调用。 * @param 无 * @retval 无 */ void vEsp8266ExitUnvarnishSend ( void ) { vDelayMs( 1000 ); vUsartPrintf ( USART2, "+++" ); vDelayMs( 500 ); } /** * @brief bEsp8266SendString * @note ESP8266模块发送字符串,该函数被外部调用。 * @param xEnumEnUnvarnishTx,声明是否已使能了透传模式 * @param pcStr,待发送的字符串首地址 * @param ulStrLength,待发送的字符串长度 * @param ucId,连接ID号 * @retval 1,发送成功 * @retval 0,发送失败 */ bool bEsp8266SendString ( FunctionalState xEnumEnUnvarnishTx, char * pcStr, uint32_t ulStrLength, eIdNo_t xId ) { char cStr [20]; bool bRet = false; if ( xEnumEnUnvarnishTx ) { vUsartPrintf ( USART2, "%s", pcStr ); bRet = true; } else { if ( xId < 5 ) sprintf ( cStr, "AT+CIPSEND=%d,%d", xId, ulStrLength + 2 ); else sprintf ( cStr, "AT+CIPSEND=%d", ulStrLength + 2 ); bEsp8266Command ( cStr, "> ", 0, 1000 ); bRet = bEsp8266Command ( pcStr, "SEND OK", 0, 1000 ); } return bRet; } /** * @brief pcEsp8266ReceiveString * @note ESP8266模块接收字符串,该函数被外部调用。 * @param xEnumEnUnvarnishTx,声明是否已使能了透传模式 * @retval 接收到的字符串首地址,未接收到返回0 */ char * pcEsp8266ReceiveString ( FunctionalState xEnumEnUnvarnishTx ) { char * pRecStr = 0; xSerialFrameRecord .Bits_t .usFrameLength = 0; xSerialFrameRecord .Bits_t .usFrameFinishFlag = 0; while ( ! xSerialFrameRecord .Bits_t .usFrameFinishFlag ); xSerialFrameRecord .cSerialReceivedBuffer [ xSerialFrameRecord .Bits_t .usFrameLength ] = '\0'; if ( xEnumEnUnvarnishTx ) pRecStr = xSerialFrameRecord .cSerialReceivedBuffer; else { if ( strstr ( xSerialFrameRecord .cSerialReceivedBuffer, "+IPD" ) ) pRecStr = xSerialFrameRecord .cSerialReceivedBuffer; } return pRecStr; }