用C#实现通过串口对设备的数据采集--Server层

今天中午没睡午觉,头昏眼花的,实在写不了代码,把这几天写的Server层数据采集的程序整理了一下。

WatrLevelDataCollectServer.cs

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.IO.Ports;
  6 using SMOS.Model.Device;
  7 using System.Text.RegularExpressions;
  8 
  9 namespace SMOS.Server.Impl.Collection
 10 {
 11     public class WaterLevelDataCollectServer : DataCollectServer
 12     {
 13         private SerialPort comm = new SerialPort();
 14         private bool Closing = false;//是否正在关闭串口,执行Application.DoEvents,并阻止再次invoke
 15         private bool Listening = false;//是否没有执行完invoke相关操作
 16         private List<byte> buffer = new List<byte>(4096);//默认分配1页内存,并始终限制不允许超过   
 17         private byte[] binary_data = new byte[6];//FF FF 01 03 1B 1D  
 18         private decimal dataValue = 0;
 19         private bool dataCatched;
 20         private bool workManner = true;//工作方式,true--使用设备默认的自动报告方式,false--使用查询方式
 21         /// <summary>
 22         /// 采集水位计数据(默认方式,自动报告方式)
 23         /// </summary>
 24         /// <param name="waterLevelSetInfo"></param>
 25         /// <returns></returns>
 26         public override Model.Device.DeviceRecordInfo GetData(Model.Device.DeviceSetInfo deviceSet)
 27         {
 28             WaterLevelSetInfo entity = deviceSet as WaterLevelSetInfo;
 29             //根据当前串口对象,来判断操作   
 30             if (comm.IsOpen)
 31             {
 32                 comm.Close();
 33             }
 34             try
 35             {
 36                 comm.PortName = entity.Port;
 37                 comm.BaudRate = entity.BaudRate;
 38                 comm.Open();
 39             }
 40             catch (Exception ex)
 41             {
 42                 throw ex;
 43             }
 44             if(workManner == false )//采集水位计数据(查询方式,需要对设备进行手动设置)
 45             {
 46                 //发送采集指令 ,16进制发送   
 47                 byte extensionNo = 0x01;//分机编号默认为"01"
 48                 byte checkData = 0x6B;//在分机编号默认时,校验位为“6B”
 49                 checkData =(byte)(0xFC + 0x6E + (int)extensionNo);
 50                 MatchCollection mc = Regex.Matches("FC 6E "+"0"+extensionNo+"00 00 "+ checkData.ToString("X"), @"(?i)[\da-f]{2}");
 51                 List<byte> buf = new List<byte>();//填充到临时列表中   
 52                 //依次添加到列表中   
 53                 foreach (Match  m in mc)
 54                 {
 55                    buf.Add(byte.Parse(m.Value, System.Globalization.NumberStyles.HexNumber));
 56                 }
 57                 //转换列表为数组后发送   
 58                 comm.Write(buf.ToArray(), 0, buf.Count);
 59             }
 60             WaterLevelRecordInfo waterLevelRecordInfo = new WaterLevelRecordInfo();
 61             //添加事件注册   
 62               comm.DataReceived += comm_DataReceived;
 63             DateTime dtOld = DateTime.Now;
 64             while (true)
 65             {
 66                 if (DateTime.Compare(dtOld.AddSeconds(Convert.ToDouble(entity.AcquisitionInterval)), DateTime.Now) > 0)
 67                 {
 68                     System.Threading.Thread.Sleep(200);
 69                     if (dataCatched)
 70                     {
 71                         waterLevelRecordInfo.MeasuredLevel = dataValue;
 72                         waterLevelRecordInfo.RecordTime = DateTime.Now;
 73                         waterLevelRecordInfo.DeviceID = entity.DeviceID;
 74                         //end operation
 75 
 76                         //解绑事件   
 77                         comm.DataReceived -= comm_DataReceived;
 78                         comm.Close();
 79                         return waterLevelRecordInfo as DeviceRecordInfo;
 80                     }
 81                 }
 82                 else
 83                 {
 84                     comm.DataReceived -= comm_DataReceived;
 85                     comm.Close();
 86                     return null;
 87                 }
 88             }   
 89         } 
 90         /// <summary>
 91         /// 串口数据接收
 92         /// </summary>
 93         /// <param name="sender"></param>
 94         /// <param name="e"></param>
 95         private void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
 96         {
 97             if (Closing) return;//如果正在关闭,忽略操作,直接返回,尽快的完成串口监听线程的一次循环   
 98             try
 99             {
100                 Listening = true;//设置标记
101                 int n  = comm.BytesToRead;//记录缓存  
102                 byte[] buf = new byte[n];//声明一个临时数组存储串口数据   
103                 comm.Read(buf, 0, n);//读取缓冲数据   
104                 dataCatched = false;//缓存记录数据是否捕获到   
105                 //缓存数据   
106                 buffer.AddRange(buf);
107                 //完整性判断   
108                 while (buffer.Count >= 6)//至少要包含头(2字节)+分机编号(1字节)+测量数据(2字节)+校验(1字节)   
109                 {
110                     //查找数据头   
111                     if (buffer[0] == 0xFF && buffer[1] == 0xFF)
112                     {
113                         int len = 6;//数据长度   
114                         //数据完整判断第一步,长度是否足够      
115                         if (buffer.Count < len) break;
116                         buffer.CopyTo(0, binary_data, 0, len);//复制一条完整数据到数据缓存 
117                         //分析数据   
118                         dataValue = (decimal)((binary_data[3] * 255 + binary_data[4]) / 1000.000);
119                         dataCatched = true;  
120                         buffer.RemoveRange(0, len);//正确分析一条数据,从缓存中移除数据  
121                     }
122                     else
123                     {
124                         //如果数据开始不是头,则删除数据                        
125                         buffer.RemoveAt(0);
126                     }
127                 }
128             }
129             catch (Exception ex)
130             {
131                 dataCatched = false;
132             }
133             finally
134             {
135                 Listening = false;//可以关闭串口  
136             }
137         }
138     }
139 }

 

在WaterLevelDataCollectServer这个类里主要通过GetData这个方法来实现的水位计数据的采集,使用SerialPort控件,当串口接收导数据的时候自动触发comm_DataReceived事件,但是由于这个事件被触发的时刻不确定,所以在GetData方法中使用循环等待,当接收到数据时跳出循环,并将采集结果返回。

  在没有实际设备的时候可以用串口调试助手并通过虚拟串口给程序发送数据,注意COM口,波特率等通信参数的设置应该一一对应。

posted on 2013-10-31 17:04  图灵之梦  阅读(1600)  评论(0编辑  收藏  举报