6

8051 マイクロコントローラーをコンピューターとワイヤレスで通信させています。マイクロコントローラーはシリアル ポート (DB9) に文字列を送信し、コンピューターはこの文字列を受信して​​操作します。

私の問題は、8051 に文字列を 1 回だけ送信させる方法がわからないことです。PC 側で文字列を操作する必要があるため、一度だけ受信する必要があります。現在、C コードでは文字列を 1 回送信していますが、コンピューターでは同じ文字列を継続的に受信しています。これは、SBUF にあるものが継続的に送信されるためだと思います。文字列を 1 回だけ送信する方法はありますか? SBUF を空にする方法はありますか?

DB9 の RTS (Request to Send) ピン (7 番目のピン) を使用しようとしました。そのピンの電圧を無効にすると、シリアル ポートへのデータの流れが停止することをどこかで読んだためです。そこで私がしたことは、文字列を送信するようにマイクロコントローラーをプログラムし、DB9 RTS ピンに接続された出力ピンに論理レベル 0 を送信することでした。しかし、それはうまくいきませんでした。

誰か提案はありますか?本当に感謝しています。

編集

私が PC で使用しているソフトウェアは、Xbee モジュール用の X-CTU です。これは私のマイクロコントローラのコードです:

include reg51.h 
void SerTx(unsigned char);  
void main(void)  
{  
  TMOD = 0x20;  
  TH1 = 0xFD;  
  SCON = 0x50;  
  TR1 = 1;   

  SerTx('O');  
  SerTx('N');  
  SerTx('L');  
  SerTx('Y'); 

}

void SerTx(unsigned char x)  
{  
  SBUF = x;  
  while(TI==0);   
  TI = 0;   
}  

誰かが実際に文字列を一度だけ送信していることを確認してもらえますか?

編集

Steve、brookesmoses、Neil は、問題を引き起こしているのは私の主な機能の後に起こっていることだと彼らが言ったとき、頭に釘を打ったようです。Steve が提示した提案されたコード (より具体的には for(;;); と main の外で serTX を定義する) を試してみたところ、完全に機能しました。コントローラーはおそらく再起動されるため、同じコードが繰り返されます。

助けてくれてどうもありがとう!:)

4

4 に答える 4

6

投稿したコードにはmain()にループがないため、「Y」を送信した後にmain()が戻ったときにコンパイラのCランタイムが何をするかを決定する必要があります。あなたの問題を考えると、コンパイラがクリーンアップを実行してからマイクロを再起動するためのコードを生成すると思います(ハードウェアをリセットするか、Cランタイムを再起動するだけかもしれません)。プログラムは作成したとおりに機能しているように見えますが、main()が呼び出される前後に何が起こるかを無視しています。

文字列を一度だけ送信したい場合はwhile(1) {}、最後の文字が送信された後に追加するようなものが必要です。しかし、プログラムは何もしていません。空のループを永久に実行するだけです。再開して文字列を送信するには、リセット(電源の入れ直しなど)が必要です。

マイクロにウォッチドッグタイマーがある場合、マイクロが介入して予期しないリセットを強制する可能性があることに注意してください。これが発生した場合、ウォッチドッグがリセットされるたびに文字列が1回送信されます(ハードウェアによって異なりますが、1秒に1回のようになります)。

また、serTx()をmain()内にネストして定義することは、おそらくあなたが望むものではありません。

于 2009-08-01T23:03:02.237 に答える
6

8051 が実際に 1 回だけデータを送信していることを確認できますか? チェックする 1 つの方法は、スコープを使用して、UART の TX ピンで何が起こっているかを確認することです。

PCで使用しているソフトウェアは何ですか?HyperTerminal やPuTTYなどの単純な通信ソフトウェアを使用することをお勧めします。PC に複数回送信されている文字列が表示されている場合は、8051 で実行されているソフトウェアに問題がある可能性があります。

編集:正直なところ、これはエンジニアが定期的に直面しなければならない種類のデバッグのように思えます。そのため、古き良き方法論的な問題解決を実践する良い機会です。

