36. WiFi——ESP8266模块通讯

36.1. Wifi模块简介

ESP8266-12F是启明6M5开发板板载的一个WiFi模块。 该模块核心处理器ESP8266在较小尺寸封装中集成了业界领先的Tensilica L106超低功耗32位微型MCU。 带有16位精简模式,主频支持80MHz和160MHz。 支持RTOS,集成Wi-Fi MAC/BB/RF/PA/LNA,板载天线。 支持标准的IEEE802.11 b/g/n协议,完整的TCP/IP协议栈。 用户可以使用该模块为现有的设备添加联网功能,也可以构建独立的网络控制器。 尤其是有过物联网开发经验的人,必然绕不过ESP8266,其低廉的价格、超高的性能和便利的开发环境,毫无疑问是业界中里程碑一样的存在。 而在启明6M5开发板中只需要通过SCI9 UART串口和AT指令就可以对ESP8266进行简单的配置。

36.2. ESP8266功能介绍

ESP8266整体架构如下图所示。

图 ESP8266架构

ESP8266强大的片上处理和存储能力,使其可通过GPIO口集成传感器及其他应用的特定设备,大大地降低了前期开发的成本。 以下为ESP8266的整体特性。

  • 完整的802.11b/g/n Wi-Fi SoC模块

  • 内置Tensilica L106超低功耗32位微型MCU,主频支持80MHz和160MHz,支持RTOS

  • 内置1路10位高精度ADC

  • 支持UART/GPIO/ADC/PWM/SPI/I2C接口

  • 采用SMD-22封装

  • 集成Wi-Fi MAC/BB/RF/PA/LNA

  • 支持多种休眠模式,深度睡眠电流低至20uA

  • 串口速率最高可达4Mbps

  • 内嵌Lwip协议栈

  • 支持STA/AP/STA+AP工作模式

  • 支持安卓、IOS的Smart Config(APP)/AirKiss(微信)一键配网

  • 支持串口本地升级和远程固件升级(FOTA)

  • 通用AT指令,可快速上手

  • 支持二次开发,集成了Windows、Linux开发环境

36.2.1. 通用输入/输出接口(GPIO)

ESP8266总共有22个管脚,如下图所示,通过配置适当的寄存器可以给它们分配不同的功能。 每一个GPIO都可以单独配置,如上拉/下拉,或者设置为高阻态。 当被配置为输⼊时,可通过读取寄存器获取输⼊值。 输⼊也可以被设置为边缘触发或电平触发来产⽣CPU中断。 这些管脚可以与其它功能复用,例如I2C、I2S、SPI、ADC、UART、PWM、IR遥控等。

图

下表为管脚的功能介绍。

ESP8266管脚功能定义

管脚

名称

功能

1

RST

复位

2

ADC

A/D转换,输入电压范围0~1V,取值范围:0~1024

3

EN

芯片使能端,高电平有效

4

IO16

GPIO16/接到RST管脚时可做deep sleep的唤醒

5

IO14

GPIO14/HSPI_CLK

6

IO12

GPIO12/HSPI_MISO

7

IO13

GPIO13/HSPI_MOSI/UART0_CTS

8

VCC

3.3V供电(VDD);外部供电电源输出电流建议在500mA以上

9

CS0

片选信号

10

MISO

多输入单输出

11

IO9

GPIO9

12

IO10

GPIO10

13

MOSI

单输入多输出

14

SCLK

时钟

15

GND

接地

16

IO15

GPIO15/MTDO/HSPICS/UART0_RTS

17

IO2

GPIO2/UART1_TXD

18

IO0

GPIO0;下载模式:外部拉低,运行模式:悬空或者外部拉高

19

IO4

GPIO4

20

IO5

GPIO5/IR_R

21

RXD

UART0_RXD/GPIO3

22

TXD

UART0_TXD/GPIO1

ESP8266引脚功能介绍

功能

引脚

作用

PWM

GPIO12(R)、GIPIO15(G)、GPIO13(B)

可以对PWM接口进行控制,以达到控制单片机外设的目的

IR Remote control

GPIO(IR_T)、GPIO5(IR_R)

红外遥控接口的功能,可以通过软件编程实现

HSPI:

GPIO12(MISO)、GPIO13(MOSI)、GPIO14(CLK)、GPIO15(CS)

以使用HSPI接口连接SPI Flash、显示屏和MCU

ADC

ADC

10位高精度模拟ADC

I2C

GPIO5(SCL)、GPIO4(SDA)

用于连接外部传感器或屏幕等

UART

UARTO:GPIO1(TX)、PIO3(RX),UART1:GPIO2(TX)、GPIO8(RX)

用于打印信息,进行调试,也可以进行数据的发送与接收

图

提示

GPIO6~GPIO11被用于连接开发板的闪存(Flash Memory),因此图中红框内的引脚不可用。

36.2.2. 使用UART与WIFI通讯

ESP8266模组与MCU的连接如下表所示:

8266模块引脚

MCU引脚

MCU外设

WIFI_TXD

P601

SCI9 UART RXD9

WIFI_RXD

P602

SCI9 UART TXD9

在下方开发板原理图中,可以看到J34的1,2引脚代表着开发板的SCI9 UART串口中的TX、RX接口。 而3,4引脚是ESP8266的SCI9 UART中的RX、TX接口,在实际的开发板中,J34的1,3引脚和2,4引脚一般是通过跳帽连接的,这代表了开发板可以通过SCI9 UART与WIFI模块进行通讯。 也就是说,想要配置ESP8266,就需要与SCI9 UART中的P601与P602两个引脚建立通信。

图

36.2.3. ESP8266工作模式介绍

ESP8266总共有三种工作模式,分别是STA(Station)、AP(Wireless Access Point)、以及STA+AP模式。

STA 模式:在STA模式下,ESP8266就像一个接收设备,此时它可以接受来自其它无线路由器发射的信号,从而连接互联网,让搭载ESP8266的设备实现远程控制。

AP 模式:在AP模式下,ESP8266成为了发射设备,也就是成为了一个热点,手机和电脑等设备都可以连接到这个热点,从而使无线设备能够与ESP8266进行远程通信。

STA + TA 模式:两种模式共同使用,既可以作为客户端连接到别的网络,也可以作为Wifi热点使用,实现广域网与局域网的无缝切换。

关于SCI UART的部分介绍可以去看本教程第19章 SCI UART——串口通信

36.3. AT指令

AT(Attention)指令集是从终端设备(Terminal Equipment,TE)或数据终端设备(Data Terminal Equipment,DTE)向终端适配器(Terminal Adapter,TA)或数据电路终端设备(Data Circuit Terminal Equipment,DCE)发送的。

在ESP8266芯片出厂时,厂家已经在芯片内部烧写了固件,这使得我们能够通过一些常见的AT指令去控制它。 当然,也可以通过获取SDK的方式重新烧写固件,修改和添加我们想要的功能,在本章节的 “实验四” 中会有涉及。

