物联网学习之旅:微信小程序控制STM32(二)--ESP8266连接mqtt服务端

ESP8266连接mqtt服务端

微信小程序控制STM32的第二步,就是要编写ESP8266固件,来连接已经搭建好的物联网服务器。也有别的方式,只要你足够了解mqtt协议,可以通过使用ESP8266原生的AT指令来连接,因为ESP8266连接mqtt服务端中mqtt协议也是通过建立TCP连接,发送相应的协议报文来连接服务端。但是乐鑫官方提供的SDK中含有连接mqtt服务端的实例代码,要做的就是根据自己的功能要求去修改代码。
我修改的固件是ESP8266与STM32之间进行串口通信,以透传的方式互相传递数据,然后ESP8266作为中转把数据发到相应的目的地。
自定义通信协议

  1. 硬件准备
    我用的是ESP8266-01这款模块
    ESP8266管脚图
    ESP8266有UART 下载模式和Flash 运行模式 ,接线不一样的地方就是在下载模式时GPIO0要接低电平,运行模式时悬空即可,每次运行模式和下载模式切换都需要重启一下模块,才能第二次烧写或者运行。
    在这里插入图片描述
    我是采用这样的连接方式来烧写固件,运行程序时把GPIO0拔掉,然后拔掉esp8266的vcc线,然后又插上,重启一下就可以了。烧写的时候把GPIO0接共地端,然后拔掉esp8266的vcc线,然后又插上,重启一下,就可以烧写程序了。至于我为什么要用这么复杂的接线方式来烧写程序,那是因为买这个esp8266调试器的时候,不懂,图便宜(根本也是因为我太穷了,哈哈哈),然而这个用来运行调试是最合适的,直接插上去即可。不过这样也能烧写固件。也可以用TTL转串口来烧写,都是可以的,原理都一样。
  2. 搭建ESP8266开发环境
    进入安信可ESP8266 系列模组专题,按照开发环境搭建的步骤搭建开发环境。
    在这里插入图片描述
    在这里插入图片描述
    点击蓝色文字下载ESP8266_NONOS_SDK-v3.0.0,也可以选择在乐鑫官网上下载最新版本的SDK,根据需要下载开发文档,我用到了这两个文档。在这里插入图片描述
    在这里插入图片描述
    值得注意的是,本项目用到的是esp_mqtt_proj这个例程,所以在构建工程文件时,需要将examples/esp_mqtt_proj目录工程目录的顶层文件中,其它的按照安信可提供的步骤搭建即可,编译没有错误之后,其实example文件夹就可以删除掉了,这个项目只用到mqtt部分,其它例程删掉后编译仍然是成功的。
  3. 编写ESP8266固件
    打开编译通过的工程,需要修改的有这几个地方
    1)user_main.c中修改
void mqttConnectedCb(uint32_t *args)
{
    MQTT_Client* client = (MQTT_Client*)args;
    mqttclient=client;
    INFO("MQTT: Connected\r\n");
    MQTT_Subscribe(client, "Topic0", 0);  //订阅Topic0主题,用于接收微信小程序的数据
    MQTT_Publish(client, "Topic1", "hello1", 6, 0, 0); //发布消息
	//Topic0用于下行通道,Topic1用于上行通道
}
void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len)
{ //接收到数据时执行
    char *topicBuf = (char*)os_zalloc(topic_len+1),
            *dataBuf = (char*)os_zalloc(data_len+1);

    MQTT_Client* client = (MQTT_Client*)args;

    os_memcpy(topicBuf, topic, topic_len);
    topicBuf[topic_len] = 0;

    os_memcpy(dataBuf, data, data_len);
    dataBuf[data_len] = 0;

    os_printf("%s\r\n",dataBuf);  //串口打印接收到的消息
    os_free(topicBuf);
    os_free(dataBuf);
}
MQTT_Client* mqttclient;  //此指针会用在uart.c中

2)uart.c中修改
通过user_main.c文件中的uart_init()定位到uart.c文件,然后对这里面进行修改。首先需要引入user_main.c定义的“MQTT_Client* mqttclient;”,这样下面在串口处理函数中,当从串口接收完数据之后,通过引入的mqtt客户端指针,将数据发到特定的主题,然后别忘了引入“mqtt.h”,因为这里要用到这里面的函数,将数据发送出去。

extern MQTT_Client* mqttclient;

最后修改串口中断处理函数。

