短期遠足
各NECプロトコルパケットは、9ミリ秒のパルスと4.5ミリ秒の一時停止という開始シーケンスで構成されています。 理論的な図面で過負荷にならないように、ロジックアナライザーからの実際のスクリーンショットを示します。
プロトコル自体は、ゼロとポーズ長のあるもののエンコードに基づいています。 各ビットの開始は、560μsの長さのパルスによって決定されます(同時に、このパルスは前のビットの終了を通知します)。 パルスに続く一時停止の長さは、ビットの論理値を決定します。 したがって、論理ゼロの合計の長さは1.12msであり、論理ユニットは2.25msです。 したがって、実際の状況では、値はわずかに異なります。
パッケージは、開始シーケンス、アドレス、およびコマンドで構成されます。 プロトコルの標準バージョンでは、アドレスとコマンドは直接形式と逆形式の両方で送信されるため、パケットの期間は常に固定です。
ボタンを押したままにすると、パッケージは再送信されません。 代わりに、11.25 msの特別な再試行コードが110 msごとに送信されます。
プログラム
必要ないので、アドレスを受け入れませんでした。 必要に応じて、プログラムを簡単に変更できます。 16 MHzクオーツを備えたATmega32がマイクロコントローラとして選択されました。 したがって、すべての時間間隔は16 MHzで計算されます。 プロトコルを実装するには、時間をカウントするタイマーと立ち下がりエッジでの外部割り込みが必要です。 タイマーは、1024の分周器、1024/16 MHzの1クロックサイクル= 64μs、64μs* 256 = 16 msのオーバーフロー割り込みで構成されます(これは明らかにパケット内のどのビットよりも大きいため、これは便利です)。
初期化および開始/停止タイマーマクロは次のようになります。
#define StopT0 TIMSK &= ~(1 << TOIE0); // #define StartT0 TIMSK |= (1 << TOIE0); // SREG|= (1<<7); //Global Interrupt Enable GICR|= (1<<INT0); // INT0 MCUCR|=(1<<ISC01)|(0<<ISC00); // TCCR0|=(1<<CS02)|(1<<CS00); // 1024, 64, 16,38 asm("sei"); //
コードはIAR環境で記述されていますが、割り込みヘッダーを置き換えることで別の環境に簡単に移植できます。
タイマーオーバーフロー割り込みは、受信を「完了する」ためにのみ必要です。 16msのオーバーフローは、プリアンブルでもビットでも、パケットのどのコンポーネントよりも大きいため、このような割り込みはパケットの終わりと見なされ、次の割り込みを受信する準備ができます。
ここで私は一つのニュアンスを持っていましたが、その説明はわかりません。 タイマーがすぐに(INT0割り込みの処理後に自動的に)開始されると、タイマーオーバーフロー割り込みがトリガーされました。 どうやって? なんで? たぶん、当時の一般的なプログラムは既に小さくなかったので、これはある種の個々のカントだったのかもしれませんが、最初の割り込みを処理せず、2番目、つまり32ms後に処理することにしました。
#pragma vector=TIMER0_OVF_vect __interrupt void TIMER0_interrupt (void) // 0 16, { if (firstT ==0) { firstT = 1; } /* , . , 32. */ else { startC = 0; // firstT = 0; // "" StopT0; // } }
INT0立ち下がりエッジ割り込み。 ここでは、ビットをカウントし、最後の中断からの経過時間を分析します。 TCNT0タイマーの値により、どのビットであったかが簡単にわかります。 ハンドラーの最後で、タイマーはゼロにリセットされ、最初からカウントダウンが開始されます。
#pragma vector=INT0_vect __interrupt void INT0_interrupt (void) { if (startC == 0) { // newC = 0; // startC = 1; // StartT0; // 0 } else { // 64, if(TCNT0>0xD2 & TCNT0<0xFF){ //13,5 ( 13,4 ... 16,3 ) i = 32; // } if(TCNT0>0x07 & TCNT0<0x16){ //1,12 ( 0,45 ... 1,41 ) if ((i>0) & (i<9)) Command1 &= ~(1<<(i-1)); // if ((i>8) & (i<17)) Command |= (1<<(i-9)); // i--; } if(TCNT0>0x19 & TCNT0<0x28){ //2,25 ( 1,60 ... 2,56 ) if ((i>0) & (i<9)) Command1 |= (1<<(i-1)); // if ((i>8) & (i<17)) Command &= ~(1<<(i-9)); // i--; } if(TCNT0>0xA9 & TCNT0<0xB8){ //11,25 ( 10,8 ... 11,8 ) newC = 1; // } if (i==0) { // StopT0; // newC = 1; // startC = 0; // firstT = 0; // "" } } TCNT0 = 0; // }
メインプログラムでは、リセットを忘れずにnewCフラグを分析します。 さて、チームのさらなる処理。
while(1) { if (newC) { // ? newC = 0; // if (Command == Command1) { // ? switch (Command) { // case 0x5F: { } //Up case 0xDF: { } //Down //........... } } } }
コマンドシステム
そして、これがED618リモートコントロールのコマンドシステムです(dx.comで購入します)。
他の同じRGBリモートの場合、コマンドシステムは異なる場合があります。 私はまったく同じリモコンを持っていますが、購入したRGBコントローラーから入手したので、コマンドシステムは非常に異なります。 自分で読んで確認してください。 たとえば、私はチームを承認し、コンピューターでUARTによってドロップしました。
アルゴリズム自体は複雑ではありません。誰かが役に立つといいのですが。 私はすでにそのようなプロトコルで複数のリモートコントロールデバイスを作成しました、すべてがうまく機能します。 次の記事では、ws2812b LEDプロトコルの実装について説明します 。