CW32模块使用 ESP01S WIFI模块

描述

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

审核编辑 黄宇

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分