MCU 的 SDK 移植说明

更新时间:2024-05-14 08:00:15下载pdf

当您在涂鸦 IoT 平台创建 Wi-Fi 网关产品时,在硬件开发阶段可以获取相应开发资料。其中,MCU SDK 是为了帮助您快速了解云模组搭配 MCU 进行网关开发的嵌入式开发方式。

SDK 介绍及下载

网关 SDK 包是根据 涂鸦 IoT 平台 上定义的产品功能,自动生成的 MCU 代码。通讯及协议解析架构已写好,可直接添加到原有 MCU 工程中,快速完成 MCU 程序开发。

在涂鸦 IoT 平台,产品创建流程中的硬件开发界面,选择好模组和固件后,可以找到 MCU SDK 的下载链接。详情请参考 网关 MCU 接入方案

注意:MCU SDK 会跟随产品相关配置的变化而变化,如果您更改了产品 DP 功能定义,或者重新选择了云模组,请需要重新下载 MCU SDK。

MCU 的 SDK 移植说明

SDK 目录结构

获得开发资料包后,MCU SDK 的主要目录结构如下所示:

|- gateway_mcu_sdk | |- system.c | |- system.h | |- mcu_api.c | |- mcu_api.h | |- protocol.c | |- protocol.h | |- cJSON.c | |- cJSON.h | |- wifi.h | |- readme.txt

部分文件的介绍如下:

执行文件 头文件 说明
mcu_api.c mcu_api.h 内含 Wi-Fi 相关函数,您可以按需调用
protocol.c protocol.h 协议文件,您需要根据项目需求,修改这 2 个文件,内含数据处理函数
system.c system.h 串口通讯协议的具体实现
wifi.h Wi-Fi 相关宏定义
cJSON.c cJSON.h 内含对 JSON 数据格式的解析和组合处理函数

SDK 移植

SDK 包对 MCU 硬件资源需求:

  • 4 字节 Flash
  • RAM 与 DP 数据长度有关,约一百字节左右
    如果使用固件 OTA 升级功能,则需要大于 260 byte
  • 函数嵌套级数 9 级

若您的设备资源不足,可自行对接串口协议,详情请参考 Wi-Fi 通用方案串口协议。但 SDK 包中的函数依然可以作为参考。

SDK 移植流程

获取到 MCU SDK 包后,按以下步骤可完成 SDK 移植:

  1. 编写 MCU 基础程序,移植 SDK 文件
  2. 确认 protocol.h 宏定义
  3. 移植 protocol.c 文件及函数调用
  4. DP 上报下发函数完善调用
  5. 配网功能及指示灯函数完善
  6. 产测功能完善

第一步:编写 MCU 基础程序和移植 SDK

在原项目工程中,加入 mcu_sdk 文件夹中的 .c.h 文件,添加相应头文件引用路径。完成 MCU 相关外设初始化,包括串口(数据通信)、外部中断(按键)、定时器(指示灯闪烁)等。

MCU 的 SDK 移植说明

第二步:确认 protocol.h 宏定义

