300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 设备接入ONENET(3)STM32 + ESP8266(MQTT协议)接入云 :官方例程移植笔记(HAL+LL库)

设备接入ONENET(3)STM32 + ESP8266(MQTT协议)接入云 :官方例程移植笔记(HAL+LL库)

时间:2018-11-18 11:08:09

相关推荐

设备接入ONENET(3)STM32 + ESP8266(MQTT协议)接入云 :官方例程移植笔记(HAL+LL库)

重要提示:由于OneNET版本迭代,导致鉴权方式可能变更,若程序无法连接,请参考官方手册或再OneNET论坛搜索相关内容

移植本意应该是指通过修改,使得运行原先在另一个平台可运行的程序。STM32CubeMx 本文简称 Mx

1. 概述

麒麟座的例程使用的是标准库,ST后续推出更新的 LL库 和 HAL库,其中LL库与标准库类似,而 HAL 则更倾向于兼容通用性,体积和效率则没有优势,如果你想在自己的工程中使用麒麟座的例程,那么移植工作是难以避免的。

移植工作主要是硬件的设配,所以首先需要了解麒麟镇开发板例程使用的基本情况:

在本文工程中,硬件配置如下:

2. 移植流程与思路

我移植工程时,通常先做一部分的准备工作,再开始具体针对硬件特性的移植:

准备工作:

① 创建一个模板工程:这个工程可以输出调试信息,可以是常用的串口或者是ST-LINK/J-LINK SWDIO 输出② 外设初始化并测试:逐个外设的初始化并测试,如本文用到串口,需要初始化串口,并测试它的收发和中断情况③ 分析硬件层接口函数:无论上层逻辑多么复杂,最终它都需要调用一个函数去控制外设,以 printf 函数为例,它最终都需要调用一个能输出一个字符的函数,去将信息展示出来,我们通过改变这个函数,就可以让信息输出到串口,或者是ST-LINK等设备中,你甚至可以打印到OLED屏幕上。④ 对比分析源工程和目标工程:这部分工作需要我们对源工程和目标工程都有比较基础的理解,例如: 以本文为例,想把标准库函数移植到 Mx 生成的工程中,那么 Mx 的mian.h包含了外设头文件,所以 标准中所有类似#include "usart.h"之类的头文件就应该换成mian.h,另外,stm32f10x.h是标准库中关于外设地址的共定义,若使用 Mx 生成的工程,该文件名为stm32f106xb.h,它被mian.h包含了(不是直接包含),所以,#include "stm32f10x.h"语句也是需要替换为include "mian.h"语句。延时函数:驱动通常包含延时函数,不同的库延时函数命名不同,单位也可能不同,虽然一般都是 ms,本文源工程延时函数为DelayXms();,需要替换为目标工程库函数的HAL_Delay(),单位不需换算,因为都是毫秒。… … ⑤ 拷贝源码文件:这一步分析我们需要移植的代码,将文件拷贝到自己的工程中,注意,在MDK中不只是将文件放在工程目录下,还需要在工程中添加一次,如果没记错 TrueStudio 会自动读取工程下的文件,添加到工中,然后是添加头文件路径。

接下来是具体的移植。

3. 麒麟座 标准 移植 LL 库

新建一个基础工程与初始化外设,使用的是 Mx ,此处不再赘述,在麒麟镇中,需要移植的源码都在其工程目录[NET]文件夹中,将其添加到本文工程如下所示:

接着添加头文件路径:

3.1 替换外设接口头文件

如前文所述,本文使用 Mx 工程,所以外设头文件统一为main.h,所以将esp8266.conenet.c中头文件替换:

3.2 替换输出调试信息

麒麟镇使用以下语句打印信息:

UsartPrintf(USART_DEBUG, "OneNet_SendData\r\n");

而本文使用:

printf("OneNet_SendData\r\n");

所以直接查找替换:

