本文分享自华为云社区《基于 CC2530_ZigBee + 华为云 IOT 设计的冷链信息采集系统【玩转华为云】》,作者: DS 小龙哥 。

  1、前言
近年来,随着人们消费需求的不断提高,连锁超市、便利店、大卖场等商超不但提供了各种各样的新鲜食品,而且采用统一进货和冷链储藏的方式,从而不但使得商品质量有保证,而且购物环境良好,越来越成为人们购物的主要场所。超市作为冷链物流产品的末端,在分销以及零售过程中都对产品质量、运营成本和功耗等方面有着较高的要求,而冷链系统的压力参数作为保证这一品质的重要参数之一,实现智能压力检测和控制对于时刻掌握冷链的工作状态非常重要,可以保证运营的安全性和经济性。因此,如果能够设计一款针对冷链系统数据采集系统,就可以实现对冷链系统进行实时监控,达到经济性运营的目的,对提高企业经济效益具有非常重要的意义。

  2、设计需求

以 CC2530 单片机为核心器件,设计一个冷链环境信息采集系统,利用传感器技术对冷藏仓内的环境参数进行采集,上传到物联网云平台,然后通过手机端或移动端进行显示,便于分析,观察冷链环境信息。

  硬件选型:
(1)ESP8266-WIFI 用于与上位机进行通信,实现数据传输
(2)CC2530 单片机,本身是 51 内核,与普通的 51 单片机编程一样,它内部多了一个 ZigBee 模块,能实现 ZigBee 组网。
(3)DHT11 温湿度传感器。这是一款有已校准数字信号输出的温湿度传感器。 其精度湿度 ±5% RH, 温度 ±2℃,量程湿度 5~95% RH, 温度 - 20~+60℃。
(4)蜂鸣器。当设置阀值超出标准时,可以发出警报提醒。
v2-6d93726a9593616fa3e663321dfabb73_720w.jpg

  3、硬件选型
  3.1 CC2530+WIFI 模块
v2-fce9f41f5ec88953819af549bb5f6897_720w.jpg

  3.2 DHT11 温湿度模块
v2-2abc9d3b1b09e98ea97a6a3760f18b06_720w.jpg

  3.3 蜂鸣器
v2-458bc3a527fb587582a5f48d36407aac_720w.jpg

  4、物联网云端配置与应用
  4.1 华为云 IoTDA 介绍
当前的设计中,用的物联网平台服务是华为云的设备接入服务(IoTDA),IoTDA 提供海量设备连接上云、设备和云端双向消息通信、批量设备管理、远程控制和监控、OTA 升级、设备联动规则等能力,并可将设备数据灵活流转到华为云其他服务。
使用物联网平台构建一个完整的物联网解决方案主要包括 3 部分:物联网平台、业务应用和设备。
物联网平台作为连接业务应用和设备的中间层,屏蔽了各种复杂的设备接口,实现设备的快速接入;同时提供强大的开放能力,支撑行业用户构建各种物联网解决方案。
设备可以通过固网、2G/3G/4G/5G、NB-IoT、Wifi 等多种网络接入物联网平台,并使用 LWM2M/CoAP、MQTT、HTTPS 协议将业务数据上报到平台,平台也可以将控制命令下发给设备。
业务应用通过调用物联网平台提供的 API,实现设备数据采集、命令下发、设备管理等业务场景。
v2-4d8ad9363982547be3abb1f845f868f3_720w.jpg
接下来就详细把整个物联网平台的使用流程进行介绍。

  4.2 产品创建
v2-53f8e02ec3a2c4dddee4e3919226dff1_720w.jpg
v2-b34b02231efe58ccdb6fab6fd74c34a2_720w.jpg
查看平台接入地址:
v2-18e0c19af18b0225bac74d2b18682df6_720w.jpg
v2-ea18ae4f89f37a854c16d5120f657339_720w.jpg
点击右上角创建产品:
v2-663e4b478a01a444787a15c295513136_720w.jpg
根据自己的产品信息填充:
v2-731fa8636f205303eb5c42d4cb5d7176_720w.jpg
v2-051ea3b5514db3c6a26806b2030d8958_720w.jpg
根据产品的传感器属性创建服务器的属性字段:
v2-613f9cd3b35ec90fb1c4baf91969c408_720w.jpg
v2-cac313c18df100f111c8a83d2af4c405_720w.jpg
v2-f93e896743dfc50e52d5ccc39b0b3370_720w.jpg
v2-2701fdc8319986782b5924f5b2d122bf_720w.jpg
v2-5eb1083792ff50dd4a22b6803b8ef1a3_720w.jpg

  4.3 设备创建
