Reputation: 742
I am using PIC16.
I am stuck on how to convert a number(binary/hex/decimal) in assembly to ASCII to be displayed in an LCD display for example:
I have a number here stored in a register
number = 0x04d2 (1234 in decimal)
0x30 = 0x04
0x31 = 0xd2
How would i go about to convert it to ASCII so that the LCD would display the 1234 in the display?
without using division.
Upvotes: 1
Views: 1381
Reputation: 1225
How would i go about to convert it to ASCII so that the LCD would display the 1234 in the display?
without using division.
The "without using division" is the tricky part. The first step is to convert a 16-bit binary number to a BCD representation. The best available method is know by several names, the most common is the "double dabble" algorithm. This is an example for the PIC16F:
;
; See:
; https://en.wikipedia.org/wiki/Double_dabble
;
BIN2BCD_VAR UDATA
A_reg: res 2
D_reg: res 3
mBits: res 1
BIN2BCD_CODE CODE
;
; Function: Bin2BCD
; Input: A_reg, 16-bit binary
;
; Output: D_reg, 3 bytes of packed BCD digits
;
Bin2BCD:
banksel D_reg
clrf D_reg+0 ; Clear result
clrf D_reg+1
clrf D_reg+2
movlw D'16' ; Set bit counter
movwf mBits
ConvertBit:
movlw H'33' ; Correct BCD value so that
addwf D_reg+0,F ; subsequent shift yields
btfsc D_reg+0,.3 ; correct value.
andlw H'F0'
btfsc D_reg+0,.7
andlw H'0F'
subwf D_reg+0,F
movlw H'33'
addwf D_reg+1,F
btfsc D_reg+1,.3
andlw H'F0'
btfsc D_reg+1,.7
andlw H'0F'
subwf D_reg+1,F
rlf A_reg+0,F ; Shift out a binary bit ...
rlf A_reg+1,F
rlf D_reg+0,F ; ... and into BCD value.
rlf D_reg+1,F
rlf D_reg+2,F
decfsz mBits,F ; Repeat for all bits
goto ConvertBit
return
The next part is to convert the BCD representation to ASCII characters 4-bits at a time.
I will leave this job to the Original Poster. Good luck.
Upvotes: 0
Reputation: 742
Made it work here is how i did it.
B_HIGH_BYTE and B_LOW_BYTE are the number you want to be converted to ASCII , everything else here is just a temporary variables
I manually divided the number by d'10000' , d'1000', d'100' , d'10' and the last one is whatever is left :)
might not be the fastest way buy made it to work for my needs. Thank you for all you suggestions.
;====================================SPECIAL DIVISION========================
SPECIAL_DIVISION
clrf SPECIAL_DIV_COUNTER
clrf SPECIAL_DIV_HIGH_BYTE
clrf SPECIAL_DIV_LOW_BYTE
clrf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
clrf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movf B_HIGH_BYTE, 0
movwf SPECIAL_DIV_HIGH_BYTE
movf B_LOW_BYTE, 0
movwf SPECIAL_DIV_LOW_BYTE
loop_SD ;getting 5th digit
movf SPECIAL_DIV_HIGH_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
movf SPECIAL_DIV_LOW_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movlw 0x10
subwf SPECIAL_DIV_LOW_BYTE,1
btfss STATUS,0
goto $+2
goto $+3
movlw 0x01
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+7
movlw 0x27
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+3
incf SPECIAL_DIV_COUNTER
goto loop_SD
movf SPECIAL_DIV_COUNTER,0
addlw 0x30
call display_digit
clrf SPECIAL_DIV_COUNTER
movf SPECIAL_DIV_PREV_ANS_HIGH_BYTE,0
movwf SPECIAL_DIV_HIGH_BYTE
movf SPECIAL_DIV_PREV_ANS_LOW_BYTE,0
movwf SPECIAL_DIV_LOW_BYTE
loop_SD2 ;getting 4th digit
movf SPECIAL_DIV_HIGH_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
movf SPECIAL_DIV_LOW_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movlw 0xe8
subwf SPECIAL_DIV_LOW_BYTE,1
btfss STATUS,0
goto $+2
goto $+3
movlw 0x01
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+7
movlw 0x03
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+3
incf SPECIAL_DIV_COUNTER
goto loop_SD2
movf SPECIAL_DIV_COUNTER,0
addlw 0x30
call display_digit
clrf SPECIAL_DIV_COUNTER
movf SPECIAL_DIV_PREV_ANS_HIGH_BYTE,0
movwf SPECIAL_DIV_HIGH_BYTE
movf SPECIAL_DIV_PREV_ANS_LOW_BYTE,0
movwf SPECIAL_DIV_LOW_BYTE
loop_SD3 ;getting 3rd digit
movf SPECIAL_DIV_HIGH_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
movf SPECIAL_DIV_LOW_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movlw 0x64
subwf SPECIAL_DIV_LOW_BYTE,1
btfss STATUS,0
goto $+2
goto $+3
movlw 0x01
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+3
incf SPECIAL_DIV_COUNTER
goto loop_SD3
movf SPECIAL_DIV_COUNTER,0
addlw 0x30
call display_digit
clrf SPECIAL_DIV_COUNTER
movf SPECIAL_DIV_PREV_ANS_HIGH_BYTE,0
movwf SPECIAL_DIV_HIGH_BYTE
movf SPECIAL_DIV_PREV_ANS_LOW_BYTE,0
movwf SPECIAL_DIV_LOW_BYTE
loop_SD4 ;getting 2nd digit
movf SPECIAL_DIV_HIGH_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
movf SPECIAL_DIV_LOW_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movlw 0x0a
subwf SPECIAL_DIV_LOW_BYTE,1
btfss STATUS,0
goto $+2
goto $+3
movlw 0x01
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+3
incf SPECIAL_DIV_COUNTER
goto loop_SD4
movf SPECIAL_DIV_COUNTER,0
addlw 0x30
call display_digit
clrf SPECIAL_DIV_COUNTER
movf SPECIAL_DIV_PREV_ANS_HIGH_BYTE,0
movwf SPECIAL_DIV_HIGH_BYTE
movf SPECIAL_DIV_PREV_ANS_LOW_BYTE,0
movwf SPECIAL_DIV_LOW_BYTE
movf SPECIAL_DIV_LOW_BYTE,0 ;getting 1st digit
addlw 0x30
call display_digit
return
Upvotes: 1
Reputation: 10937
In PIC16 assembler looks 16 bit division by 10 like...
;Input RegA2 as low byte RegA1 as High byte
;Result of division by 10 is stored back to RegA2 and RegA1
;Remainder of division is stored in RegA0
;RegAE is temporary storage
clrf RegA0
movlw 16
movwf RegAE
lslf RegA2, f
divI16by_c10_
rlf RegA1, f
rlf RegA0, f
movlw 10
subwf RegA0, f
btfsc Carry
bra divI16by_c10_OK
addwfc RegA0, f
bcf Carry
divI16by_c10_OK
rlf RegA2, f
decfsz RegAE, f
bra divI16by_c10_
return
Just copy to C language...
Upvotes: 2
Reputation: 4288
To convert a number into ASCII you just had to add 0x30
.
0 dezimal 0x30 ASCII
1 dezimal 0x30 ASCII
2 dezimal 0x32 ASCII
...
But of course you had to split your number into single digits.
Upvotes: 0
Reputation: 497
Here's an example in C, but the same can be done in assembly with few changes.
static void Console_printNum(
uint32_t num,
uint8_t base,
uint8_t point)
{
#define CHAR_BUFSIZE 33
const char* const numchars[] = {"0","1","2","3","4","5","6","7","8","9",
"A","B","C","D","E","F"};
const char* buf[CHAR_BUFSIZE];
const char** pStr = &(buf[CHAR_BUFSIZE-1]);
do {
*(--pStr) = numchars[num % base];
num /= base;
} while( num != 0 );
while( pStr < &buf[CHAR_BUFSIZE-1] ) { //copy the buffer into the queue
if((&buf[CHAR_BUFSIZE-1] - pStr) == point) {
Console_printStr("."); //print decimal point
}
Console_printStr(*pStr++);
}
}
Upvotes: 0