Home     Contact     Projects     Experiments     Circuits     Theory     BLOG     PIC Tutorials     Time for Science     RSS     Terms of services     Privacy policy  
   
 Home      Projects     Experiments     Circuits     Theory     BLOG     PIC Tutorials     Time for Science   



All about PIC microcontrollers

Within these pages, you can find many useful pieces of code mostly in assembly for the Microchip PIC micro controller family. A lot of people have spend many hours trying to put the bits and bytes together. If the code is NOT written by a member of the PCB Heaven community, then a link will be added above the code with the original website that this code was found.
Because the code is copied to our servers, you should know that:

  • The responsible web master of the website that the code is taken, has been informed and he has agreed to copy the code
  • All emails from the above contact have been kept as records but due to personal privacy cannot be shown in public.
  • The author of the code is always clearly indicated above the code. In some cases the author is unknown. If you happen to be the author of the code or you know the person who wrote it, please inform us by email and it will be added ASAP.

We would personally like to send the credits to all the people that managed to write some very interesting code and publish it, and special thanx to the people that originally hosted those code snippets and gave us the permission to copy them.


View code
Binary to BCD packed and ASCII, 24 bit to 8 or 9 digits with sign, and decimal point
Author: Tony Kuebek
This code was originally located @ http://www.piclist.com


Follow this link to go back

it's for 24 bit signed variable, then I cannot output a variable at a time ( supposed to go inside an int handler ), therefore I'm using a 9 byte string to store the result, furthermore for the decimal point and supressing of leading zeroes I needed 1 byte and 2 bit variables. ... Its a bit of 'bloatware', requires about 290 ! instructions but thats efficient enough for me, I might get back to hammer on it when I've finished off the other bits I'm starting with now. I think it goes around 480 instruction executed worst case, and all the way down to 250 something for best case. Also I added a minor conditional that makes execution a tad faster for 20 bit numbers ( as my app will have about 99 % in this range ) to the expence of more code and additional execution for larger numbers.

;**********************************************************************
; This file is a basic code template for assembly code generation *
; on the PICmicro PIC16F877. This file contains the basic code *
; building blocks to build upon. *
; *
; If interrupts are not used all code presented between the ORG *
; 0x004 directive and the label main can be removed. In addition *
; the variable assignments for 'w_temp' and 'status_temp' can *
; be removed. *
; *
; Refer to the MPASM User's Guide for additional information on *
; features of the assembler (Document DS33014). *
; *
; Refer to the respective PICmicro data sheet for additional *
; information on the instruction set. *
; *
; Template file assembled with MPLAB V4.00 and MPASM V2.20.00. *
; *
;**********************************************************************
; *
; Filename: MathTest.asm 24bit signed binary->ASCII w. dp *
; Date: 2000-03-31 *
; File Version: 0.1B *
; *
; Author: Tony Kuebek *
; Company: *
; *
; *
;**********************************************************************
; *
; Files required: *
; *
; *
; *
;**********************************************************************
; *
; Notes: Tests of binary to ASCII coversion *
; Routines from techref.massmind.org *
; Originators(16bit): Scott Dattalo and Nikolai Golovchenko*
; Routine takes 24 bit signed binary number and coverts to *
; 8/9 byte ASCII(true!) decimal string with decimal point *
; and minus sign as the first byte ( if negative ). *
; 24 bit variabel is stored in last three string bytes *
; These are 'destroyed' during processing *
; Leading zeroes are surpressed (conv. to space) *
; Resources needed: *

; DpPlacement 1 byte + 1 bit *
; PrevIsChar 1 bit ,prev. zero was surpressed*
; ASCII string of 9 bytes *
;**********************************************************************


list p=16f877 ; list directive to define processor
#include ; processor specific variable definitions

__CONFIG _CP_OFF & _WDT_ON & _BODEN_ON & _PWRTE_ON & _RC_OSC & _WRT_ENABLE_ON & _LVP_OFF& _DEBUG_OFF & _CPD_OFF

