7日間のクイックスタートZigbee:カスタム通信プロトコル設計の基礎

7日間のクイックスタートZigbee:カスタム通信プロトコル設計の基礎



左上隅“关注”クリックして、 Zigbeeの最新情報を定期的に更新してください。必要な情報が常にあります!

目次

  1. 概要概要
  2. シリアル通信のデータフレーム構造
  3. 有限状態マシンに基づくフレーム同期方法

1。概要

  シリアル通信は、マイクロプロセッサやDSPなどの組み込みシステム間、および組み込みシステムとPCまたはワイヤレスモジュール間で非常に重要で一般的に使用される通信方法です。組み込みシステムのハードウェア構造では、通常、8ビットまたは16ビットのCPUしかなく、メインプロセスを完了するだけでなく、いつでも発生するさまざまな割り込みを処理します。したがって、組み込みシステムのシリアル通信プログラムの設計とPCは非常に異なります。組み込みシステムの割り込みサービスサブルーチンがシステムの動作中に多くの時間を占める場合、割り込みサービスサブルーチンの実行中に同じタイプまたは他のタイプの別の割り込みが生成され、メインプログラムが取得する可能性があります。実行の失敗またはその後のデータ損失の中断およびその他の問題。したがって、組み込みシステムでのシリアル通信は単純に見えますが、シリアル通信プロセスでのフレーム同期など、検討する価値のある問題がまだたくさんあります。
  この記事では“基于有限状态机的帧同步方法”、シリアル通信の同期を迅速かつ効果的に実現でき、プログラム構造が明確で、保守が容易で、他のシリアル通信プロトコルへの移植が容易なすべての人に推奨します。

2.シリアル通信のデータフレーム構造

  現在のシングルチップマイクロコンピュータシステムでは、機能を共同で完了するために、複数の独立した制御モジュールが必要になることがよくあります。さまざまなモジュールが、シリアルポート、RS232、SPIなどのさまざまな通信インターフェイスを介して通信できます。通信プロセスでは、システムの信頼性と安定性を向上させるためにいくつかの通信プロトコルを追加できます。特定の通信プロトコルを完成させるために、特定の同期メカニズムが必要です。以下では、組み込みシステム通信プロセスにおけるフレーム同期方法を分析および説明するために、簡略化された通信データフレーム構造を紹介します。
シリアルポートによって送信されるデータフレーム構造は次のとおりであると想定します。

フレームヘッダー フレームの長さ フレームタイプ フレームデータ 小切手

その中で:“帧头”同期に使用されます。通常は1バイト以上です。この記事では、データフレーム同期ヘッダーが2バイト(0xFE、0xEF)であると想定しています。これ“帧长度”は、「フレームヘッダー」と「フレーム長」を除くデータパケットのバイト数を意味します。、つまり、「フレームタイプ」、「フレームデータ」、および「チェック」の全長“帧类型”、通信プロトコルで指定されたコマンドタイプ、“帧数据”送信する必要のある主な情報“校验”、単純なシングルバイトの「排他的OR」メソッドを使用できます。より複雑な点につ​​いては、「CRCチェック」を使用できます。

3.有限状態マシンに基づくフレーム同期方法

  「有限状態マシンに基づくフレーム同期方式」について説明します。この方式では、データフレームの受信プロセスを「受信フレームヘッダーHEAD1状態」、「受信フレームヘッダーHEAD2状態」、「受信」のいくつかの状態に分割します。 「フレーム長ステータス」、「受信フレームタイプステータス」、「受信データステータス」、「受信チェックサムステータス」。システムの初期状態は「受信フレームヘッドHEAD1状態」であり、受信状態間の状態遷移図を下図に示します。シリアルポート受信が新しいデータの受信を中断するため、システムの受信状態は、HEAD1→HEAD2→LEN→TYPE→DATA→CHECKになります。この方法でも迅速かつ効果的に同期を実現しますが、毎回データの完全なフレームを受信した後、システムの受信状態をHEAD1にリセットする必要があります。そうしないと、次のフレームのデータ受信に影響します。 。
ここに写真の説明を挿入
  その後、プログラムはプロトコルに従って、データフレーム長、コマンドタイプ、データ、およびチェックビットの受信を開始します。受信後、システムの受信状態をHEAD1にリセットし、同時にデータフレームを確認してください。検証が正しければ、メッセージメカニズムを使用して、データフレームを処理するか、コマンドタイプに応じて対応するコマンド操作を実行するようにメインプログラムに通知します。
このメソッドCC2530裸机のサンプルプログラムを以下に示します

#include "iocc2530.h"

#define TRUE    1
#define FALSE   0
// 状态机状态
#define HEAD1   0x00
#define HEAD2	0x01
#define LEN     0x02
#define TYPE	0x03
#define DATA	0x04
#define CHECK	0x05
// 命令
#define COMMAND1 0x01
#define COMMAND2 0x02