36.4. 实验一:AT指令接收测试

36.4.1. 硬件设计:

图

36.4.2. 软件设计

因为要通过UART进行通讯,所以可以直接在第19章工程代码的基础上继续配置。 当我们配置好之后,就可以向ESP8266发送AT指令,控制ESP8266根据AT指令做出进一步的动作。 关于AT指令可以查看AT指令集资料 AT指令集

36.4.2.1. 新建工程

对于 e2 studio 开发环境:

拷贝一份我们之前的 e2s 工程 “19_UART_Receive_Send”, 然后将工程文件夹重命名为 35_Wifi_ESP8266_AT,最后再将它导入到我们的 e2 studio 工作空间中。

对于 Keil 开发环境:

拷贝一份我们之前的 e2s 工程 “19_UART_Receive_Send”, 然后将工程文件夹重命名为 35_Wifi_ESP8266_AT,并进入该文件夹里面双击 Keil 工程文件,打开该工程。

工程新建好之后,在工程根目录的 “src” 文件夹下面新建 bsp_esp8266 文件夹, 再进入 “bsp_esp8266” 文件夹里面新建源文件和头文件:“bsp_wifi_esp8266.c” 和 “bsp_wifi_esp8266.h”。 工程文件结构如下。

文件结构
35_Wifi_ESP8266_AT
├─ ......
└─ src
   ├─ led
   │  ├─ bsp_led.c
   │  └─ bsp_led.h
   ├─ debug_uart
   │  ├─ bsp_debug_uart.c
   │  └─ bsp_debug_uart.h
   ├─ bsp_esp8266
   │  ├─ bsp_wifi_esp8266.c
   │  └─ bsp_wifi_esp8266.h
   └─ hal_entry.c

36.4.2.2. FSP配置

拷贝完成后,先打开 “35_Wifi_ESP8266_AT” 项目的FSP配置界面进行配置。

在 FSP 配置界面里面点开 “Pins”-> “Peripherals”-> “Connectivity:SCI”-> “SCI9” 来配置SCI模块, 配置为“Asynchronous UART”模式,并选择开发板使用串口引脚,如下图所示。

../../_images/uart_cfg1.png

图35-6 配置引脚

在配置界面底部点击 “Stack”,如下图所示步骤加入串口UART:

../../_images/uart_cfg2.png

图35-7 加入串口

点击刚刚加入的窗口,在左下角的“属性”窗口中配置 名字(name)、通道(Channel)、回调函数(Callback)名字即可, 引脚(Pins)、波特率(Baud Rate)等其他的属性按照默认的配置即可。

../../_images/callback.png

图35-8 配置串口属性

UART属性描述

属性

描述

Name

名字,根据读者需求设置即可

Channel

通道,根据SCI号设置即可,例如实验使用SCI9,则这里配置为通道9

Data Bits

每个字(word)的比特(bit)数,默认为8bits

Parity

校验模式,可选择“Odd”奇校验,“Even”偶校验或“None”无校验

Stop Bits

停止位,可选1或2bit

Baud Rate

波特率

Baud Rate Modulation

波特率调制,通过调整时钟周期,以减少申请波特率与实际波特率之间的误差

Max Error(%)

计算波特率时允许的最大百分比误差

Callback

回调函数的名字,根据读者需求设置即可

Receive Interrupt Priority

接收中断优先级

Transmit Data Empty Interrupt Priority

发送数据空中断优先级

Transmit End Interrupt Priority

发送完成中断优先级

Error Interrupt Priority

错误中断优先级

最后点右上角的 “Generate Project Content” 按钮,让软件自动生成配置代码。

36.4.2.3. 串口初始化函数

FSP配置并生成代码之后,我们就可以开始封装函数了

代码 35‑1 bsp_debug_wifi.c 串口初始化
/* Wifi (UART9) 串口初始化*/
void ESP8266_UART9_Init(void)
{
  fsp_err_t err = FSP_SUCCESS;

  R_SCI_UART_Open(g_uart9_esp8266.p_ctrl, g_uart9_esp8266.p_cfg);
  assert(FSP_SUCCESS == err);
}

36.4.2.4. 串口中断回调函数

由于还需要调试串口来帮助打印调试信息,还需要在工程中的的 bsp_debug_uart.c 文件中对UART4写入的字符串首地址修改为ESP8266所在地址:

图

做好这些工作之后,就可以使用刚才在FSP配置时设置的串口中断回调函数: esp8266_uart9_callback。 设置本函数的意义在于,给ESP8266发送AT指令之后,就可以得到它的回显,从而确定ESP8266的工作状态。 该函数代码如下所示:

代码 35‑2 bsp_debug_wifi.c 串口中断回调函数
/*串口中断回调函数*/
void esp8266_uart9_callback(uart_callback_args_t * p_args)
{
     switch(p_args->event)
     {
         case UART_EVENT_RX_CHAR:
            //收到发送的的AT指令后,将ESP8266的回显内容利用调试串口进行打印
             R_SCI_UART_Write(&g_uart4_ctrl, (uint8_t *)&(p_args->data), 1);
             break;
         default:
             break;
     }
}

36.4.2.5. hal_entry入口函数

最后在hal_entry函数中编写需要的代码。

代码 35‑3 hal_entry 函数
void hal_entry(void)
{
  /* TODO: add your own code here */

  Debug_UART4_Init(); // SCI4 UART 调试串口初始化
  ESP8266_UART9_Init();  // WIFI (SCI9 UART) 串口初始化

  printf("欢迎使用野火启明6M5开发板\n\n");
  printf("这是一个ESP8266AT指令测试实验\n\n");
  printf("请使用串口调试助手发送\"AT+换行回车\"测试ESP8266是否准备好\n\n");
  printf("更多AT指令请参考上文中的AT指令集资料\n\n");

  while(1){}

  #if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
  #endif
}

将调试串口与Wifi(UART9)串口初始化后,在while循环中,可以什么都不做,让单片机等待AT指令。

36.4.2.6. 下载验证

保证开发板相关硬件连接正确,用Type-C USB线连接开发板 “USB TO UART” 接口跟电脑。 本次实验需要使用到串口调试助手, 配置好串口参数并打开串口后,在调试助手的发送区域输入AT指令,即可在接收区看见ESP8266的回显内容。

图

重要

每条AT指令的最后必须是以换行符结束再发送!

36.5. 实验二:STA模式测试

由于本实验的目标是测试ESP8266的STA模式,因此我们在上一个实验的基础上修改程序。

在这之前首先要了解一下透传模式,简单的讲就是ESP8266将通过串口接收到的数据, 直接进行转发到所设置的目标服务器的端口上,不需要关心WIFI协议是如何来实现数据的传输。只需要在ESP8266上设置好服务器地址即可。

