如何从RS232串口数据中提取特定重量数值?
从RS232串口重量数据中提取特定数值
我通过USB转RS232串口连接重量指示器,开发了接收数据的应用(已能显示指示器发送的全部数据),但需要从返回数据中提取实际重量读数(比如15,000)。附当前C#代码及指示器数据表截图。
当前代码
namespace Weight_Test { public partial class Form1 : Form { string dataIN; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { string[] ports = SerialPort.GetPortNames(); cbComPort.Items.AddRange(ports); btnOpen.Enabled = true; btnClose.Enabled = false; } private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { dataIN = serialPort1.ReadExisting(); this.Invoke(new EventHandler(ShowData)); } private void ShowData(object sender, EventArgs e) { txtWeight.Text = dataIN; } private void btnOpen_Click(object sender, EventArgs e) { try { serialPort1.PortName = cbComPort.Text; serialPort1.BaudRate = Convert.ToInt32(9600); serialPort1.DataBits = Convert.ToInt32(8); serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), "One"); serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), "None"); serialPort1.Open(); btnOpen.Enabled = false; btnClose.Enabled = true; } catch (Exception err) { MessageBox.Show(err.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); btnOpen.Enabled = true; btnClose.Enabled = false; } } private void btnClose_Click(object sender, EventArgs e) { if (serialPort1.IsOpen) { serialPort1.Close(); btnOpen.Enabled = true; btnClose.Enabled = false; } } } }
解决方案
提取重量数值的核心是根据指示器的数据帧格式解析返回字符串,以下是通用处理方案及代码示例:
1. 先明确指示器的数据格式
从数据表截图中确认关键信息:
- 重量数据在帧中的固定位置(起始偏移、长度)
- 数据帧的分隔符(如
\r\n、特定前缀/后缀) - 数值格式(是否带千分位逗号、符号、小数位)
2. 代码修改示例
场景1:重量位于固定位置的子串
假设数据帧格式为WEIGHT:15,000\r\n,重量从第7位开始,长度6:
private void ShowData(object sender, EventArgs e) { if (!string.IsNullOrEmpty(dataIN)) { // 清除换行/回车干扰符 string cleanData = dataIN.Replace("\r", "").Replace("\n", ""); // 提取固定位置的重量字符串 string weightStr = cleanData.Substring(7, 6); // 转换为数值(去除千分位逗号) if (double.TryParse(weightStr.Replace(",", ""), out double weightValue)) { txtWeight.Text = weightValue.ToString("N0"); // 保留千分位显示 } else { txtWeight.Text = "解析失败"; } } }
场景2:数据以分隔符分割(如逗号)
如果返回数据是ID,123,15,000,UNIT,重量为第3个字段:
private void ShowData(object sender, EventArgs e) { if (!string.IsNullOrEmpty(dataIN)) { string cleanData = dataIN.Replace("\r", "").Replace("\n", ""); string[] parts = cleanData.Split(','); if (parts.Length >= 4) { string weightStr = parts[3]; if (double.TryParse(weightStr, out double weightValue)) { txtWeight.Text = weightValue.ToString("N0"); } else { txtWeight.Text = "解析失败"; } } } }
场景3:用正则匹配数值
如果重量是帧中唯一带千分位的数字:
using System.Text.RegularExpressions; // 添加该命名空间 private void ShowData(object sender, EventArgs e) { if (!string.IsNullOrEmpty(dataIN)) { // 匹配带千分位的整数/小数,如15,000或15,000.50 Match match = Regex.Match(dataIN, @"\d{1,3}(,\d{3})*(\.\d+)?"); if (match.Success) { string weightStr = match.Value; if (double.TryParse(weightStr.Replace(",", ""), out double weightValue)) { txtWeight.Text = weightValue.ToString("N0"); } else { txtWeight.Text = "解析失败"; } } else { txtWeight.Text = "未找到重量数据"; } } }
3. 额外注意事项
- 串口数据可能分多次接收,建议缓存完整帧后再解析(比如直到收到结束符
\r\n):// 将全局变量dataIN替换为StringBuilder StringBuilder dataBuffer = new StringBuilder(); private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { string newData = serialPort1.ReadExisting(); dataBuffer.Append(newData); // 检测结束符,触发解析 if (dataBuffer.ToString().Contains("\r\n")) { string fullFrame = dataBuffer.ToString().Split(new[] {"\r\n"}, StringSplitOptions.RemoveEmptyEntries)[0]; dataBuffer.Clear(); this.Invoke(new Action(() => ShowData(fullFrame))); } } // 修改ShowData接收完整帧 private void ShowData(string fullFrame) { // 此处用fullFrame执行解析逻辑 } - 确保串口参数(波特率、数据位等)与指示器设置完全一致,避免乱码。
内容的提问来源于stack exchange,提问作者Sathya Perera
相关产品推荐
相关产品推荐