; '__CONFIG' directive is used to embed configuration data within .asm file.
; The lables following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.

#define TEST_SMALL_NUMBER ; if defined then tests are performed
; to see number is less than +/-1048575 ( 20 bit )
; makes routine a little faster for thoose numbers
; to the expence of more code
; and adds some cycles to all numbers above if used
; but can deduct upto 62 cycles on smaller numbers

#define DECIMAL_POINT 0x2E ; '.'
#define BYTE_OFFSET 0x30 ; start decimal ASCII numbers
#define SIGN_NEGATIVE 0x2D ; '-'

;***** VARIABLE DEFINITIONS
CBLOCK 0x20 ; start userram bank 0

BitVars:1 ; used for dp-bit variable
OutPut:9 ; 8 used if no dp, else 9
DpPlacement:1 ; where to put dp, counted from start, min=1
; note an added bonus here ! as this var is
; located directly after the string and will
; 'always' be = 0x00(after conversion),
; you have an 'free' null terminator

ENDC



w_temp EQU 0x70 ; variable used for context saving
status_temp EQU 0x71 ; variable used for context saving


#define _DpUsed BitVars,0 ; decimal point has been placed
#define _PrevIsSpace BitVars,1 ; previous byte/digit is 'converted' to space

#define Sample OutPut+6 ; Note !! to save ram, 24 bit variable is stored
; in highest three byte in 9 byte string






;**********************************************************************
ORG 0x000 ; processor reset vector
clrf PCLATH ; ensure page bits are cleared
goto MAIN ; go to beginning of program


ORG 0x004 ; interrupt vector location
movwf w_temp ; save off current W register contents
movf STATUS,w ; move status register into W register
movwf status_temp ; save off contents of STATUS register


; isr code can go here or be located as a call subroutine elsewhere


movf status_temp,w ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf w_temp,f
swapf w_temp,w ; restore pre-isr W register contents
retfie ; return from interrupt



MAIN




;************************ Tony test 24 bit->8/9 digit ASCII with decimal point
; code with TEST_SMALL_NUMBER: (about)290 instructions ( excluding variable setup code )
;
; True ASCII conversion, variable decimalpoint, surpress leading zeroes
; 24 bit variable is handled as SIGNED!
;************************************
CLRF BitVars

; dp=1->dp=7(no dp), adds approx 50 cycles, i.e. dp=1 least cycles
MOVLW 1 ; note dp = 1 = between first and second digit
; dp = 7 between the last and second last digit
; if dp >= 7, dp = 0 then last digit is = 0x00
MOVWF DpPlacement

MOVLW BYTE_OFFSET ; preset with ASCII offset
MOVWF OutPut
MOVWF OutPut+1
MOVWF OutPut+2
MOVWF OutPut+3
MOVWF OutPut+4
MOVWF OutPut+5
BCF OutPut,4 ; clear bit, makes first char 'space'


; OutPut+6 - OutPut+8 will contain 24 bit sample, LSB in OutPut+8
; ** NOTE ** Sample = OutPut+6, Sample+1 = OutPut+7, Sample+2 = OutPut+8
; Sample is defined as a separate name as it makes the code easier to read


; test number : 1235783 = 0x12DB47 - ok ! cycles approx: 301 -350 depending on dp placment
; Note ! This with TEST_SMALL_NUMBER, without deduct 10 cycles
; MOVLW 0x47
; MOVWF Sample+2
; MOVLW 0xDB
; MOVWF Sample+1
; MOVLW 0x12
; MOVWF Sample

; test number : -1235783 = 0xED24B9 - ok ! cycles approx: 311 -360 depending on dp placment
; Note ! This with TEST_SMALL_NUMBER, without deduct 10 cycles
; MOVLW 0xB9
; MOVWF Sample+2
; MOVLW 0x24
; MOVWF Sample+1
; MOVLW 0xED
; MOVWF Sample

