PDA

View Full Version : Decimal to binary conversion



Demon
- 24th February 2005, 06:07
Weeee! My 1st useful contribution to this forum (a welcome change from my habitual leeching and strolling about in left field).

Here are code snippets to change a decimal 5 digit array into a binary 2 byte field (I use it as an address for external memory EEPROMs).

Note: The digits are reversed and the results are concatenated in NUMHI and NUMLO.

Robert
:)



DATAIN VAR BYTE[5]
DIGIT0 VAR BYTE
DIGIT1 VAR BYTE
DIGIT2 VAR BYTE
DIGIT3 VAR BYTE
DIGIT4 VAR BYTE
BCD48 CON %00110000
NUMHI VAR BYTE
NUMLO VAR BYTE

DIGIT4 = DATAIN[0] - BCD48
DIGIT3 = DATAIN[1] - BCD48
DIGIT2 = DATAIN[2] - BCD48
DIGIT1 = DATAIN[3] - BCD48
DIGIT0 = DATAIN[4] - BCD48

ASM
; 5 digit decimal to 16 (17) bit binary. By Peter Hemsley, March 2003.
; Input decimal digits in D0 (LSD) to D4 (MSD)
; Output 16 bit binary in NUMHI and NUMLO
; No temporary variables required
; Code size: 33 instructions
; Execution time: 33 cycles (excluding Call and Return)
; Returns carry set if > 65535 (and NUMHI-LO MOD 65536)
;
; ALTERATIONS:
; - variables and label prefixed with "_" to suit MPASM requirements.
; - variables renamed to suit individual requirements.
; - some instructions substituted to suit MPASM requirements.
_DEC2BIN
movf _DIGIT1,W ; (D1 + D3) * 2
addwf _DIGIT3,W
movwf _NUMLO
rlf _NUMLO,F

swapf _DIGIT2,W ; + D2 * 16 + D2
addwf _DIGIT2,W
addwf _NUMLO,F

rlf _DIGIT4,W ; + (D4 * 2 + D3) * 256
addwf _DIGIT3,W
movwf _NUMHI

rlf _NUMLO,F ; * 2
rlf _NUMHI,F

