Also: PIC Microcontoller Radix Math Methods
; BIN_ASC 16-bit value ; This routine converts a 16-bit number into a counted string of ; ASCII characters compatible with Serout. It suppresses ; leading zeros so that numbers like 17 are sent as "17" not "00017". buffer = 31 ; String buffer at end of memory. ASC_0 = '0' ; ASCII numbers: 30h thru 39h. ASC_dp = '.' ; ASCII char for decimal point (period). fix = 3 ; Position for fixed decimal point. org 8 dec_no Res 1 ; Decade (1,10,100...) to work on. tempH Res 1 ; 16-bit temporary variable used by tempL Res 1 ; the BIN_ASC routine. hiB Res 1 ; MSB of number to convert. lowB Res 1 ; LSB of number to convert. flags ds 1 zs = flags.0 ; Leading-zero suppression flag. P = pic16c55 ; device pic16c55,xt_osc,wdt_off,protect_off reset start org 0 ; Table consisting of values 10,000, 1000, 100, 10, and 1. decade ADDWF 02, _W RETLW 39 RETLW 16 RETLW 3 RETLW 232 RETLW 0 RETLW 100 RETLW 0 RETLW 10 RETLW 0 RETLW 1 start MOVLW $FF ; To see routines output, either MOVWF hiB MOVLW $FF ; use the PSIM PIC simulator, or MOVWF lowB CALL BIN_ASC ; merge with Serout. GOTO $ ; Endless loop ; This routine accepts a 16-bit number in hiB, lowB and converts it into ; a counted ASCII text string located at the address "buffer." The buffer ; grows downward in memory. The first (0th) item in buffer is the number ; of characters in the string. The routine destroys the contents of ; hiB, lowB. If this value is required elsewhere, make a copy. BIN_ASC CLRF buffer ; Clear char count (item 0 in buf). CLRF flags ; Clear zs flag. CLRF dec_no ; Clear decade no. MOVLW buffer-1 ; Reserve 0th byte of buffer for count. MOVWF fsr BIN_ASC_loop MOVF dec_no ,_w CALL decade ; from the lookup table. MOVWF tempH INCF dec_no ,F ; Get 2nd digit of decade no. MOVF dec_no ,_w CALL decade MOVWF tempL CALL d_point ; Insert decimal point. CALL sub_it ; Divide hiB,lowB by tempH,tempL MOVF indirect ,_w BTFSC flags, 0 ; If zs = 0 AND digit = 0 then GOTO BIN_ASC_no_zs BTFSC 3,2 ; digit is a leading zero to be GOTO BIN_ASC_no_zed BIN_ASC_no_zs MOVWF indirect ADD indirect,#ASC_0 ; an included zero (as in 7501) INCF buffer, F ; or a non-zero digit. DECF fsr, F ; Point to next memory location. BSF flags, 0 ; First non-zero digit sets zs bit. BIN_ASC_no_zed INCF dec_no,F ; Next decade. MOVLW 8 ; If dec_no = 8, we're down to ones. SUBWF dec_no ,_w BTFSS 3,2 GOTO BIN_ASC ; Otherwise, do next decade. INCF dec_no ,F ; Update decade number for d_point. CALL d_point ; Decimal point here? MOVF lowB ,_w MOVWF indirect ADD indirect,#ASC_0 ; Add offset for conversion to ASCII. INCF buffer, F ; Add 1 to character count. RETLW 0h ; This routine performs division by iterated subtraction. It is efficient ; in this application because the dividend and divisor keep getting smaller ; as BIN_ASC runs, so the quotient is never larger than nine. A general- ; purpose division routine would be slower (and longer). sub_it CLRF indirect ; Clear to track no. of subtractions. sub_it_loop MOVF tempL,_w ; Subtract LSB. SUBWF lowB, F BTFSC 3,0 ; If no borrow, continue w/MSB. GOTO sub_it_skip MOVLW 1 ; Otherwise borrow from MSB. SUBWF hiB, F BTFSC 3,0 ; If borrow causes a carry, then GOTO sub_it_skip INCF hiB, F ; add numbers back and return. MOVF tempL,_w ADDWF lowB, F RETLW 0h sub_it_skip MOVF tempH,_w ; Subtract MSB. SUBWF hiB, F BTFSC 3,0 ; If no borrow, subtract again. GOTO sub_it_skip2 ADD lowB,tempL ; Otherwise, undo the subtraction BTFSC 3,0 ; by adding entire 16-bit no. INCF hiB, F ; back together and return. ADD hiB,tempH RETLW 0 sub_it_skip2 INCF indirect, F ; No borrow, so do it again. GOTO sub_it_loop ; This routine adds a decimal point in the location set by "fix" in the ; equates at the beginning of the program. The location of the decimal point ; is in front of the "fix"ed digit, numbered starting with 0. If you fix the ; point at 0, the first (0th) character in the string produced by BIN_ASC ; will be a decimal point. If you don't want a decimal point, either move ; it out of range (fix = 6), or delete this routine and the "call d_point" ; in the body of BIN_ASC above. d_point MOVLW fix*2+1 SUBWF dec_no ,_w BTFSS 3,2 RETLW 0h BSF flags, 0 MOVLW ASC_dp MOVWF indirect INCF buffer, F DECF fsr, F RETLW 0h
Questions:
dear,
I look for a converter code (binary to ASCII) and i think that the code of Dontronics and Scott Edwards is good for me.
But the instruction "ADD indirect,#ASC_0" & "ADD lowB,tempL" are used. I don't uderstand and i don't find this instruction in the data sheet of Microchip...
I use a PIC17C756, could you help me, please?
Sébastien Desmet
Comments:
; This routine accepts a 16-bit number in hiB, lowB and converts it into ; a null terminated ASCII text string located at the address "buffer." ; The routine destroys the contents of hiB, lowB. PRDEC: clrf flags ; Clear zs flag. clrf dec_no ; Clear decade no. movlw buffer ; get buffer addr movwf FSR ; set-up indirect adressing prdeclp: movf dec_no,w call decade ; table lookup movwf tempH ; save it incf dec_no,f ; Get 2nd digit of decade no. movf dec_no,w ; incremented decade counter call decade ; table lookup movwf tempL ; save it ; call d_point ; Insert decimal point. call sub_it ; Divide hiB,lowB by tempH,tempL movf INDF,w ; get the result btfsc flags,0 ; If zs = 0 AND digit = 0 then goto prdecnzs btfsc STATUS,2 ; digit is a leading zero to be goto prdecnz prdecnzs: ;no leading 0 supression movwf INDF movlw a'0' addwf INDF,f ; add ascii '0' incf FSR,f ; Point to next memory location. bsf flags,0 ; First non-zero digit sets zs bit. prdecnz: incf dec_no,f ; Next decade. movlw 0x08 ; If dec_no = 8, we're down to ones. subwf dec_no,w btfss STATUS,2 goto prdeclp ; Otherwise, do next decade. incf dec_no,f ; Update decade number for d_point. ; call d_point ; Decimal point here? movf lowB,w movwf INDF movlw a'0' addwf INDF,f ; add ascii '0' incf FSR,f movlw 0x00 movwf INDF ; null terminated call PRLINE retlw 0x00 ; This routine performs division by iterated subtraction. It is efficient ; in this application because the dividend and divisor keep getting smaller ; as BIN_ASC runs, so the quotient is never larger than nine. A general- ; purpose division routine would be slower (and longer). sub_it: clrf INDF ; Clear to track no. of subtractions. sub_it_loop: movf tempL,w ; Subtract LSB. subwf lowB,f btfsc STATUS,0 ; If no borrow, continue w/MSB. goto sub_it_skip movlw 0x01 ; Otherwise borrow from MSB. subwf hiB,f btfsc STATUS,0 ; If borrow causes a carry, then goto sub_it_skip incf hiB,f ; add numbers back and return. movf tempL,w addwf lowB,f retlw 0x00 sub_it_skip: movf tempH,w ; Subtract MSB. subwf hiB,f btfsc STATUS,0 ; If no borrow, subtract again. goto sub_it_skip2 movf tempL,w addwf lowB,f ; Otherwise, undo the subtraction btfsc STATUS,0 ; by adding entire 16-bit no. incf hiB,f ; back together and return. movf tempH,w addwf hiB,f retlw 0x00 sub_it_skip2 incf INDF,f ; No borrow, so do it again. goto sub_it_loop ; This routine adds a decimal point in the location set by "fix" in the ; equates at the beginning of the program. The location of the decimal point ; is in front of the "fix"ed digit, numbered starting with 0. If you fix the ; point at 0, the first (0th) character in the string produced by BIN_ASC ; will be a decimal point. If you don't want a decimal point, either move ; it out of range (fix = 6), or delete this routine and the "call d_point" ; in the body of BIN_ASC above. d_point movlw fix*2+1 subwf dec_no,w btfss STATUS,2 retlw 0x00 bsf flags,0 movlw a'.' movwf INDF incf FSR,f retlw 0x00 ; Table consisting of values 10,000, 1000, 100, 10, and 1. decade addwf PCL,f retlw d'39' ; 10,000 retlw d'16' retlw d'3' ; 1,000 retlw d'232' retlw d'0' ; 100 retlw d'100' retlw d'0' ; 10 retlw d'10' retlw d'0' ; 1 retlw d'1'