:::warning 基于涂鸦NB-IoT模组的植物监测仪 :::

一、我们要做什么?

本项目作为我们在智慧农业中的第一个探索性项目,项目的出发点很简单,即监测环境并且采集数据,这两者是农业数字化的起点。通过监测农业环境的状态,我们能够了解植物的生长状态,以及对异常情况作出及时的处理等;通过持续的数据采集和大量的数据分析,我们能够优化种植的策略,从而提高农产品的质量和产量。
基于这个目的,我们将会采集农业环境中的环境温湿度、光照度、土壤湿度、土壤酸碱度和土壤氮磷钾含量这几个最重要的参数,并且发送到云端服务器,云端服务器一方面记录这些数据以供后续的数据分析;另一方面发送到手机App,当这些参数出现异常状况时,手机App给用户推送提醒。

二、系统演示与架构设计

1.总体设计

本技术方案的架构设计如下图所示。
image.png

本技术方案主要由边缘计算终端、IoT云平台以、手机App和Web管理后台这几部分组成。

2..边缘计算终端

(1)边缘计算终端内置STM32嵌入式微处理器,具备一定的边缘计算能力,边缘计算终端的原型开发板如图所示。
为了方便前期快速开发和适应需求变化,本系统选用了现成的原型开发板进行开发,其中内置了诸如转串口芯片、拨码开关和排针等辅助器件,后期在成品产品电路中去除这些辅助器件即可,软件代码无需修改
基于涂鸦NB-IoT模组的植物监测仪 - 图2
基于涂鸦NB-IoT模组的植物监测仪 - 图3
(2)边缘计算终端搭载环境温湿度传感器、光照强度传感器(光敏电阻模块)、土壤湿度传感器、土壤PH值传感器和土壤氮磷钾传感器,能够全方位感知植物的生长环境状态。这些传感器支持可插拔,即可以随意安装自己所需的传感器,而不会影响系统正常工作。
(3)在产品规划阶段中,我们设计了两种供电方式组合,即A.内置锂电池+USB线二合一供电;B.内置锂电池+太阳能供电,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图4
然而,我们采取的策略是在确定硬件器件选型后,软件开发先行,然后硬件设计、外观设计跟上。基于现有的原型开发板以及确定相关元器件的成本后,这种策略是可行的。因此,在基于原型开发板阶段,暂时只需要支持Micro USB线缆+外置电池供电即可,在后续可在硬件层面支持上述的A版本或B版本的供电方式。
(4)边缘计算终端支持监测电池电量状态。
(5)边缘计算终端内置涂鸦智能NB-IoT模组,支持把各个传感器信息、电池电量信息以及主板本身的状态信息通过NB-IoT网络上传到涂鸦智能IoT云平台

4.手机App

(1)手机App支持查看由边缘计算终端发送过来的实时数据,以环境温湿度数据为例,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图5
实时环境温湿度
(2)移动端App支持针对环境温湿度、环境光照强度、土壤湿度、土壤PH值、土壤碳磷钾含量设置上限和下限阈值,当实际值高于上限阈值或低于下限阈值的时候,能够发出警报信息。以温度的设置为例,如下演示视频所示。
设备间智能联合控制

5.云平台

(1)IoT平台支持接收来自边缘计算终端的数据并且保存下来,支持在手机App查看这些数据,支持在基于涂鸦智能的Web管理后台中各种数据行进管理。
基于涂鸦NB-IoT模组的植物监测仪 - 图6
历史温湿度数据查看
基于涂鸦NB-IoT模组的植物监测仪 - 图7
涂鸦智能Web管理后台