LOCAL void
uart0_rx_intr_handler(void *para)
{
    /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
    * uart1 and uart0 respectively
    */
    uint8_t RcvChar[256];
    uint8_t uart_no = UART0;//UartDev.buff_uart_no;
    uint8_t fifo_len = 0;
    uint8_t buf_idx = 0;
    uint8_t temp, cnt;

    if (UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)) {
        DBG1("FRM_ERR\r\n");
        WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
    } else if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) {
        DBG("f");
        uart_rx_intr_disable(UART0);
        WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR);
        system_os_post(uart_recvTaskPrio, 0, 0);
    } else if (UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) { //检测到是超时中断
    	fifo_len=(READ_PERI_REG(UART_STATUS(UART0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;  //获取数据长度
    	buf_idx=0;
    	for(buf_idx=0;buf_idx<fifo_len;buf_idx++){
    		RcvChar[buf_idx]=READ_PERI_REG(UART_FIFO(UART0))&0xFF;  //将数据储存起来
    	}
    	MQTT_Publish(mqttclient, "Topic1", RcvChar, fifo_len, 0, 0);  //把接收到的数据发送到mqtt服务端
    	os_memset(RcvChar,0,256);   //清除数据
        WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR);  //清除超时中断状态
    } else if (UART_TXFIFO_EMPTY_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_TXFIFO_EMPTY_INT_ST)) {
        DBG("e");

        CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
#if UART_BUFF_EN
        tx_start_uart_buffer(UART0);
#endif
        //system_os_post(uart_recvTaskPrio, 1, 0);
        WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_TXFIFO_EMPTY_INT_CLR);

    } else if (UART_RXFIFO_OVF_INT_ST  == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_OVF_INT_ST)) {
        WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_OVF_INT_CLR);
        DBG1("RX OVF!!\r\n");
    }

}

问为什么要这样改,官方文档中做出了说明,参考esp8266技术参考手册,串口中断状态分为:接收 full 中断、接收溢出中断、接收超时中断 tout、发送 fifo 空中断、流量量控制状态中断。我只对接收超时中断进行了配置,因为这个足够满足需求,若考虑全面,可以适当增加。手册中也有一个中断处理函数的例程,参照这个修改。
在这里插入图片描述
上面代码的注释也写的很清楚了。
3)修改mqtt_config.h

/*只有在持有人标识和之前不同的情况下才会更新系统参数,这就是为什么在配置文件这里修改MQTThost等内容时,烧进去的程序没有变化*/
#define CFG_HOLDER    0x00FF55A4    /* Change this value to load default configurations */

#define MQTT_HOST            "0.0.0.0" //改成自己服务器的公网IP
#define MQTT_PORT            1883    // the listening port of your MQTT server or MQTT broker
#define MQTT_CLIENT_ID        "esp8266"    // 自定义的clientID
#define MQTT_USER            "admin" // your MQTT login name, if MQTT server allow anonymous login,any string is OK, otherwise, please input valid login name which you had registered
#define MQTT_PASS            "public" // you MQTT login password, same as above
#define STA_SSID "**********"    //填自己的SSID
#define STA_PASS "**********" // 你的AP/路由器的密码

记得要修改CFG_HOLDER,随便更改某一个十六进制数就行,否则出现修改的参数不生效的后果,我也是一步一步采坑过来的。

不过还有一个坑,我现在才说,目的就是为了经历遇到问题,解决问题的过程。遇到问题之后自己解决,这样可以学到更多的东西。修改完中断处理函数之后,调试时,似乎根本就不会进入修改好的中断处理函数,找了各种原因:是不是没有配置好串口的相关寄存器啊,是不是mqttclient不能传递到另一个文件中使用啊,等等等。最后找到答案,ESP8266 NONOS_SDK-3.0 开发中官方例程 UART0串口进入不了中断问题。因为工程构建得有问题,esp_mqtt_proj目录中虽然有uart.h头文件,但是根本不含有uart.c文件,我们所修改的不过是没有引入到项目中的uart.c文件。所以我的解决方式是:
1)将driver_lib下的driver复制到esp_mqtt_proj项目文件夹内
在这里插入图片描述
2)在Makefile文件中加入相应的库文件目录。
在这里插入图片描述
在这里插入图片描述
把对应的二进制文件烧录进esp8266
在这里插入图片描述
4. 调试效果
1)连接好ESP8266和串口调试器,插到电脑USB口上。
在这里插入图片描述
2)打开串口调试助手(安信可官网开发工具清单中下载)。
在这里插入图片描述
这样表示mqtt服务端连接成功。
3)模拟一下微信小程序与ESP8266之间进行通信,首先在MQTTBox上添加mqtt客户端用以模拟微信小程序端,配置如下:
在这里插入图片描述
在MQTTBox上发布消息
在这里插入图片描述
可以看到esp8266串口中打印出来了消息,如果esp8266接在STM32上,STM32只需要读取串口数据就可以获取到微信小程序发来的数据了、
在这里插入图片描述
esp8266转发串口数据(AT+RST)
在这里插入图片描述
可以看到微信小程序订阅的Topic1主题,接收到了消息。
在这里插入图片描述
这样这个环节就OK了。

个人能力有限,有错误的地方欢迎指正,有问题也可以提,可以一起探讨一下

发布了3 篇原创文章 · 获赞 2 · 访问量 2164

猜你喜欢

转载自blog.csdn.net/m0_46225622/article/details/105292965