• 締切済み

PIC 10ビットをBCD変換をする方法おしえて

あるサイトで、8bitをBCD変換する方法をみつけました。それは 『  BCD変換くらいは人のプログラムを見るより算数で考えたほうが理解は簡単です。 ある8bit数 x があります。0~255ですね。求める10進数各桁は、100の位をA、10の位をBとします。 A、Bの初期値を0にします。 xが100以上なら、xから100を引いてAに1を加え、この行を繰り返します。xが100未満なら次の行へ。 これで100の位Aが分かり、xには元の数を100で割った余りが入っています。 xが10以上なら、xから10を引いてBに1を加え、この行を繰り返します。xが10未満なら次の行へ。 これで10の位Bが分かり、xには元の数を10で割った余りが入っています。つまり1の位はxです。 』 非常にわかりやすい説明です。ところで、10bitをBCD変換するには どうしたらいいでしょうか。たとえば、PICの10bitのA/Dコンバーターを 使うと、2bitのX_HIGHと8bitのX_LOWの二つのファイルに分割 されてでてきます。これをBCD変換したいんですが。

  • ny35
  • お礼率24% (7/29)

みんなの回答

  • kuro804
  • ベストアンサー率29% (523/1762)
回答No.2

PICのRAMは8bitの単位で構成されています。PICの命令(コード)もほとんどは8bitの数値を処理する命令です。従って10bitの値を扱うには工夫が必要です。 まず、数値の保存は8bitのRAMを2つ使います。これで8ビット以上16ビットまでの数値の保管ができます。ついでに上位桁をX_HIGHと、下位桁をX_LOWという名称を付けます。 例えばRAMの絶対アドレスとして割付例を示しますと(適当です) 50H X_LOW : A/D下位8ビット格納 bit0=A/D bit0 bit7=A/D bit7 51H X_HIGH : A/D上位2ビット格納 bit0=A/D bit8,bit1=A/D bit9 52H T_LOW : 保存用D下位8ビット格納 bit0=A/D bit0 bit7=A/D bit7 53H T_HIGH : 保存用上位2ビット格納 bit0=A/D bit8,bit1=A/D bit9 54H XBCD_LOW : 表示用BCDデータ1、2桁目格納 55H XBCD_HIGH: 表示用BCDデータ3、4桁目格納 56H TBCD_LOW : 処理用BCDデータ1、2桁目格納 57H TBCD_HIGH: 処理用BCDデータ3,4桁目格納 さて、質問者様は8ビットの例ではとてもわかりやすいとおっしゃってますので、”十分理解出来る”と解釈して同様のことを2バイトに渡って処理を行えば良いことになります。 しかしながら一般的には、基本は簡単もしくは理解可能の範囲で、現実的対処はとても煩雑です。努力しかありません。ただ同じ努力量を有効に使う手だてをお教え致します。 PICのメーカーサイトに行けば、数値演算用のライブラリーがあります。アッセンブラのソースが公開されていますので、これらを利用する方向で努力されれば1を知って100の応用が可能です。 PICの開発用総合環境ではシミュレーションが可能だと思いましたので、数値演算関連は容易に検証がおこなえます。 ”面倒だと”いうのは見なかったことにします。

ny35
質問者

お礼

回答ありがとうございます。 自己流プログラムでは、ひたすら引き算を繰り返す、という方法で やっておりまして、100をひいてカウントし、次に10をひくと いうのは、うまいと思いました。 10bitでもうまい方法があるのかと期待したのですが、そうは 簡単にはいかないようです。 とりあえずは「煩雑で、努力がいる」ということは理解しました。

回答No.1

8bitが10bitになったところで計算方法はまったく変わりません。 入力値が0~1024になるので、最初に1000以上か/以下かの判定が入るだけです。 入力値をX、1000の位をA、100の位をB、10の位をCとすると、 x を1000で割った商=A、その余りを100で割った商=B、その余りを10で割った商=C、その余りが1の位になります。 (『 』の方法は引き算を繰り返すことで割り算を実現しています) >2bitのX_HIGHと8bitのX_LOWの二つのファイルに分割されてでてきます。 ここで何故「ファイル」が出てくるのか意味が良く分かりません・・・ ターミナルからそういうフォーマットにして出力し、ファイル化していると言うことでしょうか??

ny35
質問者

補足

マイコンチップpicの場合、処理能力が低くて一度に8bitの 数しか処理できません。10bitの数が出てきた場合、二つに わけて処理しなければならないのでめんどうです。 そこを知りたかったわけです。