三、终端的主要硬件组成

  • 主芯片:STM32F030F4P6
  • NB-IoT模组:涂鸦智能 NE1 https://developer.tuya.com/cn/docs/iot/ne1-module-datasheet?id=K9t001ddkmio2
  • NB-IoT移动网络卡:中国移动NB-IoT卡
  • 网络天线:善学坊NB-IoT超级天线 CrossAir L01
  • 环境温湿度传感器:http://aosong.com/products-104.html
  • 光敏电阻模块:https://zhuanlan.zhihu.com/p/483620112
  • 土壤湿度传感器:https://zhuanlan.zhihu.com/p/483599993
  • 土壤PH值传感器:https://www.kancloud.cn/aiot/solution/2628607
  • 土壤碳磷钾传感器:https://www.kancloud.cn/aiot/solution/2677011

    四.主要技术参数

    1.主控芯片技术参数

    STM32F030采用ARM Cortex内核,运算速度高达48 MHz。另外,STM32F030具有全套外设,例如高速12位ADC、先进且灵活的定时器、日历RTC和通信接口。该组合轻松超越了现有的8位架构,让所有应用设计者均能得益于先进32位内核的简单性和高效率。STM32F030超值系列提供多种存储容量和引脚数组合,能与之匹敌的器件少之又少,从而进一步优化项目成本。

    2.NB-IoT模组技术参数

    NE1 是由涂鸦智能开发的一款低功耗嵌入式 NB-IoT 系列 LPWA 模组。支持 NB-IoT 无线电通信协议(3GPP Rel.14)。它由一个高集成度的 Soc EC616(内置了应用处理器、低功耗多波段窄带物联网收发器和电源管理单元PMU)和少量外围器件构成。NE1 内嵌低功耗 32 位Cortex-M3 CPU,支持 MPU,集成 272KB 晶圆内SRAM,4MB NOR Flash,还支持包括 UART、I2C、SPI、PWM、4 通道 12-bit AUXADC、32KHz RTC timer和 USIM 等接口。
    特点

  • 内置低功耗32位 Cortex-M3 处理器

  • 供电
    • 工作电压范围:2.2~4.5V
    • 典型工作电压:3.3V
  • 外设:17×GPIOs,3×UARTs, 6×PWMs,1×ADC,1×SPI,1×I2C
  • SIM: 3V/1.8V SIM card
  • NB-IoT 网络
    • Cat NB1/Cat NB2
    • 3GPP R14 NB-IoT 标准
    • B3/B5/B8
    • 最大发射功率 23dBm±2dB
    • 接收灵敏度 <-127.3dBm/15kHz(非重传)
    • 50Ω 特征阻抗,天线需第三方提供
    • 数据速率:
      • R13:
        • Single-tone:25.5kbps(下行),16.7kbps(上行)
        • Multi-tone:25.5kbps(下行),62.5kbps(上行)
      • R14:
        • Multi-tone:102kbps(下行),157kbps(上行)
    • 网络协议特性:UDP/TCP/CoAP/LWM2M/ PPP/SSL/DTLS/FTP/ HTTP/MQTT/HTTPS*
    • 正常工作温度:-35°C ~ +75°C
    • 扩展工作温度:-40°C ~ +85°C
    • 存储温度:-40°C ~+90°C
  • 升级通过主串口,FOTA

3.中国移动NB-IoT卡类型
类型为cmnbiot,这是中国移动推出的支持终端控制PSM和eDRX的NB-IoT卡类型,详细介绍可参考https://ec.iot.10086.cn/onelink/pages/nbiot.html

3.NB-IoT超级天线 CrossAir L01

CrossAir L01是一款SMT自动焊接的微型天线,详细参数如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图8

五、系统选型优势

1.NB-IoT模组对比