详细创建流程,看下面的截图:
v2-ec77a5c1f217cea00611ce56a5adadb8_720w.jpg
v2-3fba37274f1068bbee5b8b0770e9701e_720w.jpg
v2-9172fa30592cc2129c1f8a7c272e3cdc_720w.jpg
保存设备信息,接下来的 MQTT 登录需要使用。
  
{
  • "device_id": "62e732be3a884835598654f7_dev1",
  • "secret": "12345678"
  • }
  • 复制代码

      4.4 MQTT 三元组信息生成
    在这里可以使用华为云提供的工具快速得到 MQTT 三元组进行登录。
    https://support.huaweicloud.com/devg-iothub/iot_01_2127.html#ZH-CN_TOPIC_0240834853__zh-cn_topic_0251997880_li365284516112
    v2-9e6e7b6c75a7a3f5f0ad31da541f5cbd_720w.jpg
    工具的页面地址:
    https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/
    根据提示填入信息,然后生成三元组信息即可。 这里填入的信息就是在创建设备的时候生成的信息。
    v2-d3399d7c51254044aa1b5e42f17efc26_720w.jpg
      
    ClientId 62e732be3a884835598654f7_dev1_0_0_2022080102
  • Username  62e732be3a884835598654f7_dev1
  • Password  13483ebeadd786ea107527a3c92c5463a8f3c71377cd33276143ffe2fb85c1dc
  • 复制代码


      4.5 MQTT 主题订阅与发布格式
      
    //订阅主题: 平台下发消息给设备
  • $oc/devices/62e732be3a884835598654f7_dev1/sys/messages/down
  • //设备上报数据
  • $oc/devices/62e732be3a884835598654f7_dev1/sys/properties/report
  • //上报的属性消息 (一次可以上报多个属性,在json里增加就行了)
  • {"services": [{"service_id": "server_id","properties":{"温度":23.4}},{"service_id": "server_id","properties":{"湿度":80.5}}]}
  • 复制代码

      4.6 设备模拟登录测试
    v2-2e6be98881e4dc53b990d37f68d89178_720w.jpg
    v2-7b0f23f8ad5f61f9057b5dc01640eec5_720w.jpg

      4.7 应用侧开发接口介绍
    在设备上云之后,为了能方便管理设备,方便用户设备入网,都需要开发一款手机 APP 或者微信小程序、桌面软件等,进行数据交互,设备管理。
    华为云 IOT 提供了应用侧开发的 API 对接接口,这里就介绍一下使用应用侧开发的流程。这个 API 接口里常用的接口包括:产品创建、设备创建、设备属性获取、设备删除、查询设备等管理接口,可以通过 API 主动获取产品下面某个设备的属性,要求设备上报最新的数据过来。整个开发过程,都是基于 HTTP 协议的 API 接口进行交互,不依赖开发环境,不依赖开发语言。 不管是桌面软件,还是手机 APP、微信小程序、web 网页等,核心代码基本都是一样,都是 HTTP 协议交互。下面的例子里,我是采用 C++ 编写的,采用 QT 框架库完成整个开发,了解了整个思路,你就可以采用自己熟悉的语言完成相同的功能。
    官方帮助文档: https://support.huaweicloud.com/usermanual-iothub/iot_01_0045.html
    v2-1d4d203f5b1ae1bae3c9371913e94b44_720w.jpg

      5、CC2530 程序设计
      5.1 IAR 环境搭建
    完整的安装整个配套环境,需要安装以下的软件,具体的版本型号也介绍了,直接百度搜索就能找到;最简单的办法是,淘宝搜索一下 CC2530 的开发板,店铺里一般都有配套的资料包下载,里面基本都包含了下面这些软件,直接白嫖就行:
    安装集成开发环境: IAR-EW8051-8.10.1。
    安装仿真器 “SmartRF4EB” 的驱动程序。
    安装代码烧写工具: Setup_SmartRF_Programmer_1.10.2。
    安装 TI 的 Zigbee 协议栈: ZStack-CC2530-2.5.1a。
    安装过程截图请看另外的文档。
    v2-9e87f408d307b4fdb9efbebf9739ef88_720w.jpg

      5.2 硬件原理图
    v2-9aef9a88e06b12891ca25d8266da6eea_720w.jpg

      5.3 IAR 程序工程图
    v2-a130edf61b0661b1404166fb6b2b4923_720w.jpg

      5.4 DHT11.c 代码
      
    #include "uart.h"
  • /*
  • 函数功能:串口0初始化
  • */
  • void Init_Uart0(void)
  • {
  • PERCFG&=~(1<<0); //串口0的引脚映射到位置1,即P0_2和P0_3
  • P0SEL|=0x3<<2; //将P0_2和P0_3端口设置成外设功能
  • U0BAUD = 216; //32MHz的系统时钟产生115200BPS的波特率
  • U0GCR&=~(0x1F<<0);//清空波特率指数
  • U0GCR|=11<<0; //32MHz的系统时钟产生115200BPS的波特率
  • U0UCR |= 0x80; //禁止流控,8位数据,清除缓冲器
  • U0CSR |= 0x3<<6; //选择UART模式,使能接收器
  • }
  • /*
  • 函数功能:UART0发送字符串函数
  • */
  • void UR0SendString(u8 *str)
  • {
  • while(*str!='\0')
  • {
  • U0DBUF = *str; //将要发送的1字节数据写入U0DBUF
  • while(UTX0IF == 0);//等待数据发送完成
  • UTX0IF = 0; //清除发送完成标志,准备下一次发送
  •     str++;
  • }
  • }
  • /*
  • 函数功能: 模仿printf风格的格式化打印功能
  • */
  • char USART0_PRINT_BUFF[200]; //格式化数据缓存数据
  • void USART0_Printf(const char *format,...)
  • {
  •   char *str=NULL;
  • /*1. 格式化转换*/
  • va_list ap; // va_list---->char *
  • va_start(ap,format); //初始化参数列表
  • vsprintf(USART0_PRINT_BUFF,
  •         format,
  •         ap); //格式化打印
  • va_end(ap); //结束参数获取
  • /*2. 串口打印*/
  •   str=USART0_PRINT_BUFF;//指针赋值
  • while(*str!='\0')
  • {
  • U0DBUF=*str; //发送一个字节的数据
  •     str++; //指针自增,指向下一个数据
  • while(UTX0IF == 0);//等待数据发送完成
  • UTX0IF = 0; //清除发送完成标志,准备下一次发送
  • }
  • }
  • 复制代码

      5.5 ESP8266.c 代码
      
    #include "esp8266.h"
  • uint lenU1 = 0;
  • uchar tempRXU1;
  • uchar  RecdataU1[MAXCHAR];
  • //"AT+CIPSEND=0,10\r\n"   //长度10
  • //返回">" 之后就可以正常发送数据了
  • //发送成功返回 "SEND OK"
  • //发送数据
  • void ESP8266_SendData(char *p,int len)
  • {
  •    int i=0;
  •    char buff[50];
  • sprintf(buff,"AT+CIPSEND=0,%d\r\n",len);
  • clearBuffU1();
  • Uart1_Send_String(buff); //发送指令
  • DelayMs(1000); //等待
  • for(i=0;i<len;i++)
  • {
  • Uart1_Send_Char(p[i]);
  • }
  • //等待发送完成
  • DelayMs(1000);
  •    RecdataU1[lenU1]='\0';
  • UR0SendString(RecdataU1);
  • clearBuffU1();
  • }
  • /****************************************************************************
  • * 名 称: SetWifi()
  • * 功 能: 设置LED灯相应的IO口
  • * 入口参数: 无
  • * 出口参数: 无
  • ****************************************************************************/
  • void SetWifi(void)
  • {
  • P0DIR |= 0x40; //P0.6定义为输出
  • IGT = 0; //高电平复位
  • DelayMs(500);
  • IGT = 1; //低电平工作
  • }
  • /*
  • 设置WIFI为AP模式+TCP服务器
  • */
  • void SetESP8266_AP_TCP_Server()
  • {
  • clearBuffU1();
  • Uart1_Send_String("AT\r\n");
  • DelayMs(2000);
  •    RecdataU1[lenU1]='\0';
  • UR0SendString(RecdataU1);
  • clearBuffU1();
  • Uart1_Send_String("ATE0\r\n");
  • DelayMs(2000);
  •    RecdataU1[lenU1]='\0';
  • UR0SendString(RecdataU1);
  • clearBuffU1();
  • Uart1_Send_String("AT+CWMODE=2\r\n");
  • DelayMs(2000);
  •    RecdataU1[lenU1]='\0';
  • UR0SendString(RecdataU1);
  • clearBuffU1();
  • Uart1_Send_String("AT+RST\r\n");
  • DelayMs(2000);
  • DelayMs(2000);
  • DelayMs(2000);
  •    RecdataU1[lenU1]='\0';
  • UR0SendString(RecdataU1);
  • clearBuffU1();
  • Uart1_Send_String("ATE0\r\n");
  • DelayMs(2000);
  •    RecdataU1[lenU1]='\0';
  • UR0SendString(RecdataU1);
  • clearBuffU1();
  • Uart1_Send_String("AT+CWSAP="wifi_cc2530","12345678",1,4\r\n");
  • DelayMs(2000);
  • DelayMs(2000);
  • DelayMs(2000);
  • DelayMs(2000);
  •    RecdataU1[lenU1]='\0';
  • UR0SendString(RecdataU1);
  • clearBuffU1();
  • Uart1_Send_String("AT+CIPMUX=1\r\n");
  • DelayMs(2000);
  • DelayMs(2000);
  •    RecdataU1[lenU1]='\0';
  • UR0SendString(RecdataU1);
  • clearBuffU1();
  • Uart1_Send_String("AT+CIPSERVER=1,8089\r\n");
  • DelayMs(2000);
  • DelayMs(2000);
  •    RecdataU1[lenU1]='\0';
  • UR0SendString(RecdataU1);
  • clearBuffU1();
  • Uart1_Send_String("AT+CIFSR\r\n");
  • DelayMs(2000);
  • DelayMs(2000);
  •    RecdataU1[lenU1]='\0';
  • UR0SendString(RecdataU1);
  • }
  • unsigned char dataRecv;
  • unsigned char Flag = 0;
  • /*===================UR1初始化函数====================*/
  • void Init_Uart1()
  • {
  • PERCFG = 0x00;//位置1  P0.4/P0.5口
  • P0SEL |= 0x30;//P0.4,P0.5用作串口(外部设备功能)
  • U1CSR |= 0x80;//设置为UART方式
  • U1GCR |= 11;//BAUD_E        
  • U1BAUD |= 216;//BAUD_M 波特率设为115200
  • UTX1IF = 0; //UART1 TX中断标志初始置位0
  • U1CSR |= 0X40; //允许接收
  • IEN0 |= 0x88; // 开总中断,UART1接收中断
  • }
  • void clearBuffU1(void)
  • {
  •   int j;
  • for(j=0;j<MAXCHAR;j++)
  • {
  •     RecdataU1[j]=0x00;
  • }
  •   lenU1=0;
  • }
  • /*******************************************************************************
  • 串口1发送一个字节函数
  • *******************************************************************************/
  • void Uart1_Send_Char(char Data)
  • {
  • U1CSR &= ~0x40; //禁止接收
  • U1DBUF = Data;
  • while(UTX1IF == 0);
  • UTX1IF = 0;
  • U1CSR |= 0x40; //允许接收
  • }
  • /*******************************************************************************
  • 串口1发送字符串函数
  • *******************************************************************************/
  • void Uart1_Send_String(char *Data)
  • {
  • while(*Data!='\0')
  • {
  • Uart1_Send_Char(*Data);
  •         Data++;
  • }
  • }
  • /****************************************************************
  • 串口接收一个字符: 一旦有数据从串口传至CC2530, 则进入中断,将接收到的数据赋值给变量temp.
  • ****************************************************************/
  • #pragma vector = URX1_VECTOR
  • __interrupt void UART1_ISR(void)
  • {
  • if(lenU1<81)
  • {
  •     tempRXU1 = U1DBUF;
  •     RecdataU1[lenU1]=tempRXU1;
  • URX1IF = 0; // 清中断标志
  •     lenU1++;
  • }
  • }
  • 复制代码


      6、总结
    随着业务的发展,越来越多的企业选择结合物联网技术来实现自身效益增长。相比企业自建 MQTT 集群,使用华为云 IoT 服务低成本构建物联网解决方案,在能力、成本、运维、安全、生态等诸多方面具有突出优势。 广泛支持 IoT 主流的接入协议及私有协议,满足各类设备和接入场景要求;与主流模组、芯片预集成,实现多网络、多协议接入,简化设备接入难度,实现小时级设备极简接入。