确认产品信息

  • PRODUCT_KEY 为产品 PID 宏定义,该 PID 为每个产品的唯一标识,请确保代码与 涂鸦 IoT 平台 上展示的值一致,如果不是,请在产品开发流程的 硬件开发 页面重新下载 SDK 开发包。
    MCU 的 SDK 移植说明

  • MCU_VER 为软件版本,默认为 1.0.0。若 MCU 固件进行了 OTA 升级,升级后需更新版本号。

  • CONFIG_MODE 为配网方式,通常选择 默认配网 方式。

    #ifndef __PROTOCOL_H_ #define __PROTOCOL_H_ /****************************************************************************** 产品相关信息配置 ******************************************************************************/ /****************************************************************************** 1:修改产品信息 ******************************************************************************/ //pid信息,服务端自动插入 #define PRODUCT_KEY "gqkvyygeah6rdhbv" //开发平台创建产品后生成的16位字符产品唯一标识 #define MCU_VER "1.0.0" //您的软件版本,用于MCU固件升级,MCU升级版本需修改 //配网方式选择,默认为CONFIG_MODE_DEFAULT,只能三选一 #define CONFIG_MODE CONFIG_MODE_DEFAULT //默认配网方式 //#define CONFIG_MODE CONFIG_MODE_LOWPOWER //低功耗配网方式 //#define CONFIG_MODE CONFIG_MODE_SPECIAL //特殊配网方式 //smart和AP共存配网模式的特殊配置,如果不使用此宏定义,则在smart模式和AP模式之间切换 //#define CONFIG_MODE_CHOOSE 0 //同时打开AP和smart配网,不需要您切换,网络状态为0x06 //#define CONFIG_MODE_CHOOSE 1 //只使用AP配网模式

确认 MCU 是否需要支固件升级

如需要支持 MCU 固件 OTA 升级,请开启该宏。开启该宏后,需要选择固件升级包大小。

/****************************************************************************** 如需要支持MCU固件升级或者是子设备升级,请开启该宏 ******************************************************************************/ //#define SUPPORT_MCU_FIRM_UPDATE //开启MCU固件升级功能(默认关闭) #ifdef SUPPORT_MCU_FIRM_UPDATE //固件升级包大小选择 0x00:256byte(默认) 0x01:512byte 0x02:1024byte #define PACKAGE_SIZE 0x00 //MCU固件升级包大小 256byte //#define PACKAGE_SIZE 0x01 //512byte //#define PACKAGE_SIZE 0x02 //1024byte #endif

MCU升级说明

MCU 要想实现 OTA 升级,需要对 MCU 的 FLASH 进行管理,将代码分为 bootloader 和应用代码。OTA 只传输应用代码部分,固件升级包传输完成之后,由 bootloader 引导 MCU 去执行新的应用代码,实现 MCU 固件升级并成功执行。

  • bootloader 代码要烧写到 MCU 默认启动的起始地址,一般为 0x08000000,保证 MCU 每次上电或复位后,首先执行 bootloader。
  • 应用代码的烧写起始地址可以根据 bootloader 的大小往后偏移(如0x00000200)。

如果需要进行OTA升级,首先要编译好新版的bin文件,注意要在protocol.h文件中将版本号(MCU_VER)增加一个版本,参考如下代码 #define MCU_VER "1.0.1" ,用来验证是否升级成功。

#ifndef __PROTOCOL_H_ #define __PROTOCOL_H_ /****************************************************************************** 产品相关信息配置 ******************************************************************************/ /****************************************************************************** 1:修改产品信息 ******************************************************************************/ //pid信息,服务端自动插入 #define PRODUCT_KEY "gqkvyygeah6rdhbv" //开发平台创建产品后生成的16位字符产品唯一标识 #define MCU_VER "1.0.1" //您的软件版本,用于MCU固件升级,MCU升级版本需修改 //配网方式选择,默认为CONFIG_MODE_DEFAULT,只能三选一 #define CONFIG_MODE CONFIG_MODE_DEFAULT //默认配网方式 //#define CONFIG_MODE CONFIG_MODE_LOWPOWER //低功耗配网方式 //#define CONFIG_MODE CONFIG_MODE_SPECIAL //特殊配网方式

有了新版本的bin文件之后,就可以在涂鸦IoT平台配置OTA升级,详细步骤请参考 选择和管理固件版本

接下来,根据选择升级的方式进行OTA升级。固件升级完成后,MCU 重启,执行新的固件代码。OTA升级期间,会停止一切数据上报。涂鸦模组发送完所有的升级包,重新发送 01 命令字,MCU 需要在一分钟回复产品信息中的软件版本号带上升级后的 MCU 版本号,版本号需要和在涂鸦后台配置升级的版本号保持一致。