将所有UsartPrintf(USART_DEBUG,替换成printf(

3.3 延时函数

函数函数也是同理:

3.4 esp8266 接口函数(发送)

程序处理了字符串,最后是通过以下函数将数据发送到 ESP8266 的:

void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len){unsigned short count = 0;for(; count < len; count++){USART_SendData(USARTx, *str++);//发送数据while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);//等待发送完成}}

本文将其改为:

void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len){unsigned short count = 0;for(; count < len; count++){LL_USART_TransmitData8(USARTx, *str++);//发送数据while(!LL_USART_IsActiveFlag_TC(USARTx)); //等待发送完成}}

注意到,这个函数在源工程的usart.c中,这文件只需要这个函数,所以不需要复制整个文件,只需要把和这个函数添加到esp8266.c中即可。另外,这函数需要第一个参数来确定串口设备,而本文使用的是串口1,源工程使用功串口2,所以工程中,所有的语句:

Usart_SendString(USART2, (unsigned char *)cmd, strlen((const char *)cmd));

需要改为:

Usart_SendString(USART1, (unsigned char *)cmd, strlen((const char *)cmd));

3.5 esp8266 接口函数(接收)

esp8266 使用串口中断来接收数据:

void USART2_IRQHandler(void){if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断{if(esp8266_cnt >= sizeof(esp8266_buf))esp8266_cnt = 0; //防止串口被刷爆esp8266_buf[esp8266_cnt++] = USART2->DR;USART_ClearFlag(USART2, USART_FLAG_RXNE);}}

本文使用的是串口1,硬件也接入串口1,所以发生中断会进入串口1中断:

//文件:stm32f10x_it.cvoid USART1_IRQHandler(void){/* USER CODE BEGIN USART1_IRQn 0 */extern void ESP8266_IRQHandler(void);ESP8266_IRQHandler();/* USER CODE END USART1_IRQn 0 *//* USER CODE BEGIN USART1_IRQn 1 *//* USER CODE END USART1_IRQn 1 */}

通过调用ESP8266_IRQHandler()的方法,是程序处理可以写在其他文件中:

//文件:esp8266.cvoid ESP8266_IRQHandler(void){if(LL_USART_IsActiveFlag_RXNE(USART1)) //接收中断{if(esp8266_cnt >= sizeof(esp8266_buf)){esp8266_cnt = 0; //防止串口被刷爆}esp8266_buf[esp8266_cnt++] = USART1->DR;LL_USART_ClearFlag_RXNE(USART1);}}

3.6 esp8266 初始化

源文件 esp8266 初始化中初始化了所使用的串口,但在 Mx 在已经初始化了,所以需要删除,顺便将复位信号改正:

void ESP8266_Init(void){//GPIO_InitTypeDef GPIO_Initure;////RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);////ESP8266复位引脚//GPIO_Initure.GPIO_Mode = GPIO_Mode_Out_PP;//GPIO_Initure.GPIO_Pin = GPIO_Pin_5;//GPIOB5-复位//GPIO_Initure.GPIO_Speed = GPIO_Speed_50MHz;//GPIO_Init(GPIOB, &GPIO_Initure);////GPIO_WriteBit(GPIOB, GPIO_Pin_5, Bit_RESET);//HAL_Delay(250);//GPIO_WriteBit(GPIOB, GPIO_Pin_5, Bit_SET);//HAL_Delay(500);HAL_GPIO_WritePin(ESP_RST_GPIO_Port,ESP_RST_Pin,GPIO_PIN_RESET);HAL_Delay(250);HAL_GPIO_WritePin(ESP_RST_GPIO_Port,ESP_RST_Pin,GPIO_PIN_SET);HAL_Delay(500);ESP8266_Clear();printf("1. AT\r\n");while(ESP8266_SendCmd("AT\r\n", "OK"))HAL_Delay(500);printf("2. CWMODE\r\n");while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))HAL_Delay(500);printf("3. CWJAP\r\n");while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))HAL_Delay(500);printf("4. CIPSTART\r\n");while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "CONNECT"))HAL_Delay(500);printf("5. ESP8266 Init OK\r\n");}

3.7 数据下发响应

OneNet_RevPro()函数响应数据的内容,并打开和关闭LED灯,本文并没有对应的接口,所以将打开 LED 灯接口都换成打印:

另外,源文件发送数据是led状态:

unsigned char OneNet_FillBuf(char *buf){char text[16];memset(text, 0, sizeof(text));strcpy(buf, "{");memset(text, 0, sizeof(text));sprintf(text, "\"Red_Led\":%d,", led_status.Led5Sta);strcat(buf, text);memset(text, 0, sizeof(text));sprintf(text, "\"Green_Led\":%d,", led_status.Led4Sta);strcat(buf, text);memset(text, 0, sizeof(text));sprintf(text, "\"Yellow_Led\":%d,", led_status.Led3Sta);strcat(buf, text);memset(text, 0, sizeof(text));sprintf(text, "\"Blue_Led\":%d", led_status.Led2Sta);strcat(buf, text);strcat(buf, "}");return strlen(buf);}

这里你可以修改为任何值,然后看看效果如何。

四、测试

本文测试时候未接复位IO口,完成以上操作后,可以通过onenet平台下发命令来测试通信,根据说明文档:

1.修改esp8266.c下的wifi账号及密码

2.修改onenet.c下的proid、auth_info和devid

3.指令说明:

1.命令直接下发:

redled:1 打开红灯

greenled:1 打开绿灯

yellowled:1 打开黄灯

blueled:1 打开蓝灯

同理,1替换为0则是关闭

2.应用命令填写方式:

redled:{V}, 控制红灯;开关开值1,开关关值0

greenled:{V}, 控制绿灯;开关开值1,开关关值0

yellowled:{V}, 控制黄灯;开关开值1,开关关值0

blueled:{V}, 控制蓝灯;开关开值1,开关关值0

五、附件

链接:onenet_stm32_mqtt

提取码:1234

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。