関連するQ&A

  • EXCELで10進数表記をBCD表示にしたい

    あるソフトのCSVデータがあり、 その中に4664という数値があります。 実際この数値をBCDデータの1234と変換したいです。 変換後のデータは0000~9999までの4桁で、 元データもその範囲外のデータはありません。 関数を探しても、9桁以上のものは変換できないようです。 A1セルの数値をE10セルに表示できる方法を教えてください 変換途中で、他のセルで2進数に変換して、とかでもいいです。 マクロより、単に関数がいいです。 宜しくお願いします。

  • PIC16F877を用いたC言語でのAD変換について

    PICを用いてAD変換をしようとしていますが,思うように出力が出ず困っています. 可変抵抗を用いて0-5V間を調整可能な入力をAN0ピンに接続し,AD変換の結果をBポートに出力しようとしています. 使用条件は,mikroC使用,PIC16F877使用,C言語使用,水晶20MHz,Aポート入力(AN0ピンアナログ入力),Bポート出力,Tad=1.6μsです. 以下のプログラムで間違っている点をご指摘いただきたいと考えています. unsigned int out_b; void port_initialize() { INTCON=0; //割り込みなし ADCON0=0x81; ADCON1=0x8E; //AD変換中の入力範囲設定は電源と共有 TRISA = 0x3f; //AD変換用ポート(1で入力) TRISB = 0; //出力用ポート(0で出力) PORTB = 0; } void value_initialize() { out_b=0; PORTB=out_b; } void main() { port_initialize(); value_initialize(); while(1){ //endless ADCON0=0x81; //AD変換bitを選択 Delay_us(24); //アクィジション時間+AD変換後の待ち時間 ADCON0=0x85; //AD変換開始 Delay_us(20); //AD変換待ち時間 out_b=ADC_Read(0); PORTB=out_b; } }

  • PIC A/D変換での問題

    PIC16F690を使用しLCDにA/D変換をした数値を表示させる物を作ったのですが 抵抗を一定の速度で回しても数値が一定の速度で変化しません。 詳しく説明しますと、今回書いたプログラムは8bitで255までの値を表示させるものです。 抵抗をめいいっぱい回して数値を1にし(0にはどうしてもなりません。おそらく抵抗の問題) そこからゆっくりと一定の速度で抵抗を回すと数値が上がっていきます。 30辺りまでは一定の速度で数値が変化するのですが、そこから少し回すといきなり数値が220ぐらいにまで上がります。(一応30~210までの数値も出ている様なのでいきなり飛んでるわけではない) 抵抗を1Kのものから10Kものに変えてみたりしたのですが症状に変化はありませんでした。 どうしても解決できなかったので質問をした次第です。 解決方法がわかる方がいらっしゃいましたらお教え下さい。 プログラムを載せておきます。 #include<pic.h> #include<stdio.h> #include "lcd.h" unsigned int temp; unsigned int x = 1; unsigned char outString[20]; unsigned char count[20]; void init_a2d(void){ ADCON1=0x10; // A/D Clock Fosc/8 ADCON0=0x01; // A2D 入力をChannel 0 (RA0), // Left justified, A/D をON } // 指定された入力チャネルをA/D変換し8 bitの結果を返す unsigned char read_a2d(unsigned char channel){ channel&=0x0F; // 4 bitsを確認し ADCON0&=0xC3; // 現行入力チャネルをクリア ADCON0|=(channel<<2); // 新入力チャネルを設定 GODONE=1; // 変換開始 while(GODONE)continue; // 変換終了を待つ return(ADRESH); // 8 bitの結果を返 } void main(void) { pic_init(); init_a2d(); // A/D モジュール初期化 lcd_init(); lcd_goto(0x00); while(1) { __delay_us(50); // 50uS待ち(AD充電待ち) temp=read_a2d(0); sprintf(outString,"A/D=%2d",temp); lcd_puts(outString); lcd_goto(0x40); sprintf(count,"Count=%d",x); lcd_puts(count); x++; __delay_ms(100); lcd_clear(); } }

  • 2進数からアスキーコードへの変換についって

    趣味で電子工作を行っているものです。 picマイコンを使用して、A/D変換の結果10bitのデータを得ました。 8ビットのマイコンなので2つのレジスタに分かれてデータが格納されています。(上位2ビットと下位8ビット) この2進数のデータを10進数に変換し、一桁ごとにアスキーコードにして、シリアル通信を用いてPCに送りたいと思っています。 ここで、10bitのデータの2進数から10進数への変換。 10進数のデータを一桁ずつアスキーコードへ変換。 の2つのやり方がわかりません。 2進数のデータのままPCに送り、PCのソフト側で変換するほうが簡単なのですが、今回はPIC側で変換し、アスキーコードで送る必要があります。 プログラムに使用する言語はアセンブリです。 どなたか分かる方がいましたら教えてください。

  • PICでのプログラミングについて教えて下さい。

    現在電圧計を製作していて4桁の7セグダイナミック点灯で行き詰っております(超初心者です)。 PICは16F873Aを使用、コンパイラはCCS、書き込みはピックライタ、あとシリアルデバッカを使用しています。 外部から電圧をかけそれをAD変換し、AD変換結果(0~5V)を7セグに表示させようとしています。 一応今の状態でも電圧表示はできていることはできているのですが一桁目から4桁目まで目で追えるくらい遅いスピードでこれを改善したいです。ソースは下記のソースを製作しました。この状態で3日間悩んでおります...知恵をお貸しいただけないでしょうか。 よろしくお願いします。 #include <16F873a.h> #device ADC=10 //A/D変換10bitモード #use fast_io(A) /* TRISレジスタの設定が必要 */ #use fast_io(B) #use fast_io(C) #use delay (clock=10000000) //10MHz #use RS232( BAUD = 9600, XMIT = PIN_C6, RCV = PIN_C7, PARITY = N, BITS = 8 ) #fuses HS,NOWDT,PUT,NOPROTECT,NOBROWNOUT,NOLVP #define VOLTAGE PIN_A0 // (in) #define CORRENT PIN_A1 // (in) #define VREF1 PIN_A2 // (in) #define VREF2 PIN_A3 // (in) #define RESERVE1 PIN_A4 // (out) #define RESERVE2 PIN_A5 // (out) #define LED_DP PIN_B0 // (out) #define LED_A PIN_B1 // (out) #define LED_B PIN_B2 // (out) #define LED_C PIN_B3 // (out) #define LED_D PIN_B4 // (out) #define LED_E PIN_B5 // (out) #define LED_F PIN_B6 // (out) #define LED_G PIN_B7 // (out) #define DIG_0 PIN_C0 // (out) #define DIG_1 PIN_C1 // (out) #define DIG_2 PIN_C2 // (out) #define DIG_3 PIN_C3 // (out) #define INI_TRIS_A_VAL 0x0F // 7:x 6:x 5:out 4:out 3in 2:in 1:in 0:in #define INI_TRIS_B_VAL 0x00 // 7:out 6:out 5:out 4:out 3out 2:out 1:out 0:out #define INI_TRIS_C_VAL 0x80 // 7:in 6:out 5:out 4:out 3:out 2:out 1:out 0:out int ct;//数字の更新間隔 long val;//表示する数字 int digit;//表示する桁 //表示パターン int segment_data[]={0x81,0xF3,0x49,0x61,0x33,0x25,0x05,0xF1,0x01,0x31}; char st[4]; void main() { float ata1,data2,data3,data4; long data5; long val; SET_TRIS_A( INI_TRIS_A_VAL ); SET_TRIS_B( INI_TRIS_B_VAL ); SET_TRIS_C( INI_TRIS_C_VAL ); setup_adc_ports(AN0_AN1_VSS_VREF); setup_adc(ADC_CLOCK_DIV_32); //Fosc/32 最高速度 digit=0; ct=1;//数字を更新する周期 val=0;//表示する値 while(1) { output_low(RESERVE2); //動作ランプ //////////////////////電圧測定///////////////////////////////// set_adc_channel(0); delay_us(50); //アクイジションタイム待ち(マイクロ秒) data1 = read_adc(); //AD変換結果読み込み printf("ADC V %9.3f \r\n", data1 ); //AD変換データ表示 data2 = (data1 * 4.959695) / 1024; //BCDに変換 printf("Volt %6.3f \r\n", data2 ); //変換データ表示 data5 = data2 * 1000 ; //data2を整数に変換 val = data5 ; printf("val %ld \r\n", val); //整数にし表示 /////////////////////7SEG表示////////////////////////////////// ct --; if(ct == 0){//数字の更新 st[3]=val/1000; //4桁目数値取り出し st[2]=val/100-st[3]*10;//3桁目数値取り出し st[1]=val/10-((st[3]*100)+(st[2]*10));//2桁目数値取り出し st[0]=val%10;//あまり val++; if(val==1000) val=0; ct=20; } if(digit== 3){//第4桁の表示 output_b( segment_data[st[3]]); output_bit(DIG_0,1);  //4桁表示開始 output_low(LED_DP);  //小数点表示  delay_us (5); //表示期間(ミリ秒) output_bit(DIG_0,0); //表示を消す output_high(LED_DP); //小数点を消す delay_us(50); //待ち(マイクロ秒) } if(digit== 2){ output_b( segment_data[st[2]]); output_bit(DIG_1,1); delay_ms (5); output_bit(DIG_1,0); delay_us(50); } if(digit== 1){ output_b( segment_data[st[1]]); output_bit(DIG_2,1); delay_ms (5); output_bit(DIG_2,0); delay_us(50); } if(digit == 0){ output_b( segment_data[st[0]]); output_bit(DIG_3,1); delay_ms (5); output_bit(DIG_3,0); delay_us(50); } digit ++;//表示桁を変更 if(digit ==4 ) digit=0; } }

  • 8bitの2進数を入力して2つのポートに(PIC)

    8bitの2進数を入力して2つのポートに出力させる方法 PIC16F886のポートAに8bitの2進数を入力したとします。 そのとき ポートAの入力が   ポートBの出力では  ポートCの出力では ・LLLLLLLL        ・LHHHLHLH   ・HLHLLHLH ・LLLLLLLH   のとき ・LHLLHHHH   ・LHLHLHLH          ・          ・          ・ ・LLLLLLHL        ・LHHLLLLH   ・HLHHHHH ポートAに入力された2進数を変更して、ポートB、ポートCに 出力させて、1チップで14セグメントLED(英数字表示器)を点灯させたいです。 このような動作は可能なのでしょうか?

  • 行列式 1次変換

    次の行列で表わされる1次変換によって、右側の直線はどんな図形に移されるか? (1) (4 -5) (-3 6), 2x-y=1 (2) (3 -1) (6 2), 2x-y=1 (3)AB,x+y=1 (4)BA,x+y=1 解説には、「まず直線上の点として(1)はA(1,1)B(-1,-3)、(2)はA(1,1)B(2,4)を取る」と書いてあるんですが 何を元にとった点なのですか?理由と詳しい解法お願いします。

  • C言語のPICプログラミングなんですが、

    C言語のPICプログラミングなんですが、 これのどこがおかしいか教えてください。 if(input(PIN_B1)) { while(input(PIN_B2) == 0) { output_high(PIN_B7); //前進後進パルス出力 delay_us(50); //変換待ち output_low(PIN_B7); delay_us(16000); //共通遅延16000us } break; } if(input(PIN_B1)) { while(input(PIN_B2) == 0) { output_high(PIN_B7); //前進後進パルス出力 delay_us(50); //変換待ち output_low(PIN_B7); delay_us(16000); //共通遅延16000us } break; }

  • 線形変換について

    3次元ベクトルa,bがあたえられたとする。この時ベクトルXに対して (a,x)bを対応させる変換は線形変換か?線形変換である場合は、その変換に対応する行列を答えよ。ただしaベクトル=上から(1,-1,1)の行ベクトル、bベクトル=上から(2,-3,1)です。この問題がよくわかりません。 まず(a,x)bの部分は内積なのでaxbというふうになってベクトルxは定められてないので単位ベクトルe1,e2,e3をつかって x=Ae1+Be2+Ce3のようにしてから求めるんでしょうか? 問題がよくわかりません。

  • picマイコンのプログラムについて

    上位4bitと下位4bitを取り出してそれぞれを足して出力するプログラム #include<pic.h> void main(){ int x,y,z; TRISA=0x00; TRISB=0xFF; for(;;){ x=(0b11110000 & PORTB)>>4; y=(0b00001111 & PORTB)>>0; z=x+y; PORTA=z; } } pulseを読み取り、カウントするプログラム portaの第0bitからpulseを読み込んで信号が変化したとき、数を数えて、現在のカウントをportbに出力する #include <pic.h> main() { unsigned char before,after; TRISA=0xFF; TRISB=0x00; before=PORTA&1; PORTB=0; for(;;) { after=(PORTA &8)>>3; if(before==0&&after==1) { PORTB=1; } else { PORTB=0; } before=after; } } どのように変更・付け加えをしたらいいでしょうか?どなたかわかる方はお願いします。