私が非常に率直である可能性がある場合は、次のことをお勧めします。

  1. デバッグ。試してみてください。ただし、推測しないでください。実験。コードに小さな変更を加えて、何が起こるかを確認してください。考えられることはすべて試してください。詳細については、Web を検索してください。
  2. それでも解決しない場合は、ここに戻って、必要なすべての情報を提供してください。これには、コードの関連部分、使用しているハードウェアの完全な詳細、および手順 1 で試したことに関する情報が含まれます。

編集:質問を編集する担当者がいないため、OPが彼女の質問へのコメントに投稿したコードは次のとおりです。

#include<reg51.h>

void SerTx(unsigned char);

void main(void)
{
    TMOD = 0x20; TH1 = 0xFD; SCON = 0x50; TR1 = 1;
    SerTx('O'); SerTx('N'); SerTx('L'); SerTx('Y');

    void SerTx(unsigned char x)
        { SBUF = x; while(TI==0); TI = 0; } 
}

Neil と Brooksmoses が回答で言及しているように、組み込みシステムでは、メイン関数は決して終了できません。そのため、コードを無限ループ (不注意で発生している可能性があります) に入れるか、最後に無限ループを追加して、プログラムが効果的に停止するようにする必要があります。

また、関数 SerTx は main の外で定義する必要があります。これは構文的に正しいかもしれませんが、他の関数内で関数を宣言せずに物事を単純に保ちます。

これを試してみてください (コードを理解しやすくするために、いくつかのコメントも追加しました)。

#include<reg51.h>

void SerTx(unsigned char);

void main(void)
{
    /* Initialise (need to add more explanation as to what
        each line means, perhaps by replacing these "magic
        numbers" with some #defines) */
    TMOD = 0x20;
    TH1  = 0xFD;
    SCON = 0x50;
    TR1  = 1;

    /* Transmit data */
    SerTx('O'); SerTx('N'); SerTx('L'); SerTx('Y');

    /* Stay here forever */
    for(;;) {}

}

void SerTx(unsigned char x)
{
    /* Transmit byte */
    SBUF = x;

    /* Wait for byte to be transmitted */
    while(TI==0) {}

    /* Clear transmit interrupt flag */
    TI = 0;
} 
于 2009-08-01T14:25:42.303 に答える
2

8051 コードを見ずに何が問題なのかを判断するのは困難です。たとえば、その側の論理エラーにより、データが複数回送信されたり、8051 ソフトウェアが受信されない ACK を待機している可能性があります。

通常、8051 コードでは各文字を明示的に送信する必要がありますが、これは C ランタイムによって処理されると思います。

RTS/CTS (Request To Send/Clear To Send) の使用は、フロー制御 (つまり、バッファ オーバーランを防ぐため - これらのマイクロコントローラではバッファは通常非常に小さい) のためであり、送信を完全に停止するためではありません。

于 2009-08-01T11:26:56.660 に答える
2

ニールの答えを繰り返します(コメントする担当者がまだいないので、返信で):OSのない典型的なマイクロコントローラーの状況では、main(の最後に暗黙的に呼び出されるexit()関数がすぐにはわかりません) を実行する必要があります -- または、より正確には、戻る OS がないため、通常の「プログラムを終了して OS に戻る」ことはできません。

さらに、実際のアプリケーションでは、システムの電源を切らない限り、プログラムをただ停止させたいとはほとんど思いません。したがって、exit() の実装で絶対にすべきではないことの 1 つは、大量のコード スペースを占有することです。

私が取り組んできたいくつかのシステムでは、exit() は実際にはまったく実装されていません。使用しない場合は、1 バイトも無駄にしないでください。その結果、実行パスが main() の最後に到達すると、チップはメモリの次のビットにあるものは何でも実行するララランドに迷い込み、通常はすぐにループに陥るか、ループに陥ります。不正なオペコードによる障害。そして、不正なオペコードによる障害の通常の結果は...チップを再起動することです。

これは、ここで起こっていることのもっともらしい理論のように思えます。

于 2009-08-02T00:16:20.230 に答える