ESP8266系列无线模块是安信可科技自主研发设计的一系列高性价比WiFisOC模组。该系列模块支持标准的IEEE802.11 b/g/n 协议,内置完整的TCP/IP协议栈。用户可以使用该系列模块为现有的设备添加联网功能,也可以构建独立的网络控制器。即使在不了解其原理的情况下,只要有一定的串口知识理解,那么就可以轻松上手该模块,进而实现手机WiFi操作。功能特点:基于ESP8266芯片开发,模组集成了透传功能,即买即用,支持串口AT指令集,用户通过串口即可实现网络访问,广泛应用于智能穿戴,智能家居,家庭安防,遥控器,汽车电子,智慧照明,工业物联网等领域。
一模块来源
模块实物展示:
资料链接:https://pan.baidu.com/s/13mQInPq5drMzs8sXzC14dQ
资料提取码:pj4z
二规格参数
工作电压:3.0V-3.6V
工作电流:IMAX = 170mA
模块尺寸:14.4 x 24.7 MM
控制方式:串口
三移植过程
我们的目标是在立创·CW32F030C8T6开发板上能够完成无线传输的功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
3.1查看资料
该WIFI模块,有三种模式即STA、AP、STA+AP。
这里主要使用AP和STA模式作为案例,实现近距离无线控制和远距离无线控制。
STA模式是指ESP8266作为客户端连接到一个无线路由器上(或者无线热点),可以访问网络中的其他设备。
AP模式是指ESP8266作为热点,其他设备可以连接到它上面,实现无线网络通信。
STA+AP模式就是两者同时实现。、
使用前,需要烧入MQTT固件,后续的案例有使用MQTT,如不烧入MQTT固件,在涉及到MQTT的AT命令时会不断失败。
固件下载地址:
链接:https://pan.baidu.com/s/1BB_X7XhKpedunGY1EIFX7A?pwd=LCKF
提取码:LCKF
固件烧录接线:
烧录步骤:
链接:https://pan.baidu.com/s/1acnXmU3ASNQMjsner4DSrA?pwd=LCKF
提取码:LCKF
3.2引脚选择
使用串口2(串口2-TX=PA2,串口2-RX=PA3)
模块接线图
3.3移植至工程
移植步骤中的导入.c和.h文件与【CW32模块使用】DHT11温湿度传感器相同,只是将.c和.h文件更改为bsp_esp01s.c与bsp_esp01s.h。这里不再过多讲述,移植完成后面修改相关代码。
在文件bsp_esp01s.c中,编写如下代码。
/*
* Change Logs:
* Date Author Notes
* 2024-06-21 LCKFB-LP first version
*/
#include "bsp_ESP01S.h"
#include "stdio.h"
#include "hmacsha1.h"
#include "string.h"
#include <stdlib.h>
unsigned char WIFI_RX_BUFF[WIFI_RX_LEN_MAX];
unsigned char WIFI_RX_FLAG = 0;
unsigned char WIFI_RX_LEN = 0;
uint8_t wifi_link_flag = 0;//设备连接状态
//配合 Get_Device_connection_status 函数使用
// * 0=没有设备连接
// * 1=有设备连接了WIFI
// * 0=有设备断开了WIFI
// * 2=有设备连接了服务器
// * 3=有设备断开了服务器
/************************************************************
* 函数名称:WIFI_USART_Init
* 函数说明:连接WIFI的初始化
* 型 参:bund=串口波特率
* 返 回 值:无
* 备 注:无
*************************************************************/
void WIFI_USART_Init(unsigned int bund)
{
GPIO_InitTypeDef GPIO_InitStruct; // GPIO初始化结构体
RCC_WIFI_GPIO_ENABLE(); // 使能GPIO时钟
RCC_WIFI_USART_ENABLE(); // 使能UART时钟
GPIO_InitStruct.Pins = GPIO_WIFI_TX; // GPIO引脚
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; // 输出速度高
GPIO_Init(PORT_WIFI_GPIO, &GPIO_InitStruct); // 初始化
GPIO_InitStruct.Pins = GPIO_WIFI_RX; // GPIO引脚
GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP; // 上拉输入
GPIO_Init(PORT_WIFI_GPIO, &GPIO_InitStruct); // 初始化
BSP_GPS_AF_UART_TX(); // UART_TX复用
BSP_GPS_AF_UART_RX(); // UART_RX复用
// 配置UART
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = bund; // 波特率
USART_InitStructure.USART_Over = USART_Over_16; // 配置USART的过采样率。
USART_InitStructure.USART_Source = USART_Source_PCLK; // 设置时钟源
USART_InitStructure.USART_UclkFreq = 64000000; //设置USART时钟频率(和主频一致即可)
USART_InitStructure.USART_StartBit = USART_StartBit_FE; //RXD下降沿开始
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 停止位1
USART_InitStructure.USART_Parity = USART_Parity_No ; // 不使用校验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 不使用流控
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 收发模式
USART_Init(WIFI_USART, &USART_InitStructure); // 初始化串口2
// 优先级,无优先级分组
NVIC_SetPriority(WIFI_USART_IRQ, 0);
// UARTx中断使能
NVIC_EnableIRQ(WIFI_USART_IRQ);
// 使能UARTx RC中断
USART_ITConfig(WIFI_USART, USART_IT_RC, ENABLE);
}
/******************************************************************
* 函 数 名 称:WIFI_USART_Send_Bit
* 函 数 说 明:向WIFI模块发送单个字符
* 函 数 形 参:ch=字符
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void WIFI_USART_Send_Bit(unsigned char ch)
{
// 发送一个字节
USART_SendData_8bit(WIFI_USART, (uint8_t)ch);
// 等待发送完成
while( RESET == USART_GetFlagStatus(WIFI_USART, USART_FLAG_TXE) ){}
}
/******************************************************************
* 函 数 名 称:WIFI_USART_send_String
* 函 数 说 明:向WIFI模块发送字符串
* 函 数 形 参:str=发送的字符串
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void WIFI_USART_send_String(unsigned char *str)
{
printf("string : %srn",str);
while( str && *str ) // 地址为空或者值为空跳出
{
WIFI_USART_Send_Bit(*str++);
}
}
//清除串口接收的数据
/******************************************************************
* 函 数 名 称:Clear_WIFI_RX_BUFF
* 函 数 说 明:清除WIFI发过来的数据
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void Clear_WIFI_RX_BUFF(void)
{
unsigned char i = WIFI_RX_LEN_MAX-1;
while(i)
{
WIFI_RX_BUFF[i--] = 0;
}
WIFI_RX_LEN = 0;
WIFI_RX_FLAG = 0;
}
/******************************************************************
* 函 数 名 称:WIFI_Send_Cmd
* 函 数 说 明:向WIFI模块发送指令,并查看WIFI模块是否返回想要的数据
* 函 数 形 参:cmd=发送的AT指令 ack=想要的应答 waitms=等待应答的时间 cnt=等待应答多少次
* 函 数 返 回:1=得到了想要的应答 0=没有得到想要的应答
* 作 者:LC
* 备 注:无
******************************************************************/
char WIFI_Send_Cmd(char *cmd,char *ack,unsigned int waitms,unsigned char cnt)
{
uint8_t tt = 0;
re:
WIFI_USART_send_String((unsigned char*)cmd);//1.发送AT指令
while(cnt--)
{
//时间间隔
delay_1ms(waitms);
//串口中断接收蓝牙应答
if( WIFI_RX_FLAG == 1 )
{
WIFI_RX_FLAG = 0;
WIFI_RX_LEN = 0;
//查找是否有想要的数据
if( strstr((char*)WIFI_RX_BUFF, ack) != NULL )
{
return 1;
}
//清除接收的数据
memset( WIFI_RX_BUFF, 0, sizeof(WIFI_RX_BUFF) );
}
}
WIFI_RX_FLAG = 0;
WIFI_RX_LEN = 0;
if(tt < 3)
{
tt++;
goto re;
}
return 0;
}
/******************************************************************
* 函 数 名 称:WIFI_ESP01S_Init
* 函 数 说 明:WIFI模块ESP01S初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:ESP01S的默认波特率是115200
******************************************************************/
void WIFI_ESP01S_Init(void)
{
WIFI_USART_Init(115200);//默认波特率为115200
}
/******************************************************************
* 函 数 名 称:WIFI_MODE_AP_Init
* 函 数 说 明:开启AP模式,即模块开启热点让手机连接
* 函 数 形 参:无
* 函 数 返 回:1=配置成功 其他=失败
* 作 者:LC
* 备 注:手机通过WIFI模块默认的IP地址192.168.4.1和设置的端口号,进行连接
******************************************************************/
uint8_t WIFI_MODE_AP_Init(void)
{
uint8_t ret = 0;
char send_buff[200];
ret = WIFI_Send_Cmd("ATrn", "OK", 10, 3);//测试指令:ATrn 成功返回OK 失败返回ERROR
if( ret != 1 ) return ret;
ret = WIFI_Send_Cmd("AT+CWMODE=2rn","OK",30,3); //配置WIFI AP模式
if( ret != 1 ) return ret;
sprintf(send_buff, "AT+CWSAP="%s","%s",11,4rn", AP_WIFISSID,AP_WIFIPASS );
ret = WIFI_Send_Cmd(send_buff,"OK",30,3); //设置wifi账号与密码
if( ret != 1 ) return ret;
ret = WIFI_Send_Cmd("AT+RSTrn","ready",800,3); //重新复位
if( ret != 1 ) return ret;
ret = WIFI_Send_Cmd("AT+CIPMUX=1rn","OK",50,3); //开启多个连接
if( ret != 1 ) return ret;
ret = WIFI_Send_Cmd("AT+CIPSERVER=1,5000rn","OK",50,3); //开启服务器设置端口号为5000
if( ret != 1 ) return ret;
return ret;
}
/******************************************************************
* 函 数 名 称:Get_Device_connection_status
* 函 数 说 明:获取设备连接状态(AP模式)
* 函 数 形 参:无
* 函 数 返 回:0=没有设备连接
* 1=有设备连接了WIFI
* 2=有设备断开了WIFI
* 3=有设备连接了服务器
* 4=有设备断开了服务器
* 作 者:LC
* 备 注:手机要连接WIFI模块的步骤是先连接WIFI再连接服务器
//当有设备连接AP模式下的热点时,WIFI模块会给连接的设备分配IP地址
//我们只需检测是否有分配地址,则知道是否有设备连接。
//设备连接时WIFI返回:
// +STA_CONNECTED:"f0:6c:5d:d6:f6:18"
// +DIST_STA_IP:"f0:6c:5d:d6:f6:18","192.168.4.2"
//设备断开连接时返回:
// +STA_DISCONNECTED:"f0:6c:5d:d6:f6:18"
******************************************************************/
uint8_t Get_Device_connection_status(void)
{
//串口中断接收WIFI应答
if( WIFI_RX_FLAG == 1 )
{
WIFI_RX_FLAG = 0;
WIFI_RX_LEN = 0;
//有设备连接了热点
if( strstr((char*)WIFI_RX_BUFF, "+STA_CONNECTED") != NULL )
{
//清除接收的数据
wifi_link_flag = 1;
memset( WIFI_RX_BUFF, 0, sizeof(WIFI_RX_BUFF) );
#if DEBUG
printf("The device is connected to a hotspot.rn");
#endif
return 1;
}
//有设备断开了热点
if( strstr((char*)WIFI_RX_BUFF, "+STA_DISCONNECTED") != NULL )
{
//清除接收的数据
wifi_link_flag = 0;
memset( WIFI_RX_BUFF, 0, sizeof(WIFI_RX_BUFF) );
#if DEBUG
printf("The device is disconnected from the hotspot.rn");
#endif
return 2;
}
//有设备连接了服务器
if( strstr((char*)WIFI_RX_BUFF, ",CONNECT") != NULL )
{
//清除接收的数据
wifi_link_flag = 2;
memset( WIFI_RX_BUFF, 0, sizeof(WIFI_RX_BUFF) );
return 3;
#if DEBUG
printf("The device is connected to the server.rn");
#endif
}
//有设备断开了服务器
if( strstr((char*)WIFI_RX_BUFF, ",CLOSED") != NULL )
{
//清除接收的数据
wifi_link_flag = 3;
memset( WIFI_RX_BUFF, 0, sizeof(WIFI_RX_BUFF) );
return 4;
#if DEBUG
printf("The device is disconnected from the server.rn");
#endif
}
}
return 0;
}
/**********************************************************
* 函 数 名 称:Get_WIFI_AP_Data
* 函 数 功 能:解析设备发送过来的数据
* 传 入 参 数:ap_parameter要将数据保存的地址
* 函 数 返 回:1:有设备发送过来数据 0:没有设备发送过来数据
* 作 者:LC
* 备 注:device_id最大5个 //+IPD,1,4:abcd
**********************************************************/
uint8_t Get_WIFI_AP_Data(AP_PARAMETER *ap_parameter)
{
char buff[50];
char *test;
char i=0;
//接收到设备发过来的数据
if( strstr((char*)WIFI_RX_BUFF,"+IPD,") != NULL )
{
test = strstr((char*)WIFI_RX_BUFF,"+IPD,");
//记录设备ID号
strncpy(buff,test+5,1);
buff[1] ='';
ap_parameter->device_id = atoi(buff);
printf("device_id = %srn",buff);
//记录发送过来的数据长度
strncpy(buff,test+7,strcspn(test+7,":") );
buff[ strcspn(test+7,":") ] ='';
printf("device_data = %srn",buff);
ap_parameter->device_datalen = atoi(buff);
printf("device_datalen = %srn",buff);
//记录发送过来的数据
memset(buff,0,sizeof(buff));
while(test[i++]!=':');
strncpy(buff, test+i,strcspn(test+i,"r") );
printf("device_data = %srn",buff);
strcpy((char*)ap_parameter->device_data, buff);
//清除串口接近缓存
Clear_WIFI_RX_BUFF();
return 1;
}
return 0;
}
/******************************************************************
* 函 数 名 称:WIFI_Send_To_Client
* 函 数 说 明:AP模式下,WIFI发送数据至客户端(连接AP模式下热点的设备)
* 函 数 形 参:id=向第几个客户端发送数据 data=要发送的数据(字符串形式)
* 函 数 返 回:0=发送失败 1=发送成功
* 作 者:LC
* 备 注:使用该函数函数请确保WIFI模块处于AP模式
******************************************************************/
uint8_t WIFI_Send_To_Client(uint8_t id,char * data)
{
uint8_t send_buf[20]={0};
sprintf((char*)send_buf,"AT+CIPSEND=%d,%drn",id,strlen(data));
if(WIFI_Send_Cmd((char*)send_buf,">",20,3))
{
WIFI_USART_send_String((unsigned char *)data);
return 1;
}
return 0;
}
/******************************************************************
* 函 数 名 称:mstrcat
* 函 数 说 明:字符串连接
* 函 数 形 参:s1:目标字符串, s2:源字符串
* 函 数 返 回:无
* 作 者:LC
* 备 注:哈希使用
******************************************************************/
static void mstrcat(char *s1, const char *s2)
{
// 寻找s1的末尾(即''字符)
while(*s1 != '')
s1++;
// 将s2的内容复制到s1的末尾,包括s2的结束字符''
while((*s1++ = *s2++));
}
/******************************************************************
* 函 数 名 称:CalculateSha1
* 函 数 说 明:计算sha1密匙
* 函 数 形 参:password:密匙存放缓冲区
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
static void CalculateSha1(unsigned char *password)
{
unsigned char temp[3] = {0};
unsigned char digest[30]={0};
unsigned char cnt = 0;
hmac_sha1((unsigned char *)DeviceSecret,32,(unsigned char *)Encryption,46,digest);
memset(temp, 0, sizeof(temp));
for(cnt=0;cnt<20;cnt++)
{
sprintf((char *)temp,"%02X",digest[cnt]);
mstrcat((char *)password,(char *)temp);
}
}
/******************************************************************
* 函 数 名 称:WIFI_MODE_STA_Aliyun_Init
* 函 数 说 明:配置WIFI模块连接阿里云物联网平台
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void WIFI_MODE_STA_Aliyun_Init(void)
{
char AT_CMD[250]={0};
uint8_t PassWord[50] = {0}; //存放的是哈希计算的密钥
RST:
//测试指令AT
WIFI_Send_Cmd("ATrn","OK",100,3);
//配置WIFI STA
WIFI_Send_Cmd("AT+CWMODE=1rn","OK",300,3);
//设置时区 NTSP服务器 用于调整客户端自身所在系统的时间,达到同步时间的目的
WIFI_Send_Cmd("AT+CIPSNTPCFG=1,8,"ntp1.alliyun.com"rn","OK",100,3);
//连接wifi 账号&密码
sprintf(AT_CMD,"AT+CWJAP="%s","%s"rn",WIFISSID,WIFIPASS);
if( WIFI_Send_Cmd(AT_CMD,"OK",3000,3) == 0 )
{
printf("WIFI名称或密码有错,复位重启rn");
//wifi连接不上,重启
WIFI_Send_Cmd("AT+RSTrn","ready",1000,1);
goto RST;
}
//清0数组,备用
memset(AT_CMD,0,sizeof(AT_CMD));
//计算哈希
CalculateSha1(PassWord);
#if DEBUG
// sprintf(PassWord,"%s","AF7596ADFFD4C57C5FD43F1CA1A20DE961634360");
printf("haxi=%srn",PassWord);
printf("UserName=%srn",UserName);
#endif
sprintf(AT_CMD,"AT+MQTTUSERCFG=0,1,"NULL","%s","%s",0,0,""rn", UserName, PassWord);
WIFI_Send_Cmd(AT_CMD,"OK",2000,3);
//设置连接客户端ID
memset(AT_CMD,0,sizeof(AT_CMD)); //清0数组,备用
sprintf(AT_CMD,"AT+MQTTCLIENTID=0,"%s"rn",ClientId);
WIFI_Send_Cmd(AT_CMD,"OK",1000,3);
//连接到MQTT代理(阿里云平台)
memset(AT_CMD,0,sizeof(AT_CMD));
sprintf(AT_CMD,"AT+MQTTCONN=0,"%s",1883,1rn",IP);
if(WIFI_Send_Cmd(AT_CMD,"OK",2000,3)==0)
{
printf("连接aliyu失败,复位STM32重连rn");
//wifi连接不上,重启 1000延时1S 2链接次数
WIFI_Send_Cmd("AT+RSTrn","ready",1000,2);
// __set_FAULTMASK(1); //STM32程序软件复位
NVIC_SystemReset();
}
//订阅主题
memset(AT_CMD,0,sizeof(AT_CMD));
sprintf(AT_CMD, "AT+MQTTSUB=0,"%s",1rn", PublishMessageTopSet);
WIFI_Send_Cmd(AT_CMD,"OK",1000,3);
printf("连接aliyu成功rn");
Clear_WIFI_RX_BUFF();//清除串口接收缓存
//上电就上传数据至手机
// Publish_MQTT_message(publish_mqtt_message,5,); //发布主题
}
/*点击LED开关
+MQTTSUBRECV:0,"/sys/a1PJRLOWo3p/TEST/thing/service/property/set",100,
{"method":"thing.service.property.set","id":"367399823","params":{"LED_Switch":1},"version":"1.0.0"}
*/
/*滑动亮度条
+MQTTSUBRECV:0,"/sys/a1PJRLOWo3p/TEST/thing/service/property/set",101,
{"method":"thing.service.property.set","id":"812539841","params":{"brightness":75},"version":"1.0.0"}
*/
/******************************************************************
* 函 数 名 称:Get_Aliyun_json_data
* 函 数 说 明:获取阿里云JSON格式的数据(接收手机发送过来的数据)
* 函 数 形 参:data=数据的保存地址
* 函 数 返 回:1=接收到JSON数据并处理 0=没有接收到数据
* 作 者:LC
* 备 注:无
******************************************************************/
uint8_t Get_Aliyun_json_data(JSON_PUBLISH *data)
{
char *buff=0;
//串口中断接收WIFI应答
if( WIFI_RX_FLAG == SET )
{
printf("rn--rn");
WIFI_RX_FLAG = 0;
WIFI_RX_LEN = 0;
//有设备连接了热点
if( strstr((char*)WIFI_RX_BUFF, "params":") != NULL )
{
//获取功能名称
buff = strstr((char*)WIFI_RX_BUFF, "params":");
buff += strlen("params":{"");
strcpy(data->keyname,strtok(buff,"""));
printf("data->keyname = %srn",data->keyname);
//获取功能值
buff = strstr((char*)WIFI_RX_BUFF, "params":" );
buff += strlen("params":{"")+strlen(data->keyname)+2;
strcpy(data->value, strtok(buff,"}"));
return 1;
}
}
return 0;
}
/******************************************************************
* 函 数 名 称:Clear_Aliyun_json_data
* 函 数 说 明:清除JSON接收过的数据
* 函 数 形 参:data=要清除的数据
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void Clear_Aliyun_json_data(JSON_PUBLISH *data)
{
uint16_t i = 0;
while( data->keyname[i] != 0 )
{
data->keyname[i++] = '';
}
i= 0;
while( data->value[i] != 0 )
{
data->keyname[i++] = '';
}
}
//在自定义功能时,有多少个标识符,就添加多少个
//我就只有两个标识符。
//LED_Switch=LED开关 范围0-1
//brightness=亮度 范围0-100
JSON_PUBLISH publish_mqtt_message[2]=
{
{ ""LED_Switch":","0" },
{ ""brightness":","0" }
};
/******************************************************************
* 函 数 名 称:Publish_MQTT_message
* 函 数 说 明:发布主题 ,上发多个数据(设备将数据发送至手机)
* 函 数 形 参:data=publish_mqtt_message, data_num=上传的数据个数
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void Publish_MQTT_message(JSON_PUBLISH *data,uint8_t data_num)
{
char AT_CMD[384]={0};
char params[256]={0},i,*sp;
sp=params;
sprintf(data[0].value,"%d",0); //把传感器的值赋值给json结构体的value
sprintf(data[1].value,"%d",90);
// 4
for(i=0;i<data_num;i++)
{ // 3
if(i<(data_num-1))
{
sprintf(sp,"%s%s%s",data[i].keyname,data[i].value,",");
while(*sp!=0) {sp++;} //防止覆盖
}
else
sprintf(sp,"%s%s",data[i].keyname,data[i].value);
}
sprintf(AT_CMD,"AT+MQTTPUB=0,"%s","{"params":{%s}}",1,0rn",PublishMessageTopPost,params);
//发送指令后等待2000ms再判断是否发送成功,不发送成功则重发3-1次
//这里会阻塞CPU的运行,可以直接使用 WIFI_USART_send_String(AT_CMD); 发送,但是无法判断是否发送成功。
WIFI_Send_Cmd(AT_CMD,"OK",2000,3);
}
/******************************************************************
* 函 数 名 称:WIFI_USART_IRQHandler
* 函 数 说 明:连接WIFI的串口中断服务函数
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void WIFI_USART_IRQHandler(void)
{
if(USART_GetITStatus(WIFI_USART, USART_IT_RC) == SET) // 接收缓冲区不为空
{
//接收数据
WIFI_RX_BUFF[ WIFI_RX_LEN ] = USART_ReceiveData(WIFI_USART);
#if DEBUG
//测试,查看接收到了什么数据
printf("%c", WIFI_RX_BUFF[ WIFI_RX_LEN ]);
#endif
//接收长度限制
WIFI_RX_LEN = ( WIFI_RX_LEN + 1 ) % WIFI_RX_LEN_MAX;
WIFI_RX_BUFF[WIFI_RX_LEN] = ''; //字符串结尾补 ''
WIFI_RX_FLAG = SET; // 接收完成
USART_ClearITPendingBit(WIFI_USART, USART_IT_RC); //已经处理就清楚标志位
}
}
在文件bsp_esp01s.h中,编写如下代码。
/*
* Change Logs:
* Date Author Notes
* 2024-06-21 LCKFB-LP first version
*/
#ifndef _BSP_ESP01S_H_
#define _BSP_ESP01S_H_
#include "board.h"
#include "string.h"
//是否开启串口0调试,查看WIFI回显数据
#define DEBUG 1
/**************************** STA模式 ****************************/
//STA模式下,WIFI模块要连接的热点(需要自行修改为自己的参数)
#define WIFISSID "aaa" //wifi热点名称
#define WIFIPASS "12345678" //wifi热点密码
//连接的阿里云IP端口(不可修改)
#define IP "203.107.45.14" //阿里云服务器IP或域名
//#define IP "a1PaQm83lGg.iot-as-mqtt.cn-shenzhen.aliyuncs.com" //服务器IP或域名
#define PORT 1883 //连接端口号,MQTT默认1883
//阿里云三元组(需要自行修改为自己的参数)
#define DeviceName "TEST" //设备名称
#define ProductKey "a1PJRLOWo3p" //产品密匙
#define DeviceSecret "3e7a1a43694b65abdcbc4f5c724e9faf" //设备密匙
//计算哈希算法用到加密(不可修改)
#define Client "clientId123deviceName"
#define productKey "productKey"
#define Encryption (Client DeviceName productKey ProductKey)
//AT指令的
#define AND "&"
#define ClientId "123|securemode=3,signmethod=hmacsha1|" //客户端ID
#define UserName (DeviceName AND ProductKey) //用户名
//订阅发布的主题(不可修改)
#define SYS "/sys/"
#define LINK "/"
#define TOP "/thing/event/property/"
#define POST "post"
#define ESET "set"
#define PublishMessageTopPost (SYS ProductKey LINK DeviceName TOP POST)
#define PublishMessageTopSet (SYS ProductKey LINK DeviceName TOP ESET)
//上传数据结构体
typedef struct
{
char keyname[50]; //键读取
char value[20]; //读取到的值,类型字符串
}JSON_PUBLISH;
extern JSON_PUBLISH publish_mqtt_message[2];
/**************************** AP模式 ****************************/
//AP模式下,WIFI开启的热点
#define AP_WIFISSID "ESP-01S"
#define AP_WIFIPASS "12345678"
typedef struct
{
uint8_t device_id;
uint8_t device_datalen;
uint8_t device_data[200];
}AP_PARAMETER;
/**************************** 串口配置 ****************************/
#define RCC_WIFI_GPIO_ENABLE() __RCC_GPIOA_CLK_ENABLE() // 串口TX的端口时钟
#define RCC_WIFI_USART_ENABLE() __RCC_UART2_CLK_ENABLE() // 串口2的时钟
#define BSP_GPS_AF_UART_TX() PA02_AFx_UART2TXD() // GPIO的引脚复用
#define BSP_GPS_AF_UART_RX() PA03_AFx_UART2RXD() // GPIO的引脚复用
#define PORT_WIFI_GPIO CW_GPIOA // 串口TX的端口
#define GPIO_WIFI_TX GPIO_PIN_2 // 串口TX的引脚
#define GPIO_WIFI_RX GPIO_PIN_3 // 串口RX的引脚
#define WIFI_USART CW_UART2 // 串口2
#define WIFI_USART_IRQ UART2_IRQn // 串口2中断
#define WIFI_USART_IRQHandler UART2_IRQHandler // 串口2中断服务函数
#define WIFI_RX_LEN_MAX 200 //串口接收最大长度
extern uint8_t wifi_link_flag;//设备连接状态
//配合 Get_Device_connection_status 函数使用
// * 0=没有设备连接
// * 1=有设备连接了WIFI
// * 0=有设备断开了WIFI
// * 2=有设备连接了服务器
// * 3=有设备断开了服务器
void WIFI_ESP01S_Init(void); //WIFI模块初始化
uint8_t WIFI_MODE_AP_Init(void); //AP模式初始化
uint8_t Get_Device_connection_status(void);//获取连接状态
void WIFI_MODE_STA_Aliyun_Init(void); //连接阿里云初始化
uint8_t Get_WIFI_AP_Data(AP_PARAMETER *ap_parameter);
uint8_t Get_Aliyun_json_data(JSON_PUBLISH *data);
void Clear_Aliyun_json_data(JSON_PUBLISH *data);
void Publish_MQTT_message(JSON_PUBLISH *data,uint8_t data_num);
char WIFI_Send_Cmd(char *cmd,char *ack,unsigned int waitms,unsigned char cnt);
#endif
四案例一AP模式下的手机控制
>>>
使用AP模式通过AT命令,控制WIFI模块开启热点、多连接、服务器。待手机连接后,通过手机APP进行数据互传。
使用案例前,请确保bsp_esp01s.c和bsp_esp01s.h移植成功。
手机APP下载地址:
链接:https://pan.baidu.com/s/1-wh0aaqRMW8fJ5nLH1Lwyw?pwd=LCKF
提取码:LCKF
APP操作
首先使用手机连接WIFI模块的热点。其次打开APP连接服务器。服务器默认IP为192.168.4.1,端口号在代码中设置为了5000。
连接上WIFI的热点后,打开APP连接服务器。
编辑各个按钮值,方便后面我们进行控制。
在main.c中,编写如下代码。
/*
* Change Logs:
* Date Author Notes
* 2024-06-21 LCKFB-LP first version
*/
#include "board.h"
#include "stdio.h"
#include "bsp_uart.h"
#include "bsp_esp01s.h"
int32_t main(void)
{
AP_PARAMETER ap_parameter={0};
uint8_t test_ret = 0;
board_init();
uart1_init(115200U);
printf("Startrn");
//WIFI初始化
WIFI_ESP01S_Init();
//设置WIFI模块为AP模式
WIFI_MODE_AP_Init();
while(1)
{
//判断是否有设备连接
Get_Device_connection_status();
//如果当前设备连接了服务器(手机APP连接上热点)
if( wifi_link_flag == 2 )
{
if( Get_WIFI_AP_Data(&ap_parameter) == 1 )//如果接收到数据
{
//输出接收的数据
printf("ID = %drn", ap_parameter.device_id );//设备ID
printf("data len = %drn", ap_parameter.device_datalen );//发送过来的数据长度
printf("data = %srn", ap_parameter.device_data );//发送过来的数据
}
}
}
}
案例现象:
当手机APP接入WIFI连接成功之后,APP发送数据到开发板的串口。
默认ip:192.168.4.1 默认端口:5000
工程代码下载:
链接:https://pan.baidu.com/s/16IPzyT_Rdm2E2BgPvYe-pw?pwd=LCKF
提取码:LCKF