一、
总算完成了透传,感觉没几行代码,就是在昨天的基础上,对ESP8266的AT指令进行了封装,什么选择工作模式(STA 还是 AP),查询附近WIFI热点,连接WIFi,见解服务器的IP和端口,开启透传......
我的代码的缺点:1.有点简单粗暴,逻辑程序,接收到串口的数据这类的操作没有一部处理,直接把串口1接收到的(电脑上位机再串口工具上发送的数据)同步转给串口3(ESP8266),没有用一个全局数组将数据保存下,之后改进吧。
缺点2:发送指令的函数接口中,直接用HAL_Delay() 延时去做的,我想这样的坏处就是...简陋,这里同样应该改成异步的,并且应该知道每个命令的结果是什么,如果某中间的AT指令执行不成功,应该不往下执行或者重启之类的,嗯 后续改进。
二、代码
esp8266.h
#ifndef ESP8266_H
#define ESP8266_H
#include "stm32f1xx.h"
#include
/*******************************************STA模式下*******************************/
//选择要连接的热点名称和密码
#define ESP8266_JOIN_AP_NAME "HonorNote10"
#define ESP8266_JOIN_AP_PASSWORD "zdw123456"
//选择要连接的服务器和IP 端口
#define ESP8266_CONNECT_TCPSERVER_IP "192.168.43.13"
#define ESP8266_CONNECT_TCPSERVER_PORT "8000"
/*******************************************STA模式下*******************************/
/*******************************************AP模式下*******************************/
//创建wifi热点:名称 密码 加密方式
#define ESP8266_BUILD_AP_NAME "ZDW_STM32F103"
#define ESP8266_BUILD_AP_PASSWORD "zdw123456"
#define ESP8266_BUILD_AP_FUNCTION OPEN
//wifi热点的IP 端口
#define ESP8266_TcpServer_IP "192.168.1.1"
#define ESP8266_TcpServer_Port "8080"
#define ESP8266_TcpServer_OverTime "1800" //秒
/*******************************************AP模式下*******************************/
/*
ESP8266 IO <------> STM32 IO
URXD PB10(tx)
UTXD PB11 (rx)
CH-PD PB8
RST PB9
*/
/******* ESP8266 pins *************/
//8266 CH_PD引脚
#define ESP8266_CH_PD_PORT GPIOB
#define ESP8266_CH_PD_PIN GPIO_PIN_8
#define ESP8266_CH_PD_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
//8266 RST引脚
#define ESP8266_RST_PORT GPIOB
#define ESP8266_RST_PIN GPIO_PIN_9
#define ESP8266_RST_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define ESP8266_CH_PD_ENABLE() HAL_GPIO_WritePin(ESP8266_CH_PD_PORT,ESP8266_CH_PD_PIN,GPIO_PIN_SET)
#define ESP8266_RST_ENABLE() HAL_GPIO_WritePin(ESP8266_RST_PORT,ESP8266_RST_PIN,GPIO_PIN_SET)
extern UART_HandleTypeDef WifiUartHandle;
//工作模式
typedef enum
{
AP,
STA,
STA_AP
}Net_ModeTypeDef;
//wifi创建热点 加密方式
typedef enum
{
OPEN = 0,
WEP = 1,
WPA_PSK = 2,
WPA2_PSK = 3,
WPA_WPA2_PSK = 4,
}ENUM_AP_PsdMode_TypeDef;
//网络协议
typedef enum{
enumTCP,
enumUDP,
} ENUM_NetPro_TypeDef;
//模块连接服务器ID
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;
//ESP8266GPIO初始化
void ESP8266_GPIO_Config(void);
//ESP8266模块初始化
void ESP8266_Init(void);
//发送AT指令到ESP8266
void ESP8266_Cmd(uint8_t *cmd);
//查找附近wifi
void ESP8266_Find_Wifi(void);
//测试AT指令
void ESP8266_AT_Test(void);
//测试透传模式
void ESP8266_PassThrough_Test(void);
//ESP8266工作模式选择
void ESP8266_Net_Mode(Net_ModeTypeDef enum_mode);
//连接外部wifi热点
void ESP8266_JoinAP(char *name,char * password);
//ESP8266模块创建WiFi热点:wifi名 wifi密码 wifi加密方式
void ESP8266_BuildAP(char *name,char *password,ENUM_AP_PsdMode_TypeDef enunPsdMode);
//ESP8266模块启动多连接
void ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx );
//Wifi模块连接外部服务器:网络协议 IP 端口 模块连接服务器ID
void ESP8266_Link_Server ( ENUM_NetPro_TypeDef enumE, char * ip, char * port, ENUM_ID_NO_TypeDef id);
//ESP8266模块开启或关闭服务器模式:enumMode(开启/关闭) pPortNum,服务器端口号字符串 pTimeOver服务器超时时间字符串,单位:秒
void ESP8266_StartOrShutServer ( FunctionalState enumMode, char * pPortNum, char * pTimeOver );
//获取 WF-ESP8266 的连接状态,较适合单端口时使用
uint8_t ESP8266_Get_LinkStatus ( void );
//获取 F-ESP8266 的 AP IP :pApIp,存放 AP IP 的数组的首地址 ucArrayLength,存放 AP IP 的数组的长度
uint8_t ESP8266_Inquire_ApIp ( char * pApIp, uint8_t ucArrayLength );
//ESP8266模块进入透传发送
void ESP8266_UnvarnishSend ( void );
#endif
esp8266.c
#include "esp8266.h"
#include "bsp_usart.h"
//CH-PD 和RST 引脚配置
void ESP8266_GPIO_Config()
{
//GPIO结构体
GPIO_InitTypeDef GPIO_InitStruct;
//开启外设时钟
ESP8266_CH_PD_CLK_ENABLE();
ESP8266_RST_CLK_ENABLE();
GPIO_InitStruct.Pin = ESP8266_CH_PD_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(ESP8266_CH_PD_PORT,&GPIO_InitStruct);
GPIO_InitStruct.Pin = ESP8266_RST_PIN;
HAL_GPIO_Init(ESP8266_RST_PORT,&GPIO_InitStruct);
}
//esp8266初始化 main调用
void ESP8266_Init(void)
{
ESP8266_GPIO_Config();
WIFI_USART_Config();
//CHPD RST 初始化为高电平
ESP8266_CH_PD_ENABLE();
ESP8266_RST_ENABLE();
}
//发送AT指令
void ESP8266_Cmd(uint8_t *cmd)
{
uint8_t data[2] = {'\r','\n'};
Usart_SendString(&WifiUartHandle,cmd);
Usart_SendString(&WifiUartHandle,data);
}
//测试AT指令 main调用 测试成功
void ESP8266_AT_Test(void)
{
ESP8266_Cmd("AT");
HAL_Delay(2000);
//ESP8266_Cmd("AT+CWLAP");
//HAL_Delay(2000);
//ESP8266_JoinAP("HonorNote10","zdw123456");
//HAL_Delay(2000);
}
//查找附近wifi
void ESP8266_Find_Wifi(void)
{
ESP8266_Cmd("AT+CWLAP");
}
//ESP8266工作模式选择
void ESP8266_Net_Mode(Net_ModeTypeDef enum_mode)
{
switch(enum_mode)
{
case AP:
ESP8266_Cmd("AT+CWMODE=2");
case STA:
ESP8266_Cmd("AT+CWMODE=1");
case STA_AP:
ESP8266_Cmd("AT+CWMODE=3");
default :
break;
}
}
//连接外部wifi热点
void ESP8266_JoinAP(char *name,char * password)
{
char cCmd [120];
sprintf ( cCmd, "AT+CWJAP=\"%s\",\"%s\"", name, password );
ESP8266_Cmd((uint8_t*)cCmd);
}
//ESP8266模块创建WiFi热点:wifi名 wifi密码 wifi加密方式
void ESP8266_BuildAP(char* name,char* password,ENUM_AP_PsdMode_TypeDef enunPsdMode)
{
char cCmd [120];
sprintf ( cCmd, "AT+CWSAP=\"%s\",\"%s\",1,%d", name, password, enunPsdMode );
ESP8266_Cmd ( (uint8_t*)cCmd );
}
//ESP8266模块启动多连接
void ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx )
{
char cStr [20];
sprintf ( cStr, "AT+CIPMUX=%d", ( enumEnUnvarnishTx ? 1 : 0 ) );
ESP8266_Cmd ( (uint8_t*)cStr);
}
//Wifi模块连接外部服务器:网络协议 IP 端口 模块连接服务器ID
void ESP8266_Link_Server ( ENUM_NetPro_TypeDef enumE, char * ip, char * port, ENUM_ID_NO_TypeDef id)
{
char cStr [100] = { 0 }, cCmd [120];
switch ( enumE )
{
case enumTCP:
sprintf ( cStr, "\"%s\",\"%s\",%s", "TCP", ip, port );
break;
case enumUDP:
sprintf ( cStr, "\"%s\",\"%s\",%s", "UDP", ip, port );
break;
default:
break;
}
if ( id < 5 )
sprintf ( cCmd, "AT+CIPSTART=%d,%s", id, cStr);
else
sprintf ( cCmd, "AT+CIPSTART=%s", cStr );
ESP8266_Cmd ( (uint8_t*)cCmd );
HAL_Delay(3000);
}
//ESP8266模块开启或关闭服务器模式:enumMode(开启/关闭) pPortNum,服务器端口号字符串 pTimeOver服务器超时时间字符串,单位:秒
void ESP8266_StartOrShutServer ( FunctionalState enumMode, char * pPortNum, char * pTimeOver )
{
char cCmd1 [120], cCmd2 [120];
if ( enumMode ) {
sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 1, pPortNum );
sprintf ( cCmd2, "AT+CIPSTO=%s", pTimeOver );
ESP8266_Cmd ( (uint8_t*)cCmd1 );
ESP8266_Cmd ( (uint8_t*)cCmd2 );
}
else
{
sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 0, pPortNum );
ESP8266_Cmd ( (uint8_t*)cCmd1 );
}
}
//获取 WF-ESP8266 的连接状态,较适合单端口时使用
uint8_t ESP8266_Get_LinkStatus ( void )
{
ESP8266_Cmd ( "AT+CIPSTATUS" );
//这里要解决:读取ESP返回的数据
//当前处理的方法是 将ESP的数据直接转uart1 打印到上位机
/*if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:2\r\n" ) )
return 2; //获得ip
else if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:3\r\n" ) )
return 3;//建立连接
else if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:4\r\n" ) )
return 4;//失去连接
*/
return 0;//0,获取状态失败
}
//获取 F-ESP8266 的 AP IP :pApIp,存放 AP IP 的数组的首地址 ucArrayLength,存放 AP IP 的数组的长度
uint8_t ESP8266_Inquire_ApIp ( char * pApIp, uint8_t ucArrayLength )
{
char uc;
char * pCh;
ESP8266_Cmd ( "AT+CIFSR" );
//获取ESP8266结果 放内存中
/*
pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "APIP,\"" );
if ( pCh )
pCh += 6;
else
return 0;
for ( uc = 0; uc < ucArrayLength; uc ++ )
{
pApIp [ uc ] = * ( pCh + uc);
if ( pApIp [ uc ] == '\"' )
{
pApIp [ uc ] = '\0';
break;
}
}
*/
return 1;
}
//ESP8266模块进入透传发送
void ESP8266_UnvarnishSend ( void )
{
ESP8266_Cmd ( "AT+CIPMODE=1" );
HAL_Delay(2000);
ESP8266_Cmd ( "AT+CIPSEND");
}
//ESP8266模块退出透传模式
void ESP8266_ExitUnvarnishSend ( void )
{
HAL_Delay(500);
Usart_SendString (&WifiUartHandle ,"+++" );
HAL_Delay ( 500 );
}
/*
* 函数名:ESP8266_SendString
* 描述 :WF-ESP8266模块发送字符串
* 输入 :enumEnUnvarnishTx,声明是否已使能了透传模式
* :pStr,要发送的字符串
* :ulStrLength,要发送的字符串的字节数
* :ucId,哪个ID发送的字符串
* 返回 : 1,发送成功
* 0,发送失败
* 调用 :被外部调用
*/
/*
bool ESP8266_SendString ( FunctionalState enumEnUnvarnishTx, char * pStr, u32 ulStrLength, ENUM_ID_NO_TypeDef ucId )
{
char cStr [20];
bool bRet = false;
if ( enumEnUnvarnishTx )
{
macESP8266_Usart ( "%s", pStr );
bRet = true;
}
else
{
if ( ucId < 5 )
sprintf ( cStr, "AT+CIPSEND=%d,%d", ucId, ulStrLength + 2 );
else
sprintf ( cStr, "AT+CIPSEND=%d", ulStrLength + 2 );
ESP8266_Cmd ( cStr, "> ", 0, 1000 );
bRet = ESP8266_Cmd ( pStr, "SEND OK", 0, 1000 );
}
return bRet;
}*/
/*
* 函数名:ESP8266_ReceiveString
* 描述 :WF-ESP8266模块接收字符串
* 输入 :enumEnUnvarnishTx,声明是否已使能了透传模式
* 返回 : 接收到的字符串首地址
* 调用 :被外部调用
*/
/*
char * ESP8266_ReceiveString ( FunctionalState enumEnUnvarnishTx )
{
char * pRecStr = 0;
strEsp8266_Fram_Record .InfBit .FramLength = 0;
strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0;
while ( ! strEsp8266_Fram_Record .InfBit .FramFinishFlag );
strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0';
if ( enumEnUnvarnishTx )
pRecStr = strEsp8266_Fram_Record .Data_RX_BUF;
else
{
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+IPD" ) )
pRecStr = strEsp8266_Fram_Record .Data_RX_BUF;
}
return pRecStr;
}*/
//测试透传模式
void ESP8266_PassThrough_Test(void)
{
ESP8266_AT_Test();
//工作模式选择 sta
ESP8266_Net_Mode(STA);
HAL_Delay(3000);
//连接热点
ESP8266_JoinAP(ESP8266_JOIN_AP_NAME,ESP8266_JOIN_AP_PASSWORD);
HAL_Delay(5000);
//不启动多连接
ESP8266_Enable_MultipleId ( DISABLE );
HAL_Delay(5000);
//连接服务器 TCP IP PORT
ESP8266_Link_Server(enumTCP,ESP8266_CONNECT_TCPSERVER_IP,ESP8266_CONNECT_TCPSERVER_PORT,Single_ID_0);
HAL_Delay(5000);
//进入透传发送
ESP8266_UnvarnishSend();
printf("set ESP8266 OK,now go into PassThrough Mode!\n");
}
stm32f1xx_it.c
在中断中处理串口接收到的数据,串口1接收到上位机的数据,就把数据直接转给串口3,相当于发送给esp8266.
同样的,进入透传模式后,服务器将数据发送给esp8266,8266接收到数据交给串口3,刺客对于stm32来说是串口3接收到数据,接收到数据后将数据直接写在串口1中,电脑上位机会把数据打印出来....
好晕啊 ...
//串口1中断函数:stm32接收到上位机的数据
void DEBUG_USART_IRQHandler(void)
{
uint8_t ch = 1;
if (__HAL_UART_GET_FLAG( &DebugUartHandle, UART_FLAG_RXNE ) != RESET)
{
//读寄存器
ch=( uint16_t)READ_REG(DebugUartHandle.Instance->DR);
//将串口1的数据 写入串口3(串口3将数据 -> esp8266)
WRITE_REG ( WifiUartHandle.Instance->DR,ch);
}
}
//串口3中断函数:stm32接收到esp8266的数据
void WIFI_USART_IRQHandle(void)
{
uint8_t ch = 1;
if (__HAL_UART_GET_FLAG( &WifiUartHandle, UART_FLAG_RXNE ) != RESET)
{
ch=( uint16_t)READ_REG(WifiUartHandle.Instance->DR);
//给串口1 :串口1发送到上位机(显示出log)
WRITE_REG ( DebugUartHandle.Instance->DR,ch);
}
}
main.c
初始化好esp8266的硬件后,调用透传测试接口就OK了!
int main(void)
{
HAL_Init();
/* 系统时钟初始化成72 MHz */
SystemClock_Config();
/* LED 端口初始化 */
LED_GPIO_Config();
//按键中断初始化
EXTI_Key_Config();
//初始化串口1
DEBUG_USART_Config();
printf("zdw is testing Wifi.....\n\n");
//初始化esp8266
ESP8266_Init();
HAL_Delay(3000);
//透传任务测试:之后加入FreeRTOS后,开启一个wifi任务
ESP8266_PassThrough_Test();
while (1)
{
HAL_Delay(3000);
//ESP8266_AT_Test();
//test_uart1();
}
}
三、效果图
现在我的开发板和笔记本都连接着手机wifi热点,他俩在同一局域网下。
电脑端打开网络调试助手,设置自己的TCPServer的IP和端口8000,笔记本通过网络调试助手发送数据后,板子的wif模块接收到数据,将数据透传给stm32,stm32接收到数据将数据打印到上位机(也就是我的主机电脑)。
四、总结
透传做完了,感觉ESP8266的内容其实就完了。之后就去改进:加入FreeRTOS,专门给WIFI开一个任务,串口的接收也做一个任务,根据接收到的数据去完成相应动作比如点灯之类的。
可以看MQTT了,之后要做的就是:移植mqtt,阿里云物联网创建账号。
对这个现在一点不清楚该怎么做,不知道难不难.... 加油
完整工程代码:
https://download.csdn.net/download/zDavid_2018/12800241