アッセンブラ版BCD変換ルーチンをXC8に移植

目的は8桁7セグLEDを制御するルーチン群の1つとしてです。
XC8のprintf関数で行えば良いのですが、この関数はメモリを多量に消費します。
そこで、アッセンブラでの制御と同じ関数群を作り、メモリの少ないPICでもXC8でプログラムできる様にするためです。
関数操作方法は、32bit入力で戻し値が5バイトとなるので、アッセンブラ版と同じようなBCD専用広域変数に収納します。
別バージョンでは、上位桁を切り捨てて、32bitで返します。
実際の挙動に関しては、MPLAB XIDEのシミュレータで観察すると、動作確認が出来て面白くてお勧めです。


アッセンブラ版から見える、BCD変換ルーチンの動作概要

以前の考察で記した物と同じで、未だになぜこの方法でBCDに変換できるのか理屈が全く理解できません・・・ (-_-;)
見ての通り、1bitずつ左シフトしながら、4bit単位で補正処理を繰り返します。
ここでは簡略化のため、変換前の16進バイナリ数値を8bitとして進行していきます。
8bitなので8回左シフトします。ちなみに16bit数値の場合は16回、32bit数値の場合は32回左シフトします。
最後の左シフト後は補正処理しません。

変換されたBCDの格納変数はDEC12、DEC34の2バイトとし、ビットは全てクリアしておきます。
1桁4bitが基本となりますので、ここではDECを16bit変数として扱い、
さらに変換後は最大3桁12bit使用しますので、変数DECの上位4bit(bit15-bit12)は表示を省略します。
変換前の16進バイナリ数値はHEX0の1バイトで、例として値はFFHとします。
下記の用に1ビットずつ左へ(MSBへ)シフトします。

 破棄 ← DEC34   ← DEC12   ← HEX0   ← ゼロビット
       DEC4,3桁   DEC2,1桁   元値16進

変換前の16進バイナリ数値HEX0は左シフトすると、LSBには0がシフトしてくるとします。
16ビットDEC変数はLSBから順に1bitずつ左シフトされてくるが、左シフトする度に5以上の4ビット列(桁)は+3される事に注意

 START - (↓DECビット0000H) -- (↓HEXビット FFH)
 ビット列   (0000 0000 0000) ← (1111 1111)

 1回目  - (↓DECビット0001H) -- (↓HEXビット )
 ビット列   (0000 0000 0001) ← (1111 1110) 左シフト後、DEC1桁目は5未満で補正無し

 2回目  - (↓DECビット0003H) -- (↓HEXビット )
 ビット列   (0000 0000 0011) ← (1111 1100) 左シフト後、DEC1桁目は5未満で補正無し

 3回目  - (↓DECビット0007H) -- (↓HEXビット )
 ビット列   (0000 0000 0111) ← (1111 1000) 左シフト後、DEC1桁目は5以上で補正必要

 3回目  - (↓DECビット000AH) -- (↓HEXビット )
 ビット列   (0000 0000 1010) ← (1111 1000) 補正処理実行、DEC1桁目のみに+3補正

 4回目  - (↓DECビット0015H) -- (↓HEXビット )
 ビット列   (0000 0001 0101) ← (1111 0000) 左シフト後、DEC1桁目は5以上で補正必要

 4回目  - (↓DECビット0018H) -- (↓HEXビット )
 ビット列   (0000 0001 1000) ← (1111 0000) 補正処理実行、DEC1桁目のみに+3補正

 5回目  - (↓DECビット0031H) -- (↓HEXビット )
 ビット列   (0000 0011 0001) ← (1110 0000) 左シフト後、DEC1桁目,2桁目はそれぞれ5未満で補正無し

 6回目  - (↓DECビット0063H) -- (↓HEXビット )
 ビット列   (0000 0110 0011) ← (1100 0000) 左シフト後、DEC1桁目5未満,2桁目は5以上で補正必要

 6回目  - (↓DECビット0093H) -- (↓HEXビット )
 ビット列   (0000 1001 0011) ← (1100 0000) 補正処理実行、2桁目のみに+3補正

 7回目  - (↓DECビット0127H) -- (↓HEXビット )
 ビット列   (0001 0010 0111) ← (1000 0000) 左シフト後、DEC2,3桁目は5未満,1桁目は5以上で補正必要

 7回目  - (↓DECビット012AH) -- (↓HEXビット )
 ビット列   (0001 0010 1010) ← (1000 0000) 補正処理実行、1桁目のみに+3補正

 8回目  - (↓DECビット0255H) -- (↓HEXビット )
 ビット列   (0010 0101 0101) ← (0000 0000) 最終の左シフトして終了、補正処理しません


以上、8bit16進バイナリが、ちゃんと12bit10進バイナリに変換されました。
実際はこれを32bitに拡張すれば良いだけで、楽勝です。
作成関数そのものも、このビット列操作を、そのままプログラム化しています。
理屈はサッパリですが、これを考えた人は素晴らしいですね。 (^_^)

XC8版 BCD変換関数ソースファイル

16進32bit符号無し整数を40bitBCDに変換

 BCD.h

 BCD.c

16進32bit符号無し整数を32bitBCDに変換

 BCD24.h

 BCD24.c



XC8版BCD関数使用方法

関数は2種類です BCD関数は10桁表示ができるLCD等での使用が適しています、
BCD24関数は8桁7セグLED表示器等での使用が適しています。

 1) void BCD(unsigned long int 引数)
      32bit16進バイナリ数値を40bitBCDに変換します
      40bitを戻し値とする方法が解らなかったので、広域変数に収納としました。
     引数:32bit16進バイナリ符号無し数値(0H~FFFFFFFFH)
     戻値:専用広域変数に収納
         digit12 0-3bit BCD1桁目
                 4-7bit BCD2桁目
         digit34 0-3bit BCD3桁目
                 4-7bit BCD4桁目
         digit56 0-3bit BCD5桁目
                 4-7bit BCD6桁目
         digit78 0-3bit BCD7桁目
                 4-7bit BCD8桁目
         digit9A 0-3bit BCD9桁目
                 4-7bit BCD10桁目

 2) unsigned long int BCD24(unsigned long int 引数)
      32bit16進バイナリ数値を40bitBCDに変換します
      変換後は32bitBCDとして返します
      変換された40bitBCDの内、上位8bitを切り捨てます
      事実上24bit程度のBCD変換と言う事になります。
      切り捨てを行ってもエラー等は返しません

     引数:32bit16進バイナリ符号無し数値(0H~FFFFFFH)
     戻値:8桁の32bitBCD



ヘッダーファイル
 上記専用広域変数定義および関数プロトタイプ宣言をしています。

関数群ファイル(とは言っても下記の2関数のみです)
 BCD関数
 ADJ_BCD関数

ヘッダーも関数も小さいので、メインプログラムに埋め込んでも良いのではと思います。
もちろん、printf関数を使用すれば、このBCD関数は不要ですがね。
別ページに、このBCD関数を使用したデモプログラムがあります。


戻る  実験・製作の記録TOPへ戻る