C#串口读取地磅重量数据不完整问题求助
C# Web服务串口读取地磅重量不完整问题解决
问题描述
开发了一个C# Web服务用于通过串口读取地磅重量,但存在偶尔无法获取完整数值的问题:实际重量为390kg时,有时会读到39、0、9或完整的390。使用Hyper Terminal软件可正常读取完整重量,且地磅本身重量无波动。先后尝试ReadExisting方法和指定字节数的Read方法,均未解决问题。
原Web服务代码
using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.IO.Ports; using System.Linq; using System.Threading; using System.Web; using System.Web.Services; namespace WeighBridgeWS { /// <summary> /// Summary description for WeighBridge /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] [System.Web.Script.Services.ScriptService] public class WeighBridge : System.Web.Services.WebService { public static string weightRead { get; set; } public WeighBridge() { //Uncomment the following line if using designed components //InitializeComponent(); // weightRead = "10000"; } [WebMethod] #region || ReadWeight || public string ReadWeight() { try { string PortNo = "COM1"; SerialPort mySerialPort = new SerialPort(PortNo); mySerialPort.BaudRate = 2400; mySerialPort.Parity = Parity.Even; mySerialPort.StopBits = StopBits.One; mySerialPort.DataBits = 7; mySerialPort.Handshake = Handshake.None; mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); mySerialPort.Open(); Thread.Sleep(3000); mySerialPort.Close(); return weightRead; } catch (Exception ex) { ExceptionLogging.SendErrorToText(ex); return ""; } } #endregion #region || ReadWeight || public static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) { try { System.Threading.Thread.Sleep(100); SerialPort sp = (SerialPort)sender; sp.ReadTimeout = 5000; sp.WriteTimeout = 5000; if (!sp.IsOpen) sp.Open(); weightRead = sp.ReadExisting(); if (sp.IsOpen) sp.Close(); } catch (Exception ex) { ExceptionLogging.SendErrorToText(ex); } } #endregion } }
尝试的Read方法代码
int bytesToRead = 10; // 修改为需要读取的字节数 byte[] buffer = new byte[bytesToRead]; int bytesRead = sp.Read(buffer, 0, bytesToRead); // 处理接收的数据 weightRead = Encoding.ASCII.GetString(buffer, 0, bytesRead);
问题根源
- DataReceived事件特性:串口数据分批次传输,事件可能在完整数据未到达时就触发,导致单次读取仅获得部分内容。
- Web服务逻辑冲突:
ReadWeight方法用Thread.Sleep等待数据,但DataReceived事件中直接关闭串口,逻辑矛盾;静态变量weightRead在多请求场景下会被覆盖,引发数据混乱。 - 串口操作不规范:事件中重复打开/关闭串口、添加不必要的
Sleep,干扰正常数据读取流程。
解决方案
方案1:基于帧结束符读取完整数据
多数地磅串口输出会以换行符(\r\n或\n)作为完整帧的结束标识,直接读取整行数据即可确保拿到完整重量值:
using System; using System.IO.Ports; using System.Web.Services; namespace WeighBridgeWS { [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] [System.Web.Script.Services.ScriptService] public class WeighBridge : System.Web.Services.WebService { [WebMethod] public string ReadWeight() { string weight = string.Empty; SerialPort serialPort = null; try { // 初始化串口,匹配地磅参数 serialPort = new SerialPort("COM1") { BaudRate = 2400, Parity = Parity.Even, StopBits = StopBits.One, DataBits = 7, Handshake = Handshake.None, ReadTimeout = 5000, NewLine = "\r\n" // 根据地磅实际帧结束符调整 }; serialPort.Open(); // 读取完整一行数据,直到换行符 weight = serialPort.ReadLine().Trim(); // 验证数据有效性,确保是数字格式 if (!int.TryParse(weight, out _)) { weight = string.Empty; } } catch (Exception ex) { ExceptionLogging.SendErrorToText(ex); weight = string.Empty; } finally { // 确保串口资源释放 serialPort?.Close(); serialPort?.Dispose(); } return weight; } } }
方案2:固定长度数据读取(无结束符场景)
如果地磅输出是固定长度的字节流,可循环读取直到获取足够字节:
// 替换方案1中ReadLine的代码段 int fixedLength = 5; // 假设地磅每个重量值固定占5字节 byte[] buffer = new byte[fixedLength]; int totalBytesRead = 0; while (totalBytesRead < fixedLength) { int bytesRead = serialPort.Read(buffer, totalBytesRead, fixedLength - totalBytesRead); totalBytesRead += bytesRead; } weight = System.Text.Encoding.ASCII.GetString(buffer).Trim();
关键注意事项
- 务必确认地磅的串口通信协议细节:包括帧结束符、数据长度、编码格式,这是解决问题的核心(Hyper Terminal能正常读取说明参数匹配,只需按完整帧读取)。
- 禁止使用静态变量存储重量数据,避免多并发请求导致的数据混乱。
- 串口操作必须在
finally块中关闭并释放资源,防止端口被占用。
内容的提问来源于stack exchange,提问作者Akshatha M S
相关产品推荐
相关产品推荐

