基于无线传输的多点温度采集系统

1,481 阅读5分钟

Github地址

这是我们大三第一学期的课程设计题目:基于无线传输的多点温度采集系统

摘要

文中设计了一种基于无线传输的多点温度采集系统,通过温度传感器采集温度信号,使用无线传感器通讯,结合单片机来处理并通过上位机进行显示,实现了温度采集、多点测量和上位机实时检测的功能。该检测系统使用简单、方便,对于提高工业自动化水平和环境温度测量具有重大意义。

框架图

这次的课程设计分为三部分:硬件实现,软件实现,文案以及视频制作。我在这次课设中负责的是软件设计。

  • 硬件部分介绍

    1.控制器模块设计

    单片机控制器主要用于温度数据的采集、传输以及接收,将接收到的数据通过上位机软件在上位机上显示。对于控制器的选择采用STC8 9C52,该单片机算术运算功能强,软件编程灵活、自由度大,可用软件编程实现各种算法和逻辑控制。相对于FPGA来说,它的芯片引脚少,在硬件很容易实现。并且它还具有功耗低、体积小、技术成熟和成本低等优点。

    2.温度采集模块设计

    本次设计采用的是Dallas公司生产的单总线数字温度传感器DS18B20,其温度测量范围为-55~+125℃。每个从机设有一个温度传感器,环境温度通过温度传感器DS18B20采集到从机单片机中进行处理。从机单独供电,这样设计稳定性好,抗干扰能力强。

    3.无线收发模块设计

    NRF24L01是一款新型单片射频收发器件,工作于2.4~2.5 GHz ISM频段。内置频率合成器、功率放大器、晶体振荡器、调制器等功能模块,并融合了增强型ShockBurst技术,其中输出功率和通信频道可通过程序进行配置。本设计系统把从温度传感器采集得到的数据经过无线模块NRF24L01传输到主机中。无线传输可以工作在一些高危领域,避免了有限传输的局限性,本设计能进行连续的数据传输,无线模块NRF24L01的传输精度高,性能稳定,成本低。

    4.显示模块设计

    本设计方案采用128x64LCD液晶显示器和上位机共同显示,液晶显示器功率低,驱动方法和硬件连接电路较为简单,显示屏幕大、可对汉字和字符进行显示。

    5.串口通信电路设计

    系统要把测量到的温度送到上位机上显示出来,就需要通过电脑与单片机之间的串口通信,单片机的工作电压是5 V,电脑串口的工作电压是12 V,需要通过电平转换芯片进行正常通信。

  • 文案以及视频部分介绍 课程设计完毕之后,需要撰写报告,以及制做相应的视频。

  • 软件部分介绍

    当上位机收到数据后,需要和电脑进行串口通信,将上位机收到的数据通过串口传给电脑,然后使用编程语言处理数据,最后须将数据以折线图的形式展示出来。

    我这里使用node.js的serialport模块对串口进行数据监听。

    var SerialPort = require("serialport"); 
    var serialPort = new SerialPort("COM3", {
        baudRate: 9600,  //波特率
        autoOpen:false
    }); 
    serialPort.open(function(error){ 
        if(error){ 
            console.log("打开端口COM3错误:"+error);
        }else{  
            console.log("打开端口成功,正在监听数据中");
            serialPort.on('data',function(data){
                sendToClient(data)   //将数据发往客户端,客户端进行数据在折线图上的实时显示。
                insertDataToMysql(data);//将数据插到mysql数据库
            })
        }
    })
    

    使用websocket进行数据的实时通信,客户端收到数据后,使用echarts的setOption,使数据实时显示在图表上。 服务端

    思路:先建立websocket连接,然后进行串口的监听,如果有数据,就利用ws.send(),将数据发往客户端。

    const wss = new WebSocket.Server({ port: 7009 });
    
    wss.on('connection', function connection(ws, req) {
         ws.on('message', function incoming(message) { 
          if(flag) {
          serialPortopen(ws); //设置flag的原因是保证serialPortopen函数只被执行一次。
            flag = false;
          }
        });
    });
    
    function serialPortopen(ws) {
        serialPort.open(function(error){ 
            if(error){ 
                console.log("打开端口COM3错误:"+error);
            }else{  
                console.log("打开端口成功,正在监听数据中");
                serialPort.on('data',function(data){
                    let dataInfo = data.toString().trim();
                    name = dataInfo.charAt('0').trim();
                    let temSign = dataInfo.indexOf('T'); //T出现的下标
                    let cSign = dataInfo.indexOf('C'); //第一个C符号出现的下标
                    let lastColon =  dataInfo.lastIndexOf(":");//最后一个冒号出现的下标
                    tem = dataInfo.substring(temSign+2,cSign+1).trim();
                    hum = dataInfo.substring(lastColon+1).trim();
                    console.log(name, tem, hum);
                    sendToClient(ws)
                    insertDataToMysql(name, tem, hum);
                })
            }
        })
    }
    
    var sendToClient = function(ws) {
      let d = new Date();
      time = d.getFullYear() + "-" +(d.getMonth()+1) + "-" 
                  + d.getDate() + " " + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds(); 
      let obj = {
        name: name,
        tem: tem,
        hum: hum,
        time:time
      }
    
      ws.send(JSON.stringify(obj));
    }
    

客户端

```
        connectionServer: function() {
        var _this = this;
        var ws = new WebSocket("ws://localhost:7009");
        ws.onopen = function (e) {
            ws.send("hello")
        }
        ws.onmessage = function(event) {                
            let data = JSON.parse(event.data);
            let name = data.name;
            _this[name+"temYList"].push(parseInt(data.tem));
            _this[name+"humYList"].push(parseInt(data.hum));
            _this[name+"timeList"].push(data.time);
            _this.showChart(name); //将数据显示在图表上。
        }; 
    },
```

折线图的设计:使用echarts

这里我由于先入为主的思想,在这里踩了一天的坑,我一直认为数据实时显示,只需要给原来的数据追加一条数据就可以了。但其实不是,当数据发生变化时,必须重新setOption()。