36.5.1. 软件设计

36.5.1.1. 新建工程

对于 e2 studio 开发环境:

拷贝一份我们之前的 e2s 工程 35_Wifi_ESP8266_AT, 然后将工程文件夹重命名为 35_Wifi_ESP8266_STA,最后再将它导入到我们的 e2 studio 工作空间中。

对于 Keil 开发环境:

拷贝一份我们之前的 e2s 工程 35_Wifi_ESP8266_AT, 然后将工程文件夹重命名为 35_Wifi_ESP8266_STA,并进入该文件夹里面双击 Keil 工程文件,打开该工程。

工程文件结构如下。

文件结构
35_Wifi_ESP8266_STA
├─ ......
└─ src
   ├─ led
   │  ├─ bsp_led.c
   │  └─ bsp_led.h
   ├─ debug_uart
   │  ├─ bsp_debug_uart.c
   │  └─ bsp_debug_uart.h
   ├─ bsp_esp8266
   │  ├─ bsp_wifi_esp8266.c
   │  └─ bsp_wifi_esp8266.h
   └─ hal_entry.c

首先,打开网络调试助手,选择协议类型为TCP Server,也就是客户端模式,具体配置如下图所示。

图

配置好之后,选择启动监听。

36.5.1.2. 宏定义函数

首先在bsp_wifi_esp8266.h文件中将我们所需要的数据以及指令用宏定义封装起来。 后续需要更改配置信息只需要在宏定义中稍加修改就可以。

代码 35‑4 bsp_wifi_esp8266.h 函数
 /*宏定义调试信息*/
 #define ESP8266_DEBUG   1

 #if     (ESP8266_DEBUG == 1)
 #define     ESP8266_DEBUG_MSG(fmt, ... )        printf ( fmt, ##__VA_ARGS__ )
 #else
 #define     ESP8266_DEBUG_MSG(fmt, ... )
 #endif


 #define   ID             "AP_DEVICE"           //要连接的热点的名称
 #define   PASSWORD       "123456789"           //要连接的热点的密钥

 #define   SeverIP        "192.168.103.166"     //要连接的服务器IP
 #define   SeverPort      "8000"                //要连接的服务器端口

 #define ESP8266_MODULE_ENABLE     R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_01_PIN_15, BSP_IO_LEVEL_HIGH);  //使能ESP8266模块
 #define ESP8266_MODULE_DISABLE    R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_01_PIN_15, BSP_IO_LEVEL_LOW);   //关闭ESP8266模块

 /*红灯闪烁*/
 #define ESP8266_ERROR_Alarm()     R_PORT4->PODR ^= 1<<(BSP_IO_PORT_04_PIN_00 & 0xFF); \
                                   R_BSP_SoftwareDelay(500, BSP_DELAY_UNITS_MILLISECONDS);

 /*清除UART9数据缓冲区函数*/
 #define   Clear_Buff()   memset( At_Rx_Buff , 0 , sizeof(At_Rx_Buff) ); \
                          Uart9_Num = 0;

36.5.1.3. ESP8266-STA功能函数

随后在bsp_wifi_esp8266.c文件中添加配置ESP8266所需要的函数。

