今天中午没睡午觉,头昏眼花的,实在写不了代码,把这几天写的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>();//默认分配1页内存,并始终限制不允许超过
  17. private byte[] binary_data = new byte[];//FF FF 01 03 1B 1D
  18. private decimal dataValue = ;
  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 "+""+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(), , 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) > )
  67. {
  68. System.Threading.Thread.Sleep();
  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, , n);//读取缓冲数据
  104. dataCatched = false;//缓存记录数据是否捕获到
  105. //缓存数据
  106. buffer.AddRange(buf);
  107. //完整性判断
  108. while (buffer.Count >= )//至少要包含头(2字节)+分机编号(1字节)+测量数据(2字节)+校验(1字节)
  109. {
  110. //查找数据头
  111. if (buffer[] == 0xFF && buffer[] == 0xFF)
  112. {
  113. int len = ;//数据长度
  114. //数据完整判断第一步,长度是否足够
  115. if (buffer.Count < len) break;
  116. buffer.CopyTo(, binary_data, , len);//复制一条完整数据到数据缓存
  117. //分析数据
  118. dataValue = (decimal)((binary_data[] * + binary_data[]) / 1000.000);
  119. dataCatched = true;
  120. buffer.RemoveRange(, len);//正确分析一条数据,从缓存中移除数据
  121. }
  122. else
  123. {
  124. //如果数据开始不是头,则删除数据
  125. buffer.RemoveAt();
  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口,波特率等通信参数的设置应该一一对应。

用C#实现通过串口对设备的数据采集--Server层的更多相关文章

  1. S3C6410串口平台设备注册流程分析

    1.mdesc->map_io() start_kernel -->setup_arch(&command_line); -->paging_init(mdesc); --& ...

  2. [python] 3 、基于串口通信的嵌入式设备上位机自动测试程序框架(简陋框架)

    星期一, 20. 八月 2018 01:53上午 - beautifulzzzz 1.前言 做类似zigbee.ble mesh...无线网络节点性能测试的时候,手动操作然后看表象往往很难找出真正的原 ...

  3. [连载]《C#通讯(串口和网络)框架的设计与实现》-2.框架的总体设计

    目       录 C#通讯(串口和网络)框架的设计与实现... 1 (SuperIO)- 框架的总体设计... 1 第二章           框架总体的设计... 2 2.1           ...

  4. 【工业串口和网络软件通讯平台(SuperIO)教程】二.架构和组成部分

    1.1    架构结构图 1.1.1    层次示意图 1.1.2    模型对象示意图 1.2    IO管理器 IO管理器是对串口和网络通讯链路的管理.调度.针对串口和网络通讯链路的特点,在IO管 ...

  5. Linux下串口编制【转】

    串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用.常用的串口是RS-232-C接口(又称EIA RS-232-C)它是在1970年由美国电子工业协会(EIA)联合贝尔系统.调制解调 ...

  6. Smart210学习记录------linux串口驱动

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=27025492&id=327609 一.核心数据结构 串口驱动有 ...

  7. 四轴飞行器1.2.2 RT-Thread 串口

    四轴飞行器1.2.2 RT-Thread 串口        本来是打算说根据RT-Thread的设备管理提供的驱动接口些串口驱动的,但是仔细一看,我去,串口驱动写好了,只需要调用就可以了.下面我们说 ...

  8. Linux串口编程详解(转)

    串口本身,标准和硬件 † 串口是计算机上的串行通讯的物理接口.计算机历史上,串口曾经被广泛用于连接计算机和终端设备和各种外部设备.虽然以太网接口和USB接口也是以一个串行流进行数据传送的,但是串口连接 ...

  9. linux串口编程总结

    串口本身.标准和硬件 † 串口是计算机上的串行通讯的物理接口.计算机历史上,串口以前被广泛用于连接计算机和终端设备和各种外部设备.尽管以太网接口和USB接口也是以一个串行流进行数据传送的.可是串口连接 ...

随机推荐

  1. 【C++】深度探索C++对象模型读书笔记--执行期语意学(Runtime Semantics)

    对象的构造和析构: 全局对象 C++程序中所有的global objects都被放置在程序的data segment中.如果显式指定给它一个值,此object将以此值为初值.否则object所配置到的 ...

  2. 第83天:jQuery中操作form表单

    操作form表单 1. 属性操作 设置属性: // 第一个参数表示:要设置的属性名称 // 第二个参数表示:该属性名称对应的值 $(selector).attr(“title”, “传智播客”); 获 ...

  3. struts 普通的action

    1.使用普通方式javaBean作为Action动作类,不需要继承任何父类,也不需要实现接口. l 方法一定是public公用的, l 返回值是字符串用来决定跳转到哪个视图 l 不需要参数 l 方法名 ...

  4. hdfs源码分析第二弹

    以写文件为例,串联整个流程的源码: FSDataOutputStream out = fs.create(outFile); 1. DistributedFileSystem 继承并实现了FileSy ...

  5. 【bzoj5028】小Z的加油店 扩展裴蜀定理+差分+线段树

    题目描述 给出 $n$ 个瓶子和无限的水,每个瓶子有一定的容量.每次你可以将一个瓶子装满水,或将A瓶子内的水倒入B瓶子中直到A倒空或B倒满.$m$ 次操作,每次给 $[l,r]$ 内的瓶子容量增加 $ ...

  6. 【bzoj5099】[POI2018]Pionek 双指针法

    题目描述 给你 $n$ 个平面向量,选出它们中的一部分,使得它们的和的长度最大.求这个最大长度的平方. 输入 第一行包含一个正整数n(n<=200000),表示指令条数. 接下来n行,每行两个整 ...

  7. Python中int()函数的用法浅析

      int()是Python的一个内部函数 Python系统帮助里面是这么说的 >>> help(int)  Help on class int in module __builti ...

  8. Shell脚本重启Python程序

    # restart.sh old_pid=$(ps ax|grep Service.py|grep -v grep|awk '{print $1}') echo "old_pid=${old ...

  9. 【刷题】洛谷 P4143 采集矿石

    题目背景 ZRQ成功从坍塌的洞穴中逃了出来.终于,他看到了要研究的矿石.他想挑一些带回去完成任务. 题目来源:Zhang_RQ哦对了ZRQ就他,嗯 题目描述 ZRQ发现这里有 \(N\) 块排成一排的 ...

  10. 洛谷5月月赛T30212 玩游戏 【分治NTT + 多项式求ln】

    题目链接 洛谷T30212 题解 式子很容易推出来,二项式定理展开后对于\(k\)的答案即可化简为如下: \[k!(\sum\limits_{i = 0}^{k} \frac{\sum\limits_ ...