MCU 升级类型分为四种:

  • App 提醒升级:用户每次进入设备控制面板都会收到升级提醒的弹窗,是否确认升级由用户自己在 App 确认。

  • App 静默升级:App 不会有任何提醒弹窗,固件上电后一分钟内会自动去检测升级发现有高版本的升级包会自动开始拉取相关升级包,第一次上电后模组会间隔 24 小时去云端检测一次是否有升级包配置。

  • App 强制升级: App 端会有升级提醒弹窗,如果用户不确认升级,用户就没法正常使用这个产品的控制面板。

  • App 检测升级:App 端不会有任何升级提醒的弹窗,必须要用户在 App 端自己去点击相关固件版本检测,如果有高版本的固件配置才会显示升级提示信息。

定义收发缓存

修改缓冲区大小,根据 DP 定义,串口接收和发送缓存大小要大于数据最长的 DP 数据长度。默认大小为 24 字节。需要做 MCU OTA 升级的缓存大小建议大于 260 字节。接收队列大小,若 RAM 紧张可以适当缩小。

/****************************************************************************** 3:定义收发缓存: 用户根据实际情况定义收发缓存的大小 ******************************************************************************/ #ifndef SUPPORT_MCU_FIRM_UPDATE #define WIFI_UART_QUEUE_LMT 16 //数据接受队列大小,如MCU的RAM不够,可缩小 #define WIFI_UART_RECV_BUF_LMT 128 //串口数据接收缓存区大小,如MCU的RAM不够,可缩小 #define WIFI_DATA_PROCESS_LMT 128 //串口数据处理缓存区大小,根据用户DP数据大小量定,建议大于24 #else #define WIFI_UART_RECV_BUF_LMT 128 //串口数据接收缓存区大小,如MCU的RAM不够,可缩小 //当选择升级包单包大小的时候,选择单包256byte,512byte,1024byte,必须要扩大该buf的大小 //固件升级缓冲区,需大缓存 #define WIFI_DATA_PROCESS_LMT 300 //单包256byte //#define WIFI_DATA_PROCESS_LMT 600 //单包512byte //#define WIFI_DATA_PROCESS_LMT 1200 //单包1024byte #endif #define WIFIR_UART_SEND_BUF_LMT 128 //根据用户DP数据大小量定,用户可根据实际情况修改

定义模组工作方式(必要)

  1. 如果配网触发及指示由 MCU 控制(配网按键和 LED 接在 MCU 端),选择“模组和 MCU 配合处理”工作模式(常用),请保持 define 在注释状态。

    /******************************************************************************
                            4:定义模块工作方式
    模块自处理:
            wifi指示灯和wifi复位按钮接在wifi模块上(开启WIFI_CONTROL_SELF_MODE宏)
            并正确定义WF_STATE_KEY和WF_RESET_KEY
    MCU自处理:
            wifi指示灯和wifi复位按钮接在MCU上(关闭WIFI_CONTROL_SELF_MODE宏)
            MCU在需要处理复位wifi的地方调用mcu_api.c文件内的mcu_reset_wifi()函数,并可调用mcu_get_reset_wifi_flag()函数返回复位wifi结果
            或调用设置wifi模式mcu_api.c文件内的mcu_set_wifi_mode(WIFI_CONFIG_E mode)函数,并可调用mcu_get_wifi_work_state()函数返回设置wifi结果
    ******************************************************************************/
    //#define         WIFI_CONTROL_SELF_MODE                       //wifi自处理按键及LED指示灯;如为MCU外界按键/LED指示灯请关闭该宏
    
  2. 如果 Wi-Fi 指示灯和按键是接在 Wi-Fi 模组上的(模组自处理工作模式),那么请开启

    #define WIFI_CONTROL_SELF_MODE
  3. 根据实际的硬件连接,将指示灯和按键所连接的 GPIO 脚位填入下面两行。

    //例如:PORT为2,pin为3则代表选择GPIO C_3 #ifdef WIFI_CONTROL_SELF_MODE //模块自处理 #define WF_LED_PORT 0 //wifi状态指示灯的PORT(prot选择范围:0~3[依次代表A到D]),请根据实际GPIO管脚设置 #define WF_LED_PIN 0 //wifi状态指示灯的PIN(prot选择范围:0~7),请根据实际GPIO管脚设置 #define WF_RESERT_KEY_PORT 0 //重置按键的PORT(prot选择范围:0~3[依次代表A到D]),请根据实际GPIO管脚设置 #define WF_RESERT_KEY_PIN 0 //重置按键的PIN(prot选择范围:0~7),请根据实际GPIO管脚设置 #endif

