C# 串口通信 查找帧头算法,if版

串口通信通常会需要判断帧头.


byte[] headbyte = new byte[]{0x5F,0x5F,0xF5,0xF5};
/// <summary>
/// 查找帧头, if版
/// </summary>
/// <param name="serialPort"></param>
/// <returns></returns>
public void ReadToPackHead(SerialPort serialPort)
{
    while (true)
    {
        if (serialPort.ReadByte() == headbyte[0])
        {
            if (serialPort.ReadByte() == headbyte[1])
            {
                if (serialPort.ReadByte() == headbyte[2])
                {
                    if (serialPort.ReadByte() == headbyte[3])
                    {
                        break;
                    }
                }
            }
        }
    }
}

不得不说, 这个版本看上去有点傻, 但是从容易理解的角度来讲, 比起while 循环要好的太多了. 一般我们在设计帧头方面, 一般不会太过长的.

如果你更加喜好 循环版, 那么代码如下.

 // 查找帧头 , 循环版, 这个看起来就不是那么容易理解了
 public int ReadToPackHead(SerialPort serialPort)
 {
     int h = 1;
     while (h < serialPort.BytesToRead)
     {
         if (serialPort.ReadByte() == headbyte[0])
         {
             bool ishead = true;

             while (h < headbyte.Length)
             {
                 if (serialPort.ReadByte() == headbyte[h])
                 {
                     h++;
                 }
                 else
                 {
                     ishead = false;
                     break;
                 }
             }
             if (ishead)
             {
                 break;
             }
         }
     }
     return h;
 }

串口读取数据的主代码

if(serialPort.IsOpen ==false)
{
     serialPort.Open(); 
     Thread.Sleep(200);
 }

// 现在发送的命令返回的数据, 下次才能读取到.
 serialPort.Write(cmdGetData, 0, cmdGetData.Length);
 Thread.Sleep(500);
 

//找到起始帧
ReadToPackHead(serialPort);
//然后开始读取数据长度帧
byte[] lenbytes = new byte[2];
serialPort.Read(lenbytes, 0, 2);
int onePackLength = BitConverter.ToUInt16(lenbytes, 0);// 16位的数据, 按照8位发的所以需要*2
//pindex = pindex + 2;

Console.WriteLine("本包数据长度" + onePackLength);
//然后循环读取数据, 直到全部读取完整. 如果是小包的数据, 例如20个以下的, 会比较简单.
//但是如果数据量比较大, 则一次无法完全读取完毕所以应该要写入到buffer中然后进行合并.
byte[] onePackBuffer = new byte[onePackLength];
int newDataIndex = 0;

//这里使用循环的原因是, 串口的速度比较慢, 需要等串口把指定长度的数据都传过来之后再进行后续的处理.
while (newDataIndex < onePackLength)
{
    if (serialPort.BytesToRead == 0)
    {
        continue;
    }
    serialPort.Read(onePackBuffer, newDataIndex, onePackLength);
    newDataIndex = newDataIndex + serialPort.BytesToRead;
    Thread.Sleep(1);
}
              
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基本串口设置 串口设置:选择使用的串口号,可以通过“查找” 按钮自动查询当前系统可用串口。 波特率设置:输入将要使用波特率。 检验位设置:O=ODD=奇校验,E=EVEN=偶检验,N=无校验 10/16进制选择:当勾选后,接收缓冲区将以16进制数据格式显示,发送缓冲区数据必须是16进制格式,点击“发送”按钮时,将以16进制格式发送。否则(未勾选时),将以发送缓冲区将ASCII码的形式显示,点击“发送”按钮时,将以ASCII码直接发送。 打开串口:按配置打开相应串口,同时使能其他可能使用串口的按钮,再次点击则失能其他可能使用串口的按钮(如果未打开串口点击串口发送相关按钮会出现异常,另,修改串口基本设置后需要重新打开串口一次才会生效)。 帮助:即打开本文档 其他:略 简单通讯协议 界面操作说明 本协议将每数据数据分为H,长L,参数P,数据D,校验C,尾E这6大部分,其中每个字段是否使用和使用的字节长度均可以选择或设置。格式设定: H字段:以16进制直接写入,软件自动计算所占字节数,将存入变量H1、H2、H3……的格式中。 长L字段:以16进制直接写入,设置长所占字节,然后软件自动计算长,并将存入变量L1、L2、L3……的格式中。 参数P字段:以16进制直接写入,软件自动计算参数所占字节数,将存入变量P1、P2、P3……格式中。 数据D字段:这里只选择数据所占的字节数,数据的内容在后面的Dt框中填入,并将数据存入到变量Dt中。 校验C字段:这里只选择校验所占的字节数,校验的方式按后面的公式计算而来。C1、C2、C3…… 尾E字段:以16进制直接写入,软件自动计算尾所占字节数,将存入变量E1、E2、E3……格式中。 公式说明的使用方法 变量:上述字段中的H1、H2、H3……、L1、L2、L3……、P1、P2、P3……、Dt、C1、C2、C3……、E1、E2、E3……即为公式的变量名称; 立即数:操作立即数以2位16进制数,立即数中的字母必须小写。 操作符:目前只支持+(加)、-(减)、*(乘)、/(除)、&(与)、|(或)、~(非)、^(异或)、@(循环)操作,其中~(非)操作的前面变量或立即数无效; 结果变量:公式的结果存入到F1、F2、F3……变量中,同时可以供下一个公式可以使用; 结束符:整个公式以’;’号结尾,最后一次使用的结果变量将成为最终的运算结果投入到串口的使用; 注意: 操作符与结束符占1字节,其余均为2字节,整个公式必须有9字节并严格按照格式进行输入,否则软件无法正确识别; 变量名必须大写,16进制数必须小写,变量名只支持上述字段中的名称且序号不得超过10个,否则会出错; 中间不能插入空格; 举例:比如,在Dt字符框中输入100; 执行F1=Dt+00;F2=F1+00;表示F1=100;F2=100;最后输出F2的值100。 执行F1=Dt+10;F2=F1+20;表示F1=116;F2=148;最后输出F2的值148。 执行F1=Dt*10;F2=F1+00;表示F1=116;F2=148;最后输出F2的值148。 执行F1=Dt+00;F2=F1*0a;F1=01@F2;表示从F1开始按步进01循环发数据到F2为止,即for(i=100;i<1000;i+=1)类似的循环,发送的数据=i;循环操作目前还有待完善,不建议使用。 校验公式与此是一样的操作,但@后表示选择程序集成的特殊协议如Modbus协议。 @01表示Modbus协议,代码略 @02表示CRC-CTII协议,代码如下: U16 Crc16_B(u8 *puchMsg, u16 usDataLen){ U8 aCRCHi[256]= {0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,……,0xC1,0x81,0x40}; U8 aCRCLo[256] ={0x00,0xC0,0xC1,0x01,0xC3,0x03,0x02,0xC2,0xC6,0x06,……,0x81,0x80,0x40}; U8 uIndex,uchCRCHi=0xff,uchCRCLo=0xff; while(usDataLen--){ uIndex=uchCRCHi^*puchMsg++; uchCRCHi=uchCRCLo^aCRCHi[uIndex]; uchCRCLo=aCRCLo[uIndex]; } return (uchCRCHi<<8|uchCRCLo); } @03~FF保留未使用 Setting.ini配置文件 不同的使用者可能会对协议作频繁的改动,为了减少许多重复工作量,所以在左边设计了下拉菜单,选择经常使用的通讯协议配置,但即使
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值