日期:2014-05-18  浏览次数:20864 次

SerialPort接收数据并解析格式化数据问题,内有详解?
我现在有个读卡设备,设备是不停向计算机串口发送数据,但发送的数据不固定,因为有刷卡记录时就发刷卡记录,没有记录就会隔1ms左右发一次设备状态等消息。

我用串口调试器可以取到数据,但现在主要是取到数据向解析格式化数据问题,如下:
02 00 0C 03 03 01 48 50 B3 A5 04 00 0B 12 03
为一个完整的包,规定以02开头,03结尾。
从第二个字节开始 00 0C为从00开始到12之前的数据长度,并且高位在前。
倒数第2个数 12 为校验位。

现在的目的就是想接到一个完整的包后然后执行另一个程序(如解析各数据作用),问题就是每次传过来的字节数并不完整,如
02 00
0C 03 03 01
48 50 B3 A5 04 00 0B 12 03
我设置SerilPort.ReceivedBytesThreshold 事件也不行,因为我不知道这个包有多少个字节,只能等到第 2 和 3 字节(00 0C)后才知道这个包的长度,然后才接收,到倒数第2位时再计算一下前面校验数是否等于 12 ,这些条件都符合执行解析方法,否则丢弃此包。

我本想声明一个类内变量byte[] bArray;
在serialPort_DataReceived事件中首先:
int bytes = serialPort.BytesToRead;

这个方法中思维特别忙,请各位串口方面有过开发经验的朋友给予指点。本人开发C#应用软件方面比较多,特别对于byte,二进制数头疼。不管您能不能帮忙,给出建议,均非常感谢!

------解决方案--------------------
楼主是不是用的serialport控件来实现串口通信的,如果是,请注意以下几点:
如果串口数据比较频繁,建议使用多线程和队列来操作,这样不会造成串口数据丢失,我看了楼主从取到的数据,发觉很有可能是因为通信过快所以数据丢失了。

serialport的datarecevie事件中将收到的数据及时写入到一个数组缓存中,然后另开一个线程专门处理该数组中数据内容,这样可以确保万无一失。
------解决方案--------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

using System.Data.SqlClient;
using System.Configuration;
using System.IO;

namespace UDMS200.showDig
{

public partial class setPara : Form
{


//存放输入数据的变量
string inputData = string.Empty;


//this delegate enables asynchronous calls for setting
//the text property on a TextBox control;
delegate void SetTextCallback(string text);

public setPara()
{
InitializeComponent();

//获取当前PC机上的所有串口 nice methods to browse all available ports;
string[] ports = SerialPort.GetPortNames();
//将获得的所有串口绑定到combobox控件 add all port names to the comboBox;
foreach (string port in ports)
{
ComboBox_ports.Items.Add(port);
}
}

private void setPara_Load(object sender, EventArgs e)
{
bind();
}



//初始化页面
protected void bind()
{
}


//选择串口后,下拉列表关闭后触发的事件
private void ComboBox_ports_SelectionChangeCommitted(object sender, EventArgs e)
{
if (SpCom.IsOpen) SpCom.Close();
SpCom.PortName = ComboBox_ports.SelectedItem.ToString();
label_motion.Text = "串口信息:" + SpCom.PortName + ":9600,8n1";
//try to open the selected port;
try
{
SpCom.Open();
}
//give a message,if the port is not available;
catch
{
MessageBox.Show("Serial port" + SpCom.PortName + "cannot be opened!", "RS232 tester", MessageBoxButtons.OK, MessageBoxIcon.Warning);
ComboBox_ports.Text = "";
label_motion.Text = "Select serial port!";
}
}



//接收读入的数据
private void SpCom_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//System.Threading.Thread.Sleep(500);
inputData = SpCom.ReadExisting();
try
{
if (inputData != string.Empty)
{
SetText(inputData);
}
}
catch (Exception ex)
{