You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);

问题根源

  1. DataReceived事件特性:串口数据分批次传输,事件可能在完整数据未到达时就触发,导致单次读取仅获得部分内容。
  2. Web服务逻辑冲突:ReadWeight方法用Thread.Sleep等待数据,但DataReceived事件中直接关闭串口,逻辑矛盾;静态变量weightRead在多请求场景下会被覆盖,引发数据混乱。
  3. 串口操作不规范:事件中重复打开/关闭串口、添加不必要的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 20:40:57