摘要:一個(gè)寫(xiě)的接收電子稱數(shù)據(jù)并解析出重量數(shù)據(jù)的類。之前單位購(gòu)買了兩架電子稱,同時(shí)多帶帶購(gòu)買了配套的軟件。電子稱參數(shù)類有些電子稱發(fā)送的數(shù)據(jù)格式是沒(méi)有小數(shù)點(diǎn)分隔符例如耀華沒(méi)有小數(shù)點(diǎn)的數(shù)中整數(shù)部分長(zhǎng)度數(shù)據(jù)接收處理類比較簡(jiǎn)單,請(qǐng)參考注釋即可。
一個(gè)C#寫(xiě)的接收電子稱數(shù)據(jù)并解析出重量數(shù)據(jù)的類。
之前單位購(gòu)買了兩架電子稱,同時(shí)多帶帶購(gòu)買了配套的軟件。該軟件是用Delphi 7寫(xiě)就的,界面老舊就不說(shuō)了,關(guān)鍵是功能太弱了,基本只能簡(jiǎn)單地記錄一下稱重的數(shù)據(jù),打印的標(biāo)簽效果亦只能是簡(jiǎn)單的文字打印,基本上無(wú)法使用。想著之前曾經(jīng)有用POS指令控制串口打印機(jī)的經(jīng)驗(yàn),應(yīng)該不是很難,就自己寫(xiě)了一個(gè),以解決零散分包標(biāo)簽打印和裝箱標(biāo)簽打印的需要。
共接觸到三種電子稱數(shù)據(jù)格式,如數(shù)據(jù)格式不在此列,則使用例如串口調(diào)試助手之類的工具接收電子稱數(shù)據(jù)自行分析并作相應(yīng)調(diào)整即可。
電子稱狀態(tài)變更通告事件類,注意此輔助助類原處于不同的命名空間,請(qǐng)自行修改或合并到相同的命名空間。
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace CommonLib{ /// /// 電子稱狀態(tài)變更通告事件類定義 /// 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; } /// /// 電子稱狀態(tài)變更通告事件 /// /// 電子稱標(biāo)號(hào),對(duì)應(yīng)數(shù)據(jù)庫(kù)中的ID /// 實(shí)時(shí)屏顯重量 /// 連接已丟失 /// 端口(串口)打開(kāi)錯(cuò)誤 public ScaleStateChangeEventArgs(int scaleID, float? weight, bool disconnected, bool portOpenError) { this.ScaleID = scaleID; this.Weight = weight; this.Disconnected = disconnected; this.PortOpenError = portOpenError; } }}
電子稱參數(shù)類,作為主類構(gòu)造函數(shù)的參數(shù),用于封裝電子稱的主要參數(shù):串口及數(shù)據(jù)格式的參數(shù)。
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace DataReceiver{ /// /// 電子稱參數(shù)類 /// 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; } /// /// 有些電子稱發(fā)送的數(shù)據(jù)格式是沒(méi)有小數(shù)點(diǎn)分隔符例如:耀華 Xk3190 /// public bool HasDecimalSeparatorFlag { get; set; } /// /// 沒(méi)有小數(shù)點(diǎn)的數(shù)中整數(shù)部分長(zhǎng)度 /// public short IntegerPortionLength { get; set; } }}
比較簡(jiǎn)單,請(qǐng)參考注釋即可。
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{ /// /// 電子稱數(shù)據(jù)接收類 Receiver /// public class Receiver { /// /// 電子稱狀態(tài)變更通告事件 /// public event EventHandler<ScaleStateChangeEventArgs> ScaleStateChange; /// /// 電子稱參數(shù) /// private ScaleParam scale; /// /// 連接類型:串口 /// private SerialPort comport; /// /// (從電子稱)最后一次收到的正確的字節(jié)數(shù)據(jù) /// private byte[] lastReceivedBytes = new byte[1]; /// /// (從電子稱)最后一次收到的正確的重量 /// private float? lastReceivedWeight; /// /// 電子稱發(fā)送的有效數(shù)據(jù)長(zhǎng)度 /// int DataLength = -1; /// /// 從串口讀取的數(shù)據(jù)長(zhǎng)度,為保證接到的數(shù)據(jù)包含有效數(shù)據(jù), /// 讀取的數(shù)據(jù)長(zhǎng)度為:DataLength * 2 /// 此處或可再優(yōu)化,實(shí)際使用正常,故未作深究 /// int bytesToRead = -1; /// /// 電子稱連接丟失標(biāo)志 /// private bool lostConnectionFlag = false; /// /// 接收到錯(cuò)誤的數(shù)據(jù)標(biāo)志 /// 通常,電子稱開(kāi)機(jī)時(shí)、波特率不匹配時(shí)數(shù)據(jù)格式會(huì)有問(wèn)題 /// private bool errorDataReceivedFlag = false; /// /// 定時(shí)讀取串口數(shù)據(jù)的定時(shí)器 /// private Timer DataChecker; /// /// /// //private GlobalData globalData = GlobalData.Instance; public Receiver() { } /// /// 自定義構(gòu)造器 /// /// 電子稱參數(shù) 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(); } /// /// 初始化招收器 /// 設(shè)置標(biāo)志、初始化接收數(shù)組、打開(kāi)串口等 /// 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 { } } } /// /// 電子稱數(shù)據(jù)處理例程 /// /// private void DataProcessor(object state) { // 如果串口未打開(kāi)或緩沖區(qū)接收到的數(shù)據(jù)長(zhǎng)度少于 bytesToRead 的定義值 if (!comport.IsOpen || comport.BytesToRead < bytesToRead) { if (!lostConnectionFlag) { lostConnectionFlag = true; ScaleStateChange?.Invoke(this, new ScaleStateChangeEventArgs(scale.ScaleID, null, true, false)); } // 直接返回以直至收到足夠的數(shù)據(jù) return; } // 已接收到足夠的數(shù)據(jù),無(wú)須繼續(xù)接收(因?yàn)殡娮臃Q的數(shù)據(jù)是連繼重復(fù)發(fā)送的) DataChecker.Change(Timeout.Infinite, Timeout.Infinite); // Stop byte[] buffer = new byte[bytesToRead]; // 從緩沖區(qū)讀長(zhǎng)度為 bytesToRead 的數(shù)據(jù) comport.Read(buffer, 0, bytesToRead); // 定位有效數(shù)據(jù)首字節(jié)出現(xiàn)的位置 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]; // 復(fù)制完整數(shù)據(jù)至字節(jié)緩存數(shù)組 Buffer.BlockCopy(buffer, begingOffset, data, 0, DataLength); // 調(diào)用數(shù)據(jù)處理例程 ProcessingScaleData(data); } catch (Exception ex) { //Console.WriteLine(">>>>>>>>>>>>>>>>>>>>>> Exception: " + ex.Message); } // 清空串口接收緩沖區(qū)以保證數(shù)據(jù)實(shí)時(shí)性 comport.DiscardInBuffer(); //Start over // 重新啟動(dòng)數(shù)據(jù)接收定時(shí)器 DataChecker.Change(scale.CheckingInterval, scale.CheckingInterval); // Start } /// /// 電子稱數(shù)據(jù)處理例程 /// /// 電子稱發(fā)送的字節(jié)數(shù)據(jù) private void ProcessingScaleData(byte[] receivedBytes) { // 只有和最后一次收到的數(shù)據(jù)不同時(shí)才需要處理 if (!ByteArrayCompare(lastReceivedBytes, receivedBytes)) { ProcessingData(receivedBytes); } // 收到相同數(shù)據(jù)時(shí)檢查電子稱的串口連接是否斷開(kāi) // 如果曾經(jīng)斷開(kāi)過(guò)連接,屏幕會(huì)顯示 ERROR // 此時(shí)需重置標(biāo)志并更新顯示 else if (lostConnectionFlag) { lostConnectionFlag = false; ProcessingData(receivedBytes); } } /// /// 更新 lastReceivedBytes 變更數(shù)據(jù) /// 并調(diào)用數(shù)據(jù)解析例程 /// /// 電子稱發(fā)送的字節(jié)數(shù)據(jù) private void ProcessingData(byte[] receivedBytes) { lastReceivedBytes = receivedBytes; // 字節(jié)數(shù)據(jù)轉(zhuǎn)換為字符串?dāng)?shù)據(jù)并傳給解析例程 ParseData(Encoding.ASCII.GetString(receivedBytes)); } string tmpWeightData = string.Empty; string weightData = string.Empty; float weightResult; /// /// 電子稱數(shù)據(jù)解析例程 /// 支持3種電子稱數(shù)據(jù)格式,請(qǐng)參考圖示 /// 可根據(jù)需要擴(kuò)充 /// /// 電子稱發(fā)送過(guò)來(lái)的字符串?dāng)?shù)據(jù) 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); /// /// 字節(jié)數(shù)組比較例程 /// /// 字節(jié)數(shù)組1 /// 字節(jié)數(shù)組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日志記錄例程 /// /// 待寫(xiě)入日志文件中的字符串?dāng)?shù)據(jù) 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,具體請(qǐng)參考 https://mahapps.com/docs/controls/metrowindow
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/121828.html
摘要:命名空間可以解決以下兩類問(wèn)題用戶編寫(xiě)的代碼與內(nèi)部的類函數(shù)常量或第三方類函數(shù)常量之間的名字沖突。在命名空間內(nèi)部訪問(wèn)全局類函數(shù)和常量調(diào)用全局函數(shù)訪問(wèn)全局常量實(shí)例化全局類命名空間和動(dòng)態(tài)語(yǔ)言特征命名空間的實(shí)現(xiàn)受到其語(yǔ)言自身的動(dòng)態(tài)特征的影響。 PHP 命名空間(namespace)是在PHP 5.3中加入的,如果你學(xué)過(guò)C#和Java,那命名空間就不算什么新事物。 不過(guò)在PHP當(dāng)中還是有著相當(dāng)重要...
閱讀 1166·2021-11-22 15:22
閱讀 3837·2021-10-19 13:13
閱讀 3570·2021-10-08 10:05
閱讀 3292·2021-09-26 10:20
閱讀 2984·2019-08-29 14:21
閱讀 2192·2019-08-27 10:55
閱讀 1871·2019-08-26 10:31
閱讀 2578·2019-08-23 16:47