2011-01-28 6 views
3

私はシリアル通信方式を書いていると再発する問題が発生し始めています。これはタイミングが原因であるようです。私の組み込みプラットフォームはRabbit Semiconductor BL2600です。この場合、RS232のデバイスと通信しています。デバイスにコマンドを送信すると、デバイスはBL2600に返信を返し、処理されます。組み込み機器で堅牢なRS232シリアル通信方式を作るには?

私の問題は、私がコマンドを送信してから応答を待つと、私は問題を起こさないということです。しかし、私が適切な場所にブレークポイントを設定し、コードを一歩進めると、しばしば応答が得られます。私はコンピュータをBL2600とデバイスの間に置いて、(最初の問題を見た後に)RS232ストリームをリッスンし、ブレークポイントかどうかにかかわらず応答が送信されますが、BL2600はバッファ内にしか見えません私がコードを解析して、そのスタートビットを見つけようとする部分の直前で止まったら、後で文字列全体を読み込んだときにブレークポイントを設定しても、それを見つけることはできません。

私は十分待っているようには思えません。ちょうどばかげて、バッファを1秒間チェックするためのタイムアウトを設定しました(38400のボーレートで、私はブレークポイントとシングルステップがなければ何も得られません。以下は

私のコードの重要な部分である:

//clear the buffers 
serCwrFlush(); 
while(serCwrUsed()) 
{ 
    ; 
} 
startwait = MS_TIMER; 
while((serCrdUsed() > 1) && (device_timeout_check < 1000)) 
{ 
    if (MS_TIMER < startwait) 
    {         // fix the rollover 
    device_timeout_check = MS_TIMER + (ULONG_MAX - startwait); 
    } 

    else 
    {         //set it like normal 
    device_timeout_check = MS_TIMER - startwait;  
    } 

    serCrdFlush(); 
} 
serCputs("mpcal=d\r");  //This is what requests the response from the device 
while(serCwrUsed()) 
{ 
    ; 
} 
startwait = MS_TIMER; 
while((serCrdUsed() < 11) && (device_timeout_check < 1000)) 
{ 
    if (MS_TIMER < startwait) 
    {      // fix the rollover 
    device_timeout_check = MS_TIMER + (ULONG_MAX - startwait); 
    } 
    else 
    {      //set it like normal 
    device_timeout_check = MS_TIMER - startwait;  
    } 
} 
//grab it 
temp=serCpeek(); 
i=0; 
     //It expects a response like "H0V0M00.0 /r" 
     //So I am looking for the first character. 
while((temp != 'H') && (i<100)) 
{ 
    serCgetc();  //breakpoint works here 
    temp=serCpeek(); 
    i++; 
} 
c=serCread(comp_cal_string,20, 20); //breakpoint doesn't work here 

私は、車輪を再発明して、誰かが、おそらくそう、少なくとも別のプラットフォーム上で、私の前にこれを行っていることだという気持ちを持っていますデータが受信されるのに十分な長さであるが、実際にデータを捕捉するのに十分なほど速いことがわかる。

+0

オシロスコープで信号を見ましたか?適切な範囲なしでは、このようなことはできません。 UART回線に不具合などがある場合、誤入力が発生している可能性があります。常に、実際の信号がコード内で掘り下げられる前に確認されていることを確認することから始めます。 – Lundin

答えて

3

割り込み駆動型RS-232通信を使用していない理由はありますか?通常、何が起こるかは、RS-232回路からのエッジ遷移で割り込みがトリガされ、それを処理する割り込みサービスルーチン(ISR)を設定します。つまり、割り込みはハードウェアなので、常に情報を処理します駆動される。 RS-232回路のパルスの場合、あなたのポーリングループ(上記)が見えないだけの短さになることがあります。

、ここで説明したように、あなたのBL2600が同じデバイスの場合:

http://ftp1.digi.com/support/documentation/019-0113_N.pdf

は、マニュアルのリストは、デバイス上のすべての4つのシリアルポートのためのベクターを割り込むこと - またページ476

にsetVectInternを参照してください、古いRS-232回路は16バイトの内部バッファしかサポートしていませんでした。ボーレートを上げるには、BL2600のDMA機能を使用する必要があります。 (DMA機能は、メモリからシリアルポートへの大きなデータブロックの転送を自動化する必要があります。)

2

堅牢性の鍵はエラー処理です。

タイムアウトが発生する可能性のあるループは2つありますが、タイムアウトが発生しても何も変わりません。戻り値のエラーがチェックされていない関数への呼び出しがあります。エラーを処理しないコードは決して堅牢ではありません。その値がループ内で設定される前にdevice_timeout_checkの値がテストされ

  • タイムアウトループはあなたの読書に影響を与える可能性の三つの方法で分割されます。

  • MS_TIMERは揮発性であり、テストされてから計算するまでに変更される可能性があります。device_timeout_check
  • タイムアウトが発生しても何も行われません。 unsigned long startwait;

は、最初のロールオーバー問題を回避するためにstartwaitの宣言を変更し、これらの問題を修正するには。そして、このようなタイムアウトループを実装します。device_timeout_checkはあなたのコードに達したときに999よりも大きい場合

startwait = MS_TIMER; 
do { 
    device_timeout_check = (MS_TIMER - startwait >= 1000); 
} while((serCrdUsed() > 1) && !device_timeout_check); 

if (device_timeout_check) { 
    /* Handle the timeout error here */ 
} 

これは、問題を解決します。

ループに最初の 'H'文字を検出しようとすると、別の問題が発生します。それ以前のコードでは11文字しか使用できません。検出ループは100回実行されますが、文字の受信に余分な時間はかかりません。バッファにすでに11以上の非 'H'文字がある場合、それらは直ちに消費され、 'H'を待つでしょう。

最初に 'H'を待ってから11文字を待つ方が良いでしょう。これは、所望の入力の前に望ましくない入力がある場合、問題を解決します。

0

私はディンゴが彼の最初の発見で正しい答えを持っていると思います。 device_timeout_checkは、少なくともここに示すコードでは初期化されていません。それが初期化されていない場合は、コールスタックに残っているゴミが何であれ、簡単に1000を超えることがあります。その場合、whileループはすぐに静かに落ちます(tsk tsk)。シリアルポートから何も(おそらく)何も引っ張らないで100回繰り返します。

ところで、なぜ100?バッファを空にすると、余分な読み込みが非常に速く起こり、新しいものを見つけることができなくなります。

これは、デバッガの動作も完全に説明しています。あなたの遅延ループは決して何も遅らせることはありませんでした。そして、あなたがserCgetc()にブレークポイントを置くと、あなたはシリアルポートがプログラムに追いつくことを許していました。

実際にそうであるかどうかを確認する簡単な方法は、シリアルポートからデータを読み取ろうとする前に、何らかの外部通知を設定することです。 LEDを点滅させるか、シリアルポートを介して「メッセージ受信」パケットを送信してください。安価なOスコープを使用すると、データを受信する前に "メッセージ受信"パケット(またはLED点滅)が簡単に表示されるはずです。

これらのpeek関数とread関数はデータを返すためエラー状態を返さないが、少なくともFIFOのパリティエラーやバイトをチェックし、代わりにポインタの状態でステータスを返すラッパーに簡単に配置できる返される可能性があります。このようなもの

STATUS myCpeek(unsigned char *data) 
{ 
    if (0 == serCrdUsed()) 
    return ERROR_NO_DATA; 
    *data = serCpeek(); 
    if (serCParityError()) //Just guessing at a function name here 
    { 
    return ERROR_PARITY_BAD; 
    } 
    return OK; 
} 

またはそれに類するもの。

関連する問題