// 状态机用到的全局变量
unsigned char g_datrev[48];				// 串口数据缓存
unsigned char g_cmd;					// 接收的命令
unsigned char g_recok;					// 串口事件标志位
unsigned char g_recstate = HEAD1;       // 接收状态
unsigned char g_len = 0;                // 已接收的数据长度
unsigned char g_check_sum = 0;          // 校验和
unsigned char g_lentotal = 0;           // 包长

void main(void)
{
    
    
  // 初始化程序
  
  
  // 任务轮询
  while(1)
  {
    
    
    // 有新的事件发生
    if(g_recok==TRUE)
    {
    
    
      // 清除串口事件标志位
      g_recok = FALSE;
      // 处理命令
      switch(g_cmd)
      {
    
    
        case COMMAND1:
          {
    
    
            // 处理命令1
            
          }
          break;
          
        case COMMAND2:
          {
    
    
            // 处理命令2
            
          }
          break;
          
        default:
          break;
      }
    }
  }
}

// 串口0中断处理函数
#pragma vector = URX0_VECTOR
__interrupt void UART0_ISR(void)
{
    
    
  // 接收串口数据
  unsigned char recdata = 0;
  // 清中断标志
  URX0IF = 0;
  
  // 接收串口0数据
  recdata = U0DBUF;
  // 进入接收状态机
  switch(g_recstate)
  {
    
    
    case HEAD1:
    {
    
    
      // 如果接收到HEAD1的值0xFE,则进入状态HEAD2
      if(recdata==0xFE)
      {
    
    
        g_recstate = HEAD2;
      }
    }
    break;
    
    case HEAD2:
    {
    
    
      // 如果接收到HEAD2的值0xEF,则进入状态LEN接收帧数据长度
      if(recdata==0xEF)
      {
    
    
        g_recstate = LEN;
      }
      // 如果接收到的还是HEAD1的数据0xFE,则不跳转,等待下一个数据
      else if(recdata==0xFE)
      {
    
    
        g_recstate = HEAD2;
      }
      // 如果没有接收到HEAD1或HEAD2的数据则返回HEAD1状态重新再来
      else
      {
    
    
        g_recstate = HEAD1;
      }
    }
    break;
    
    case LEN:
    {
    
    
      // 将状态机指向下一个状态“TYPE”
      g_recstate = TYPE;
      // 接收帧数据长度
      g_lentotal = recdata;
      // 异或校验,先校验“HEAD1”和“HEAD2”
      g_check_sum = 0xFE^0xEF;
    }
    break;
    
    case TYPE:
    {
    
    
      // 将状态机指向下一个状态“DATA”
      g_recstate = DATA;
      // 接收帧命令数据
      g_cmd = recdata;
      // 校验命令数据
      g_check_sum = g_check_sum ^ recdata;
      // 将下一状态要用的“g_len”先清零
      g_len = 0;
    }
    break;
    
    case DATA:
    {
    
    
      // 将接收到的帧数据存储在数据缓存数组中
      g_datrev[g_len] = recdata;
      // 校验帧数据
      g_check_sum = g_check_sum ^ recdata;
      // 记录接收了多少字节数据
      g_len++;
      // 接收总帧长度的数据后转向“CHECK”状态校验整个帧是否正确
      if(g_len>=g_lentotal)
      {
    
    
        g_recstate = CHECK;
      }
    }
    break;
    
    case CHECK:
    {
    
    
      // 检测接收到的帧数据是否正确,正确则通知主函数有新的事件;错误则抛弃此帧,重置状态机
      if(g_check_sum==recdata)
      {
    
    
        g_recok = TRUE;
      }
      g_recstate = HEAD1;
    }
    break;
    
    default:
    {
    
    
      g_recstate = HEAD1;
    }
    break;
  }
}

  ステートマシンとメッセージメカニズムの構造の結果として、上記の設計アイデアはシリアル通信の同期を迅速かつ効果的に実現し、プログラム構造は明確で、保守が容易で、他のシリアル通信プロトコルへの移植が容易です。さらに、シリアルポート割り込みサービスルーチンで処理する作業が非常に少ないため、割り込みサービスプログラムを受信するためのシリアルポートへの圧力が大幅に軽減され、組み込みシステムの限られたリソースと需要の間の矛盾が緩和され、組み込みシステムの安定性が向上します。
あなたのサポートは、テクノロジーを共有する私の動機です。それを再印刷する必要があるときに、元の著者のブログを添付できることを願っています:https//blog.csdn.net/u012993936、ありがとう。



- - 終わり - -
あなたも見たいかもしれません:

>高度なZigbee:汎用モジュール
>無料のZigbeeキャプチャアーティファクト!Ubiquaよりも使いやすいです!


文章都看完了,随手点个赞吧~
ここに写真の説明を挿入
↓↓↓ ↓↓↓

おすすめ

転載: blog.csdn.net/u012993936/article/details/88051118