摘要:一個寫的接收電子稱數據并解析出重量數據的類。之前單位購買了兩架電子稱,同時多帶帶購買了配套的軟件。電子稱參數類有些電子稱發送的數據格式是沒有小數點分隔符例如耀華沒有小數點的數中整數部分長度數據接收處理類比較簡單,請參考注釋即可。
一個C#寫的接收電子稱數據并解析出重量數據的類。
之前單位購買了兩架電子稱,同時多帶帶購買了配套的軟件。該軟件是用Delphi 7寫就的,界面老舊就不說了,關鍵是功能太弱了,基本只能簡單地記錄一下稱重的數據,打印的標簽效果亦只能是簡單的文字打印,基本上無法使用。想著之前曾經有用POS指令控制串口打印機的經驗,應該不是很難,就自己寫了一個,以解決零散分包標簽打印和裝箱標簽打印的需要。
共接觸到三種電子稱數據格式,如數據格式不在此列,則使用例如串口調試助手之類的工具接收電子稱數據自行分析并作相應調整即可。
電子稱狀態變更通告事件類,注意此輔助助類原處于不同的命名空間,請自行修改或合并到相同的命名空間。
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace CommonLib{ /// /// 電子稱狀態變更通告事件類定義 /// public class ScaleStateChangeEventArgs:EventArgs { public int ScaleID { get; private set; } public float? Weight { get; private set; } public bool Disconnected { get; private set; } public bool PortOpenError { get; private set; } /// /// 電子稱狀態變更通告事件 /// /// 電子稱標號,對應數據庫中的ID /// 實時屏顯重量 /// 連接已丟失 /// 端口(串口)打開錯誤 public ScaleStateChangeEventArgs(int scaleID, float? weight, bool disconnected, bool portOpenError) { this.ScaleID = scaleID; this.Weight = weight; this.Disconnected = disconnected; this.PortOpenError = portOpenError; } }}
電子稱參數類,作為主類構造函數的參數,用于封裝電子稱的主要參數:串口及數據格式的參數。
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace DataReceiver{ /// /// 電子稱參數類 /// public class ScaleParam { public int ScaleID { get; set; } public string Name { get; set; } public string COMPortName { get; set; } public int BaudRate { get; set; } public int DataBits { get; set; } public string StopBits { get; set; } public string Parity { get; set; } public int CheckingInterval { get; set; } public int DataLength { get; set; } public int BeginByte { get; set; } public int EndByte { get; set; } public int ScaleDataBeginLoc { get; set; } public int ScaleDataLength { get; set; } /// /// 有些電子稱發送的數據格式是沒有小數點分隔符例如:耀華 Xk3190 /// public bool HasDecimalSeparatorFlag { get; set; } /// /// 沒有小數點的數中整數部分長度 /// public short IntegerPortionLength { get; set; } }}
比較簡單,請參考注釋即可。
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.IO;using System.IO.Ports;using System.Runtime.InteropServices;using CommonLib;using DataReceiver;namespace DataReceiver{ /// /// 電子稱數據接收類 Receiver /// public class Receiver { /// /// 電子稱狀態變更通告事件 /// public event EventHandler<ScaleStateChangeEventArgs> ScaleStateChange; /// /// 電子稱參數 /// private ScaleParam scale; /// /// 連接類型:串口 /// private SerialPort comport; /// /// (從電子稱)最后一次收到的正確的字節數據 /// private byte[] lastReceivedBytes = new byte[1]; /// /// (從電子稱)最后一次收到的正確的重量 /// private float? lastReceivedWeight; /// /// 電子稱發送的有效數據長度 /// int DataLength = -1; /// /// 從串口讀取的數據長度,為保證接到的數據包含有效數據, /// 讀取的數據長度為:DataLength * 2 /// 此處或可再優化,實際使用正常,故未作深究 /// int bytesToRead = -1; /// /// 電子稱連接丟失標志 /// private bool lostConnectionFlag = false; /// /// 接收到錯誤的數據標志 /// 通常,電子稱開機時、波特率不匹配時數據格式會有問題 /// private bool errorDataReceivedFlag = false; /// /// 定時讀取串口數據的定時器 /// private Timer DataChecker; /// /// /// //private GlobalData globalData = GlobalData.Instance; public Receiver() { } /// /// 自定義構造器 /// /// 電子稱參數 public Receiver(ScaleParam targetScale) :base() { scale = targetScale; DataLength = scale.DataLength; bytesToRead = DataLength * 2; Initializer(); DataChecker = new Timer(DataProcessor, null, scale.CheckingInterval, scale.CheckingInterval); } public void Reset() { DataChecker.Change(Timeout.Infinite, Timeout.Infinite); // Stop comport.Close(); Initializer(); DataChecker.Change(scale.CheckingInterval, scale.CheckingInterval); // Start } public void ClosePort() { comport.Close(); } /// /// 初始化招收器 /// 設置標志、初始化接收數組、打開串口等 /// public void Initializer() { lastReceivedBytes = new byte[DataLength]; lostConnectionFlag = false; errorDataReceivedFlag = false; bool error = false; comport = new SerialPort(); if (comport.IsOpen) comport.Close(); else { comport.PortName = scale.COMPortName; comport.BaudRate = scale.BaudRate; comport.DataBits = 8; comport.StopBits = StopBits.One; comport.Parity = Parity.None; comport.DtrEnable = true; comport.RtsEnable = true; try { comport.Open(); } catch (UnauthorizedAccessException) { error = true; } catch (IOException) { error = true; } catch (ArgumentException) { error = true; } if (error) { ScaleStateChange?.Invoke(this, new ScaleStateChangeEventArgs(scale.ScaleID, null, true, true)); } else { } } } /// /// 電子稱數據處理例程 /// /// private void DataProcessor(object state) { // 如果串口未打開或緩沖區接收到的數據長度少于 bytesToRead 的定義值 if (!comport.IsOpen || comport.BytesToRead < bytesToRead) { if (!lostConnectionFlag) { lostConnectionFlag = true; ScaleStateChange?.Invoke(this, new ScaleStateChangeEventArgs(scale.ScaleID, null, true, false)); } // 直接返回以直至收到足夠的數據 return; } // 已接收到足夠的數據,無須繼續接收(因為電子稱的數據是連繼重復發送的) DataChecker.Change(Timeout.Infinite, Timeout.Infinite); // Stop byte[] buffer = new byte[bytesToRead]; // 從緩沖區讀長度為 bytesToRead 的數據 comport.Read(buffer, 0, bytesToRead); // 定位有效數據首字節出現的位置 int begingOffset = -1; for (int i= 0; i < buffer.Count(); i++) { if (buffer[i] == scale.BeginByte) // { begingOffset = i; break; } } try { byte[] data = new byte[DataLength]; // 復制完整數據至字節緩存數組 Buffer.BlockCopy(buffer, begingOffset, data, 0, DataLength); // 調用數據處理例程 ProcessingScaleData(data); } catch (Exception ex) { //Console.WriteLine(">>>>>>>>>>>>>>>>>>>>>> Exception: " + ex.Message); } // 清空串口接收緩沖區以保證數據實時性 comport.DiscardInBuffer(); //Start over // 重新啟動數據接收定時器 DataChecker.Change(scale.CheckingInterval, scale.CheckingInterval); // Start } /// /// 電子稱數據處理例程 /// /// 電子稱發送的字節數據 private void ProcessingScaleData(byte[] receivedBytes) { // 只有和最后一次收到的數據不同時才需要處理 if (!ByteArrayCompare(lastReceivedBytes, receivedBytes)) { ProcessingData(receivedBytes); } // 收到相同數據時檢查電子稱的串口連接是否斷開 // 如果曾經斷開過連接,屏幕會顯示 ERROR // 此時需重置標志并更新顯示 else if (lostConnectionFlag) { lostConnectionFlag = false; ProcessingData(receivedBytes); } } /// /// 更新 lastReceivedBytes 變更數據 /// 并調用數據解析例程 /// /// 電子稱發送的字節數據 private void ProcessingData(byte[] receivedBytes) { lastReceivedBytes = receivedBytes; // 字節數據轉換為字符串數據并傳給解析例程 ParseData(Encoding.ASCII.GetString(receivedBytes)); } string tmpWeightData = string.Empty; string weightData = string.Empty; float weightResult; /// /// 電子稱數據解析例程 /// 支持3種電子稱數據格式,請參考圖示 /// 可根據需要擴充 /// /// 電子稱發送過來的字符串數據 private void ParseData(string data) { try { weightData = data.Substring(scale.ScaleDataBeginLoc, scale.ScaleDataLength); if (!scale.HasDecimalSeparatorFlag) { tmpWeightData = weightData; weightData = tmpWeightData.Substring(0, scale.IntegerPortionLength) + "." + tmpWeightData.Substring(scale.IntegerPortionLength, scale.ScaleDataLength-scale.IntegerPortionLength); } if (float.TryParse(weightData, out weightResult)) { errorDataReceivedFlag = false; lastReceivedWeight = weightResult; ScaleStateChange?.Invoke(this, new ScaleStateChangeEventArgs(scale.ScaleID, weightResult, false, false)); } else if (!errorDataReceivedFlag) { errorDataReceivedFlag = true; ScaleStateChange?.Invoke(this, new ScaleStateChangeEventArgs(scale.ScaleID, lastReceivedWeight, false, false)); lastReceivedBytes = new byte[1]; } } catch (Exception ex) { ScaleStateChange?.Invoke(this, new ScaleStateChangeEventArgs(scale.ScaleID, null, false, false)); lastReceivedBytes = new byte[1]; } } [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)] static extern int memcmp(byte[] b1, byte[] b2, long count); /// /// 字節數組比較例程 /// /// 字節數組1 /// 字節數組2 /// 相同則返回True;否則False static bool ByteArrayCompare(byte[] b1, byte[] b2) { // Validate buffers are the same length. // This also ensures that the count does not exceed the length of either buffer. return b1.Length == b2.Length && memcmp(b1, b2, b1.Length) == 0; } /// /// TXT日志記錄例程 /// /// 待寫入日志文件中的字符串數據 private void WriteFile(string data) { FileStream fs = new FileStream(AppDomain.CurrentDomain.BaseDirectory + "Logger.txt", FileMode.Append); StreamWriter sw = new StreamWriter(fs); sw.Write(data); sw.Flush(); sw.Close(); fs.Close(); } } // class ends}
程序界面使用了MahApps.Metro.Controls,具體請參考 https://mahapps.com/docs/controls/metrowindow
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/121828.html
摘要:命名空間可以解決以下兩類問題用戶編寫的代碼與內部的類函數常量或第三方類函數常量之間的名字沖突。在命名空間內部訪問全局類函數和常量調用全局函數訪問全局常量實例化全局類命名空間和動態語言特征命名空間的實現受到其語言自身的動態特征的影響。 PHP 命名空間(namespace)是在PHP 5.3中加入的,如果你學過C#和Java,那命名空間就不算什么新事物。 不過在PHP當中還是有著相當重要...
閱讀 1172·2021-11-22 15:22
閱讀 3843·2021-10-19 13:13
閱讀 3590·2021-10-08 10:05
閱讀 3303·2021-09-26 10:20
閱讀 2988·2019-08-29 14:21
閱讀 2196·2019-08-27 10:55
閱讀 1876·2019-08-26 10:31
閱讀 2586·2019-08-23 16:47