【stm32】wifi ESP8266的透传 实验二(HAL库开发)

一、

总算完成了透传,感觉没几行代码,就是在昨天的基础上,对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 <stdio.h>


/*******************************************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

猜你喜欢

转载自blog.csdn.net/zDavid_2018/article/details/108366860