; ; *************************************************************************** ; *** Bubble Software Parallax to PIC Source Converter. Copyright 1999. *** ; *** http://www.picnpoke.com email: sales@picnpoke.com *** ; *************************************************************************** ; ; 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". P = pic16c55 #include <16c55.inc> ; processor assembler definitions _CONFIG _xt_osc & _wdt_off & _protect_off reset start buffer equ d'31' ; String buffer at end of memory. ASC_0 equ '0'; ASCII numbers: 30h thru 39h. ASC_dp equ '.'; ASCII char for decimal point (period). fix equd'3' ; Position for fixed decimal point. org 8 dec_no Res d'1' ; Decade (1,10,100...) to work on. tempH Res d'1' ; 16-bit temporary variable used by tempL Res d'1' ; the BIN_ASC routine. hiB Res d'1' ; MSB of number to convert. lowB Res d'1' ; LSB of number to convert. flags Res 1 zs equ ; Leflags.0ading-zero suppression flag. org 0 decade ADDWF pcl RETLW d'39' RETLW d'16' RETLW d'3' RETLW d'232' RETLW d'0' RETLW d'100' RETLW d'0' RETLW d'10' RETLW d'0' RETLW d'1' start MOVLW 0x00FF ; To see routine's output, either MOVWF hiB MOVLW 0x00FF ; 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. 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 ; Get 1st hex digit of decade no. CALL decade ; from the lookup table. MOVWF tempH INCF dec_no ; Get 2nd digit of decade no. MOVF dec_no,w ; from the table. CALL decade MOVWF tempL CALL d_point ; Insert decimal point. CALL sub_it ; Divide hiB,lowB by tempH,tempL MOVF indirect,w ; returning answer in indirect. BTFSC flags,d'0' ; If zs = 0 AND digit = 0 then GOTO BIN_ASC_no_zs BTFSC status,z ; digit is a leading zero to be GOTO BIN_ASC_no_zed BIN_ASC_no_zsMOVWF indirect ; ignored. Otherwise, it's either MOVLW ASC_0 ; an included zero (as in 7501) ADDWF indirect INCF buffer ; or a non-zero digit. DECF fsr ; Point to next memory location. BSF flags,d'0' ; First non-zero digit sets zs bit. BIN_ASC_no_zed INCF dec_no ; Next decade. MOVLW d'8' ; If dec_no = 8, we're down to ones. SUBWF dec_no,w BTFSS status,z GOTO BIN_ASC_loop ; Otherwise, do next decade. INCF dec_no ; Update dec_no CALL d_point ; and call d_point. MOVF lowB,w ; Whatever's left belongs in ones. MOVWF indirect MOVLW ASC_0 ; Add offset for conversion to ASCII. ADDWF indirect INCF buffer ; 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 BTFSC status,c ; If no borrow, continue w/MSB. GOTO sub_it_skip MOVLW d'1' ; Otherwise borrow from MSB. SUBWF hiB BTFSC status,c ; If borrow causes a carry, then GOTO sub_it_skip INCF hiB ; add numbers back and return. MOVF tempL,w ADDWF lowB RETLW 0h sub_it_skip MOVF tempH,w ; Subtract MSB. SUBWF hiB BTFSC status,c ; If no borrow, subtract again. GOTO sub_it_skip2 MOVF tempL,w ; Otherwise, undo the subtraction ADDWF lowB BTFSC status,c ; by adding entire 16-bit no. INCF hiB ; back together and return. MOVF tempH,w ADDWF hiB RETLW 0h sub_it_skip2 INCF indirect ; 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,z RETLW 0h BSF flags,d'0' MOVLW ASC_dp MOVWF indirect INCF buffer DECF fsr RETLW 0h end