2016-10-24 5 views
7

以下は、符号なしint関数get_ADC_value()によって設定された特定の周波数で2多重化7セグメントディスプレイを駆動しようとするC(PIC18F8722マイクロプロセッサ用)で書いた主な機能です。ディスプレイには現在の多重化周波数も表示されます。この周波数範囲は、Iがintからfloatへの暗黙的な変換があると思いしかし働かない範囲LAB_FminとLAB_Fmaxになるように#defineによって設定されget_ADC_value()増加するにつれてスケーリングしなければならない、または0から255Cでfloatを使用する/使用しないで割り算

このコードに減少しますfreq =

このエラーを浮動小数点数で修正し、整数型(intchar ...)のみを使用して代替を見つけることが課題です。

while (1) { 

    unsigned int x, y, z; 
    float freq, delay; 

    x = get_ADC_value(); 
    y = x & 0b00001111; 
    z = (x & 0b11110000) >> 4 ; 

    freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin))/ 255)*x ; 
    delay = 1/(freq*1000); // convert hZ to ms delay accurately 

    LATF = int_to_SSD(y); 
    LATH = 0b11111110; //enable 7seg U1 
    for (unsigned int i = 0; i<(delay) ; i++){ 
     Delay10TCYx(250); //1ms delay 
    } 

    LATF = int_to_SSD(z); 
    LATH = 0b11111101; //enable 7seg U2 
    for (unsigned int j = 0; j<(delay) ; j++){ 
     Delay10TCYx(250); //1ms delay 
    } 
} 
+0

1hzは1000msecの遅延、2Hzは500msecなので、遅延計算は 'delay = 1000/freq'であるはずです。 – user3386109

+11

@MitchWheat:あなたの答えは受け入れないでください。他の、新しい、答えが出てくるかもしれないかどうかをしばらく待つのは良いことです。それは3時間だけです!私は215k - repのユーザーがそれを知っていると思います。 –

+5

私は自分の答えを受け入れるよう求めていません。ポスターは任意の回答を受け入れることができます。私は218Kのユーザーがそれを理解すると期待しています! –

答えて

16

Cは、整数の除算を使用してint Sを分割するために定義され、ある場合にのみフロートはそれをしません」他のintfloatに最初に昇格させてください。これがfloatに割り当てられる場合でも、右辺がすべてintである場合、除算はすべて整数になり、最後の割り当てではintの結果がfloatに変換されます。

だから、あなたのラインを持つ:それはすべてLAB_FmaxLAB_Fminが何であるかに依存し

freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin))/ 255)*x ; 

freqまたはxが何であるかは重要ではありません。なぜなら、括弧が最初に除外されているために「被害」が既に行われているからです。

それらLAB_F変数がintのであれば、浮動小数点除算を使用する最も簡単な方法は、単に小数点を使用することにより、浮動小数点数ではなく整数255定数を作ることによって、あなたがしたいCを伝えることです:255. (または255.0は微妙ではありません)。

整数演算のみを使用する場合は、通常は、すべての除算の前に乗算を行うことをお勧めします。もちろん、中間結果がオーバーフローするリスクがあります。にする場合は、タイプlongを使用できます。 longとしてあなたLAB_Fx変数を定義し、最後の分裂を行います。整数と

freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin)) * x/255); 
+0

与えられた0 <= x <= 255 LAB_Fmax-LAB_Fminの範囲は、バージョン。それらが#defineされていると、コンパイル時にオーバーフローアウト/インを制御することが可能です。 – Persixty

+3

多くのシステム(ほとんどの32ビットシステム、Win64ベースのシステム)では、 'long'は' int'と同じサイズです。 –

6

整数の除算については正しいです。

freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin))/255.0)*x; 
                ^^ 
+0

彼のコードから: 'float freq、delay;' – Magisch

+3

彼らはもともとそこにいませんでした! –

+3

ええ、今はそうだし、その事実を知らせたいので、私はコメントしました:p – Magisch

4
freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin))/ 255)*x ; 

へ 変更は、これは確かに整数への暗黙的な変換で、あなたはそれを行うには整数の除算をやっています。

これは、255が整数リテラルであるためです。

255.0に変更すると、ダブルリテラルになります。これは計算にうまくいくはずです。

さらに正確にするには、255.0fなどの浮動小数点定数や、(float)255などの明示的キャストを使用することもできます。

