求助:如何用C#通过串口将电子秤重量读取到文本框
电子秤重量数据读取问题解决(POS程序适配)
问题描述
我正尝试仅将电子秤的重量数据读取到应用程序中,试了一些代码但都无效。我需要仅将重量数据显示到文本框中,用于POS程序。试过多种代码片段均无法实现需求。
原使用代码:
namespace WS_POS { public partial class Test1 : XtraForm { static SerialPort _serialPort; private const int BaudRate = 9600; public Test1() { InitializeComponent(); } private void Test1_Load(object sender, EventArgs e) { string[] portNames = SerialPort.GetPortNames(); foreach (var portName in portNames) { comboBox1.Items.Add(portName); } comboBox1.SelectedIndex = 0; } private delegate void Closure(); private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs) { if (InvokeRequired) BeginInvoke(new Closure(() => { SerialPortOnDataReceived(sender, serialDataReceivedEventArgs); })); else { int dataLength = _serialPort.BytesToRead; byte[] data = new byte[dataLength]; int nbrDataRead = _serialPort.Read(data, 0, dataLength); if (nbrDataRead == 0) return; string str = System.Text.Encoding.UTF8.GetString(data); T2.Text = str.ToString(); } } private void simpleButton1_Click(object sender, EventArgs e) { if (_serialPort != null && _serialPort.IsOpen) _serialPort.Close(); if (_serialPort != null) _serialPort.Dispose(); _serialPort = new SerialPort(comboBox1.Text, BaudRate, Parity.None, 8, StopBits.One); //<-- Creates new SerialPort using the name selected in the combobox _serialPort.DataReceived += SerialPortOnDataReceived; //<-- this event happens everytime when new data is received by the ComPort _serialPort.Open(); //<-- make the comport listen T1.Text = "Listening on " + _serialPort.PortName + "...\r\n"; } } }
解决方案
原代码核心问题是未处理串口数据的分段接收,电子秤输出的重量通常是带格式的完整帧(如以\r\n结尾),且包含非重量字符。以下是修改后的代码,解决数据拼接、格式解析问题:
namespace WS_POS { public partial class Test1 : XtraForm { static SerialPort _serialPort; private const int BaudRate = 9600; // 缓存串口分段接收的数据 private string _receivedBuffer = string.Empty; // 电子秤帧结束符(根据设备手册调整,常见为\r\n) private const string FrameTerminator = "\r\n"; public Test1() { InitializeComponent(); } private void Test1_Load(object sender, EventArgs e) { string[] portNames = SerialPort.GetPortNames(); foreach (var portName in portNames) { comboBox1.Items.Add(portName); } comboBox1.SelectedIndex = 0; } // 更新UI的委托 private delegate void UpdateWeightDelegate(string weight); private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs e) { try { // 读取当前串口缓冲区所有数据 string newData = _serialPort.ReadExisting(); _receivedBuffer += newData; // 处理所有已收到的完整帧 while (_receivedBuffer.Contains(FrameTerminator)) { int terminatorIndex = _receivedBuffer.IndexOf(FrameTerminator); string fullFrame = _receivedBuffer.Substring(0, terminatorIndex); // 移除已处理的帧,更新缓冲区 _receivedBuffer = _receivedBuffer.Substring(terminatorIndex + FrameTerminator.Length); // 提取纯重量数字(含小数点) string weightStr = new string(fullFrame.Where(c => char.IsDigit(c) || c == '.').ToArray()); if (!string.IsNullOrEmpty(weightStr)) { // 跨线程安全更新UI T2.Invoke(new UpdateWeightDelegate(UpdateWeightDisplay), weightStr); } } } catch (Exception ex) { // 捕获异常并写入日志框 T1.Invoke(new Action(() => T1.Text += $"Error: {ex.Message}\r\n")); } } // 更新重量显示 private void UpdateWeightDisplay(string weight) { T2.Text = weight; // 可选:添加单位,比如 T2.Text = $"{weight} kg"; } private void simpleButton1_Click(object sender, EventArgs e) { try { if (_serialPort != null && _serialPort.IsOpen) { _serialPort.Close(); _serialPort.Dispose(); } _serialPort = new SerialPort(comboBox1.Text, BaudRate, Parity.None, 8, StopBits.One); _serialPort.DataReceived += SerialPortOnDataReceived; _serialPort.NewLine = FrameTerminator; _serialPort.Open(); T1.Text = $"Listening on {_serialPort.PortName}...\r\n"; _receivedBuffer = string.Empty; // 重置缓冲区 } catch (Exception ex) { T1.Text += $"Failed to open port: {ex.Message}\r\n"; } } } }
关键修改说明
- 数据缓存与帧解析:用
_receivedBuffer缓存分段数据,直到检测到结束符,确保处理完整的重量帧。 - 重量提取逻辑:过滤字符提取纯数字(含小数点),适配常见电子秤输出格式(如
WEIGHT: 12.34 kg\r\n)。 - 线程安全优化:用
Invoke安全更新UI,避免跨线程操作异常。 - 异常处理:添加捕获机制,避免串口操作异常导致程序崩溃,便于调试。
注意:若电子秤输出格式特殊(如固定长度、特定前缀),需根据设备手册调整FrameTerminator和重量提取逻辑。
内容的提问来源于stack exchange,提问作者Ayman Alhaj
相关产品推荐
相关产品推荐

