シリアル・データ・フレーム同期

シリアル・データ・フレーム同期

入門

シリアルは、あなたが私たちは、マイクロコントローラを使用する方法とシリアルポートで、その結果、シリアルデータを処理する必要がありますが、PCベースの緩衝機構のシリアルポートのすべての時間が異なる場合があり、非常に一般的なリソースである
各データ・バッファを取得した後、ヘッダか否かを判断し、データストレージの新たなカウントを開始した後、データは、最終的には、データ伝送を満たしています。

原則

私たちは、彼らのストレージの結果として、独自のストレージの結果を使用し、データフレームの長さは、一般的に使用されているプロジェクトと一致している、私たちのプログラムは、この原理に基づいています

class SerialData
{
    public:
    uchar *data_;   ///< 帧数据
    uchar *head_;   ///< 帧头数据
    int dat_len_;   ///< 数据帧长度
}

我々はデータを想定し、それらのプロトコルに従って、ヘッダとコンテンツデータのデータ長を初期化する必要があるが、典型的には14バイトであって、送信の形式に応じて行われるシリアル通信を用いてデータ、

[ヘッダー] [長さ] [住所] [コマンド] [データ] [チェックサム]
00 01 02 03 04 05 06 07 08 09 12 13である10 11
68 00 84 0D 00 04 09 00 81 13 45 79 11 01

frame_len = 14;
data_ = new uchar[frame_len];               ///< 存储数据
head_ = new uchar[4]{ 0x68,0x0D,0x00,0x84 }; ///< 旧版协议头

実際に、我々は、通信プロトコルを決定し、コマンドを解析するようなPCまたは、最初の4つのバイトがヘッダを処理することができ、存在しない
たびに4つのヘッダは、既に再開指示受信データのバイト収集されたデータは、後続のデータの処理を続行するために、対応するプロセスに格納することができます

  1. データが正常であれば、配列がいっぱいになるまでバック充填データに続いて、同じヘッダデータを想定し、ヘッダデータを読んだ後、あなたはヘッダデータを再度取得します
  2. 前のフレームの状態コード、値が4つの満たすヘッダデータを満たすように設定されている場合、現在の値を決定し、処理後続バイト
  3. ターン比較データとヘッダ配列では、使用位置$は$ヒットが記録されている、とされていない場合、ゼロは、次回も開始flg_status、
  4. 決定に対応する各4バイトの後に、$が蓄積する$ 4 flg_status、データのためのこの時間は、結果に応じて、現在のデータフレームの値は、キューに押し込まれるチェック
  5. 以上方法会导致第一帧校验失败,但是后续的帧处理结果可以保证不会出现问题, 相当于将四个字符作为了帧尾处理
    static int data_cnt = 0;
    static int flg_status = 0;  // 0 普通数据,与数据头1 比较, 1 数据头1,2 数据头2, 3 数据头3,
                                // 每次将缓冲区 数据全部读出来,
                                // 判断上一帧读取到了什么状态, 数据分为 前4个字节的帧头数据和 后面的数据
                                // 1.读取到了帧头 // 2. 读取到了一般数据帧
                                // 每次计数, 读取到帧头的时候, 判断数据是否已经满了, 已经满了进行数据校验, 满足就加入数据
                                // 数据未满, 则可能数据未满, 
    QByteArray recv = serial_->readAll();   // QSerial  读取的数据类型是 QByteArrray
    int N = recv.size();
    if (recv.isEmpty())
    {
        Sleep(5);   // 休眠5毫秒
        LError("recv data is empty");
        return false;
    }
    // 遍历得到的数据数组
    for (int i = 0; i < N; i++)
    {
        uchar tmp = char2uchar(recv[i]);

        // 每次来了数据与上次的置位比较, 如果一致, 比较后一位, 
        //  如果前面4位都一致,表示已经开始了新的一帧, 将数据依次复制
        //    如果数据已经满足帧头, 将之前的数据 校验满足之后加入队列中, 其他线程处理
        if (tmp == m_Frame.head_[flg_status])
        {
            flg_status++;
            if (flg_status == 4)
            {
                // 由于存在每次存入数据的时候存在上一帧的数据 问题 所以这里校验可能失败
                m_read_queue_->Push(m_Frame);
                // 更新前面4个字节的帧头数据
                for (int i = 0; i < 4; i++)
                    m_Frame.data_[i] = m_Frame.head_[i];
                // 匹配重新置零, 同时将数据前面数据复制过去
                flg_status = 0;
            }
        }
        else
        {
            flg_status = 0; // 如果前面的匹配上了, 后面匹配不上, 则重新开始进行匹配
        }
        m_Frame.data_[data_cnt++] = tmp;    // 移动指针, 将数据存储到数组中
        // 超过设定值, 减去一个长度,避免越界  // 与取与操作 % 处理一致 
        // 重新开始的位置 从可以刷新的数据开始
        if (data_cnt == m_Frame.dat_len_)
            data_cnt = 0;
    }

更多

这个程序是自己目前在使用的方法,简单有效, 适用于串口通信的数据处理,十分好用, 这个算是项目文档 的一部分,后续可能再拓展, 但是基本框架不变, 测试起来也很好用

自己测试过程可以使用 VSPD虚拟串口 6.9 汉化版 模拟出来两个相连的串口,初始设置一下就好, 然后使用普通的串口调试软件打开两个串口即可进行通信,十分方便,

参考链接

おすすめ

転載: www.cnblogs.com/hugochen1024/p/12570783.html