swapf _DIGIT3,W ; - D3 * 16
subwf _NUMLO,F
BTFSS 3,0 ; SKPC (not supported in MPASM
decf _NUMHI,F

swapf _DIGIT2,W ; + D2 * 16 + D1
addwf _DIGIT1,W
addwf _NUMLO,F
BTFSC 3,0 ; SKPNC (not supported in MPASM
incf _NUMHI,F

swapf _DIGIT4,W ; + D4 * 16 + D0
addwf _DIGIT0,W

rlf _NUMLO,F ; * 2
rlf _NUMHI,F

addwf _NUMLO,F
BTFSC 3,0 ; SKPNC (not supported in MPASM
incf _NUMHI,F

movf _DIGIT4,W ; - D4 * 256
subwf _NUMHI,F

swapf _DIGIT4,W ; + D4 * 16 * 256 * 2
addwf _NUMHI,F
addwf _NUMHI,F

return ; Q.E.D.
ENDASM

Luciano
- 24th February 2005, 16:08
Hi!

The following will also work.

==================================

Example:

"6" "2" "3" "4" "7"
Your 5 digits represents the decimal number 62347

Pseudo-Code:

variable_tenthousands = 6
variable_thousands = 2
variable_hundreds = 3
variable_tens = 4
variable_units = 7
variable_ee_address = 0

variable_ee_address = variable_units
variable_ee_address = variable_ee_address + (variable_tens * 10)
variable_ee_address = variable_ee_address + (variable_hundreds * 100)
variable_ee_address = variable_ee_address + (variable_thousands * 1000)
variable_ee_address = variable_ee_address + (variable_tenthousands * 10000)

Now the variable_ee_address will contain the value 62347

===================================

From your code I see that the 5 decimal digits (input data)
are stored in a 5 bytes array. One byte per digit, so there is
no binary-coded decimal. (No BCD).

Best regards,

Luciano

Demon
- 24th February 2005, 18:45
Hi Luciano,

"From your code I see that the 5 decimal digits (input data)
are stored in a 5 bytes array. One byte per digit, so there is
no binary-coded decimal. (No BCD)."

That's why I do this:

DIGIT4 = DATAIN[0] - BCD48
DIGIT3 = DATAIN[1] - BCD48
DIGIT2 = DATAIN[2] - BCD48
DIGIT1 = DATAIN[3] - BCD48
DIGIT0 = DATAIN[4] - BCD48

Using 0 as an example, I convert each digit individually from an ASCII value (0011 0000), to a binary value (0000 0000), by subtracting 48 (0011 0000). I am left with digits which are compatible with BCD format; bits in the lower nibble representing 0 to 9.

The Assembler sub-routine takes care of doing all the math, all I had to do was prepare the digits. I tested the routine with numbers like 56,789 and it worked flawlessly, the 2nd time (11011101 11010101). LOL I had some stuff backwards and used the wrong variable as input. But that's a chair-keyboard problem, the sub-routine is good.

I'm curious though, can you tell me how many cycles your code converts into once it's all said and done? The author of the sub-routine boasts 33 cycles, I wonder if that is truly remarkable, or if he's only 2 or 3 cycles less than your solution.

Robert
:)

Demon
- 24th February 2005, 18:56
Luciano,

One thing that appeals to me about your solution is the ease of expansion. I can easily add digits without convoluted maths exercises. I requested an expanded version of the sub-routine from the author to support 128MBytes, but I don't like doing that. If I need additionnal digits for gigabytes for example, then his sub-routine won't work and I am unable to expand it myself.

I really like the fact that your solution can be easily expanded with an extra variable and a simple math statement.

I'm just curious in the resulting performance difference. Is it really a big deal?

Robert
:)

Luciano
- 24th February 2005, 22:10
Robert,

From where do you receive the 5 digits?
(Terminal program > Serial port)?

Luciano

Demon
- 24th February 2005, 23:36
Hi Luciano,

Yes, and no. Yes from the serial port, no from the terminal program, kinda. I'm using an RS232 chip into COM1. I'm using the serial window in IDE 'cause it's the only way I can transfer data down to the PIC. The reception variable is defined as VAR BYTE[5].

You probably know my opinion of HyperTerminal if you read my post in the other thread. LOL I'm trying RealTerm, but I don't know what I have to set. I get the COM1 8N1 thing done, but I must be missing other key parameters 'cause I can't get it to work.

My goal is to download a file in one instruction. Right now I'm sending parts of a record at a time manually. Good for testing, bad for final implementation. I have 2 sequential HSERINs for now:

HSERIN recordtype

IF recordtype = bla-bla-bla
HSERIN recordformat
ENDIF

When I send "recordtype-recordformat" in one SEND, it doesn't work. I'm still trying to figure what I'm missing. I can send both separately, but I can't chain them in a single string and have the program treat data section by section.

The plan is to add several other formats, and have them processed depending on the record type prefix. I'm still learning serial communication so I can quite easily have flaws in my approach. This works on main frames, but I'm not in Kansas any more.

Robert

:)

Luciano
- 24th February 2005, 23:42
Hi Robert!


The following will also work.

========================================
Pseudo-Code:

ee_address VAR WORD
SERIN2 RxPin,84,[DEC5 ee_address]

========================================

Type the decimal number 62347 in
your PC terminal program.


After receiving the 5 ASCII bytes
the SERIN2 command will store the
decimal value 62347 in the
variable ee_address.

See PBP manual for SERIN2 modifiers, works
also with command HSERIN and HSERIN2.


Luciano

Demon
- 25th February 2005, 02:28
Uhhh, so you're saying I'm doing this conversion for nothing?

Robert
LMAO!

mister_e
- 25th February 2005, 04:05
Uhhh, so you're saying I'm doing this conversion for nothing?


Indeed dude.



I'm trying RealTerm, but I don't know what I have to set. I get the COM1 8N1 thing done, but I must be missing other key parameters 'cause I can't get it to work.

go to 'pin' tab then uncheck RTS and DTR... you'll be in business. Chances are because you're using an ICD adapter ;) and those pins force your chip to reset.... that's it IMHO. OR you type in text box... you can send number

pretty sure HSEROUT is not working also ?!?



My goal is to download a file in one instruction. Right now I'm sending parts of a record at a time manually. Good for testing, bad for final implementation.

you may need 1 or 2 extra flow control pin for that to avoid dumb or messy download. 1 to tell the pic you're going to receive data, one from the pic to the PC to confirm you receive a byte and you're ready to receive another.

Demon
- 25th February 2005, 21:05
Thanks, but oh poop...

I guess I'm not finished getting this darned RS232 download to work if I'm a couple pins short.

Robert
:(