Zigbee无线传感网 CC2530+DHT11&DS18B20 温湿度采集 串口上位机显示

Posted Link2Points

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Zigbee无线传感网 CC2530+DHT11&DS18B20 温湿度采集 串口上位机显示相关的知识,希望对你有一定的参考价值。


一、介绍

  1. 硬件:4块CC2530模块,2个DS18B20温度传感器、1个DHT11传感器、一个抽水器(可无)。
  2. 软件:基于C#开发上位机(.NET Framework 4.8)、ZStack-2.5.1a协议栈。
  3. 由协调器及各节点组建星型网,采用点播通讯(P2P),结合上位机的限制最多可以接入6个终端节点。
  4. 硬件效果图图1

二、上位机数据采集

(一)采集数据

打开串口,显示情况和波动。
在这里插入图片描述

(二)拓扑结构

显示节点的数据和其短地址。
在这里插入图片描述

(三)新节点加入网络

在这里插入图片描述

(四)节点事件

节点4湿度高于 70%,进行提示,拓扑图隐藏该节点,与此同时抽水器停止工作。
在这里插入图片描述
在这里插入图片描述

三、实现分析

(一)配置文件

  1. 在f8wConfig.cfg中
    设置信道 : -DDEFAULT_CHANLIST=
    (似乎11信道容易受WIFI信号影响)
    设置PAN_ID: -DZDAPP_CONFIG_PAN_ID=
  2. 在SampleApp.h
    数据发送间隔 3 s
    #define SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT 3000