; test number : 60900 = 0x00EDE4 - ok ! cycles approx: 315 -371 depending on dp placment
; Note ! This with TEST_SMALL_NUMBER, without add 63 cycles
; MOVLW 0xE4
; MOVWF Sample+2
; MOVLW 0xED
; MOVWF Sample+1
; MOVLW 0x00
; MOVWF Sample

; test number : -60900 = 0xFF121C - ok ! cycles approx: 325 -381 depending on dp placment
; Note ! This with TEST_SMALL_NUMBER, without add 56 cycles
; MOVLW 0x1C
; MOVWF Sample+2
; MOVLW 0x12
; MOVWF Sample+1
; MOVLW 0xFF
; MOVWF Sample



; test number : 231 = 0xE7 - ok !, cycles approx 244-302 depending on dp placement
; NOTE ! With TEST_SMALL_NUMBER, without add 62 cycles

; MOVLW 0xE7
; MOVWF Sample+2
; MOVLW 0x00
; MOVWF Sample+1
; MOVLW 0x00
; MOVWF Sample

; test number : -1 = 0xFFFFFF - ok !, cycles approx:262-326 depending on dp placement
; This with TEST_SMALL_NUMBER, without add 62 cycles
;

; MOVLW 0xFF
; MOVWF Sample+2
; MOVLW 0xFF
; MOVWF Sample+1
; MOVLW 0xFF
; MOVWF Sample

; test number : 1048575 = 0x0FFFFF - ok !, cycles approx: 297-348 depending on dp placement
; this with TEST_SMALL_NUMBER, without add 8 cycles
; MOVLW 0xFF
; MOVWF Sample+2
; MOVLW 0xFF
; MOVWF Sample+1
; MOVLW 0x0F
; MOVWF Sample

; test number : 1000000 = 0x0F4240 - ok !, cycles approx: 291-350 depending on dp placement
; this with TEST_SMALL_NUMBER, without add 8 cycles
; MOVLW 0x40
; MOVWF Sample+2
; MOVLW 0x42
; MOVWF Sample+1
; MOVLW 0x0F
; MOVWF Sample

; test number : 8388607 = 0x7FFFFF - ok !, cycles approx: 394-445 depending on dp placement
; this with TEST_SMALL_NUMBER, without add 8 cycles
; MOVLW 0xFF
; MOVWF Sample+2
; MOVLW 0xFF
; MOVWF Sample+1
; MOVLW 0x7F
; MOVWF Sample
; test number : -7099999 = 0x93A9A1 - ok !, cycles approx:429-480 depending on dp placement
; this with TEST_SMALL_NUMBER, without add 8 cycles
MOVLW 0xA1
MOVWF Sample+2
MOVLW 0xA9
MOVWF Sample+1
MOVLW 0x93
MOVWF Sample


TEST_NEGATIVE
BTFSS Sample,7 ; test if negative
IFDEF TEST_SMALL_NUMBER
GOTO TEST_TOPNIBBLE ; nope
ELSE
GOTO SUB4M ; nope
ENDIF

; sample is negative
; make two's complement
COMF Sample+2,F
COMF Sample+1,F
COMF Sample,F
MOVLW 1
ADDWF Sample+2,F
SKPNC
ADDWF Sample+1,F
SKPNC
ADDWF Sample,F

MOVLW SIGN_NEGATIVE
MOVWF OutPut ; first digit minus sign



IFDEF TEST_SMALL_NUMBER ; test for small numbers and skips some loops
; use if number is often in 0-1048575 range ( negative or not)
; i.e. 0x000000 - 0x0FFFFF ( 2.5 bytes 20 bits )

TEST_TOPNIBBLE
; test if top nibble is zero, i.e. number less than 1048575 ( decimal )
; if so we can skip to sub300k routine

MOVF Sample,w
ANDLW 0x70 ; Mask out top three bits
BNZ SUB4M ; nope do full conversion