代码 35‑5 文件 bsp_wifi_esp8266.c 函数
 _Bool               Uart9_Receive_Flag = false; //用来判断UART9接收以及发送数据是否完成
 _Bool               Uart9_Show_Flag = false;    //控制UART9收发数据显示标志

 /*用来接收UART9数据的缓冲区*/
 char                At_Rx_Buff[256];
 uint8_t             Uart9_Num = 0;

 /*自动配置ESP8266函数*/
 void ESP8266_STA_Test(void)
 {

    ESP8266_DEBUG_MSG("\r\n正在初始化ESP8266...\r\n");
    ESP8266_UART9_Init();

    ESP8266_DEBUG_MSG("\r\n设置STA模式中...\r\n");
    ESP8266_STA();

    ESP8266_DEBUG_MSG("\r\n正在连接WIFI中...\r\n");
    ESP8266_STA_JoinAP( ID , PASSWORD , 20 );
    Link_Mode( 0 );

    ESP8266_DEBUG_MSG("\r\n正在连接服务器中...\r\n");
    ESP8266_STA_JoinServer( SeverIP , SeverPort , 20 );

    ESP8266_DEBUG_MSG("\r\n正在配置为透传发送模式...\r\n");
    ESP8266_STA_Transmission();
    ESP8266_Send_Data();

 }

 /*ESP8266 (SPI9 UART) 初始化函数*/
 void ESP8266_UART9_Init(void)
 {
    fsp_err_t err = FSP_SUCCESS;

    err = R_SCI_UART_Open(g_uart9_esp8266.p_ctrl, g_uart9_esp8266.p_cfg);
    assert(FSP_SUCCESS == err);
 }

 /*向ESP8266发送AT指令函数*/
 void ESP8266_AT_Send(char * cmd )
 {
    /*向ESP8266(UART9)发送指令*/
    R_SCI_UART_Write(&g_uart9_esp8266_ctrl, (uint8_t *)cmd, strlen(cmd));

    /*AT指令发送完成标志*/
    Uart9_Receive_Flag = false;

 }

 /*设置ESP8266为 STA 模式*/
 void ESP8266_STA ( void )
 {
    ESP8266_AT_Send ( "AT+CWMODE=1\r\n" );

    /*等待设置完成*/
    while ( !Uart9_Receive_Flag )
    {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
          ESP8266_DEBUG_MSG("\r\nESP8266已切换为STA模式\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
    }
 }

 /*设置ESP8266为 AP 模式*/
 void ESP8266_AP ( void )
 {
    ESP8266_AT_Send ( "AT+CWMODE=2\r\n" );

    /*等待设置完成*/
    while ( !Uart9_Receive_Flag )
    {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
          ESP8266_DEBUG_MSG("\r\nESP8266已切换为AP模式\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
    }
 }

 /*设置ESP8266为 STA + AP 模式*/
 void ESP8266_STA_AP ( void )
 {
       ESP8266_AT_Send ( "AT+CWMODE=3\r\n" );

       /*等待设置完成*/
       while ( !Uart9_Receive_Flag )
       {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
          ESP8266_DEBUG_MSG("\r\nESP8266已切换为STA+AP模式\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
       }
 }

 /*ESP8266连接WiFi函数*/
 void ESP8266_STA_JoinAP( char * id ,  char * password , uint8_t timeout ) //timeout:期望连接时间,单位为秒
 {
    char  JoinAP_AT[256];

    uint8_t i;

    sprintf( JoinAP_AT , "AT+CWJAP=\"%s\",\"%s\"\r\n" , id , password);

    ESP8266_AT_Send( JoinAP_AT );

    /*判断Wifi连接是否成功*/
    for(i = 0; i <= timeout; i++)
    {
          if ( strstr( At_Rx_Buff , "OK\r\n" ) )
          {
                ESP8266_DEBUG_MSG("\r\nWifi连接成功\r\n");
                Clear_Buff();      //清除缓冲区数据
                break;
          }
          if ( strstr( At_Rx_Buff , "ERROR\r\n" ) )    //根据ESP8266的固件版本不同有不同的响应,一般为“FAIL”或“ERROR”
          {
                if( strstr( At_Rx_Buff , "+CWJAP:1\r\n" ))
                ESP8266_DEBUG_MSG("\r\nWifi连接超时,请检查各项配置是否正确\r\n");

                if( strstr( At_Rx_Buff , "+CWJAP:2\r\n" ))
                ESP8266_DEBUG_MSG("\r\nWifi密码错误,请检查Wifi密码是否正确\r\n");

                if( strstr( At_Rx_Buff , "+CWJAP:3\r\n" ))
                   ESP8266_DEBUG_MSG("\r\n无法找到目标Wifi,请检查Wifi是否打开或Wifi名称是否正确\r\n");

                if( strstr( At_Rx_Buff , "+CWJAP:4\r\n" ))
                ESP8266_DEBUG_MSG("\r\nWifi连接失败,请检查各项配置是否正确\r\n");

                while(1)
                {
                ESP8266_ERROR_Alarm();
                }      //LED灯警告错误,红灯闪烁
          }
          if ( i == timeout )
          {
                ESP8266_DEBUG_MSG("\r\nWifi连接超出期望时间,请检查各项配置是否正确\r\n");
                while(1)
                {
                ESP8266_ERROR_Alarm();
                }      //LED灯警告错误,红灯闪烁
          }
          R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);
       }
 }

 /*设置连接模式为单连接或者多连接*/
 void Link_Mode( uint8_t mode )
 {
       switch ( mode ){
          case 0 :
             ESP8266_AT_Send("AT+CIPMUX=0\r\n"); //设置为单连接模式,透传只有在单连接模式下才能进行
             break;
          case 1 :
             ESP8266_AT_Send("AT+CIPMUX=1\r\n"); //设置为多连接模式,服务器只有在多连接模式下才能打开
             break;
       }

       /*等待设置完成*/
       while ( !Uart9_Receive_Flag )
       {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
                if( mode )
                ESP8266_DEBUG_MSG("\r\nESP8266已切换为多连接模式\r\n");
                else
                ESP8266_DEBUG_MSG("\r\nESP8266已切换为单连接模式\r\n");
                Clear_Buff();      //清除缓冲区数据
          }
       }
 }

 /*ESP8266连接服务器函数*/
 void ESP8266_STA_JoinServer( char * server_id ,  char * port , uint8_t timeout ) //timeout:期望连接时间,单位为秒
 {
    char  JoinServer_AT[256];

    uint8_t i;

    sprintf( JoinServer_AT , "AT+CIPSTART=\"TCP\",\"%s\",%s\r\n" , server_id , port );

    ESP8266_AT_Send( JoinServer_AT );

       /*判断服务器连接是否设置成功*/
       while ( !Uart9_Receive_Flag )
       {
          /*超时判断,timeout:期望最长等待时间*/
          for(i = 0; i <= timeout; i++)
         {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
                ESP8266_DEBUG_MSG("\r\n服务器连接成功\r\n");
                Clear_Buff();      //清除缓冲区数据
                break;
          }
          if (strstr( At_Rx_Buff , "ERROR\r\n" ))
          {
                ESP8266_DEBUG_MSG("\r\n服务器连接失败,请检查服务器是否打开以及参数是否正确\r\n");
                while(1)
                {
                ESP8266_ERROR_Alarm();
                }      //LED灯警告错误,红灯闪烁
          }
          if ( i == timeout )
          {
                ESP8266_DEBUG_MSG("\r\n服务器连接超出期望时间,请检查各项配置是否正确\r\n");
                while(1)
                {
                ESP8266_ERROR_Alarm();
                }      //LED灯警告错误,红灯循环闪烁
          }
          R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);
         }
       }
 }

 /*设置ESP8266为透传模式*/
 void ESP8266_STA_Transmission( void )
 {
       ESP8266_AT_Send ( "AT+CIPMODE=1\r\n" );

       /*等待设置完成*/
       while ( !Uart9_Receive_Flag )
       {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
          ESP8266_DEBUG_MSG("\r\nESP8266已切换为透传模式\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
       }
 }

 /*设置ESP8266为发送数据模式*/
 void ESP8266_Send_Data( void )
 {
       ESP8266_AT_Send ( "AT+CIPSEND\r\n" );

       /*等待设置完成*/
       while ( !Uart9_Receive_Flag )
       {
             if (strstr( At_Rx_Buff , "OK\r\n" ))
             {
                ESP8266_DEBUG_MSG("\r\nESP8266已进入透传发送模式\r\n\r\n>");
                Uart9_Show_Flag = true;
                Clear_Buff();      //清除缓冲区数据
             }
     }
 }

36.5.1.4. 中断回调函数

代码 35‑6 中断回调函数
 /*Wifi串口回调函数*/
 void esp8266_uart9_callback(uart_callback_args_t * p_args)
 {
       switch(p_args->event)
       {
          case UART_EVENT_RX_CHAR:

                At_Rx_Buff[Uart9_Num++] = ( char ) p_args->data;  //将UART9收到的数据放到Buff缓冲区中

                /*进入透传模式后打开串口调试助手收发数据显示*/
                if( Uart9_Show_Flag )
                R_SCI_UART_Write(&g_uart4_ctrl, (uint8_t *)&(p_args->data), 1);

                break;

          case UART_EVENT_TX_COMPLETE:
          {
                Uart9_Receive_Flag = true;      //ESP8266回应完成标志

                break;
          }
          default:
                break;
       }
 }

36.5.1.5. hal_entry入口函数

代码 35‑7 hal_entry 函数
 void hal_entry(void)
 {
    /* TODO: add your own code here */

    Debug_UART4_Init(); // SCI4 UART 调试串口初始化

    ESP8266_STA_Test(); // ESP8266 自动配置函数

    while(1){}

 #if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
 #endif
 }

以下实验的hal_entry函数均与本实验大致相同,不再过多展示。

36.5.1.6. 下载验证

首先使用电脑或手机设备打开热点,并将热点名称和密码设置完成。 编译并下载程序后,可以得到程序的提示信息。

图

此时就代表ESP8266已经配置完成,其中包括AP以及服务器的连接。 这时就可以打开网络调试助手发送信息,可以看到串口能够接收到发送的信息。

图

同样的,在串口调试助手中发送信息,网络调试助手同样可以收到。

图

提示

透传模式的结束指令为“+++”,在不使用透传模式时要记得发送指令结束该模式。 如果不发送结束指令,下一次重新上电时ESP8266将仍处于透传模式。 如果不想因为忘记关闭透传指令而带来问题的话,可以先发送 “+++” 关闭透传模式,随后发送 “AT+SAVETRANSLINK=0” 这一指令, 这可以让下一次重新上电后不自动进入透传模式。 同样的,如果需要每一次上电都位于透传模式下,也只需要发送 “AT+SAVETRANSLINK=1” 这一指令即可。

36.6. 实验三:AP模式测试

由于本实验的目标是测试ESP8266的AP模式,在上一个实验中我们已经封装了一些函数,因此我们可以在上一个实验的基础上继续修改程序。

36.6.1. 软件设计

36.6.1.1. 新建工程

对于 e2 studio 开发环境:

拷贝一份我们之前的 e2s 工程 35_Wifi_ESP8266_STA, 然后将工程文件夹重命名为 35_Wifi_ESP8266_AP,最后再将它导入到我们的 e2 studio 工作空间中。

对于 Keil 开发环境:

拷贝一份我们之前的 e2s 工程 35_Wifi_ESP8266_STA, 然后将工程文件夹重命名为 35_Wifi_ESP8266_AP,并进入该文件夹里面双击 Keil 工程文件,打开该工程。

工程文件结构如下。

文件结构
35_Wifi_ESP8266_AP
├─ ......
└─ src
   ├─ led
   │  ├─ bsp_led.c
   │  └─ bsp_led.h
   ├─ debug_uart
   │  ├─ bsp_debug_uart.c
   │  └─ bsp_debug_uart.h
   ├─ bsp_esp8266
   │  ├─ bsp_wifi_esp8266.c
   │  └─ bsp_wifi_esp8266.h
   └─ hal_entry.c

36.6.1.2. 宏定义函数

在上一个实验的基础上,只需要添加和更改文件bsp_wifi_esp8266.h中的几个宏定义就可以了。 同样,我们在后续想要修改配置信息时也只需要稍加修改即可。

代码 35‑8 bsp_wifi_esp8266.h 函数
 #define   ID             "ESP8266"             //要设置的热点的名称
 #define   PASSWORD       "123456789"           //要设置的热点的密钥
 #define   CHANNEL        "1"                   //要设置的通道号
 #define   ENCRY_MODE     "3"                   //要设置的加密方式

 #define   SERVER_MODE    "1"                   //建立/关闭 服务器,1为建立,0为关闭
 #define   SERVER_PORT    "8080"                //设置服务器端口号

其中AP配置指令各参数为: “AT+CWSAP=”热点名称”,”热点密码”,通道号,加密方式” 。 其中加密方式分为:

  • 0 : OPEN

  • 1 : WEP

  • 2 : WPA_PSK

  • 3 : WPA2_PSK

  • 4 : WPA_WPA2_PSK

36.6.1.3. ESP8266-AP功能函数

在文件bsp_wifi_esp8266.c中,添加所需要的函数功能。

代码 35‑9 bsp_wifi_esp8266.c 函数
 _Bool               Uart9_Receive_Flag = false; //用来判断UART9接收以及发送数据是否完成
 _Bool               Uart9_Show_Flag = false;    //控制UART9收发数据显示标志

 /*用来当作接收UART9数据的缓冲区*/
 char                At_Rx_Buff[256];
 uint8_t             Uart9_Num = 0;

 /*自动配置ESP8266函数*/
 void ESP8266_AP_Test(void)
 {

    ESP8266_DEBUG_MSG("\r\n正在初始化ESP8266...\r\n");
    ESP8266_UART9_Init();

    ESP8266_DEBUG_MSG("\r\n设置AP模式中...\r\n");
    ESP8266_AP();
    ESP8266_Rst();  //重启ESP8266模块

    ESP8266_DEBUG_MSG("\r\n正在配置Wifi中...\r\n");
    ESP8266_AP_SetAP( ID , PASSWORD , CHANNEL , ENCRY_MODE );
    Link_Mode( 1 );

    ESP8266_DEBUG_MSG("\r\n正在建立服务器中...\r\n");
    ESP8266_AP_SetServer( SERVER_MODE , SERVER_PORT );

    ESP8266_DEBUG_MSG("\r\n等待连接...\r\n");
    Query_Address();  //提示配置信息

 }

 /*ESP8266 (SPI9 UART) 初始化*/
 void ESP8266_UART9_Init(void)
 {
    fsp_err_t err = FSP_SUCCESS;

    err = R_SCI_UART_Open(g_uart9_esp8266.p_ctrl, g_uart9_esp8266.p_cfg);
    assert(FSP_SUCCESS == err);
 }

 /*向ESP8266发送AT指令函数*/
 void ESP8266_AT_Send(char * cmd )
 {
    /*向ESP8266(UART9)发送指令*/
    R_SCI_UART_Write(&g_uart9_esp8266_ctrl, (uint8_t *)cmd, strlen(cmd));

    /*AT指令发送完成标志*/
    Uart9_Receive_Flag = false;
 }

 /*重启ESP8266函数*/
 void ESP8266_Rst(void)
 {
    ESP8266_AT_Send ( "AT+RST\r\n" );

    /*判断是否设置成功*/
    while ( !Uart9_Receive_Flag )
    {
          if (strstr( At_Rx_Buff , "ready\r\n" ))
          {
          R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);  //等待重启完成
          ESP8266_DEBUG_MSG("\r\nESP8266已重启\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
    }
 }

 /*设置ESP8266为 STA 模式*/
 void ESP8266_STA ( void )
 {
    ESP8266_AT_Send ( "AT+CWMODE=1\r\n" );

    /*判断是否设置成功*/
    while ( !Uart9_Receive_Flag )
    {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
          ESP8266_DEBUG_MSG("\r\nESP8266已切换为STA模式\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
    }
 }

 /*设置ESP8266为 AP 模式*/
 void ESP8266_AP ( void )
 {
       ESP8266_AT_Send ( "AT+CWMODE=2\r\n" );

       /*判断是否设置成功*/
       while ( !Uart9_Receive_Flag )
       {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
          ESP8266_DEBUG_MSG("\r\nESP8266已切换为AP模式\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
       }
 }

 /*设置ESP8266为 STA + AP 模式*/
 void ESP8266_STA_AP ( void )
 {
       ESP8266_AT_Send ( "AT+CWMODE=3\r\n" );

       /*判断是否设置成功*/
       while ( !Uart9_Receive_Flag )
       {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
          ESP8266_DEBUG_MSG("\r\nESP8266已切换为STA+AP模式\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
       }
 }

 /*ESP8266配置热点信息函数*/
 void ESP8266_AP_SetAP( char * id ,  char * password , char * channel_num , char * encry_mode )
 {
    char  SetAP_AT[256];

    sprintf( SetAP_AT , "AT+CWSAP=\"%s\",\"%s\",%s,%s\r\n" , id , password , channel_num , encry_mode );

    ESP8266_AT_Send( SetAP_AT );

    /*判断是否设置成功*/
    while ( !Uart9_Receive_Flag )
    {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
          ESP8266_DEBUG_MSG("\r\nESP8266已配置好Wifi\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
    }

 }

 /*设置连接模式为单连接或者多连接*/
 void Link_Mode( uint8_t mode )
 {
       switch ( mode ){
          case 0 :
             ESP8266_AT_Send("AT+CIPMUX=0\r\n"); //设置为单连接模式,透传只有在单连接模式下才能进行
             break;
          case 1 :
             ESP8266_AT_Send("AT+CIPMUX=1\r\n"); //设置为多连接模式,服务器只有在多连接模式下才能打开
             break;
       }

       /*等待设置完成*/
       while ( !Uart9_Receive_Flag )
       {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
                if( mode )
                ESP8266_DEBUG_MSG("\r\nESP8266已切换为多连接模式\r\n");
                else
                ESP8266_DEBUG_MSG("\r\nESP8266已切换为单连接模式\r\n");
                Clear_Buff();      //清除缓冲区数据
          }
       }
 }

 /*建立/关闭 TCP 或 SSL 服务器*/
 void ESP8266_AP_SetServer( char * mode ,  char * port )
 {
    char  SetServer_AT[256];

    sprintf( SetServer_AT , "AT+CIPSERVER=%s,%s\r\n" , mode , port );

    ESP8266_AT_Send( SetServer_AT );

    /*判断是否设置成功*/
    while ( !Uart9_Receive_Flag )
    {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
          ESP8266_DEBUG_MSG("\r\nESP8266已配置好服务器信息\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
    }

 }

 /*获取打印ESP8266的AP配置信息*/
 void Query_Address(void)
 {
    /*获取IP/MAC地址*/
    ESP8266_AT_Send ( "AT+CIFSR\r\n" );

    const char s[1] = "\"";
    char * AP_ID;

    while ( !Uart9_Receive_Flag )
    {
       if (strstr( At_Rx_Buff , "OK\r\n" ))
       {
       AP_ID = strtok( At_Rx_Buff , s ); //获取IP地址
       AP_ID = strtok( NULL , s );
       }
    }
    ESP8266_DEBUG_MSG("\nWifi名称为  '%s'\n",ID);
    ESP8266_DEBUG_MSG("Wifi密码为  '%s'\n",PASSWORD);

    ESP8266_DEBUG_MSG("\nIP地址为  '%s'\n",AP_ID);
    ESP8266_DEBUG_MSG("服务器端口号为  '%s'\n", SERVER_PORT);

    Clear_Buff();      //清除缓冲区数据

    Uart9_Show_Flag = true; //开启回显
 }

36.6.1.4. 中断回调函数

代码 35‑10 中断回调函数
 /*Wifi串口回调函数*/
 void esp8266_uart9_callback(uart_callback_args_t * p_args)
 {
       switch(p_args->event)
       {
          case UART_EVENT_RX_CHAR:

                At_Rx_Buff[Uart9_Num++] = ( char ) p_args->data;  //将UART9收到的数据放到Buff缓冲区中

                /*普通传输模式时打开串口调试助手收发数据显示*/
                if( Uart9_Show_Flag )
                R_SCI_UART_Write(&g_uart4_ctrl, (uint8_t *)&(p_args->data), 1);

                break;

          case UART_EVENT_TX_COMPLETE:
          {
                Uart9_Receive_Flag = true;      //ESP8266回应完成标志

                break;
          }
          default:
                break;
       }
 }

36.6.1.5. 下载验证

编译并下载程序后,可以得到程序的反馈信息。 这里使用手机,根据提示信息连接ESP8266所建立的热点,并打开网络调试助手连接ESP8266建立的TCP网络。

../../_images/AP_cfg1.png

随后用手机发送数据,可以看到ESP8266能够接受到数据,同样,我们也可以用AT+CIPSEND等AT指令来让ESP8266发送数据,具体用法请参考 AT指令集

../../_images/AP_cfg3.png ../../_images/AP_cfg2.png

36.7. 实验四:MQTT测试

由于本实验的目标是测试ESP8266的MQTT模式,需要在STA模式下进行,因此我们在STA模式实验的基础上修改程序。

MQTT,翻译过来就是消息队列遥测传输,是在ISO标准(ISO/IEC PRF 20922)下基于 发布/订阅 范式的消息协议。 它工作在TCP/IP协议族上,是专门为硬件性能低下的远程设备以及网络不好的情况下而设计的,为此,它需要一个消息中间件。

MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。 在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(IoT)。 其在,通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居、及一些小型化设备中已广泛使用。

在实验开始之前,通常还需要进行ESP8266固件的更新。 首先可以通过 “AT+GMR” 指令来查询ESP8266的固件版本。 关于如何更新固件大家可以自行去网上搜索具体教程,这里不再赘述,只告诉大家更新固件的引脚接法以及固件包的选择。

36.7.1. 更新固件

固件更新流程:

  1. 断电

  2. 断开J32中1,2脚的连接,并将2,3脚连接在一起

  3. 断开J34中1,3和2,4引脚连接,并连接3 ,5和4,6引脚

  4. 断开J35的连接

  5. 打开电源,更新固件

36.7.1.1. 硬件说明

../../_images/12f_pin_mode.png ../../_images/hardware3.png

在ESP8266-12F的产品规格书上面可以看到,当IO0引脚拉低时为下载模式,拉高(或外部悬空)时为运行模式。 所以想要更新固件,就要把ESP8266首先设置为下载模式,根据开发板原理图来看,也就是断开J32中1,2脚的连接,并将2,3脚连接在一起。

../../_images/hardware1.png ../../_images/hardware2.png

想要下载固件,自然就要让USB串口与ESP8266进行连接,所以根据原理图可以看到,断开J34中1,3和2,4引脚连接,并连接3 ,5和4,6引脚,并断开J35的连接,不然USB传输的数据会被传输到SPI4 UART串口。

36.7.1.2. 固件包的选择

在下载固件包的时候,可以选择下图中的固件进行下载并对ESP8266进行更新。

../../_images/firmware.png

固件下载地址为 固件下载

固件更新好之后,使用 “AT+GMR” 指令查询ESP8266的版本,可以得到以下信息:

../../_images/versions.png

这就说明ESP8266的固件已经更新好了,可以进行下一步的工作。

36.7.2. 创建MQTT服务器

关于创建 MQTT 服务器的教程大家可以去网上搜索教程,自行创建远程或本地服务器,这里同样不过多赘述。

36.7.3. 软件设计

关于MQTT的指令部分功能可以去 MQTT AT 命令集 进行查阅。

36.7.3.1. 新建工程

对于 e2 studio 开发环境:

拷贝一份我们之前的 e2s 工程 35_Wifi_ESP8266_STA, 然后将工程文件夹重命名为 35_Wifi_ESP8266_MQTT,最后再将它导入到我们的 e2 studio 工作空间中。

对于 Keil 开发环境:

拷贝一份我们之前的 e2s 工程 35_Wifi_ESP8266_STA, 然后将工程文件夹重命名为 35_Wifi_ESP8266_MQTT,并进入该文件夹里面双击 Keil 工程文件,打开该工程。

工程文件结构如下。

文件结构
35_Wifi_ESP8266_MQTT
├─ ......
└─ src
   ├─ led
   │  ├─ bsp_led.c
   │  └─ bsp_led.h
   ├─ debug_uart
   │  ├─ bsp_debug_uart.c
   │  └─ bsp_debug_uart.h
   ├─ bsp_esp8266
   │  ├─ bsp_wifi_esp8266.c
   │  └─ bsp_wifi_esp8266.h
   └─ hal_entry.c

36.7.3.2. 宏定义函数

在STA实验的基础上,同样要对bsp_wifi_esp8266.h中的几个宏定义进行修改。

代码 35‑11 宏定义函数
 #define   ID             "AP_DEVICE"           //要连接的热点的名称
 #define   PASSWORD       "123456789"           //要连接的热点的密钥

 #define   CLIENT_ID      "QiMing"              //MQTT用户ID
 #define   USER_NAME      "ESP8266"             //MQTT用户名称
 #define   USER_PASSWORD  "1234567"             //MQTT用户密码

 #define   MQTT_IP        "121.40.133.245"     //要连接的MQTT服务器IP
 #define   MQTT_Port      "1883"               //要连接的MQTT服务器端口

 #define   MQTT_TOPICS    "ESP8266_Test"       //要订阅的主题名
 #define   TOPICS_DATA    "Hello_I'm_ESP8266"    //要发送的数据

36.7.3.3. MQTT功能函数

在文件bsp_wifi_esp8266.c中,添加所需要的函数功能。

代码 35‑12 bsp_wifi_esp8266.c 函数
 _Bool               Uart9_Receive_Flag = false; //用来判断UART9接收以及发送数据是否完成
 _Bool               Uart9_Show_Flag = false;    //控制UART9收发数据显示标志

 /*用来接收UART9数据的缓冲区*/
 char                At_Rx_Buff[256];
 uint8_t             Uart9_Num = 0;

 /*自动配置ESP8266函数*/
 void ESP8266_MQTT_Test(void)
 {

    ESP8266_DEBUG_MSG("\r\n正在初始化ESP8266...\r\n");
    ESP8266_UART9_Init();

    ESP8266_DEBUG_MSG("\r\n设置STA模式中...\r\n");
    ESP8266_STA();
    ESP8266_Rst();

    ESP8266_DEBUG_MSG("\r\n正在连接WIFI中...\r\n");
    ESP8266_STA_JoinAP( ID , PASSWORD , 20 );

    ESP8266_DEBUG_MSG("\r\n正在配置MQTT用户信息...\r\n");
    MQTT_SetUserProperty( CLIENT_ID , USER_NAME, USER_PASSWORD );

    ESP8266_DEBUG_MSG("\r\n正在连接MQTT服务器...\r\n");
    Connect_MQTT( MQTT_IP , MQTT_Port , 10 );

    ESP8266_DEBUG_MSG("\r\n正在订阅主题...\r\n");
    Subscribes_Topics( MQTT_TOPICS );

    ESP8266_DEBUG_MSG("\r\n正在发布消息...\r\n");
    Send_Data( MQTT_TOPICS , TOPICS_DATA );

 }


 /*ESP8266 (SPI9 UART) 初始化函数*/
 void ESP8266_UART9_Init(void)
 {
    fsp_err_t err = FSP_SUCCESS;

    err = R_SCI_UART_Open(g_uart9_esp8266.p_ctrl, g_uart9_esp8266.p_cfg);
    assert(FSP_SUCCESS == err);
 }


 /*向ESP8266发送AT指令函数*/
 void ESP8266_AT_Send(char * cmd )
 {
    /*向ESP8266(UART9)发送指令*/
    R_SCI_UART_Write(&g_uart9_esp8266_ctrl, (uint8_t *)cmd, strlen(cmd));

    /*AT指令发送完成标志*/
    Uart9_Receive_Flag = false;

 }


 /*设置ESP8266为 STA 模式*/
 void ESP8266_STA ( void )
 {
    ESP8266_AT_Send ( "AT+CWMODE=1\r\n" );

    /*等待设置完成*/
    while ( !Uart9_Receive_Flag )
    {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
          ESP8266_DEBUG_MSG("\r\nESP8266已切换为STA模式\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
    }
 }


 /*设置ESP8266为 AP 模式*/
 void ESP8266_AP ( void )
 {
       ESP8266_AT_Send ( "AT+CWMODE=2\r\n" );

       /*等待设置完成*/
       while ( !Uart9_Receive_Flag )
       {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
          ESP8266_DEBUG_MSG("\r\nESP8266已切换为AP模式\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
       }
 }


 /*设置ESP8266为 STA + AP 模式*/
 void ESP8266_STA_AP ( void )
 {
       ESP8266_AT_Send ( "AT+CWMODE=3\r\n" );

       /*等待设置完成*/
       while ( !Uart9_Receive_Flag )
       {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
          ESP8266_DEBUG_MSG("\r\nESP8266已切换为STA+AP模式\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
       }
 }

 /*重启ESP8266函数*/
 void ESP8266_Rst(void)
 {
    ESP8266_AT_Send ( "AT+RST\r\n" );

    /*判断是否设置成功*/
    while ( !Uart9_Receive_Flag )
    {
          if (strstr( At_Rx_Buff , "ready\r\n" ))
          {
          R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);  //等待重启完成
          ESP8266_DEBUG_MSG("\r\nESP8266已重启\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
    }
 }

 /*ESP8266连接WiFi函数,timeout:期望最大连接时间*/
 void ESP8266_STA_JoinAP( char * id ,  char * password , uint8_t timeout )
 {
    char  JoinAP_AT[256];

    uint8_t i;

    sprintf( JoinAP_AT , "AT+CWJAP=\"%s\",\"%s\"\r\n" , id , password);

    ESP8266_AT_Send( JoinAP_AT );

    /*判断连接是否设置成功,失败则打印错误信息*/
    while ( !Uart9_Receive_Flag )
    {
    for(i = 0; i <= timeout; i++)
       {
          if ( strstr( At_Rx_Buff , "OK\r\n" ) )
          {
                ESP8266_DEBUG_MSG("\r\nWifi连接成功\r\n");
                Clear_Buff();      //清除缓冲区数据
                break;
          }
          if ( strstr( At_Rx_Buff , "ERROR\r\n" ) )
          {
                if( strstr( At_Rx_Buff , "+CWJAP:1\r\n" ))
                ESP8266_DEBUG_MSG("\r\nWifi连接超时,请检查各项配置是否正确\r\n");

                if( strstr( At_Rx_Buff , "+CWJAP:2\r\n" ))
                ESP8266_DEBUG_MSG("\r\nWifi密码错误,请检查Wifi密码是否正确\r\n");

                if( strstr( At_Rx_Buff , "+CWJAP:3\r\n" ))
                   ESP8266_DEBUG_MSG("\r\n无法找到目标Wifi,请检查Wifi是否打开或Wifi名称是否正确\r\n");

                if( strstr( At_Rx_Buff , "+CWJAP:4\r\n" ))
                ESP8266_DEBUG_MSG("\r\nWifi连接失败,请检查各项配置是否正确\r\n");

                while(1)
                {
                ESP8266_ERROR_Alarm();
                }      //LED灯警告错误,红灯闪烁
          }
          if ( i == timeout )
          {
                ESP8266_DEBUG_MSG("\r\nWifi连接超出期望时间,请检查各项配置是否正确\r\n");
                while(1)
                {
                ESP8266_ERROR_Alarm();
                }      //LED灯警告错误,红灯闪烁
          }
          R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);
       }
       }
 }

 /*设置 MQTT 用户属性*/
 void MQTT_SetUserProperty( char * client_id , char * user_name, char * user_password )
 {
    char  SetUserProperty_AT[256];

    sprintf( SetUserProperty_AT , "AT+MQTTUSERCFG=0,1,\"%s\",\"%s\",\"%s\",0,0,\"\"\r\n" , client_id , user_name , user_password);

    ESP8266_AT_Send ( SetUserProperty_AT );

    /*等待设置完成*/
    while ( !Uart9_Receive_Flag )
    {
          if (strstr( At_Rx_Buff , "OK\r\n" ))
          {
          ESP8266_DEBUG_MSG("\r\nMQTT用户属性已设置完成\r\n");
          Clear_Buff();      //清除缓冲区数据
          }
    }

 }

 /*连接MQTT服务器函数*/
 void Connect_MQTT( char * mqtt_ip , char * mqtt_port , uint8_t timeout )
 {
    char  Connect_MQTT_AT[256];

    uint8_t i;

    sprintf( Connect_MQTT_AT , "AT+MQTTCONN=0,\"%s\",%s,0\r\n" , mqtt_ip , mqtt_port);

    ESP8266_AT_Send( Connect_MQTT_AT );

       /*判断连接是否设置成功,失败则打印错误信息*/
    while ( !Uart9_Receive_Flag )
    {
    for(i = 0; i <= timeout; i++)
       {
          if ( strstr( At_Rx_Buff , "OK\r\n" ) )
          {
                ESP8266_DEBUG_MSG("\r\nMQTT服务器连接成功\r\n");
                Clear_Buff();      //清除缓冲区数据
                break;
          }
          if ( strstr( At_Rx_Buff , "ERROR\r\n" ) )
          {
                ESP8266_DEBUG_MSG("\r\nMQTT服务器连接失败,请检查各项配置是否正确\r\n");
                while(1)
                {
                ESP8266_ERROR_Alarm();
                }      //LED灯警告错误,红灯闪烁
          }
          if ( i == timeout )
          {
                ESP8266_DEBUG_MSG("\r\nMQTT服务器连接超出期望时间,请检查各项配置是否正确\r\n");
                while(1)
                {
                ESP8266_ERROR_Alarm();
                }      //LED灯警告错误,红灯闪烁
          }
          R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);
       }
       }


 }

 /*订阅主题函数*/
 void Subscribes_Topics( char * topics )
 {
    char  Sub_Topics_AT[256];

    sprintf( Sub_Topics_AT , "AT+MQTTSUB=0,\"%s\",1\r\n" , topics);

    ESP8266_AT_Send( Sub_Topics_AT );

    while ( !Uart9_Receive_Flag )
       {
          R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);  //订阅等待时间

          if ( strstr( At_Rx_Buff , "OK" ) )
          {
                ESP8266_DEBUG_MSG("\r\n主题订阅成功\r\n");
                Clear_Buff();      //清除缓冲区数据
                break;
          }
          if ( strstr( At_Rx_Buff , "ALREADY\r\n" ) )
          {
                ESP8266_DEBUG_MSG("\r\n已经订阅过该主题\r\n");
                Clear_Buff();      //清除缓冲区数据
                break;
          }
       }
 }

 /*发布MQTT消息函数*/
 void Send_Data( char * topics , char * data )
 {
    char  Send_Data[256];

    sprintf( Send_Data , "AT+MQTTPUB=0,\"%s\",\"%s\",1,0\r\n" , topics , data );

    ESP8266_AT_Send( Send_Data );

    while ( !Uart9_Receive_Flag )
       {
          R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);  //发布等待时间

          if ( strstr( At_Rx_Buff , "OK\r\n" ) )
          {
                ESP8266_DEBUG_MSG("\r\n消息发布成功\r\n");
                Uart9_Show_Flag = true;  //打开串口回显
                Clear_Buff();      //清除缓冲区数据
                break;
          }
          if ( strstr( At_Rx_Buff , "ALREADY" ) )
          {
                ESP8266_DEBUG_MSG("\r\n消息发布失败,请检查消息格式等信息是否正确\r\n");
                Clear_Buff();      //清除缓冲区数据
                break;
          }
       }
 }

36.7.3.4. 中断回调函数

代码 35‑13 串口中断回调函数
 /*Wifi串口回调函数*/
 void esp8266_uart9_callback(uart_callback_args_t * p_args)
 {
       switch(p_args->event)
       {
          case UART_EVENT_RX_CHAR:

                At_Rx_Buff[Uart9_Num++] = ( char ) p_args->data;  //将UART9收到的数据放到Buff缓冲区中

                /*进入透传模式后打开串口调试助手收发数据显示*/
                if( Uart9_Show_Flag )
                R_SCI_UART_Write(&g_uart4_ctrl, (uint8_t *)&(p_args->data), 1);

                break;

          case UART_EVENT_TX_COMPLETE:
          {
                Uart9_Receive_Flag = true;      //ESP8266回应完成标志

                break;
          }
          default:
                break;
       }
 }

36.7.3.5. 下载验证

由于本实验还要测试ESP8266的主题信息发布功能,所以在编译之前还需要其它的 MQTT 客户端测试工具验证,在本实验中使用的是 MQTTX 软件。 使用 MQTT 客户端测试工具连接创建好的服务器,并订阅与程序中配置相同的主题。 随后使用电脑或手机等设备打开热点,并将热点名称和密码设置完成。 编译并下载程序后,可以得到程序的提示信息。

图

打开 MQTT 客户端测试工具,可以看到ESP8266发送的信息。

图

同样,我们在 MQTT 客户端测试工具中发送消息,ESP8266同样也可以收到。

图