【问题标题】:C# - Change format of Data received from Serial PortC# - 更改从串口接收的数据格式
【发布时间】:2020-09-22 17:43:14
【问题描述】:

我正在制作一个 C# 表单应用程序,该应用程序接收来自以波特率 2400、无奇偶校验、8 位数据、1 个停止位进行通信的仪器的数据。 数据以 [000000][000000][000000] 形式出现在连续的字符串行中。例如,如果在一个过程中,仪器上的读数变化为 0.50,0.49,0.72,0.61,0.48,那么接收到的数据字符串将为 [000050][000049][000072][000061][000048],这就是它目前正在文本框中显示。

我需要以正确的格式将程序期间达到的最大值显示到文本框中,例如在本例中它应该是 0.72。我不知道代码是什么。

下面是我目前的串口通信代码。

    public Form2()
    {
        InitializeComponent();
    }

    private void Form2_Load(object sender, EventArgs e)
    {

    }

    private void Main_Load(object sender, EventArgs e)
    {
    }
    
   //this is the button to open port.
    private void button1_Click(object sender, EventArgs e)
    {
        button1.Enabled = false;
        button2.Enabled = true;
        try
        {
            serialPort1.PortName = comboBox1.Text;
            serialPort1.Open();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

    
    //Event handler for data received.
    private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
    {
        SerialPort sp = (SerialPort)sender;
        string indata = sp.ReadExisting();
        Regex rx = new Regex(@"\[(\d+)\]");
        double.TryParse(richTextBox2.Text, out double max);
        foreach (Match match in rx.Matches(indata))
        {
            double val = int.Parse(match.Groups[1].Value) / 100.0;
            if (val > max)
                max = val;
        }
        richTextBox2.Text = max.ToString();
    }
    


    private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        

    }

    //this is the button to close port
    private void button2_Click(object sender, EventArgs e)
    {
        button1.Enabled = true;
        button2.Enabled = false;
        try
        {
            serialPort1.Close();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

    private void button3_Click(object sender, EventArgs e)
    {
        if (serialPort1.IsOpen)
        {
            serialPort1.DataReceived += DataReceivedHandler;
        }
        else
        {
            MessageBox.Show("Error : Port needs to be open or wrong port selected!");
        }
        
    }   


    private void Form2_FormClosing(object sender, FormClosingEventArgs e)
    {
        if (serialPort1.IsOpen)
            serialPort1.Close();
    }


    private void button4_Click(object sender, EventArgs e)
    {
        string[] ports = SerialPort.GetPortNames();
        comboBox1.Items.AddRange(ports);
        comboBox1.SelectedIndex = 0;
        button2.Enabled = false;

    }

【问题讨论】:

  • 这个[000050][000049][000072][000061][000048]怎么代表一个日期?您可能需要参考仪器的 API 编程手册。每个块可能都有一个含义,例如:[000050]
  • 大概如果你得到的读数是 000356,它会被表示为 3.56?换句话说,末尾的 2 个数字代表小数,小数之前的数字是十、百等。
  • 是的,最后两个数字在小数点后,其余前四个分别代表单位,十、百、千。这是一个体重秤。如果它给出 [123456] 那么它必须被读作 1234.56

标签: c# dataframe serialization serial-port


【解决方案1】:

所以你想在每次有数据处理的时候处理数据对吧?

如果您使用的是“System.IO.Ports”,并且您的 serialPort1 是 SerialPort 类型,则您可以使用“DataReceived”事件。因此,在您实例化 serialPort1 之后,您可以:

private void button1_Click(object sender, EventArgs e)
{
    button1.Enabled = false;
    button2.Enabled = true;
    try
    {
        //check and set the settings of your device
        serialPort1 = new SerialPort
        {
            PortName = comboBox1.Text,
            BaudRate = 2400,
            Parity = Parity.None,
            StopBits = StopBits.Odd,
            DataBits = 8,
            Handshake = Handshake.None,
            RtsEnable = true
        };

        serialPort1.DataReceived += DataReceivedHandler;
        serialPort1.Open();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

然后你只需要声明事件处理程序,如下所示:

private void DataReceivedHandler(object sender,SerialDataReceivedEventArgs e)
{
    SerialPort sp = (SerialPort)sender;
    string indata = sp.ReadExisting();
    Regex rx = new Regex(@"\[(\d+)\]");
    double.TryParse(textBox13.Text, out double max);
    foreach (Match match in rx.Matches(indata))
    {
        double val = int.Parse(match.Groups[1].Value) / 100.0;
        if (val > max)
            max = val;
    }
    textBox13.Text = max .ToString();
}

这将比较接收到的值和文本框中的当前值。

【讨论】:

  • 这是一个很好的解决方案,但部分问题仍然存在。单击按钮时,它仅捕获瞬时值。随着仪器中的值上升和下降,例如 ... 0.48、0.30、0.49、0.50、0.73,程序需要能够不断地将文本框中的显示值更改为字符串中达到的最高值。不应该每次仪器上的值上升时都需要点击按钮,无论如何也不可能跟上仪器快速上升和下降的值。有什么建议吗?
  • 我已经尝试过这个解决方案,但结果并没有什么不同。我已经编辑了我的问题以包含与串行通信相关的所有代码,以便您仔细阅读。我尝试通过接收按钮调用事件处理程序,然后尝试在 Main_Load 中调用它,然后在 Form2_Load 中调用它,但没有不同的结果。我尝试过循环,但我承认我的循环条件可能不合适。请再看看这个。请注意,数据来自连续的水平线字符串,而不是垂直列表。
  • @KshitijBali 我不完全确定出了什么问题,但我已将 SerialPort 创建添加到答案中并移动了“serialPort1.DataReceived += DataReceivedHandler;”在打开端口之前。
  • @KshitijBali 当您尝试此解决方案时实际发生了什么?和你的目标有什么不同?以便我们更好地确定要修复的内容
  • 想象一个秤。如果一个人用拇指在天平上施加压力,那么仪器上的读数会增加,直到达到最大压力,然后当一个人抬起拇指时,天平上的压力会下降,读数也会下降。对象。是读数从 0.00 上升到 1.17 应该在 TextBox 中可见,因为它在仪器上可见,但是如果 1.17 是达到的最高值,那么即使读数下降,1.17 也应该在显示屏上冻结。除非应用高于 1.17 的压力或再次单击按钮(兼作刷新),否则它不应更改。
【解决方案2】:

如果我理解您的格式要求正确,您基本上希望从每个数字的前面删除零,然后比较它们以找到最大值并以 x.xx 的格式显示它们如果是这种情况,请创建一个单独的方法来处理它:

    private decimal GetMaxReading(string rawReadingData)
    {
        decimal maxReading = 0;
        var readings = rawReadingData.Split('[',).ToList();

        foreach (var reading in readings)
        {
            var readingString = reading.TrimStart('0')
                                       .TrimEnd(']');

            var isInt = int.TryParse(readingString, out int readingValue);
            var value = isInt ? (decimal)readingValue / 100 : 0;
            maxReading = value > maxReading ? value : maxReading;
        }

        return maxReading;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-17
    • 1970-01-01
    • 1970-01-01
    • 2021-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多