本方案中默认选取了涂鸦智能NE1模组,我们拿国内的另外的NB-IoT模组来对比一下。
价格对比
对于大多数的企业来说,元器件的价格是一个重要的参考因素,涂鸦智能NE1模组的价格仅为14元(含3元的云平台使用授权费),如图所示。(价格查询时间为2022年3月15日)
基于涂鸦NB-IoT模组的植物监测仪 - 图9
涂鸦智能NE1模组价格
而国内的其他模组零售价如图所示。据我们过往采购的经验来看,采购量在1000片以内时,价格比零售价便宜约1~3元,可见涂鸦智能的NE1几乎是全网最便宜的!(价格查询时间为2022年3月15日,查询链接:点击自动跳转淘宝搜索
基于涂鸦NB-IoT模组的植物监测仪 - 图10
基于涂鸦NB-IoT模组的植物监测仪 - 图11
资源对比
涂鸦智能NE1模组的资源上文已经罗列过,此处我们给出在淘宝销量第1的模组的资源说明,如图所示。(图片来自其官网)
基于涂鸦NB-IoT模组的植物监测仪 - 图12
可见双方的资源和技术参数有一定差异,但是均能满足本技术方案的需求。
稳定性对比
稳定性是很重要的参考指标,但作为模块的用户,我们非常难去测试,因此大部分的情况下,我们只能从模块厂商的知名度、模块本身的出货量等方面去简介评估模块的稳定性。
从厂商的知名度来看,据涂鸦智能官网介绍,它是“全球IoT云平台上市第1股”(参考链接:https://www.tuya.com/cn/?_source=d441cd2712521cfcb4c151e9e58d4c8b),知名度可见一斑。

2.IoT云平台对比

涂鸦智能NE1模组能够直连涂鸦智能云平台,而其他模组一般需要对接第三方云平台。我们把涂鸦智能云平台与第3方云平台做一个简单的对比,见表。

项目 涂鸦智能云平台 主流第3方云平台
资费 无(使用模组即可连接云平台) 按通信数据量、连接时长或设备数量收费
通信模组提供方 自营 第3方
终端设备开发 0代码,支持自定义开发 支持二次开发
手机App端开发 0代码,支持二次开发 支持二次开发
微信小程序端开发 提供SDK供二次开发 支持二次开发
云平台端开发 0代码,支持云云对接 支持二次开发

总的来说,如果涂鸦智能的标准设备模型如果满足功能需要,那么从终端设备、手机App、云平台端的开发量将会非常少,非常适用于希望减少开发工作量和加快产品上市时间的团队。

六、云平台与手机App的实现

登录涂鸦智能官网https://www.tuya.com/,然后点击“登录IoT平台”,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图13
输入账号密码,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图14
选择产品,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图15
点击创建产品,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图16
依次选择传感、植物监测仪,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图17
选择产品开发,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图18
选择自定义方案,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图19
输入名称,并且选择NB-IoT、DRX,然后点击创建产品,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图20
选择红框中的功能点,然后点击确定,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图21
点击下一步设备交互,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图22
选择默认的Studio面板,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图23
点击下一步硬件开发,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图24
选择NE1模组,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图25
点击下一步产品配置,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图26
点击下一步测试服务,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图27
至此,云平台和App端的配置已经初步完成,读者可以初步测试一下App端的效果。点击设备交互,并且使用”智能生活“App扫描页面中的二维码,即可体验,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图28

七、设备终端的实现

7.1 涂鸦智能MCU SDK下载

点击硬件开发,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图29
下翻到页面底部,然后下载功能点调试文件、快速入门指南、MCU SDK等资料,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图30
解压其中的MCU SDK文件,得到如下内容。
基于涂鸦NB-IoT模组的植物监测仪 - 图31
把这个SDK添加进自有的工程中,这里以STM32F030F4P6 + Keil MDK工程为例,如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图32

7.2 终端代码架构设计

7.2.1 MVC 架构简介
经典的MVC是一种常用的代码架构设计思想,其中M表示Model(模型),V表示View(视图),C表示控制器(Controller),相关含义如下:

  • Model(模型):封装了数据和对数据的操作,是实际进行数据处理的地方
  • View(视图):负责程序和用户之间的交互,例如负责把数据在在屏幕上显示出来
  • Controller(控制器):用于操作模型和视图

7.2.2 SDK 设计模式
SDK可以分解成3个层次,自定向下分别是:
基于涂鸦NB-IoT模组的植物监测仪 - 图33

  • HAL: HAL(Hardware Abstraction Layer,硬件抽象层),前面课程已经一步一步地带读者实现了部分HAL API。
  • Service:服务组件,对HAL进行服务化抽象和管理。HAL的重点是操作和管理某一个硬件,例如串口和显示器等。然而,Service的重点是为上层提供服务,例如Log组件为上层提供日志打印服务,这个组件既能通过串口写入日志数据,又能通过显示器上显示日志;又例如Sender组件为上层提供NB-IoT数据发送服务,上层无需理会使用哪个型号的NB-IoT模组去发送的,因此这个组件会自行去处理这些细节。
  • Task:是指某种更贴合用户需求的任务,例如定时地获取传感器的数值,并上报给指定的服务器。

7.2.3 终端代码详解
代码下载链接:https://pan.baidu.com/s/1uw5YxxaHSd8IqVTRMqTvkw 密码:d8io
完整的结构如图所示。
基于涂鸦NB-IoT模组的植物监测仪 - 图34
其中较为重要的的分别是HalPort、Users和Tuya。HalPort负责硬件驱动与抽象,Users负责处理终端的业务逻辑,而Tuya中存放的是Tuya MCU SDK。
其中的Tuya MCU SDK,我们主要需要修改的是protocol.c文件,修改后的代码如下:

  1. /****************************************Copyright (c)*************************
  2. ** 版权所有 (C), 2015-2020, 涂鸦科技
  3. **
  4. ** http://www.tuya.com
  5. **
  6. **--------------文件信息-------------------------------------------------------
  7. **文 件 名: protocol.c
  8. **描 述: 下发/上报数据处理函数
  9. **使 用 说 明 :
  10. *******非常重要,一定要看哦!!!********
  11. ** 1、用户在此文件中实现数据下发/上报功能
  12. ** 2、DP的ID/TYPE及数据处理函数都需要用户按照实际定义实现
  13. ** 3、当开始某些宏定义后需要用户实现代码的函数内部有#err提示,完成函数后请删除该#err
  14. **-----------------------------------------------------------------------------
  15. ******************************************************************************/
  16. #include "nbiot.h"
  17. /******************************************************************************
  18. 移植须知:
  19. 1:MCU必须在while中直接调用mcu_api.c内的nbiot_uart_service()函数
  20. 2:程序正常初始化完成后,建议不进行关串口中断,如必须关中断,关中断时间必须短,关中断会引起串口数据包丢失
  21. 3:请勿在中断/定时器中断内调用上报函数
  22. ******************************************************************************/
  23. /******************************************************************************
  24. 第一步:初始化
  25. 1:在需要使用到nbiot相关文件的文件中include "nbiot.h"
  26. 2:在MCU初始化中调用mcu_api.c文件中的nbiot_protocol_init()函数
  27. 3:将MCU串口单字节发送函数填入protocol.c文件中uart_transmit_output函数内,并删除#error
  28. 4:在MCU串口接收函数中调用mcu_api.c文件内的uart_receive_input函数,并将接收到的字节作为参数传入
  29. 5:单片机进入while循环后调用mcu_api.c文件内的nbiot_uart_service()函数
  30. ******************************************************************************/
  31. /******************************************************************************
  32. 1:dp数据点序列类型对照表
  33. **此为自动生成代码,如在开发平台有相关修改请重新下载MCU_SDK**
  34. ******************************************************************************/
  35. const DOWNLOAD_CMD_S download_cmd[] =
  36. {
  37. {DPID_SOIL_HUMIDITY, DP_TYPE_VALUE},
  38. {DPID_SOIL_PH, DP_TYPE_VALUE},
  39. {DPID_AIR_HUMIDITY, DP_TYPE_VALUE},
  40. {DPID_AIR_TEMP, DP_TYPE_VALUE},
  41. {DPID_RAIN_INTENSITY, DP_TYPE_VALUE},
  42. {DPID_SUN_INTENSITY, DP_TYPE_VALUE},
  43. {DPID_LIQUID_TEMP, DP_TYPE_VALUE},
  44. {DPID_LIQUID_TURBIDITY, DP_TYPE_VALUE},
  45. };
  46. /******************************************************************************
  47. 2:串口单字节发送函数
  48. 请将MCU串口发送函数填入该函数内,并将接收到的数据作为参数传入串口发送函数
  49. ******************************************************************************/
  50. /*****************************************************************************
  51. 函数名称 : uart_transmit_output
  52. 功能描述 : 发数据处理
  53. 输入参数 : value:串口收到字节数据
  54. 返回参数 : 无
  55. 使用说明 : 请将MCU串口发送函数填入该函数内,并将接收到的数据作为参数传入串口发送函数
  56. *****************************************************************************/
  57. void uart_transmit_output(unsigned char value)
  58. {
  59. halUartWrite(&value, 1);
  60. // #error "请将MCU串口发送函数填入该函数,并删除该行"
  61. /*
  62. //示例:
  63. extern void Uart_PutChar(unsigned char value);
  64. Uart_PutChar(value); //串口发送函数
  65. */
  66. }
  67. /******************************************************************************
  68. 第二步:实现具体用户函数
  69. 1:APP下发数据处理
  70. 2:数据上报处理
  71. ******************************************************************************/
  72. /******************************************************************************
  73. 1:所有数据上报处理
  74. 当前函数处理全部数据上报(包括可下发/可上报和只上报)
  75. 需要用户按照实际情况实现:
  76. 1:需要实现可下发/可上报数据点上报
  77. 2:需要实现只上报数据点上报
  78. 此函数为MCU内部必须调用
  79. 用户也可调用此函数实现全部数据上报
  80. ******************************************************************************/
  81. //自动化生成数据上报函数
  82. /*****************************************************************************
  83. 函数名称 : all_data_update
  84. 功能描述 : 系统所有dp点信息上传,实现APP和muc数据同步
  85. 输入参数 : 无
  86. 返回参数 : 无
  87. 使用说明 : 此函数SDK内部需调用;
  88. MCU必须实现该函数内数据上报功能;包括只上报和可上报可下发型数据
  89. *****************************************************************************/
  90. void all_data_update(void)
  91. {
  92. // #error "请在此处理可下发可上报数据及只上报数据示例,处理完成后删除该行"
  93. if(DHT20_Alive())// 如果DHT20传感器存在,则读取温湿度数据
  94. {
  95. DHT20_ReadHT();//读取AHT20的 20Bit原始数据
  96. StandardUnitCon();//实际标准单位转换
  97. mcu_dp_value_update(DPID_AIR_HUMIDITY,(unsigned long)DHT20_Humi()); //VALUE型数据上报;
  98. mcu_dp_value_update(DPID_AIR_TEMP,(unsigned long)DHT20_Temp()); //VALUE型数据上报;
  99. }
  100. //此代码为平台自动生成,请按照实际数据修改每个可下发可上报函数和只上报函数
  101. mcu_dp_value_update(DPID_SOIL_HUMIDITY,get_Soil()); //VALUE型数据上报;
  102. mcu_dp_value_update(DPID_SOIL_PH,get_PH());
  103. mcu_dp_value_update(DPID_RAIN_INTENSITY,get_Rain());
  104. mcu_dp_value_update(DPID_SUN_INTENSITY,get_Sun()); //VALUE型数据上报;
  105. mcu_dp_value_update(DPID_LIQUID_TURBIDITY,get_Turbidity()); //VALUE型数据上报;
  106. mcu_dp_value_update(DPID_LIQUID_TEMP,halDS18B20GetTemp()); //VALUE型数据上报;
  107. }
  108. /*****************************************************************************
  109. 函数名称 : dp_record_combine_update
  110. 功能描述 : 记录型数据组合上报
  111. 输入参数 : time : 时间数据长度7,首字节表示是否传输标志位,其余依次为年、月、日、时、分、秒
  112. dp_bool : bool型dpid号, v_bool:对应值
  113. dp_enum : enum型dpid号, v_enum:对应值
  114. dp_value : value型dpid号, v_value:对应值
  115. dp_string: string型dpid号, v_string:对应值,len:string长度
  116. 返回参数 : 无
  117. *****************************************************************************/
  118. unsigned char dp_record_combine_update(unsigned char time[],
  119. unsigned char dp_bool,unsigned char v_bool,
  120. unsigned char dp_enum,unsigned char v_enum,
  121. unsigned char dp_value,unsigned char v_value,
  122. unsigned char dp_string,unsigned char v_string[],unsigned char len)
  123. {
  124. unsigned short length = 0;
  125. if(stop_update_flag == ENABLE)
  126. return SUCCESS;
  127. //local_time
  128. length = set_nbiot_uart_buffer(length,(unsigned char *)time,7);
  129. //bool
  130. length = set_nbiot_uart_byte(length,dp_bool);
  131. length = set_nbiot_uart_byte(length,DP_TYPE_BOOL);
  132. length = set_nbiot_uart_byte(length,0);
  133. length = set_nbiot_uart_byte(length,1);
  134. if(v_bool == FALSE)
  135. {
  136. length = set_nbiot_uart_byte(length,FALSE);
  137. }
  138. else
  139. {
  140. length = set_nbiot_uart_byte(length,1);
  141. }
  142. //enum
  143. length = set_nbiot_uart_byte(length,dp_enum);
  144. length = set_nbiot_uart_byte(length,DP_TYPE_ENUM);
  145. length = set_nbiot_uart_byte(length,0);
  146. length = set_nbiot_uart_byte(length,1);
  147. length = set_nbiot_uart_byte(length,v_enum);
  148. //value
  149. length = set_nbiot_uart_byte(length,dp_value);
  150. length = set_nbiot_uart_byte(length,DP_TYPE_VALUE);
  151. length = set_nbiot_uart_byte(length,0);
  152. length = set_nbiot_uart_byte(length,4);
  153. length = set_nbiot_uart_byte(length,v_value >> 24);
  154. length = set_nbiot_uart_byte(length,v_value >> 16);
  155. length = set_nbiot_uart_byte(length,v_value >> 8);
  156. length = set_nbiot_uart_byte(length,v_value & 0xff);
  157. //string
  158. length = set_nbiot_uart_byte(length,dp_string);
  159. length = set_nbiot_uart_byte(length,DP_TYPE_STRING);
  160. length = set_nbiot_uart_byte(length,len / 0x100);
  161. length = set_nbiot_uart_byte(length,len % 0x100);
  162. length = set_nbiot_uart_buffer(length,(unsigned char *)v_string,len);
  163. nbiot_uart_write_frame(STATE_RC_UPLOAD_CMD,length);
  164. return SUCCESS;
  165. }
  166. /******************************************************************************
  167. WARNING!!!
  168. 2:所有数据上报处理
  169. 自动化代码模板函数,具体请用户自行实现数据处理
  170. ******************************************************************************/
  171. /******************************************************************************
  172. WARNING!!!
  173. 此代码为SDK内部调用,请按照实际dp数据实现函数内部数据
  174. ******************************************************************************/
  175. #ifdef SUPPORT_MCU_RTC_CHECK
  176. /*****************************************************************************
  177. 函数名称 : mcu_write_rtctime
  178. 功能描述 : MCU校对本地RTC时钟
  179. 输入参数 : 无
  180. 返回参数 : 无
  181. 使用说明 : MCU需要自行实现该功能
  182. *****************************************************************************/
  183. void mcu_write_rtctime(unsigned char time[])
  184. {
  185. #error "请自行完成RTC时钟写入代码,并删除该行"
  186. /*
  187. time[0]为是否获取时间成功标志,为 0 表示失败,为 1表示成功
  188. time[1] 为 年 份 , 0x00 表 示2000 年
  189. time[2]为月份,从 1 开始到12 结束
  190. time[3]为日期,从 1 开始到31 结束
  191. time[4]为时钟,从 0 开始到23 结束
  192. time[5]为分钟,从 0 开始到59 结束
  193. time[6]为秒钟,从 0 开始到59 结束
  194. time[7]为星期,从 1 开始到 7 结束,1代表星期一
  195. */
  196. if(time[0] == 1)
  197. {
  198. //正确接收到模块返回的本地时钟数据
  199. }
  200. else
  201. {
  202. //获取本地时钟数据出错,有可能是当前模块未联网
  203. }
  204. }
  205. #endif
  206. /*****************************************************************************
  207. 函数名称 : nbiot_update_handle
  208. 功能描述 : MCU请求mcu固件升级返回函数
  209. 输入参数 : status:校验标志
  210. 返回参数 : 无
  211. 使用说明 : MCU主动调用 nbiot_update_request 函数完成后该函数内可获取升级当前状态
  212. *****************************************************************************/
  213. void nbiot_update_handle(unsigned char status)
  214. {
  215. // #error "请自行完成模块升级状态返回代码,并删除该行"
  216. switch (status)
  217. {
  218. case 0:
  219. {
  220. //开始检查固件更新
  221. break;
  222. }
  223. case 1:
  224. {
  225. //已经是最新固件
  226. break;
  227. }
  228. case 2:
  229. {
  230. //正在更新固件
  231. break;
  232. }
  233. case 3:
  234. {
  235. //固件更新成功
  236. break;
  237. }
  238. case 4:
  239. {
  240. //固件更新失败
  241. break;
  242. }
  243. default:
  244. break;
  245. }
  246. }
  247. #ifdef SUPPORT_MCU_FIRM_UPDATE
  248. /*****************************************************************************
  249. 函数名称 : mcu_firm_update_handle
  250. 功能描述 : MCU进入固件升级模式
  251. 输入参数 : value:固件缓冲区
  252. position:当前数据包在于固件位置
  253. length:当前固件包长度(固件包长度为0时,表示固件包发送完成)
  254. 返回参数 : 无
  255. 使用说明 : MCU需要自行实现该功能
  256. *****************************************************************************/
  257. unsigned char mcu_firm_update_handle(const unsigned char value[],unsigned long position,unsigned short length)
  258. {
  259. // #error "请自行完成MCU固件升级代码,完成后请删除该行"
  260. if(length == 0)
  261. {
  262. //固件数据发送完成
  263. //#error "请完成crc32校验,结果返回0或者1,完成后请删除该行"
  264. //mcu_firm_update_data_ack(1, 0); //请根据crc32校验情况,去回复crc成功或者失败
  265. }
  266. else
  267. {
  268. //mcu_firm_update_data_ack(0, 0);
  269. //固件数据处理
  270. }
  271. return SUCCESS;
  272. }
  273. /*****************************************************************************
  274. 函数名称 : mcu_file_update_handle
  275. 功能描述 : MCU文件下载数据处理
  276. 输入参数 : value:固件缓冲区
  277. position:当前数据包在于固件位置
  278. length:当前固件包长度(固件包长度为0时,表示固件包发送完成)
  279. 返回参数 : 无
  280. 使用说明 : MCU需要自行实现该功能
  281. *****************************************************************************/
  282. unsigned char mcu_file_update_handle(const unsigned char value[],unsigned long position,unsigned short length)
  283. {
  284. //#error "请自行完成MCU文件下载数据处理,完成后请删除该行"
  285. if(length == 0)
  286. {
  287. //文件数据接收完成
  288. // #error "请完成crc32校验,crc32_result结果返回0或者1,完成后请删除该行"
  289. //mcu_file_data_ack(1, 0); //请根据crc32校验情况,去回复crc成功或者失败
  290. }
  291. else
  292. {
  293. //mcu_file_data_ack(0, 0);
  294. //固件数据处理
  295. }
  296. return SUCCESS;
  297. }
  298. #endif
  299. #ifdef SUPPORT_NBIOT_DONGLE_SERVICE
  300. /*****************************************************************************
  301. 函数名称 : get_nb_active_info_response
  302. 功能描述 : 复合产品下 NB返回的激活所需的设备信息
  303. 输入参数 : NB返回的激活信息
  304. 返回参数 : 无
  305. 使用说明 : MCU需要自行实现该功能
  306. *****************************************************************************/
  307. void get_nb_active_info_response(unsigned char nb_active_info[], unsigned short active_info_len)
  308. {
  309. //nb_active_info[0]为是否获取激活信息成功标志,为 0 表示失败,为 1表示成功
  310. //nb_active_info[1] - nb_active_info[active_info_len-1] 为数据内容
  311. //{"pv":"2.0","bv":"3.0","sv":"1.0.0","i":"860102040125729","opt":0,"h":28800}
  312. if(nb_active_info[0] == 1)
  313. {
  314. //返回激活信息成功 后续可进行NB的激活 并调用mcu_set_nb_active_response 回复给NB
  315. }
  316. else
  317. {
  318. //返回激活信息成失败
  319. }
  320. }
  321. /*****************************************************************************
  322. 函数名称 : get_mcu_active_response
  323. 功能描述 : 复合产品下 NB返回的 为MCU激活的结果
  324. 输入参数 : NB返回的激活信息
  325. 返回参数 : 无
  326. 使用说明 : MCU需要自行实现该功能
  327. *****************************************************************************/
  328. void get_mcu_active_response(unsigned char mcu_active_ack[], unsigned short active_ack_len)
  329. {
  330. //mcu_active_info[0]为是否获取激活信息成功标志,为 0 表示失败,为 1表示成功
  331. //mcu_active_info[1] - mcu_active_info[active_info_len-1] 为数据内容
  332. //例如:{"localkey":"12345678"}
  333. if(mcu_active_ack[0] == 1)
  334. {
  335. //获取MCU激活信息成功
  336. }
  337. else
  338. {
  339. //获取MCU激活信息失败
  340. }
  341. }
  342. #endif
  343. /******************************************************************************
  344. WARNING!!!
  345. 以下函数用户请勿修改!!
  346. ******************************************************************************/
  347. /*****************************************************************************
  348. 函数名称 : dp_download_handle
  349. 功能描述 : dp下发处理函数
  350. 输入参数 : dpid:DP序号
  351. value:dp数据缓冲区地址
  352. length:dp数据长度
  353. 返回参数 : 成功返回:SUCCESS/失败返回:ERRO
  354. 使用说明 : 该函数用户不能修改
  355. *****************************************************************************/
  356. unsigned char dp_download_handle(unsigned char dpid,const unsigned char value[], unsigned short length)
  357. {
  358. /*********************************
  359. 当前函数处理可下发/可上报数据调用
  360. 具体函数内需要实现下发数据处理
  361. 完成用需要将处理结果反馈至APP端,否则APP会认为下发失败
  362. ***********************************/
  363. unsigned char ret;
  364. switch(dpid)
  365. {
  366. default:
  367. break;
  368. }
  369. return ret;
  370. }
  371. /*****************************************************************************
  372. 函数名称 : get_download_cmd_total
  373. 功能描述 : 获取所有dp命令总和
  374. 输入参数 : 无
  375. 返回参数 : 下发命令总和
  376. 使用说明 : 该函数用户不能修改
  377. *****************************************************************************/
  378. unsigned char get_download_cmd_total(void)
  379. {
  380. return(sizeof(download_cmd) / sizeof(download_cmd[0]));
  381. }

编译整份源代码并烧录到模块中,即可运行并观察结果。

补充一句

如果你也想尝试使用涂鸦云平台开发物联网项目,可联系他们的工作人员进行咨询,工作人员个人号:qtbb121