; this digit is zero, and dp is not yet set
; then downshift to space
BSF _PrevIsSpace
BCF OutPut+1,4

GOTO SUB300k ; continue

ENDIF ; TEST_SMALL_NUMBER


SUB4M:
; subtract 4 million from sample
MOVLW 4
ADDWF OutPut+1, f
MOVLW low(4000000)
SUBWF Sample+2, f

MOVLW low(4000000>>8)
SKPC
MOVLW low(4000000>>8)+1
SUBWF Sample+1, f

MOVLW low(4000000>>16)
SKPC
MOVLW low(4000000>>16) + 1
SUBWF Sample, f


SKPNC ; overflow, i.e. negative
GOTO SUB4M

ADD1M:
; add 1 million to sample
DECF OutPut+1, f
MOVLW low(1000000)
ADDWF Sample+2, f

MOVLW low(1000000>>8)
SKPNC
MOVLW low(1000000>>8) + 1
ADDWF Sample+1, f

MOVLW low(1000000>>16)
SKPNC
MOVLW low(1000000>>16) + 1
ADDWF Sample, f

SKPC ; done ?
GOTO ADD1M

; test for leading zeroes
MOVLW BYTE_OFFSET
SUBWF OutPut+1,w
BNZ SUB300k

; this digit is zero, and dp is not yet set
; then downshift to space
BSF _PrevIsSpace
BCF OutPut+1,4


SUB300k:
; substract 300 thousand from sample
MOVLW 3
ADDWF OutPut+3, f
MOVLW low(300000)
SUBWF Sample+2, f

MOVLW low(300000>>8)
SKPC
MOVLW low(300000>>8)+1
SUBWF Sample+1, f

MOVLW low(300000>>16)
SKPC
MOVLW low(300000>>16) + 1
SUBWF Sample, f


SKPNC
GOTO SUB300k

ADD100k
; add 100 thousand to sample
DECF OutPut+3, f
MOVLW low(100000)
ADDWF Sample+2, f

MOVLW low(100000>>8)
SKPNC
MOVLW low(100000>>8) + 1
ADDWF Sample+1, f

MOVLW low(100000>>16)
SKPNC
MOVLW low(100000>>16) + 1
ADDWF Sample, f

SKPC ; done
GOTO ADD100k
IFDEF TEST_SMALL_NUMBER ; if this test enabled it is possible
; to have an overflow here

; test for overflow ( Output+3 = 10 )

MOVLW BYTE_OFFSET+0x0A
SUBWF OutPut+3,W
BTFSS STATUS,Z ; test if non zero
GOTO ADD100k_TstDp


; over flow, result is = 10, second digit = 1, third = 0
MOVLW BYTE_OFFSET
MOVWF OutPut+3
BTFSS _DpUsed ; test if dp already used
BSF OutPut+1,0 ; if no dp used set this digit to one
BSF OutPut+2,0 ; set also third digit to 1 ( in case dp is used )

; restore previous digit
BTFSS _PrevIsSpace
GOTO ADD100k_TstDp

BSF OutPut+1,4
BCF _PrevIsSpace

ENDIF

ADD100k_TstDp:

; test for dp
DECFSZ DpPlacement,F ; test for dp placement
GOTO ADD100k_NoDp ; no dp yet
; place dp
BSF _DpUsed ; dp is used
MOVLW DECIMAL_POINT ;
MOVWF OutPut+2 ; dp is third digit

; restore zero before dp
BTFSC _PrevIsSpace
BSF OutPut+1,4

GOTO SUB30k ; continue

ADD100k_NoDp:
; no dp copy back number
MOVF OutPut+3,W
MOVWF OutPut+2

; test for leading zeroes
MOVLW BYTE_OFFSET
SUBWF OutPut+2,w
BTFSS STATUS,Z
BCF _PrevIsSpace
BNZ SUB30k

BTFSS _PrevIsSpace
GOTO SUB30k

