C# SerialPort 使用DataReceived接口利用空闲中断原理接收完整一帧数据

说明

  • 使用SerialPort类
  • 使用SerialPort.DataReceived 接收事件
  • DataReceived事件触发无规律,不可作为一帧数据的判断
  • 数据接收也可使用单独一个线程轮询判断,判断更为精确,但是要完全占用一个线程,无堵塞,费资源。
  • 欢迎补充指导

开启串口

SerialPort mySerialPort;//本地串口
mySerialPort = new SerialPort(comName);
mySerialPort.BaudRate = (int)dr.baud;//波特率
mySerialPort.DataBits = Convert.ToInt32(dr.databits);//数据位
mySerialPort.StopBits = (StopBits)Convert.ToInt32(dr.stopbits);//停止位
mySerialPort.Parity = (Parity)Enum.Parse(typeof(Parity), dr.parity);//校验位
mySerialPort.WriteTimeout = 500;
LocalPort localport = new LocalPort(mySerialPort);
if (mySerialPort.IsOpen == false)
{
    Console.Write("open " + comName + " Error.\r\n");
    return response; ;
}
else
{
    localport.port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(ReceiveFromDevice);//打开成功则创建接收数据事件
    localport.LocalPortName = comName;
    localportList.Add(comName, localport);
    Console.Write("open " + comName + " Ok.\r\n");

}

串口接收事件

接收到数据后使用委托处理,更为高效,也防止堵塞串口接收数据事件

//本地串口事件  接收来自设备发向本地串口的数据
private static void ReceiveFromDevice(object sender, SerialDataReceivedEventArgs e)
{
    SerialPort serialPort = (SerialPort)sender;

    foreach (string key in localportList.Keys)
    {
        if (serialPort.PortName == key)
        {
            LSPReceiveDelegate lsprd = new LSPReceiveDelegate(Receive);
            lsprd(localportList[key]);
        }
    }        
}    

数据处理判断

使用类似空闲中断方法区分一帧数据,对缓存数据大小也做了限制,同时对最后一组数据做了定时器判断。

public static void Receive(LocalPort localPort)
{
    try
    {
        SerialPort LP = localPort.port;
        int revcount_new = LP.BytesToRead;
        TimeSpan span;
        int oneByteTime = 0;
        if (LP.Parity == Parity.None)
            oneByteTime = 1000000 / (LP.BaudRate / 10);
        else
            oneByteTime = 1000000 / (LP.BaudRate / 11);
        int diffCount = 0;
        try
        {
            if (localPort.isNewFrame)
                localPort.dt = DateTime.Now;
            DateTime dt = DateTime.Now;
            span = dt - localPort.dt;
            localPort.dt = dt;
            diffCount = revcount_new - localPort.revcount;
            localPort.revcount = revcount_new;
            if (span.Ticks > ((diffCount + 3) * oneByteTime * 10))
            {
                byte[] recvBytes = new byte[LP.BytesToRead];
                LP.Read(recvBytes, 0, recvBytes.Length);
                //string recvData = LP.ReadExisting();
                localPort.revcount = 0;
                SendToCloudDelegate stcd = SendToCloud;
                stcd("receive", LP.PortName, null, ByteToHexStr(recvBytes));
                localPort.isNewFrame = true;
            }
            else if (localPort.revcount > 2048)
            {
                byte[] recvBytes = new byte[LP.BytesToRead];
                LP.Read(recvBytes, 0, recvBytes.Length);
                //string recvData = LP.ReadExisting();
                localPort.revcount = 0;
                SendToCloudDelegate stcd = SendToCloud;
                stcd("receive", LP.PortName, null, ByteToHexStr(recvBytes));
                localPort.isNewFrame = true;
            }
            else
            {
                localPort.isNewFrame = false;
                try
                {
                    localPort.timer.Stop();
                    localPort.timer.Close();
                }
                catch
                { }
                localPort.timer = new System.Timers.Timer(10);
                localPort.timer.Elapsed += new System.Timers.ElapsedEventHandler(LSPTimeOut); //到达时间的时候执行事件;   
                localPort.timer.AutoReset = false;   //设置是执行一次(false)还是一直执行(true);   
                localPort.timer.Enabled = true;     //是否执行System.Timers.Timer.Elapsed事件;
                localPort.timer.Start();
            }
        }
        catch
        {
            Console.WriteLine(LP.PortName + "closed!");
            SendToProcess(LP.PortName + "closed!");
        }


    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
    //}

}

使用该方法可以有效区分接收一帧数据,但是也存在弊端。如最后一帧数据会有一个定时器定时的时间延时,如果数据包发送比较缓慢,每一帧数据都存在定时器那个时间的延时。

  • 8
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
SerialPortC# 中用于串口通信的类。DataReceivedSerialPort 类中的一个事件,用于在接收数据时触发相应的操作。 当 SerialPort 对象接收数据时,DataReceived 事件会自动触发。在事件处理程序中,可以获取接收到的数据并进行相应的处理。例如,可以将数据显示在界面上,或者进行数据解析等操作。 以下是 DataReceived 事件的基本用法: 1. 创建 SerialPort 对象并设置相应的属性(如串口号、波特率等)。 2. 通过 DataReceived 事件添加事件处理程序。 3. 在事件处理程序中,使用 SerialPort 对象的 Read 方法获取接收到的数据,并进行相应的处理。 以下是一个简单的示例代码: ``` private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { // 获取 SerialPort 对象 SerialPort sp = (SerialPort)sender; // 读取接收到的数据 string data = sp.ReadExisting(); // 在界面上显示数据 textBox1.Invoke(new Action(() => { textBox1.AppendText(data); })); } ``` 在该示例中,当 SerialPort 对象接收数据时,会触发 DataReceived 事件,该事件处理程序会将接收到的数据显示在一个 TextBox 控件中。 需要注意的是,在使用 DataReceived 事件时,可能会出现数据接收完整或者丢失的情况。为了避免这种情况,建议使用 SerialPort 类中的 ReadLine 或者 ReadExisting 方法来读取数据,并根据具体情况进行相应的处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值