确认 MCU 是否需要支持校时功能

如需要支持校时功能,请开启该宏。并在 Protocol.c 文件内 mcu_write_rtctime 实现代码,MCU 在 Wi-Fi 模组正确联网后可调用 mcu_get_system_time() 函数发起校时功能。

/****************************************************************************** MCU是否需要支持校时功能 如需要请开启该宏,并在Protocol.c文件内mcu_write_rtctime实现代码 mcu_write_rtctime内部有#err提示,完成函数后请删除该#err mcu在wifi模块正确联网后可调用mcu_get_system_time()函数发起校时功能 ******************************************************************************/ //#define SUPPORT_MCU_RTC_CHECK //开启校时功能

确认是否开启 Wi-Fi 产测功能(开启)

为保证最终量产效率及品质,建议开启该宏。具体产测功能实现,见步骤六产测部分。

/****************************************************************************** MCU是否需要支持wifi功能测试 如需要请开启该宏,并且mcu在需要wifi功能测试处调用mcu_api.c文件内mcu_start_wifitest 并在protocol.c文件wifi_test_result函数内查看测试结果, wifi_test_result内部有#err提示,完成函数后请删除该#err ******************************************************************************/ #define WIFI_TEST_ENABLE //开启WIFI产测功能(扫描指定路由)

