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

WatrLevelDataCollectServer.cs

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using SMOS.Model.Device;
using System.Text.RegularExpressions; namespace SMOS.Server.Impl.Collection
{
public class WaterLevelDataCollectServer : DataCollectServer
{
private SerialPort comm = new SerialPort();
private bool Closing = false;//是否正在关闭串口,执行Application.DoEvents,并阻止再次invoke
private bool Listening = false;//是否没有执行完invoke相关操作
private List<byte> buffer = new List<byte>();//默认分配1页内存,并始终限制不允许超过
private byte[] binary_data = new byte[];//FF FF 01 03 1B 1D
private decimal dataValue = ;
private bool dataCatched;
private bool workManner = true;//工作方式,true--使用设备默认的自动报告方式,false--使用查询方式
/// <summary>
/// 采集水位计数据(默认方式,自动报告方式)
/// </summary>
/// <param name="waterLevelSetInfo"></param>
/// <returns></returns>
public override Model.Device.DeviceRecordInfo GetData(Model.Device.DeviceSetInfo deviceSet)
{
WaterLevelSetInfo entity = deviceSet as WaterLevelSetInfo;
//根据当前串口对象,来判断操作
if (comm.IsOpen)
{
comm.Close();
}
try
{
comm.PortName = entity.Port;
comm.BaudRate = entity.BaudRate;
comm.Open();
}
catch (Exception ex)
{
throw ex;
}
if(workManner == false )//采集水位计数据(查询方式,需要对设备进行手动设置)
{
//发送采集指令 ,16进制发送
byte extensionNo = 0x01;//分机编号默认为"01"
byte checkData = 0x6B;//在分机编号默认时,校验位为“6B”
checkData =(byte)(0xFC + 0x6E + (int)extensionNo);
MatchCollection mc = Regex.Matches("FC 6E "+""+extensionNo+"00 00 "+ checkData.ToString("X"), @"(?i)[\da-f]{2}");
List<byte> buf = new List<byte>();//填充到临时列表中
//依次添加到列表中
foreach (Match m in mc)
{
buf.Add(byte.Parse(m.Value, System.Globalization.NumberStyles.HexNumber));
}
//转换列表为数组后发送
comm.Write(buf.ToArray(), , buf.Count);
}
WaterLevelRecordInfo waterLevelRecordInfo = new WaterLevelRecordInfo();
//添加事件注册
comm.DataReceived += comm_DataReceived;
DateTime dtOld = DateTime.Now;
while (true)
{
if (DateTime.Compare(dtOld.AddSeconds(Convert.ToDouble(entity.AcquisitionInterval)), DateTime.Now) > )
{
System.Threading.Thread.Sleep();
if (dataCatched)
{
waterLevelRecordInfo.MeasuredLevel = dataValue;
waterLevelRecordInfo.RecordTime = DateTime.Now;
waterLevelRecordInfo.DeviceID = entity.DeviceID;
//end operation //解绑事件
comm.DataReceived -= comm_DataReceived;
comm.Close();
return waterLevelRecordInfo as DeviceRecordInfo;
}
}
else
{
comm.DataReceived -= comm_DataReceived;
comm.Close();
return null;
}
}
}
/// <summary>
/// 串口数据接收
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (Closing) return;//如果正在关闭,忽略操作,直接返回,尽快的完成串口监听线程的一次循环
try
{
Listening = true;//设置标记
int n = comm.BytesToRead;//记录缓存
byte[] buf = new byte[n];//声明一个临时数组存储串口数据
comm.Read(buf, , n);//读取缓冲数据
dataCatched = false;//缓存记录数据是否捕获到
//缓存数据
buffer.AddRange(buf);
//完整性判断
while (buffer.Count >= )//至少要包含头(2字节)+分机编号(1字节)+测量数据(2字节)+校验(1字节)
{
//查找数据头
if (buffer[] == 0xFF && buffer[] == 0xFF)
{
int len = ;//数据长度
//数据完整判断第一步,长度是否足够
if (buffer.Count < len) break;
buffer.CopyTo(, binary_data, , len);//复制一条完整数据到数据缓存
//分析数据
dataValue = (decimal)((binary_data[] * + binary_data[]) / 1000.000);
dataCatched = true;
buffer.RemoveRange(, len);//正确分析一条数据,从缓存中移除数据
}
else
{
//如果数据开始不是头,则删除数据
buffer.RemoveAt();
}
}
}
catch (Exception ex)
{
dataCatched = false;
}
finally
{
Listening = false;//可以关闭串口
}
}
}
}

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

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

最新文章

  1. Win10 UI入门 圆形控件
  2. 使用 Redis 实现分布式锁
  3. 【XLL 框架库函数】 TempActiveRow/TempActiveRow12
  4. RSA加密前端JS加密,后端asp.net解密,报异常
  5. 如何在.net4.0中使用.net4.5的async/await
  6. sprytabbedpanels.js库之在页面中插入Tabbed Panels
  7. 02day1
  8. UITableView滑动按钮的操作
  9. 【LeetCode】Sum Root to Leaf Numbers
  10. 怎么在Ubuntu Scope中获取location地址信息
  11. MySql学习笔记(一) —— 关键字的使用
  12. php 数组变成树状型结构
  13. android 向webview传值
  14. Angular为什么选择TypeScript?
  15. 对于python爬虫urllib库的一些理解(抽空更新)
  16. Postgresql查询出换行符和回车符:
  17. 玩转Linux服务器常用命令
  18. python之requests urllib3 连接池
  19. AFN不支持 &quot;text/html&quot; 的数据的问题:unacceptable content-type: text/html
  20. easyui datagrid里的复选框置灰方法

热门文章

  1. Web模块:spring-boot-starter-web
  2. innerHTML与innerText的区别: 前者获取的是dom对象内的所有html元素 后者获取的是dom对象里面的纯文本元素
  3. BZOJ 2190 仪仗队(线性筛欧拉函数)
  4. 【uoj#22】[UR #1]外星人 组合数学+dp
  5. 《Java程序设计》第九周学习总结 20165218 2017-2018-2
  6. Git入门指南
  7. css样式表设置
  8. Codeforces 311.E Biologist
  9. codeforces 691F 暴力
  10. linux jq命令小结