; this digit is zero, and dp is not yet set
; then downshift to space
BSF _PrevIsSpace
BCF OutPut+2,4


SUB30k:
; subtract 30'000 from sample
MOVLW 3
ADDWF OutPut+4, f
MOVLW low(30000)
SUBWF Sample+2, f

MOVLW low(30000>>8)
SKPC
MOVLW low(30000>>8)+1
SUBWF Sample+1, f

MOVLW low(30000>>16)
SKPC
MOVLW low(30000>>16) + 1
SUBWF Sample, f


SKPNC ; negative ?
GOTO SUB30k
ADD10k:
; add 10'000 to sample

DECF OutPut+4, f
MOVLW low(10000)
ADDWF Sample+2, f

MOVLW low(10000>>8)
SKPNC
MOVLW low(10000>>8) + 1
ADDWF Sample+1, f

MOVLW low(10000>>16)
SKPNC
MOVLW low(10000>>16) + 1
ADDWF Sample, f

SKPC ; done ?
GOTO ADD10k

BTFSC _DpUsed
GOTO SUB3k ; dp is already used continue

; test for dp
DECFSZ DpPlacement,F ; test for dp placement
GOTO ADD10k_NoDp ; no dp yet
; place dp
BSF _DpUsed ; dp is used
MOVLW DECIMAL_POINT ;
MOVWF OutPut+3 ; dp is fourth digit

; restore zero before dp
BTFSS _PrevIsSpace
BSF OutPut+2,4


GOTO SUB3k ; continue

ADD10k_NoDp:
; no dp copy back number
MOVF OutPut+4,W
MOVWF OutPut+3

; test for leading zeroes
MOVLW BYTE_OFFSET
SUBWF OutPut+3,w
BTFSS STATUS,Z
BCF _PrevIsSpace
BNZ SUB3k

BTFSS _PrevIsSpace
GOTO SUB3k

; this digit is zero, and dp is not yet set
; then downshift to space
BSF _PrevIsSpace
BCF OutPut+3,4

SUB3k:
; subtract 3000 from sample
MOVLW 3
ADDWF OutPut+5, f
MOVLW low(3000)
SUBWF Sample+2, f

MOVLW low(3000>>8)
SKPC
MOVLW low(3000>>8)+1
SUBWF Sample+1, f

SKPNC ; negative ?
GOTO SUB3k
ADD1k:
; add 1000 to sample
DECF OutPut+5, f
MOVLW low(1000)
ADDWF Sample+2, f

MOVLW low(1000>>8)
SKPNC
MOVLW low(1000>>8) + 1
ADDWF Sample+1, f

SKPC
GOTO ADD1k

BTFSC _DpUsed
GOTO SUB300_PreLoad ; dp is already used continue

; test for dp
DECFSZ DpPlacement,F ; test for dp placement
GOTO ADD1k_NoDp ; no dp yet
; place dp

BSF _DpUsed ; dp is used
MOVLW DECIMAL_POINT ;
MOVWF OutPut+4 ; dp is fifth digit

; restore zero before dp
BTFSC _PrevIsSpace
BSF OutPut+3,4

GOTO SUB300_PreLoad ; continue

ADD1k_NoDp:
; no dp copy back number
MOVF OutPut+5,W
MOVWF OutPut+4

; test for leading zeroes
MOVLW BYTE_OFFSET
SUBWF OutPut+4,w
BTFSS STATUS,Z
BCF _PrevIsSpace
BNZ SUB300_PreLoad

BTFSS _PrevIsSpace
GOTO SUB300_PreLoad

; this digit is zero, and dp is not yet set
; then downshift to space
BSF _PrevIsSpace
BCF OutPut+4,4

SUB300_PreLoad
MOVLW BYTE_OFFSET
MOVWF OutPut+6
SUB300:
; subtract 300 from sample
MOVLW 3
ADDWF OutPut+6, f
MOVLW low(300)
SUBWF Sample+2, f

