前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。
人工智能编程入门博客
看到群里的小伙伴在修改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模块两个串口的所在位置:
我们使用一个Micro USB线与D1 mini ESP8266模块相连,上文编译后的固件烧录之后,串口助手中会收到如下打印信息:
我们可以看到默认的linkkitapp示例,Log信息是通过UART0发送出来的,而且里面有很多咱们不关心的信息,应该将此部分信息进行屏蔽。
所以我们需要做如下几个工作:
- 将串口0和串口1的比特率设为一致;
- 交换UART0和UART1,让UART1输出Log日志;UART0与STM32进行通信;
- 将STM32发上来的信息,通过UART0接收并发送到云端;将云端下发的有用的信息通过UART0转发给STM32。
解决问题1. 串口的初始化api在platform\mcu\esp8266\bsp\driver\uart.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= 1\n ");
//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-Things\platform\mcu\esp8266\hal\uart.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;
}
编译一下,报错:
去掉platform\mcu\esp8266\bsp\driver\uart.c
60行, LOCAL void uart1_write_char(char c)
函数前面的LOCAL。
再次编译正常。
修改串口初始化,文件所在路径:platform\mcu\esp8266\bsp\entry.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 -- \r\n",(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 \r\n", 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.
- 下发有用信息:
修改文件app\example\linkkitapp\linkkit_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;
}
- 上发有用信息:
修改文件 app\example\linkkitapp\linkkit_example_solo.c
27行处添加头文件:
#include "aos/hal/uart.h"
在include\aos\hal\uart.h
文件102行后增加两个函数声明:
int32_t hal_uart0_printf(const void *data);
int32_t hal_uart0_send(const void *data, uint32_t size);
在AliOS-Things\platform\mcu\esp8266\hal\uart.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;
}
修改文件app\example\linkkitapp\linkkit_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的双向通信。
各位小伙伴可以在我的基础上随意扩展,这样你的设备就实现了接入阿里云物联网平台。
要获取本人修改后的源码可以加程序员小哈好友索取!
欢迎关注
程序员小哈带你玩转嵌入式,微信搜索:嵌入式从0到1,更多干货等着你。
想进小哈技术交流群,请加程序员小哈个人微信,带你嵌入式入门进阶。