7.パケット取得開始タイミングの決定(タイマ1)


7.1. 基本概念

シリアル通信では多くの場合、スタートビットにより通信開始を相手側に知らせます。RS232Cでは、連続したHレベルに続いて、1bitのスタートビット(Lレベル)から通信が始まります。DCCでは14個以上のプリアンブル(1)で予告しておいて、スタートビット(0)の後からデータを流します。

 一方、MMプロトコルではパケットの開始を示すスタートビットのたぐいがありません。そこで、パケット取得のタイミングを何らかの方法で決める必要があります。各パルス間のLレベルの間隔に注目すると、次の図に示すように4種類の間隔があることがわかります。


Lレベルの間隔

 パケット中での間隔は192.5 μsまたは27.5 μsと短い間隔であるのに対し、ダブルパケット中のパケット間では約1.35 ms、ダブルパケットどうしの間隔は4 ms以上となっています。したがって、この間隔が約1.35 ms, または4 ms以上の場合にパケット取得を開始すれば良いことになります。また、この間隔の違いによりダブルパケットの一番目のパケットか、二番目のパケットかを判別することもできます。以上の記述は機関車向けのパケットについて述べたものですが、アクセサリ向けの場合には時間はすべて1/2となります。

7.2. タイマ1を使ったパルス幅計測

そこで、各パルス間の間隔を測定します。この間隔は単純にパルスの立ち下がりでタイマをスタートさせて、次のパルスの立ち上がりでタイマを止めれば測定できるはずです。また、PIC12F1822のタイマ1にはゲート機能があるので、入力ピンRA4(RXPINと定義)がLowの条件でのみカウントさせるようにもしています。(これは必要ないかもしれません。)
 RA4(RXPIN)の状態変化(IOCIF, IOCAF4)で割り込みをかけます。割り込み関数では、立ち下がりの場合にはカウンタレジスタ(TMR1H, TMR1L)をリセットしてタイマ1(TMR1ON)をスタートさせます。立ち上がりの場合は、タイマ1を止めてカウンタレジスタを他の変数(TMH, TML)に退避させます。


間隔の測定

 メイン関数では、パルスが立ち上がりの場合にTMHの値によりパルスの間隔を評価します。ここはおおよその値でも問題ないので、カウンタの下位8bitは無視しています。TMHが0の場合はパケット中のパルスとして読み飛ばします。実測よりダブルパケット中の間隔は約750 μs以上なのでTMHは2,3,4(1024 μs-512 μs)、ダブルパケット間の間隔は、約1500 μs以上でTMHは5(1280 μs)以上としました。TMHが最長の場合は一番目のパケットを取得し、データを他の変数に退避させます。TMHが中間の場合は二番目のパケットなのでパケットを取得し、退避させていたデータと比較します。これらが一致すれば、パケットの取得に成功しているので、アクセサリ用パケットであることを確認、アドレスを比較します。自分に向けたものであれば、信号機を動かし、現在の信号機の状態(赤か緑か)をEEPROMに書き込みます。パケットの取得については次章で述べます。
 なお、クロック8 MHz、プリスケーラ1/8の条件ではタイマ1の1カウントは1 μsに相当します。

7.3. プログラミング

割り込み処理では、RXPINの状態変化割り込みにより、各パルスの間隔を測定します。メイン主要部は信号機処理のほとんどが記述されています。まだ、説明していない部分もありますが、流れはおおよそわかると思います。


割り込み部

  if(IOCAF4 == 1){ //RA4が状態変化した場合
    if(RXPIN == 0){ //パルスの立ち下がりでは
      Packet_N=0; //mainでパケットを取得しない
      TMR1L = 0; //タイマ1を初期化してタイマ1スタート
      TMR1H = 0;
      TMR1ON = 1;
    }
    if(RXPIN == 1){ //パルスの立ち上がりでは
      Packet_N=1; //mainでパケット取得の可能性(TMHの値による)
      TMR1ON = 0; //タイマ1停止
      TMH=TMR1H;  //lowレベルの長さのおおよその値を取得
    }
    IOCAF4=0; //RA4状態変化フラグをクリア
  }



メインの主要部

  if(Packet_N == 1){ //パルスの立ち上がりならば
    IOCIE=0; //とりあえず状態変化割り込みを禁止
    if(TMH >= 5){ //Lowレベルが最長の場合、一番目のパケットを取得
      Get_Packet(); //パケット取得
      DataA1=DataA; //一番目のパケットデータを退避
      DataF1=DataF;
      DataD1=DataD;
    }
    else{
      if((TMH > 1)&&(TMH < 5)){ /*二番目のパケット取得
                         そうでなければパケット中なので読み飛ばし*/
        Get_Packet(); //パケット取得
        if((DataA==DataA1)&&(DataF==DataF1)&&(DataD==DataD1)){
        /*ダブルパケットが一致するか?*/
          if(DataF == 0){ //ソレノイド用のアドレスか?
            Data_Adr = DataD & 0b00111100;
            //データ部のアドレス部分を抽出
            if((DataA==My_AdrH)&&(Data_Adr==My_AdrL)){
            /*自分のアドレスか?*/
              Activate_Signal();//信号機を動かす
              Previous_State = DataD&0b00000011;
              //EEPROMに信号の状態を書き込む
              if(Previous_State == 0)
                eeprom_write(2,0); //赤
              else
                eeprom_write(2,1); //緑
              }
            }
          }
        }
      }
      IOCIE=1; //状態変化割り込み許可:タイマ2は停止:割り込みは状態変化のみ
    }
  }



6.テスト用回路 TOP pageへ 8.パケット取得(タイマ2)
inserted by FC2 system