12

アーム マイクロプロセッサでプログラミングを行っており、UART 経由で印刷ステートメントを使用してデバッグしようとしています。stdlibsデバッグのためだけに追加したくありません。stdio.h/なしでコンソールに出力する方法はありiostream.hますか? 自分で書くことは可能printf()ですか?

別の方法として、DMA コントローラーを使用して UART に直接書き込むこともできます。しかし、私はそれが可能であることを避けたいと思います。組み込みのテスト機能「echo」または「remote loop-back」を使用すると、UART が適切に構成されていることがわかります。

4

4 に答える 4

10

簡単な答え: はい、両方のソリューションを実行することは完全に可能です。

すべてのデータ型と形式をサポートしたい場合、printf 関数は非常に複雑です。しかし、いくつかの異なる基数で文字列または整数を出力できるものを書くことはそれほど難しくありません (ほとんどの人は 10 進数と 16 進数しか必要としませんが、8 進数は、10 進数と 16 進数があれば、おそらくさらに 3 ~ 4 行のコードを追加するだけです)。

通常、printf は次のように記述されます。

 int printf(const char *fmt, ...)
 {
     int ret;
     va_list args; 

     va_start(args, fmt)
     ret = do_xprintf(outputfunc, NULL, fmt, args); 
     va_end(args);
     return ret;
}

そして、do_xprintf()すべてのバリアント (printf、sprintf、fprintf など) のハードワークをすべて実行します。

int do_xprintf(void (*outputfunc)(void *extra, char c), void *extra, const char *fmt, va_list args)
{
    char *ptr = fmt;
    while(1)
    {
       char c = *ptr++;

       if (c == '%')
       {
            c = *ptr++; // Get next character from format string. 
            switch(c)
            {
               case 's': 
                  char *str = va_arg(args, const char *);
                  while(*str)
                  {
                      count++;
                      outputfunc(extra, *str);
                      str++;
                  }
                  break; 
               case 'x': 
                  base = 16;
                  goto output_number;

               case 'd':
                  base = 10;
         output_number:
                  int i = va_arg(args, int);
                  // magical code to output 'i' in 'base'. 
                  break;

               default:
                  count++;
                  outputfunc(extra, c);
                  break;
         }
         else
             count++;
             outputfunc(extra, c);
     }
     return count;
 }                

あとは、上記のコードの一部を埋めて、シリアル ポートに出力する outputfunc() を記述するだけです。

これは大まかなスケッチであり、コードにいくつかのバグがあると確信していることに注意してください-浮動小数点または「幅」をサポートしたい場合は、もう少し作業する必要があります...

(追加のパラメータに注意してください -FILE *ファイルポインタになるa への出力のsprintf場合、 for 、バッファの構造体とバッファ内の位置などを渡すことができます)

于 2013-05-08T21:52:39.037 に答える
2

組み込みシステムのシリアル ポートを介して情報を出力すると、メイン プログラムのタイミングが変更されるため、私が見つけた最善の解決策は、2 バイトでエンコードされた小さなメッセージを送信することです (場合によっては 1 バイトで問題なく動作します)。これらのメッセージをデコードし、必要な情報を提供します。これには、統計情報や必要なすべてのものを含めることができます。このようにして、メイン プログラムにほんの少しのオーバーヘッドを追加し、PC にメッセージを処理するための大変な作業を任せています。多分このようなもの:

  • 1 バイト メッセージ: ビット 7:4 = モジュール ID、ビット 3:0 = デバッグ情報。

  • 2 バイト メッセージ: ビット 15:12 = モジュール ID、ビット 11:8 = デバッグ情報、ビット 7:0 = データ。

次に、PC ソフトウェアで、特定のモジュール ID/デバッグ情報のペアにマップされるメッセージを含むテーブルを宣言し、それらを使用して画面に出力する必要があります。

デコードするために PC 内のメッセージの固定セットが必要なため、疑似 printf 関数ほど柔軟ではないかもしれませんが、前に述べたように、オーバーヘッドはあまり追加されません。

それが役に立てば幸い。

フェルナンド

于 2013-05-20T11:49:00.193 に答える
1

バックグラウンド デバッグでは、循環バッファーに文字をエンキューし、uart 送信レジスターのポーリング ルーチンによって排出されることが私の選択方法であることがわかりました。

エンキュー ルーチンは、文字、文字列、および可変サイズ (16 進数または固定幅 10 進数) に基づいています。また、デラックス バッファ ルーチンは、予約文字によるオーバーフローを示す可能性があります。

このアプローチは、ターゲット操作へのオーバーヘッド/影響が最も低く、割り込みルーチンで (注意して) 使用でき、アイデアは簡単に転送できるため、使用したすべてのシステムでデバッガーを無視しました。

于 2013-05-09T07:30:43.517 に答える