Jake quin
Jake quin

Reputation: 742

A number to LCD display in assembly in PIC16Fxx

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

Answers (5)

Dan1138
Dan1138

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

Jake quin
Jake quin

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

GJ.
GJ.

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

Mike
Mike

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

Oleg Mazurov
Oleg Mazurov

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

Related Questions