周三的网文阅读量好惨,到了周日还没过 200,本想暂时不更此方面内容了。
但是看到群里的小伙伴在修改 linkkitapp 例程遇到了麻烦,今天再分享一下代码修改的全过程,本文我在虚拟机中重复修改验证了三遍,包你可以顺利移植成功。
本文的实现,在上一篇网文的基础上实现,开发环境的搭建参见下文:
AliOS Things 物联网操作系统学习第一步:Windows 下 AliOS Things 开发环境搭建
本文我们实现 linkkitapp 例程修改、ESP8266 固件的下载、一键配网和云智能 APP 绑定设备。
需要解决的问题
ESP8266 有两个 UART:UART0 和 UART1。
UART0 有 TX、RX,可以作为系统的打印信息输出接口和数据收发口。
UART1 的 RX 被 Flash 占用,只有发送引脚 TX(GPIO2,即 UART1_TXD),所以一般作为打印信息输出接口(调试用)。
通常情况下,我们使用 UART0 和外设通讯,而使用 UART1 作为日志打印端口。
D1 mini ESP8266 模块两个串口的所在位置:
ESP8266 D1 mini 模块
我们使用一个 Micro USB 线与 D1 mini ESP8266 模块相连,上文编译后的固件烧录之后,串口助手中会收到如下打印信息:
我们可以看到默认的 linkkitapp 示例,Log 信息是通过 UART0 发送出来的,而且里面有很多咱们不关心的信息,应该将此部分信息进行屏蔽。
所以我们需要做如下几个工作:
- 将串口 0 和串口 1 的比特率设为一致;交换 UART0 和 UART1,让 UART1 输出 Log 日志;UART0 与 STM32 进行通信;将 STM32 发上来的信息,通过 UART0 接收并发送到云端;将云端下发的有用的信息通过 UART0 转发给 STM32。
解决问题 1. 串口的初始化函数在platformmcuesp8266bspdriveruart.c
411 行 中,初始化 uart1,uart0 的波特率都为 115200。
void
uart_init_new(uart_dev_t *uart)
{
UART_WaitTxFifoEmpty(UART0);
UART_WaitTxFifoEmpty(UART1);
if (uart == NULL)
{
return;
}
if (uart->port == 1)
{
//printf("port= 1n ");
//uart1 setting
UART_ConfigTypeDef uart_config;
uart_config.baud_rate = uart->config.baud_rate;
uart_config.data_bits = UART_WordLength_8b;
uart_config.parity = USART_Parity_None;
uart_config.stop_bits = USART_StopBits_1;
uart_config.flow_ctrl = USART_HardwareFlowControl_None;
uart_config.UART_RxFlowThresh = 120;
uart_config.UART_InverseMask = UART_None_Inverse;
//UART_ParamConfig(UART0, &uart_config);
//uart2 setting for log
//uart_config.baud_rate = uart->config.baud_rate;
UART_ParamConfig(UART1, &uart_config);
UART_SetPrintPort(UART1);
//UART_intr_handler_register(uart0_rx_isr, NULL);
ETS_UART_INTR_ENABLE();
}
else
{
//printf("port= 0 n ");
UART_ConfigTypeDef uart_config;
uart_config.baud_rate = uart->config.baud_rate;
// uart_config.baud_rate = BIT_RATE_921600;
uart_config.data_bits = UART_WordLength_8b;
uart_config.parity = USART_Parity_None;
uart_config.stop_bits = USART_StopBits_1;
uart_config.flow_ctrl = USART_HardwareFlowControl_None;
uart_config.UART_RxFlowThresh = 120;
uart_config.UART_InverseMask = UART_None_Inverse;
UART_ParamConfig(UART0, &uart_config);
UART_IntrConfTypeDef uart_intr;
uart_intr.UART_IntrEnMask = UART_RXFIFO_TOUT_INT_ENA | UART_FRM_ERR_INT_ENA | UART_RXFIFO_FULL_INT_ENA | UART_TXFIFO_EMPTY_INT_ENA;
uart_intr.UART_RX_FifoFullIntrThresh = 100;//10
uart_intr.UART_RX_TimeOutIntrThresh = 10;//2
uart_intr.UART_TX_FifoEmptyIntrThresh = 20;
UART_IntrConfig(UART0, &uart_intr);
UART_SetPrintPort(UART0);
UART_intr_handler_register(uart0_rx_isr, NULL);
ETS_UART_INTR_ENABLE();
}
}
解决问题 2. 交换 UART0 和 UART1:修改此文件:AliOS-Thingsplatformmcuesp8266haluart.c
17 行。
int32_t hal_uart_send(uart_dev_t *uart, const void *data, uint32_t size, uint32_t timeout)
{
int i = 0;
char* pdata = (char *)data;
for(i = 0; i < size; i++)
{
//uart0_write_char(pdata[i]);
if(uart->port == 1)
uart0_write_char(pdata[i]);
else
uart1_write_char(pdata[i]);
}
return 0;
}
编译一下,报错:
去掉platformmcuesp8266bspdriveruart.c
60 行, LOCAL void uart1_write_char(char c)
函数前面的 LOCAL。
再次编译正常。
修改串口初始化,文件所在路径:platformmcuesp8266bspentry.c
60 行,修改后的代码具体如下:
void user_init(void)
{
int ret = 0;
extern int32_t hal_uart_init(uart_dev_t *uart);
extern void key_gpio_init(void);
key_gpio_init();
///hal_uart_init(&uart_0);
uart_config_t uartConfig0;
uartConfig0.baud_rate = 115200;
uartConfig0.parity = 0;
uartConfig0.stop_bits = 1;
uart_dev_t uart0;
uart0.port = 0;
uart0.config = uartConfig0;
hal_uart_init(&uart0);
uart_config_t uartConfig1;
uartConfig1.baud_rate = 115200;
uart_dev_t uart1;
uart1.port = 1;
uart1.config = uartConfig1;
hal_uart_init(&uart1);
printf("[%d] -- Message from printf -- user_init -- rn",(unsigned)aos_now_ms());
hal_wifi_register_module(&aos_wifi_esp8266);
ret = hal_wifi_init();
if (ret){
printf("waring: wifi init fail ret is %d rn", ret);
}
#if defined(SUPPORT_SINGAPORE_DOMAIN)
aos_task_new("main", app_entry, 0, 7.5*1024);
#elif defined(ESP8266_CHIPSET)
aos_task_new("main", app_entry, 0, 2*1024);
#else
aos_task_new("main", app_entry, 0, 6*1024);
#endif
}
解决问题 3.
- 下发有用信息:
修改文件appexamplelinkkitapplinkkit_example_solo.c
109 行。
/** recv event post response message from cloud **/
static int user_property_set_event_handler(const int devid, const char *request, const int request_len)
{
int res = 0;
EXAMPLE_TRACE("Property Set Received, Request: %s", request);
hal_uart0_send(request,strlen(request)); //xiaoha +++
res = IOT_Linkkit_Report(EXAMPLE_MASTER_DEVID, ITM_MSG_POST_PROPERTY,
(unsigned char *)request, request_len);
EXAMPLE_TRACE("Post Property Message ID: %d", res);
return 0;
}
- 上发有用信息:
修改文件 appexamplelinkkitapplinkkit_example_solo.c
27 行处添加头文件:
#include "aos/hal/uart.h"
在includeaoshaluart.h
文件 102 行后增加两个函数声明:
int32_t hal_uart0_printf(const void *data);
int32_t hal_uart0_send(const void *data, uint32_t size);
在AliOS-Thingsplatformmcuesp8266haluart.c
文件 32 行后增加两个函数实现:
int32_t hal_uart0_printf(const void *data)
{
int i = 0;
char* pdata = (char *)data;
while(* pdata)
uart0_write_char(* pdata++);
return 0;
}
int32_t hal_uart0_send(const void *data, uint32_t size)
{
int i = 0;
char* pdata = (char *)data;
for(i = 0; i < size; i++)
{
uart0_write_char(pdata[i]);
}
uart0_write_char('r');
uart0_write_char('n');
return 0;
}
修改文件appexamplelinkkitapplinkkit_example_solo.c
378 行, 修改上传属性的数据:
/* Post Proprety Example */
uint8_t receive_bytes[255];
memset(receive_bytes,0,255); // 或者 memset(receive_bytes,0,128*sizeof(char));
int32_t ret = -1;
uint32_t i, recv_size = 0;
uart_dev_t uart0;
uart0.port = 0;
ret = hal_uart_recv_II(&uart0, &receive_bytes, 255, &recv_size, 20);
if ((ret == 0))
{
hal_uart0_printf(receive_bytes);
char property_payload[30] = {0};
HAL_Snprintf(property_payload,sizeof(property_payload),"%s",receive_bytes);
res = IOT_Linkkit_Report(EXAMPLE_MASTER_DEVID,ITM_MSG_POST_PROPERTY,
(unsigned char *)property_payload,strlen(property_payload));
EXAMPLE_TRACE("Post Property Message ID: %d",res);
}
修改智能设备的三元组信息:
// for demo only
#define PRODUCT_KEY "a1xHkDXXXXX"
#define PRODUCT_SECRET "0miHcO6f4E8XXXXX"
#define DEVICE_NAME "ZNFS0001"
#define DEVICE_SECRET "xnOe5VcOkvXFTBAZaik4hz7y67XXXXXX"
登录阿里云飞燕平台:https://living.aliyun.com/#/
创建阿里云物联网智能设备的方法请参见下文:
七步快速开启产品智能化
在产品页面获得ProductSecret
:
在设备页面获得设备的三元组信息:
烧写固件
使用云智能 APP 配网并添加设备
固件烧写完成之后,复位 ESP8266 模块,可以看到 ESP8266 的串口 1 打印如下信息:
此时虽然在扫描 SSID,但是扫描二维码并不能正常添加设备,需要先进入配网模式,再扫描二维码添加设备。
进入配网模式的方法:
使用一个跳线,先把 D5(GPIO14)接 GND,再接 3.3V。
出现如下 Log 即进入配网模式:
然后使用云智能 APP 扫描上面的二维码添加设备并配网。
配网成功,云智能 APP 出现如下界面:
配网成功,串口助手可以收到来自服务器端的如下 Log 日志:
此时查看阿里云飞燕平台的后台,可以看到设备已经成功上线。
模拟上传属性
经过上面的改造之后,我们只需要向 UART0 发送 JSON 格式的数据,即可修改服务器端的数值,比如发送:
{"CurrentTemperature":26}
发送完毕,服务器端的当前温度值将会修改为 26℃,在运行状态中可以实时看出来当前温度值是实时变化的。
模拟设置属性
手机端 APP 点击某个按钮之后,将会将数据包发送至 ESP8266,ESP8266 将有用信息通过 UART0 的 TX 引脚发送给 STM32,STM32 将收到服务器端指令,对此指令进行解析,进而做相应的动作,具体逻辑类似下图所示。
调试真实设备中,对电源开关设置为 1,即{"PowerSwitch":1},在串口助手中我们收到指令{"PowerSwitch":1};
我们对电源开关设置为 0,即{"PowerSwitch":0},可以看到串口助手中,收到对应的指令{"PowerSwitch":0}。
STM32 中我们使用 cJSON 对上面字符串进行解析即可,然后做相应的动作,即完成了云端对设备的远程控制。
细心的人可能发现了,为什么我们用 CurrentTemperature 或者 PowerSwitch 来设置属性呢?其实他们就是我们创建产品的时候,进行功能定义的时候,设置的标识符。
至此,使用 ESP8266 模块,已经完成了烧写 AliOS Things 3.0 固件,成功配网、添加设备并连上了阿里云服务器。
让 ESP8266 的串口 0 与 STM32 的串口进行数据通信,发送模拟上传属性中的数据完成属性的上报,串口接收、解析服务器返回的数据,根据解析的结果进而完成对设备的控制,从而实现了 STM32 和 ESP8266 的双向通信。
各位小伙伴可以在我的基础上随意扩展,这样你的设备就实现了接入阿里云物联网平台。