第三步:移植 protocol.c 文件及函数调用

  1. 在需要使用到 Wi-Fi 相关文件的文件中 include wifi.h 文件,如 main.c

    MCU 的 SDK 移植说明

  2. 在 MCU 外设初始化后调用 mcu_api.c 文件中的 wifi_protocol_init()函数。

    MCU 的 SDK 移植说明

  3. 将 MCU 串口单字节发送函数填入 protocol.c 文件中 uart_transmit_output 函数内,并删除#error。例如:

    /** * @brief 串口发送数据 * @param[in] {value} 串口要发送的1字节数据 * @return Null */ void uart_transmit_output(unsigned char value) { #error "请将MCU串口发送函数填入该函数,并删除该行" UART3_SendByte(value); /* //示例: extern void Uart_PutChar(unsigned char value); Uart_PutChar(value); //串口发送函数 */ }
  4. 在串口接收中断服务函数里面调用 mcu_api.c 文件内的 uart_receive_input 函数,并将接收到的字符作为参数传入。例如:

    MCU 的 SDK 移植说明

  5. 单片机进入 while 循环后调用 mcu_api.c 文件内的 wifi_uart_service()函数。

    main.c 中示例代码结构如下:

    include "wifi.h"
    …
    void main(void)
    {
        wifi_protocol_init();
        …
        while(1)
        {
            wifi_uart_service();
            …
        }
    }
    

    注意:MCU 必须在 while 中直接调用 mcu_api.c 内的 wifi_uart_service()函数程序正常初始化完成后,建议不进行关串口中断,如必须关中断,关中断时间必须短,关中断会引起串口数据包丢失,请勿在中断内调用上报函数。

第四步:DP 上报下发函数完善调用

上报所有 DP 数据

在模组重启或者重新配网后,Wi-Fi 模组主动下发状态查询指令,此时需要 MCU 上报设备所有 DP 状态给 Wi-Fi 模组进行同步。

  1. 打开 protocol.c 找到函数 all_data_update(void)

  2. 把所有需要上报的 DP 初值填入相应上报函数,为面板提供开机显示初值。

    注意:请勿随意调用 all_data_update()函数,该函数会在特定时间主动调用。

上报单个 DP 数据

在某 DP 状态发生变化时,MCU 需要主动上报,App 会更新显示。上报格式为 mcu_dp_xxxx_updata(DPID_X,n,子设备id,子设备id长度),DPID_X 为状态改变的 DP,n表示该 DP 的值,子设备 ID 为字符串,当子设备 ID 为0000时,表示网关本身的 DP。all_data_update()内的函数,均可单独调用。例如:

mcu_dp_bool_update(DPID_SWITCH,1,"0000",strlen("0000")); //BOOL 型数据上报 mcu_dp_value_update(DPID_TEMPER_SET,25,"1234",strlen("1234")); //VALUE 型数据上报 mcu_dp_string_update(DPID_DAY,"1234",4,"5678",strlen("5678")); //STRING 型数据上报

DP数据下发处理函数

protocol.c 文件中,每个可下发的 DP,都有一个单独下发数据处理函数。格式为 dp_download_xxx_handle(),xxx 为可下发 DP。函数解析功能点之后,MCU 需在相应位置完成逻辑控制。以接收到防拆报警 DP 数据为例:

MCU 的 SDK 移植说明

temper_alarm_ctrl(ON)temper_alarm_ctrl(OFF)为 MCU 控制开关函数,完成具体动作。当设备状态在非 App 控制下发生变化,MCU 中需要调用 mcu_dp_bool_update(DPID_TEMPER_ALARM,temper_alarm,sub_id_buf,sub_id_len);上传功能点(开关)状态实时状态,形成反馈,一般接收处理函数已经自动调用该函数。

第五步:配网功能及指示灯函数完善

说明:如果您的模组是自处理工作模式,无需关注此本小节内容。

当移植协议成功后,还需要将配网指令及指示灯功能完善,才能让设备配网。配合处理模式的 MCU,配网触发方式和指示方式,可以根据实际情况自行决定。通常为按键触发和 LED 快闪/慢闪指示。

Wi-Fi 设备配网支持以下两种模式:

  • Wi-Fi 快连配网:操作简便,通常以灯快闪做指示
  • 热点配网:配网可靠,通常以灯慢闪做指示

配网指令

配网指令有两个函数可以实现:mcu_api.c中的 mcu_reset_wifi()mcu_set_wifi_mode()。通常在按键触发配网后,在按键处理函数中调用。

mcu_reset_wifi()调用后重置 Wi-Fi 模组,重置后会将之前的配网信息全部清除,模组进入待配网状态。在模组已经处于待配网状态时,调用mcu_reset_wifi()会切换配网模式,在 AP 和 smart 之间循环切换。

MCU 的 SDK 移植说明

mcu_set_wifi_mode()参数:SMART_CONFIGAP_CONFIG。调用后清除配网信息,明确进入 SMART 模式或者 AP 模式。与 mcu_reset_wifi()作用一样,客户根据自己实际设备方便选择调用。

配网指示

通常在 while(1) 调用 mcu_get_wifi_work_state() 函数返回 Wi-Fi 状态,根据 Wi-Fi 状态,写入相应闪灯的模式。

设备联网状态 描述 状态值 LED 显示
状态 1 smart 配置状态 0x00 快闪 250ms
状态 2 AP 配置状态 0x01 慢闪 1500ms
状态 3 Wi-Fi 已配置但未连上路由器 0x02 熄灭
状态 4 Wi-Fi 已配置且连上路由器 0x03 常亮
状态 5 已连上路由器且连接到云端 0x04 常亮
状态 6 Wi-Fi 设备处于低功耗模式 0x05 熄灭

调用函数 mcu_get_wifi_work_state()获取连接状态,函数架构如下:

void main(void) { ... while(1) { ... switch(mcu_get_wifi_work_state()) { case SMART_CONFIG_STATE: //smart config 配置状态 LED 快闪 ,led闪烁请您自行完成 break; case AP_STATE: //AP配置状态 LED慢闪 break; case WIFI_NOT_CONNECTED: //Wi-Fi 配置完成,正在连接路由器,LED常暗 break; case WIFI_CONNECTED: //路由器连接成功 LED常亮 break; default:break; } ... } }

第六步:产测功能完善

默认为通用 Wi-Fi 功能测试流程-扫描指定路由,您也可以自行制定自己的产测流程。以下流程可重复进行:

  1. 准备一个路由器,或者使用电脑手机等设备创建无线热点。
  2. 将无线名称修改为 tuya_mdev_test,频率设置为 2.4GHz。
  3. 触发设备配网流程。可以由按键触发,如长按某按键 3 秒,也可以用您设定的特定条件触发。
  4. MCU 调用 mcu_api.c 文件中的 mcu_start_wifitest() 函数,让 MCU 向网关设备发送扫描指定路由指令。
  5. 网关扫描名为 tuya_mdev_test 的无线热点,然后将结果返回给MCU。
  6. MCU 解析返回结果,判断产测是否成功。

MCU SDK 与模组数据通信

有关数据帧格式说明,请参考 Wi-Fi 通用方案串口协议 的帧格式章节。

初始化通信

在 MCU 和模组上电后,要进行一些初始化配置,在此期间,需要进行验证 MCU 与模组是否能正常工作,通信连接是否正常,模组激活所需要数据的获取,模组获取工作方式等流程。

查询产品信息

设备上电后,模组需要查询 MCU 固件的版本号、配网方式、设备能力和产品 PID 等信息。

  • 版本号:在 OTA 升级完成后验证是否升级成功。
  • 配网方式:用于选择模组的配网方式,可选择默认配网、低功耗配网、特殊配网。
  • 设备能力:根据网关设备的应用场景选择,可选择本地群组、本地场景、网关有功能 DP、是sigmesh、支持 MCU 升级、群组控制指令带 sub_id 等选项。
  • PID:用于产品激活,可以根据模组发送帧数据的版本字段,来决定 MCU 是否回复 PID。版本为 0x00 表示 不需回复,为 0x01 表示需回复,默认回复 PID。

查询 MCU 和设定模组工作方式

用来设置模组工作方式,选择MCU与模组配合处理方式或者模组自处理方式。可根据 Wi-Fi 网络状态指示灯和模组重置按键的硬件连接位置来选择。

模组工作模式主要针对如何指示 Wi-Fi 的工作状态以及如何重置 Wi-Fi 而言,主要分两种 情况:

  • MCU 与模组配合处理:即模组通过串口通知 MCU Wi-Fi 当前的工作状态,由 MCU 提供显示支持;MCU 检测出 Wi-Fi 的重置需求,通过串口通知模组重置 Wi-Fi。

  • 模组自处理:Wi-Fi 模组的工作状态通过 Wi-Fi 的 GPIO 引脚驱动 LED 状态显示;Wi-Fi 重置通过检测 GPIO 输入需求处理。

    模组自处理 Wi-Fi 重置方法为:Wi-Fi 检测 GPIO 入口低电平持续 5s 以上触发 Wi-Fi 重置。指示灯与按钮所使用的 GPIO 管脚由以下命令配置。

数据交互注意事项

  • 为避免出现不可预测的问题,建议 DP 下发和上报、OTA 升级等正常数据通信要在初始化完成之后进行。

  • 设备重新上电之后,数据交互要等设备整个初始化完成之后进行。

初始化数据交互流程

MCU 的 SDK 移植说明