あなたのコードは、この後、次のようになります。

freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin))/ 255.0)*x ; 

それともこれを:

freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin))/ (float)255)*x ; 
3

数学の操作は、デフォルトでは、あまりにも整数になり、 ので、あなたはダブル/ floatとしてリテラルのいずれかを表現するためにどちらかの必要があります

freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin))/ 255.0)*x ; 

または最初のオプションは、最も一般的に実装されている(float)

のような他の多くの状態をキャスト。

10

コードレビュー:組み込みシステム上の生の整数型を使用して

  • unsigned int x, y, z;は避けてください。 stdint.hの正確な幅の型は常に使用する必要がありますので、使用するサイズを正確に把握してください。 stdint.hにアクセスできない場合は、それらの型を自分でtypedefしてください。

  • float freq, delay;浮動小数点数は、通常、ほとんどの組み込みシステムでは避けるべきです。特にFPUなしの8ビットMCUで!これにより、ソフトウェア定義の浮動小数点数は非常に遅く、メモリを消費します。このプログラムで浮動小数点数を使用する理由はないようですが、厳密な精度要件がない限り、このアルゴリズムをuint16_t以下で記述できるように見えるでしょう。

  • x = get_ADC_value(); ADCの8ビットに興味があるように思えるので、なぜ8ビットタイプを使用しないのですか?

  • 進数リテラルはC.

  • ((LAB_Fmax) - (LAB_Fmin))/ 255これは魚に見える標準ではありませんのでご注意ください。まず第一に、これらの整数または浮動小数点数ですか?彼らのサイズは何ですか?あなたの質問に対する答えはそれに依存します。リテラルを255.0fにスワップすることで、強制的に変換を浮動させることができます。しかし、あなたは部門が255でなければならないと確信していますか?そして、256ではない?

  • i<(delay)。ループ条件内で浮動小数点式を使用することは避けてください。なぜなら、ループが不必要に遅くなり、浮動小数点の不正確なバグにつながる可能性があるからです。また、かっこは目的を満たしていません。全体的に

、あなたのプログラムは、プログラマが各式で使用されているどのような種類についての考えを与えていないことを意味し、「ずさんなタイピング」に苦しんでいます。リテラルにも型があることに注意してください。暗黙の変換によって、これらの式の多くが大きすぎるタイプで計算される可能性があります。これはPICにとって非常に悪いニュースです。私は "平衡"、別名の通常の算術変換を読むことをお勧めします。

この「かすかな型指定」は、プログラムが非常に肥大化し、速度が遅くなり、何も得られなくなります。 PICはおそらくコード効率の最も低いMCUであることに留意してください。 8ビットMCU用のCコードを書くときは、8ビット以上の型は避けてください。特に、ペストのような32ビットの整数や浮動小数点数は避けるべきです。

プログラムは、すべてのデータをプログラマの思考を容易にするタイプに再スケーリングします。これは一般的な設計ミスです。代わりに、プログラムでプロセッサー用に使いやすいタイプを使用する必要があります。たとえば、ミリ秒単位ではなく、タイマーティックを単位として使用できます。

+0

'x 'が符号なし8ビット値で、' x = 0'を 'freq = LAB_Fmin'と' x = 255'にマッピングすることを想定して255で除算するのは確かに正しいでしょう。 'freq = LAB_Fmax'に変更します。しかし、変換が実装されている方法では、整数演算のみを使用しても動作しません(簡単に動作させることはできません)。より良い方法は、整数演算のみを使用し、 'const int scale =((LAB_Fmax - LAB_Fmin)* 256)/ 255'となる' freq = LAB_Fmin +(x * scale)>> 8'のようなものです。 –

+0

とにかく、次の行で 'delay'を計算するために' freq'を反転させると、浮動小数点数(または少なくとも整数型の整数型)を必要とするため、おそらく8ビットMCUの最も効率的な実装は、 'x'を' delay'に直接マッピングするハードコードされた256要素ルックアップテーブルです。あるいは、スペースが重視される場合は、より少ないエントリーを使用し、それらの間で直線的に補間する。 –

+1

@IlmariKaronen精度要件に応じて、整数演算が機能する場合と動作しない場合があります。私たちは要件やアルゴリズムを知らないので、実際にはそれについてコメントすることはできません。手動で '/ 256'を' >> 8 'に置き換えようとするべきではないので、コンパイラに任せてください。 – Lundin

関連する問題