前言
本文所使用的软硬件开发环境:
1.STM32F4系板子
2.ESP8266wifi模块
3.USB-UART模块
4.xcom串口调试助手
ESP8266
引脚使用:
使用3.3v供电,通过RX TX 与STM32进行通信,GND接地
ESP8266内置了TCP/IP协议栈,支持三种网络模式:AP、STA和AP+STA。
AP模式:模块作为WIFI热点,等待其他设备的连接,进行局域网通信
STA模式:模块作为客户端通过路由器连接外网,和服务器进行通信
混合模式:两个模式共存,可以进行任意切换
该模块集成由AT指令集,通过发送mcu向模块发送AT指令即可实现操作,简单快捷。
常用AT指令
命令 | 描述 |
---|---|
AT | 测试AT启动 |
AT+RST | 重启模块 |
AT+RESTORE | 重置模块 |
AT+CWMODE | 设置网络模式 |
AT+CWJAP | 连接WIFI |
AT+CIPSTART | 建立TCP连接 |
AT+CIPMODE | 设置模块传输模式 |
AT+CIPSEND | 传输数据 |
+++ | 退出透传模式 |
简单介绍:
AT+CWMODE=mode
- mode=1 STA模式(做客户端,连接其他热点)
- mode=2 AP模式(做服务器,自己作为热点给别人连)
- mode=3 混合模式
AT+CWJAP =“wifi名”,“密码”
AT+CIPSTART=“TCP”,“IP地址”,端口号
AT+CIPMOD=1 开启透传模式
AT+CIPSEND=n
- n=1开始透传,直到使用+++退出透传
- n>1传输n个字节的数据后退出透传
STM32F4与esp8266通信
硬件连接:
esp8266与stm32通过UART通信,需要四根线,分别是电源3v3,GND,TX,RX。
代码编写
1.串口配置
本实验是使用的hal库编写,故该步骤可使用cubemx来进行配置
2.编写串口相关函数
//声明要使用的变量
uint8_t USART1Rev=0;
uint8_t USART5Rev=0;
uint8_t USART5Rev_Flag=0;
uint8_t USART1Rev_Flag=0;
#define MAX 1024
#define MAX_LEN 1024
typedef struct{
uint8_t Txdata[MAX];
uint8_t Txcnt;
uint8_t Rxdata[MAX];
uint16_t Rxcnt;
uint8_t Rxflag;
}WIFI_DATA;
WIFI_DATA wifi={0};
首先开启接收中断和空闲中断
void UART5_Init(void)//串口5初始化
{
__HAL_UART_ENABLE_IT(&huart5,UART_IT_IDLE);//开启空闲中断
HAL_UART_Receive_IT(&huart5,&USART5Rev,1);//注册接收中断
}
void USART1_Init(void)
{
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
HAL_UART_Receive_IT(&huart1,&USART1Rev,1);
}
在串口中断中判断空闲中断,并进入回调函数
void UART5_IRQHandler(void)
{
/* USER CODE BEGIN UART5_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart5,UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart5);
HAL_UART_IdleCallback(&huart5);
}
/* USER CODE END UART5_IRQn 0 */
HAL_UART_IRQHandler(&huart5);
/* USER CODE BEGIN UART5_IRQn 1 */
/* USER CODE END UART5_IRQn 1 */
}
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
HAL_UART_IdleCallback(&huart1);
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
编写回调函数
//空闲中断回调函数
void HAL_UART_IdleCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==UART5)
{
wifi.Rxflag=1;
revCount=0;
}
}
//串口接收回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1)
{
revBuff[revCount++]=USART1Rev;
// UART5->DR=USART5Rev;
HAL_UART_Receive_IT(&huart1,&USART1Rev,1);
}
if(huart->Instance==UART5)
{
wifi.Rxdata[wifi.Rxcnt++]=USART5Rev;
USART1->DR=USART5Rev;
HAL_UART_Receive_IT(&huart5,&USART5Rev,1);
}
}
编写串口发送函数
//串口发送字符串
void USART5_SendStr(uint8_t *data)
{
while(*data)
{
HAL_UART_Transmit(&huart5,(uint8_t *)data,1,100);
data++;
}
//HAL_UART_Transmit(&huart5,data,sizeof(data),HAL_MAX_DELAY); //错误,直接发一串数据过去不行
}
void USART5_SendStrlen(uint8_t *data,uint16_t len)
{
int i=0;
for(i=0;i<len;i++)
{
HAL_UART_Transmit(&huart5,(uint8_t *)data,1,100);
data++;
}
}
2.编写ESP8266相关函数
数据缓冲区清理函数
void Clean_buff(void)
{
memset(wifi.Rxdata,0,sizeof(wifi.Rxdata));
wifi.Rxcnt=0;
wifi.Rxflag=0;
wifi.Txcnt=0;
}
向ESP8266发送数据函数
uint8_t WIFI_SendCMD(uint8_t *CMD,uint8_t *ACK,uint16_t timeout)
{
// printf("%s\r\n",CMD);
Clean_buff();
USART5_SendStr(CMD);
while(timeout--)
{
if(wifi.Rxflag==1)
{
if(strstr((char *)wifi.Rxdata,(char *)ACK)!=NULL)
{
return 1;
}
}
HAL_Delay(1);
}
return 0;
}
3.最后一步WIFI连接
//初始化WIFI,进入透传模式
uint8_t WIFI_Init(void)
{
if(WIFI_SendCMD((uint8_t *)"AT\r\n",(uint8_t *)"OK",500)==0) return 1;
if(WIFI_SendCMD((uint8_t *)"AT+CWMODE=1\r\n",(uint8_t *)"OK",2000)==0) return 2;
if(WIFI_SendCMD((uint8_t *)"AT+CWJAP=\"PC-20220213UNDT 2427\",\"12345678\"\r\n",(uint8_t *)"OK",12000)==0) return 3;
if(WIFI_SendCMD((uint8_t *)"AT+CIPSTART=\"TCP\",\"iot-06z00d6p8f3ii1c.mqtt.iothub.aliyuncs.com\",1883\r\n",(uint8_t *)"OK",12000)==0) return 4;
if(WIFI_SendCMD((uint8_t *)"AT+CIPMODE=1\r\n",(uint8_t *)"OK",5000)==0) return 5;
if(WIFI_SendCMD((uint8_t *)"AT+CIPSEND\r\n",(uint8_t *)">",5000)==0) return 6;
return 0;
}
结语
使用STM32与ESP8266建立通信后,可以实现很多任务,比如通过wifi获取时间,通过wifi连接云平台,通过wifi获取天气与地址等等,这些内容将在下一篇具体展示。