加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
    • 需要解决的问题
    • 烧写固件
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

保姆级教程,虚拟机中重复验证了三遍,包你顺利接入阿里云物联网平台

2020/12/28
331
阅读需 19 分钟
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

周三的网文阅读量好惨,到了周日还没过 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 发送出来的,而且里面有很多咱们不关心的信息,应该将此部分信息进行屏蔽。

所以我们需要做如下几个工作:

  1. 将串口 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 的双向通信。

各位小伙伴可以在我的基础上随意扩展,这样你的设备就实现了接入阿里云物联网平台。

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
SN65HVD232DRG4 1 Texas Instruments 3.3 V CAN Transceiver 8-SOIC -40 to 85

ECAD模型

下载ECAD模型
$2.26 查看
TCAN1042VDRBRQ1 1 Texas Instruments Automotive fault-protected CAN transceiver with I/O level shifting and flexible data-rate 8-SON -55 to 125

ECAD模型

下载ECAD模型
$7.05 查看
XB3-24Z8PT-J 1 Digi International Inc Telecom Circuit, 1-Func, MODULE-20

ECAD模型

下载ECAD模型
$20.06 查看
阿里巴巴

阿里巴巴

阿里巴巴集团经营多项业务,另外也从关联公司的业务和服务中取得经营商业生态系统上的支援。业务和关联公司的业务包括:淘宝网、天猫、聚划算、全球速卖通、阿里巴巴国际交易市场、1688、阿里妈妈、阿里云、蚂蚁金服、菜鸟网络等。

阿里巴巴集团经营多项业务,另外也从关联公司的业务和服务中取得经营商业生态系统上的支援。业务和关联公司的业务包括:淘宝网、天猫、聚划算、全球速卖通、阿里巴巴国际交易市场、1688、阿里妈妈、阿里云、蚂蚁金服、菜鸟网络等。收起

查看更多

相关推荐

电子产业图谱

公众号『嵌入式从0到1』,号主:程序员小哈,是一个软硬件全栈开发工程师(12年工作经验的老司机),电子发烧友论坛鸿蒙版块版主,公众号内容专注于嵌入式学习。坚持原创,写有图、有视频的保姆级教程文章,篇篇有干货。做一个讲清楚,说明白,大家学得会的交流平台。