(二)发送

  1. 在 SampleApp.c 中
  //无线发送到协调器
  if ( AF_DataRequest( &SampleApp_P2P_DstAddr, &SampleApp_epDesc,
                       SAMPLEAPP_P2P_CLUSTERID,
                       len,  // 数据长度
                       str,	 // 数据内容
                       &SampleApp_MsgID,
                       AF_DISCV_ROUTE,
                       AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
  {
  }
}

(三)短地址和数据获取

短地址 pkt->srcAddr.addr.shortAddr 是网络随机分配的,
MAC地址 pkt->macDestAddr 更适合作为数据存储的主键,
数据 uint8 temperature=pkt->cmd.Data[0]; uint8 humidity=pkt->cmd.Data[1];

  1. 在AF.h中
typedef struct
{
  union
  {
    uint16      shortAddr; // (短地址)
    ZLongAddr_t extAddr;
  } addr;
  afAddrMode_t addrMode;
  uint8 endPoint;
  uint16 panId;  // used for the INTER_PAN feature
} afAddrType_t;


typedef struct
{
  osal_event_hdr_t hdr;     /* OSAL Message header */
  uint16 groupId;           /* Message's group ID - 0 if not set */
  uint16 clusterId;         /* Message's cluster ID (簇ID) */
  afAddrType_t srcAddr;     /* Source Address, if endpoint is STUBAPS_INTER_PAN_EP,
                               it's an InterPAN message */
  uint16 macDestAddr;       /* MAC header destination short address (MAC地址) */
  uint8 endPoint;           /* destination endpoint */
  uint8 wasBroadcast;       /* TRUE if network destination was a broadcast address */
  uint8 LinkQuality;        /* The link quality of the received data frame (网络连接质量) */
  uint8 correlation;        /* The raw correlation value of the received data frame */
  int8  rssi;               /* The received RF power in units dBm (信号能量) */
  uint8 SecurityUse;        /* deprecated */
  uint32 timestamp;         /* receipt timestamp from MAC */
  uint8 nwkSeqNum;          /* network header frame sequence number */
  afMSGCommandFormat_t cmd; /* Application Data */
} afIncomingMSGPacket_t;
  1. 在 SampleApp.h 中
void SampleApp_ProcessMSGCmd( afIncomingMSGPacket_t *pkt )
{
  uint8 buff[50]={0};

  switch ( pkt->clusterId )
  {
  // 接收终端上传的温湿度数据
  case SAMPLEAPP_P2P_CLUSTERID: 
    {
      // 取出温湿度数据
      uint8 temperature = pkt->cmd.Data[0];
      uint8 humidity= pkt->cmd.Data[0];
      // 取出短地址
      uint16 shortAddress = pkt->srcAddr.addr.shortAddr;
      // 处理和数据打包上传串口略····
    }
    break;
  // 接收温度    
  case SAMPLEAPP_DS18B20_CLUSTER:
  	{
  	  // 略····
  	}
  	break;
  default:
  	break;

(四)数据包分析

串口数据打包格式:
在这里插入图片描述

长度:14;
校验位:C4;
功能码:02;
数据:3B 31 3B 54 3A 32 37 2E 30 20 43 3B 34 34 34 31 3B
结尾:0D 0A 。

补充

  1. 数据部分的3B作为数据内容分隔符(;):(功能码)+(;)+(采集数据)+(;)+(短地址)+(;)。
  2. 并以换行符为结尾 \\r\\n 比较省事
    在这里插入图片描述

(五)上位机

        // 是否打开串口
        bool isOpenSP;
        // 记录数
        private int recordNum = 0;
        // 记录各个节点的检测结果 用于 拓扑图
        private string[] pointsTopology = {"", "", "", "", "", ""};
        // 绘图
        private Graphics graphics;
        
        private void mainForm_Load(object sender, EventArgs e)
        {
            Resize += mainForm_Resize;

            refreshBtn_Click(null, null);
            // 波特率
            int[] BR =
            {
                4_800, 9_600, 14_400, 19_200, 38_400, 56_000, 57_600, 115_200, 128_000,
                256_000, 460_800, 512_000, 750_000, 921_600, 1_500_000
            };
            foreach (int val in BR)
            {
                BRComboBox.Items.Add(val);
            }
            
            // 手动添加事件处理程序
            serialPort1.DataReceived += serialPort1_DataReceived;
            // 绘图初始化
            graphics = topologyPanel.CreateGraphics();
        }
  1. 串口部分
    通过Rider开发的上位机,似乎在VS中串口部分会出问题(这时就需要利用委托delege)
        /*
         * 3. 功能实现
         *  打开串口按键按键 openBtn_Click 
         *  串口数据接收 serialPort1_DataReceived 
         *  接收数据清空 clearBtn_Click 
         *  刷新串口号按键 refreshBtn_Click 
         */

        private void openBtn_Click(object sender, EventArgs e)
        {
            if (SPComboBox.Text.Equals("") || BRComboBox.Text.Equals(""))
            {
                return;
            }
            
            if (!isOpenSP)
            {
                try
                {
                    serialPort1.PortName = SPComboBox.SelectedItem.ToString();
                    serialPort1.BaudRate = Convert.ToInt32(BRComboBox.SelectedItem.ToString());
                    serialPort1.Open();
                }
                catch
                {
                    MessageBox.Show("端口错误,请检查串口" , "错误");
                    return;
                }
            }
            else
            {
                serialPort1.Close();
            }

            openBtn.Text = isOpenSP ? "打开" : "关闭";
            SPComboBox.Enabled = !SPComboBox.Enabled;
            BRComboBox.Enabled = !BRComboBox.Enabled;
            isOpenSP = !isOpenSP;
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (isOpenSP)
            {
                try
                {
                    // 读取串口数据
                    string revStr = serialPort1.ReadLine();
                    revRichTextBox.AppendText(revStr);
                    revRichTextBox.SelectionStart = revRichTextBox.Text.Length;
                    // 显示
                    string[] pointsData = revStr.Split('\\n'); 


                    Label[] pointsLabel = {point1Label, point2Label, point3Label, point4Label, point5Label, point6Label}; 
                    // 节点名称
                    Label[] pointsName = {pointName1Label, pointName2Label, pointName3Label, pointName4Label, pointName5Label, pointName6Label};
                    foreach (string pointData in pointsData)
                    {
                        int preSplit = pointData.IndexOf(";") + 1;
                        int nextSplit = pointData.IndexOf(";", preSplit);
                            // 获取采集节点 显示 id - 1
                        int index = Convert.ToInt32(pointData.Substring(preSplit,nextSplit - preSplit)) - 1;
                        preSplit = nextSplit + 1;
                        nextSplit = pointData.IndexOf(";", preSplit);
                        // 串口格式解析显示
                        pointsLabel[index].Text = pointData.Substring(preSplit, nextSplit - preSplit);
                        // 温度
                        string temp = pointData.Substring(preSplit + 2, pointData.IndexOf(" C") - preSplit - 2);
                        



						chart1.Series[index].Points.AddXY(recordNum, temp);
                        // 该曲线的节点名称
                        chart1.Series[index].Name = pointsName[index].Text + "温度";
                        // 湿度
                        string humidity = "50";
                        if (index % 2 != 0)
                        {
                            humidity = pointData.Substring(pointData.IndexOf("H:") + 2,
                                nextSplit - pointData.IndexOf("H:") - 2);
                            chart1.Series[pointsLabel.Length + index].Points.AddXY(recordNum, humidity);
                            // 该曲线的节点名称
                            chart1.Series[pointsLabel.Length + index].Name = pointsName[index].Text + "湿度";
                        }
                        // 给予处理 温度低于5度 湿度大于70% 则颜色提示
                        if (Convert.ToDouble(temp) < 5 || Convert.ToDouble(humidity) > 70)
                        {
                            pointsLabel[index].BackColor = Color.FromArgb(74, 140, 218);
                            pointsTopology[index] = "";
                        }
                        else
                        {
                            pointsLabel[index].BackColor = Color.White;
                            // 记录可处理的值 用于拓扑图
                            pointsTopology[index] = pointData.Substring(pointData.IndexOf(";") + 1);
                        }
                        pointsName[index].BackColor = pointsLabel[index].BackColor;
                    }
               
               
                    recordNum++;
                    chart1.ChartAreas[0].AxisX.Title = "时间";
                    chart1.ChartAreas[0].AxisY.Title = "数据";
                }
                catch (Exception exception)
                {
                    MessageBox.Show(exception.ToString());
                }
            }
        }
        
        private void clearBtn_Click(object sender, EventArgs e)
        {
            revRichTextBox.Text = "";

            point1Label.Text = "0";
            point2Label.Text = "0";
            point3Label.Text = "0";
            point4Label.Text = "0";
            point5Label.Text = "0";
            point6Label.Text = "0";
        }
        
        private void refreshBtn_Click(object sender, EventArgs e)
        {
            SPComboBox.Items.Clear();
            // 获取端口号
            string[] PortNames = SerialPort.GetPortNames();
            for (int i = 0; i < PortNames.Length; i++)
            {
                //将数组内容加载到comboBox控件中
                SPComboBox.Items.Add(PortNames[i]);
            }
        }
  1. 数据拓扑部分
        /*
         * 2 功能选项
         *  功能列表缩放 funBtn_Click
         *  按键初始化 funBtnsInit 
         *  数据采集界面按键 dataBtn_Click 
         *  拓扑图界面按键 topologyBtn_Click 
         */
        private void funBtn_Click(object sender, EventArgs e)
        {
            funPanel.Width = funPanel.Width == 40 ? 250 : 40;
            titLabel.Width = funPanel.Width;
        }

        private void funBtnsInit()
        {
            dataBtn.BackColor = funPanel.BackColor;
            topologyBtn.BackColor = funPanel.BackColor;

            dataPanel.Visible = false;
            topologyPanel.Visible = false;
        }


        private void dataBtn_Click(object sender, EventArgs e)
        {
            funBtnsInit();
            dataBtn.BackColor = clickedBgColor;
            dataPanel.Visible = true;
        }

        private void topologyBtn_Click(object sender, EventArgs e)
        {
            funBtnsInit();
            topologyBtn.BackColor = clickedBgColor;
            topologyPanel.Visible = true;
            
            // 绘制静态拓扑图
            graphics.Clear(topologyPanel.BackColor);
            graphics.FillRectangle(new SolidBrush(Color.Crimson),300, 300, 50, 50);
            Pen pen = new Pen(Color.Coral);
            Brush brush = new SolidBrush(Color.Coral);
            Point[] startPoint =
            {
                new Point(300, 300), new Point(325, 300), new Point(350, 300),
                new Point(350, 350), new Point(325, 350), new Point(300, 350)
            };
            Point[] endPoint =
            {
                new Point(100, 100), new Point(325, 200), new Point(450, 400),
                new Point(450, 450), new Point(325, 450), new Point(250, 200)
            };
            int index = 0;
            foreach (string pointTopology in pointsTopology)
            {
                if (pointTopology.Equals(""))
                {
                    continue;
                }
                
                graphics.DrawLine(pen,startPoint[index], endPoint[index]);
                
                graphics.FillEllipse(brush, endPoint[index].X, endPoint[index].Y, 20, 20);
                graphics.DrawString(pointTopology, 
                    new Font("微软雅黑", 10), 
                    new SolidBrush(Color.Black),
                    endPoint[index].X + 5, endPoint[index].Y + 5);
                index++;
            }
            
            pointsTopology = new []{"", "", "", "", "", ""};
        }

四、IAR

  1. iar软件和协议栈之间似乎有对应的联系,Z-stack 2.5.1的协议栈在 高版本 IAR 下编译出问题参考
  2. IAR 设置 外部编辑器
    Tools > Options
    在这里插入图片描述
    Editor > External Editor > 勾选 Use External Editor > 选择外部编辑器程序地址 > 填写 Arguments栏内容为 “$FILE_PATH$” > 点击确认
    在这里插入图片描述
    点击文件,即可通过其它编辑器编辑,然而也会有中文乱码的问题。

以上是关于Zigbee无线传感网 CC2530+DHT11&DS18B20 温湿度采集 串口上位机显示的主要内容,如果未能解决你的问题,请参考以下文章

( zigbee)CC2530+BH1750光敏传感器获取光照强度

ZigBee无线传感器网络入门

ZigBee无线传感器的网络协议栈

二IAR新建一个工程

基于CC2530的ZigBee转以太网网关的设计与实现

zigbee是啥