1. 程式人生 > >串列埠接收一幀資料及解析

串列埠接收一幀資料及解析

3. 下位機中的資料接收和協議解析
    下位機接收資料也有兩種方式,一、等待接收,處理器一直查詢串列埠狀態,來判斷是否接收到資料。二、中斷接收。兩種方法的優缺點在此前的一篇關於串列埠通訊的文章中詳細討論過。得出的結論是採用中斷接收的方法比較好。
    資料包的解析過程可以設定到不同的位置。如果協議比較簡單,整個系統只是處理一些簡單的命令,那麼可以直接把資料包的解析過程放入到中斷處理函式中,當收到正確的資料包的時候,置位相應的標誌,在主程式中再對命令進行處理。如果協議稍微複雜,比較好的方式是將接收的資料存放於緩衝區中,主程式讀取資料後進行解析。也有兩種方式交叉使用的,比如一對多的系統中,首先在接收中斷中解析“連線”命令,連線命令接收到後主程式進入設定狀態,採用查詢的方式來解析其餘的協議。
    以下給出具體的例項。在這個系統中,串列埠的命令非常簡單。所有的協議全部在串列埠中斷中進行。資料包的格式如下:
0x55, 0xAA, 0x7E, 0x12, 0xF0, 0x02, 0x23, 0x45, SUM, XOR, 0x0D
    其中0x55, 0xAA, 0x7E為資料幀的幀頭,0x0D為幀尾,0x12為裝置的目的地址,0xF0為源地址,0x02為資料長度,後面接著兩個資料0x23, 0x45,從目的地址開始結算累加、異或校驗和,到資料的最後一位結束。
    協議解析的目的,首先判斷資料包的完整性,正確性,然後提取資料型別,資料等資料,存放起來用於主程式處理。程式碼如下:
if(state_machine == 0)       // 協議解析狀態機
{
      if(rcvdat == 0x55)       // 接收到幀頭第一個資料
          state_machine = 1;
      else
          state_machine = 0;      // 狀態機復位
}
else if(state_machine == 1)
{
      if(rcvdat == 0xAA)       // 接收到幀頭第二個資料
          state_machine = 2;
      else
          state_machine = 0;      // 狀態機復位
}
else if(state_machine == 2)
{
      if(rcvdat == 0x7E)       // 接收到幀頭第三個資料
          state_machine = 3;
     else
          state_machine = 0;      // 狀態機復位
}
else if(state_machine == 3)
{
      sumchkm = rcvdat;       // 開始計算累加、異或校驗和
      xorchkm = rcvdat;
      if(rcvdat == m_SrcAdr)      // 判斷目的地址是否正確
          state_machine = 4;
      else
          state_machine = 0;
}
else if(state_machine == 4)
{
      sumchkm += rcvdat;
      xorchkm ^= rcvdat;
      if(rcvdat == m_DstAdr)      // 判斷源地址是否正確
          state_machine = 5;
      else
          state_machine = 0;
   }
else if(state_machine == 5)
{
      lencnt = 0;            // 接收資料計數器
      rcvcount = rcvdat;        // 接收資料長度
      sumchkm += rcvdat;
      xorchkm ^= rcvdat;
      state_machine = 6;
}
else if(state _machine == 6 || state _machine == 7)
{
      m_ucData[lencnt++] = rcvdat;     // 資料儲存
      sumchkm += rcvdat;
      xorchkm ^= rcvdat;
      if(lencnt == rcvcount)      // 判斷資料是否接收完畢
          state_machine = 8;
      else
          state_machine = 7;
}
else if(state_machine == 8)
{
      if(sumchkm == rcvdat)      // 判斷累加和是否相等
          state_machine = 9;
      else
          state_machine = 0;
}
else if(state_machine == 9)
{
      if(xorchkm == rcvdat)      // 判斷異或校驗和是否相等
          state_machine = 10;
      else
          state_machine = 0;
}
else if(state_machine == 10)
{
      if(0x0D == rcvdat)       // 判斷是否接收到幀尾結束符
      {
          retval = 0xaa;    // 置標誌,表示一個數據包接收到
      }
      state_machine = 0;     // 復位狀態機
}

    此過程中,使用了一個變數state_machine作為協議狀態機的轉換狀態,用於確定當前位元組處於一幀資料中的那個部位,同時在接收過程中自動對接收資料進行校驗和處理,在資料包接收完的同時也進行了校驗的比較。因此當幀尾結束符接收到的時候,則表示一幀資料已經接收完畢,並且通過了校驗,關鍵資料也儲存到了緩衝去中。主程式即可通過retval的標誌位來進行協議的解析處理。
    接收過程中,只要哪一步收到的資料不是預期值,則直接將狀態機復位,用於下一幀資料的判斷,因此係統出現狀態死鎖的情況非常少,系統比較穩定,如果出現丟失資料包的情況也可由上位機進行命令的補發,不過這種情況筆者還沒有碰到。