MOVLW low(300>>8)
SKPC
MOVLW low(300>>8)+1
SUBWF Sample+1, f

SKPNC ; negative ?
GOTO SUB300

MOVLW 100

ADD100:
; add 100 to sample
DECF OutPut+6, f
ADDWF Sample+2, f
SKPC
GOTO ADD100
INCF Sample+1, f
BTFSC Sample+1, 7
GOTO ADD100

BTFSC _DpUsed
GOTO SUB30_PreLoad ; dp is already used continue

; test for dp
DECFSZ DpPlacement,F ; test for dp placement
GOTO ADD100_NoDp ; no dp yet
; place dp
BSF _DpUsed ; dp is used
MOVLW DECIMAL_POINT ;
MOVWF OutPut+5 ; dp is sixth digit

; restore zero before dp
BTFSC _PrevIsSpace
BSF OutPut+4,4

GOTO SUB30_PreLoad ; continue

ADD100_NoDp:
; no dp copy back number
MOVF OutPut+6,W
MOVWF OutPut+5

; test for leading zeroes
MOVLW BYTE_OFFSET
SUBWF OutPut+5,w
BTFSS STATUS,Z
BCF _PrevIsSpace
BNZ SUB30_PreLoad

BTFSS _PrevIsSpace
GOTO SUB30_PreLoad

; this digit is zero, and dp is not yet set
; then downshift to space
BSF _PrevIsSpace
BCF OutPut+5,4


SUB30_PreLoad:
MOVLW 30
SUB30:
; subtract 30 from sample
INCF OutPut+7, f
SUBWF Sample+2, f
SKPNC
GOTO SUB30
MOVFW OutPut+7
RLF OutPut+7, f
ADDWF OutPut+7, f
MOVLW 10

ADD10:
; add 10 to sample
DECF OutPut+7, f
ADDWF Sample+2, f
SKPC
GOTO ADD10

MOVLW BYTE_OFFSET
ADDWF OutPut+7,f

BTFSC _DpUsed
GOTO LAST_DIGIT ; dp is already used continue

; test for dp
DECFSZ DpPlacement,F ; test for dp placement
GOTO ADD10_NoDp ; no dp yet
; place dp
BSF _DpUsed ; dp is used
MOVLW DECIMAL_POINT ;
MOVWF OutPut+6 ; dp is seventh digit

; restore zero before dp
BTFSC _PrevIsSpace
BSF OutPut+5,4

GOTO LAST_DIGIT ; continue

ADD10_NoDp
; no dp copy back number
MOVF OutPut+7,W
MOVWF OutPut+6
; test for leading zeroes
MOVLW BYTE_OFFSET
SUBWF OutPut+6,w
BNZ LAST_DIGIT

BTFSS _PrevIsSpace
GOTO LAST_DIGIT

; this digit is zero, and dp is not yet set
; then downshift to space
BSF _PrevIsSpace
BCF OutPut+6,4

LAST_DIGIT:

MOVLW BYTE_OFFSET
ADDWF Sample+2,w
MOVWF Sample+2

BTFSS _DpUsed
MOVWF OutPut+7 ; save in previous byte
BTFSC _DpUsed
GOTO END_CONV

DECFSZ DpPlacement,F ; test for dp placement
GOTO CLEAR_LAST ; no dp used at all ??
MOVLW DECIMAL_POINT ;
MOVWF OutPut+7 ; dp is eigth digit

; restore zero before dp
BTFSC _PrevIsSpace
BSF OutPut+6,4

GOTO END_CONV
CLEAR_LAST:
; no dp used copy back number, and clear last digit
BTFSS _DpUsed
CLRF OutPut+8 ; clear last digit no dp used

END_CONV
NOP ; done :-)
GOTO MAIN




END ; directive 'end of program'

Follow this link to go back






delicious
digg
reddit this Reddit this
Faves



 HOT in heaven!