XK3168E电子吊秤串口数据读取(也可推广到其他,主要看电子秤串口的位数)
XK3168E 基本资料
分秤体跟仪表两部分,秤体即吊车下挂的部分,它跟仪表通过无线通讯,有效距离>100米,
仪表部分有个串口,可以跟电脑串口连接,采用DB9连线,有2,3,5三根线,2,3两线交叉,5是地线,2,3线一根发数据一根是收数据
将仪表的串口设置成9600波特率,8位无校验,连续模式
当秤体有负重时仪表会每100毫秒发送帧数据,3.5分钟后每1秒发送,2.5小时后停止发送.
串口通信的基本概念
接收数据通过2号线一位一位的发送过来,每个位占用 1/BaudRate 秒时间
波特率:即每秒种信号(电压)的最大改变次数,约等于每秒能发送多少bit
串口采样按16倍波特率的频率进行
开始位:由空闲信号变成逻辑0,长度1bit
数据位:即一桢中数据的位数,有,5,7,8等
校验:即奇偶校验,长度1bit,可以不用
停止位:一桢数据接受完后,空闲信号持续的时间,可以是1,2,1.5等(保持线路逻辑1时电压的时间,等于 1|2|1.5 * 1/波特率 (秒))
数据帧: 开始位(1)+数据(5~8)+校验(0~1)+停止(1~2)
电子秤数据格式
固定为 17个字节,采用ASCII,开始是stx(0x02) 结束是CL(0x13),1-3字节是状态子,4-9字节是重量信息10-15字节是皮重信息
默认时4-9字节的重量信息的保留一位小数点,即在8与9字节间加入.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DotNet.ElecScales
{
using System.IO.Ports;
using System.Text;
using System.Threading;
/// <summary>
/// 针对XK3168E
/// 厂家:杭州福达电子设置厂
/// 设置成 波特率9600, 8位无校验,连续模式
/// 编写:Wdfrog
///
/// </summary>
public class ElecScalesReader
{
#region 属性d定义
/// <summary>
/// 属性部分
/// </summary>
private List<Byte> _BufferList = new List<byte>(1024 * 10);
private byte C_STX = 0x02; //开始位标志
private byte C_END = 0x0D; //结束位标志
private int C_MaxQueueElem = 30;//队列里存放的最多元素个数
private int C_FrameLength = 17;
private bool Enabled = false;
private Thread WorkThread { get; set; }
//公开属性
public Queue<GatherDataInfo> DataQueue { get; private set; }
public SerialPort COMPort { get; private set; }
public Exception LastError { get; set; }
#endregion
/// <summary>
/// 构造
/// </summary>
public ElecScalesReader()
{
DataQueue = new Queue<GatherDataInfo>();
}
private void EnsureCOMPortOpen()
{
if (COMPort == null)
{
//配置COMPort
COMPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
COMPort.Encoding = Encoding.ASCII;
//COMPort.DtrEnable = true;
}
if (!COMPort.IsOpen)
{
COMPort.Open();
}
}
/// <summary>
/// 格式-> 状态,读数,原始数据16进制表示,备注
/// 状态-> 1:成功,0:无数据,4:错误
/// </summary>
/// <returns></returns>
public string GetValue()
{
string valueTmp = "{0},{1},{2},{3}";//状态{1成功,0无数据,4错误},读数,原始数据16进制表示,备注
try
{
if (WorkThread == null || WorkThread.IsAlive!=true )
{
Launch();
Thread.Sleep(100);
}
}
catch (Exception ex)
{
LastError = ex;
return string.Format(valueTmp, "4", "", "", ex.Message);
}
GatherDataInfo data = new GatherDataInfo() { Status = 0, AddTime = DateTime.Now, Bytes = null, StrValue = Thread.CurrentThread.ManagedThreadId.ToString() + ":" + this.GetHashCode().ToString(), };
lock (DataQueue)
{
if (DataQueue.Count > 0)
{
data = DataQueue.Last();
}
}
return string.Format(valueTmp, data.Status, data.StrValue, data.Bytes == null ? "" : BitConverter.ToString(data.Bytes.ToArray()), "");
}
/// <summary>
/// 关闭COM
/// </summary>
public void Close()
{
this.Enabled = false;
while (COMPort != null && COMPort.IsOpen) Thread.Sleep(10);
}
/// <summary>
/// 启动
/// </summary>
private void Launch()
{
EnsureCOMPortOpen();
Enabled = true;
WorkThread = new Thread(DoReceive);
WorkThread.IsBackground = true;
WorkThread.Priority = ThreadPriority.Highest;
WorkThread.Start();
}
private void DoReceive()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
#region
try
{
byte[] buffer = new byte[COMPort.ReadBufferSize];
while (Enabled)
{
Thread.Sleep(15);
if (COMPort.BytesToRead <= 0) continue;
var readLen = COMPort.Read(buffer, 0, COMPort.BytesToRead);
Array.Resize<byte>(ref buffer, readLen);
_BufferList.AddRange(buffer);
Array.Resize(ref buffer, COMPort.ReadBufferSize);
#region 数据解析
if (_BufferList.Count <= 0) return;
var stxIndex = _BufferList.IndexOf(C_STX);
if (stxIndex >= 0)
{
var endIndex = stxIndex + C_FrameLength - 1; //一个包17个字节
if (_BufferList.Count > endIndex)
{
byte[] frameBytes = new byte[C_FrameLength];
_BufferList.CopyTo(stxIndex, frameBytes, 0, C_FrameLength);
//清空该帧以及该帧前面的全部数据
_BufferList.RemoveRange(0, endIndex);
//验证有效性
if (frameBytes[frameBytes.Length - 1] == C_END)
{
var str = Encoding.ASCII.GetString(frameBytes, 4, 6);
var val = (str.Substring(0, 5) + "." + str.Substring(5, 1)).Trim();
//将数据入队列
var data = new GatherDataInfo() { Status = 1, AddTime = DateTime.Now, Bytes = new List<byte>(frameBytes), StrValue = val };
lock (DataQueue)
{
DataQueue.Enqueue(data);
if (DataQueue.Count > C_MaxQueueElem)
{
DataQueue.Dequeue();
}
}
}
else
{
Console.WriteLine("无效帧,结尾不是CR符号!");
}
Console.WriteLine(BitConverter.ToString(frameBytes));
}
}
//已经收到17个字节但是还没有找到开始标志的
//则放弃缓存中的数据
if (_BufferList.Count > C_FrameLength && stxIndex < 0)
{
_BufferList.RemoveRange(0, _BufferList.Count);
}
#endregion
}
}
catch (Exception ex)
{
LastError = ex;
throw;
}
finally
{
if (COMPort != null && COMPort.IsOpen)
{
COMPort.Close();
}
}
#endregion
}
}
/// <summary>
/// 获取的有效桢信息
/// </summary>
public class GatherDataInfo
{
public DateTime? AddTime { get; set; }
/// <summary>
/// 字节信息
/// </summary>
public List<byte> Bytes { get; set; }
/// <summary>
/// 转化后的信息
/// </summary>
public string StrValue { get; set; }
/// <summary>
/// 1,有效果
/// 0,无效
/// </summary>
public int Status { get; set; }
}
public class ElecScalesHelper
{
private static ElecScalesReader _Reader;
public static ElecScalesReader Reader
{
get
{
if (_Reader == null)
{
_Reader = new ElecScalesReader();
}
return _Reader;
}
}
/// <summary>
/// 格式-> 状态,读数,原始数据16进制表示,备注
/// 状态-> 1:成功,0:无数据,4:错误
/// </summary>
/// <returns></returns>
public static string GetValue()
{
lock (typeof(ElecScalesHelper))
{
return Reader.GetValue();
}
}
/// <summary>
/// 关闭COM
/// </summary>
public static string Close()
{
lock (typeof(ElecScalesHelper))
{
Reader.Close();
_Reader = null;
}
return "";
}
}
}