Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

16f84A breaking down decimal into individual digit

Status
Not open for further replies.

wejos

Member
hi guys,

is it possible to breakdown a decimal value e.g. 123 through code and assign the individual numbers to GPR. something like: in address 0x0C, the value 1 is stored; in address 0x1C, the value 2 is stored; and in address 0x0D, the value 3 is stored. this way this will really really spare me a lot of space.

what iv'e done is i hard coded the value and this went on to 255 of this routine:

Code:
MOVF  VALIN,W
	   XORLW 0x00
	   btfsc STATUS, Z
       GOTO  WR0
       GOTO  WR1X
WR0    MOVLW 0x00
       MOVWF VALF	
       MOVLW 0x00
       MOVWF VALS	
       MOVLW 0x00
       MOVWF VALT	
      

WR1X   MOVF  VALIN,W
	   XORLW 0x01
	   btfsc STATUS, Z
       GOTO  WR1
       GOTO  WR2X
WR1    MOVLW 0x01
       MOVWF VALF	
       MOVLW 0x00
       MOVWF VALS	
       MOVLW 0x00
       MOVWF VALT	
      

WR2X   MOVF  VALIN,W
	   XORLW 0x02
	   btfsc STATUS, Z
       GOTO  WR2
       GOTO  WR3X
WR2    MOVLW 0x02
       MOVWF VALF	
       MOVLW 0x00
       MOVWF VALS	
       MOVLW 0x00
       MOVWF VALT

if my math is correct i have to use 3-4 16f84 chips. but if you can split VALIN to 3 decimal values, only two is needed to drive a 7-seg display (X3).

i guess i ran out of space because i get this error "0566 not between 0000 and 03FF". so more PIC is needed and if there is a way to split decimal, boy that'd really save my day : )

thanks in advance
 
Last edited:
WOAH what did you do there lol. Here use this code PLEASE:

Code:
;*************************************
; Program : 16 Bit Bin to 4 Digit Dec
; Date    : September 6th, 2009
;*************************************


	List	P=16F628a
	#include	"P16F628a.INC"
	__CONFIG	_PWRTE_ON  & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _BODEN_ON & _LVP_OFF & _CP_OFF & _MCLRE_OFF

;*** Cblock ***

	CBLOCK	0x20		 
	Ones								;
	Tens								;
	Hund								;
	Thou								;
	TenK								;
	Hi
	Lo
	ENDC

;*** START OF RAM ***
	ORG	0x000							; Start of program vector
	GOTO	Start						;
	ORG	0x004							; Interrupt vector

;*** Configuration ***

Start:
	MOVLW	0x07						; Turn comparators off and enable pins for I/O
	MOVWF	CMCON						; ^
	CLRF	PORTA						; PortA all low
	CLRF	PORTB						; PortB all low
	
	BSF		STATUS,RP0					; Bank 1
	MOVLW	b'00100000'					; Bit 5 input
	MOVWF	TRISA						; PortA all output except MCLR
	CLRF	TRISB						; PortB all output
	BCF		STATUS,RP0					; Bank 0

;*** Main Code ***

Main:
	MOVLW	b'00001010'
	MOVWF	NumL						; 6666
	MOVLW	b'00011010'
	MOVWF	NumH
	CALL	Convert
	GOTO	Main

;*** Bin to BCD routine ***
Convert:                      		  	; Takes number in NumH:NumL 
;{

    swapf   Hi,w                     ; Returns decimal in 
	iorlw	b'11110000'                 ; TenK:Thou:Hund:Tens:Ones
    movwf   Thou
    addwf   Thou,f
    addlw   0xe2
    movwf   Hund
    addlw   0x32
    movwf   Ones

    movf    Hi,w
    andlw   0x0f
    addwf   Hund,f
    addwf   Hund,f
    addwf   Ones,f
    addlw   0xe9
    movwf   Tens
    addwf   Tens,f
    addwf   Tens,f

    swapf   Lo,w
    andlw   0x0f
    addwf   Tens,f
    addwf   Ones,f

    rlf     Tens,f
    rlf     Ones,f
    comf    Ones,f
    rlf     Ones,f

    movf    Lo,w
    andlw   0x0f
    addwf   Ones,f
    rlf	    Thou,f

    movlw   0x07
    movwf   TenK

    movlw   0x0A                        ; Ten
Lb1:									; At this point, the original number is
    addwf   Ones,f                    	; equal to
    decf    Tens,f                    	; TenK*10000+Thou*1000+Hund*100+Tens*10+Ones
    btfss   3,0                    		; if those entities are regarded as two's
    goto   	Lb1                   		; complement binary.  To be precise, all of
Lb2:                    				; them are negative except TenK.  Now the number
    addwf   Tens,f                    	; needs to be normalized, but this can all be
    decf    Hund,f                    	; done with simple byte arithmetic.
    btfss   3,0
    goto   	Lb2
Lb3:
    addwf   Hund,f
    decf    Thou,f
    btfss   3,0
    goto   	Lb3
Lb4:
    addwf   Thou,f
    decf    TenK,f
    btfss   3,0
    goto  	Lb4

	return	
;}

	END

; That's all folks!
 
if my math is correct i have to use 3-4 16f84 chips. but if you can split VALIN to 3 decimal values, only two is needed to drive a 7-seg display (X3).

If you multiplex the displays you can run up to 4x 7-segment displays from a single 16F84 -

**broken link removed**

The MCLR pullup resistor and the oscillator circuit were omitted from the schematic for the sake of clarity.

To display decimal numbers 1, 2, 3, and 4, the code would look something like this -

Code:
COUNT		EQU	0x20

START		movlw	0x06
		movwf	PORTB
		bsf	PORTA,3
		call	On_Delay
		bcf	PORTA,3

		movlw	0x5B
		movwf	PORTB
		bsf	PORTA,2
		call	On_Delay
		bcf	PORTA,2

		movlw	0x4F
		movwf	PORTB
		bsf	PORTA,1
		call	On_Delay
		bcf	PORTA,1

		movlw	0x66
		movwf	PORTB
		bsf	PORTA,0
		call	On_Delay
		bcf	PORTA,0

		goto	START

On_Delay	movlw	0xFF
		movwf	COUNT		;or whatever GP RAM address you want to use for a counter
repeat		decfsz	COUNT,F
		goto	repeat

		return

You'll notice in the schematic that RA 0-3 control the ground source to each display unit via the 4 transistors. In the code, you write the appropriate hex value that lights up the required segments for each digit to Port B. Then you set the RA bit that turns the grounding transistor for the display you want to activate on, run a delay loop, then immediately turn it off by clearing the appropriate RA bit.

You then write the next hex value to Port B, then set the appropriate RA bit to turn the next display on, then off again...so on and so forth down the line.

You want to clear the RA bit that controls the previous digit prior to writing the required hex value for the digit to be displayed for the next display unit to Port B.

In reality, you're writing the hex value that is required to light up the appropriate segments for the digit to be displayed, turning the display on, then off again sequentially for each display unit. The catch here is that the uC does this all too fast for the human eye to actually see the numbers turning on and off. Thus to the human eye it will appear that all of the digits are constantly on but are different decimal values.

With longer delay loops you can do scrolling digits as well.

With some complex multiplexing and the addition of a couple of BCD to 7 segment LED drivers, you can drive 8 7 segment displays with a single 16F84 -

**broken link removed**
 
Last edited:
If you use the SUBLW instruction to subtract W from the literal value, the carry flag is set if the result in W is less than or equal to the literal value -

W < N - Carry Flag Set
W > N - Carry Flag Clear

Where "N" is the literal value used in the SUBLW instruction.
 
Last edited:
sorry for the late responce guys, apart from the mountain laundry i had to deal with it also took a while before all that stuff you told me to register in my head

:eek: it's 3,000+ line of code but you will not believe i actually typed all the 255 of them. i understand it will work but won't be cost effective and because there is much simpler way to accomplish this, there is no point really to head that direction

first off, birdman's code is too advance for me but i copied some ideas from the code he posted and came up with the one below. i'm afraid that i have to port it to 16f84 so i was saving it for last resort. now i simulated the code below it using osohonsoft, it appears to be working so far

Code:
valin    equ 0x1C
hundreds equ 0x1D
hpasses  equ 0x1E
tpasses  equ 0x1F
tens     equ 0x0C
ones     equ 0x20

start        movlw 0x1F  ;example value coming from lm35 to adc0804 and finally to 16f84
             movwf valin
             movf  valin,w
             movwf hundreds
mainhundreds movlw 0x64                  
	         subwf hundreds
	         btfsc STATUS, C
	         goto  counthundred
             movlw 0x64
             addwf hundreds     
starttens    movf  hundreds,w
             movwf tens  
tenspoint    movlw 0x0A
             subwf tens 
             btfsc STATUS, C
             goto counttens
             movlw 0x0A
             addwf tens
             movf  tens,w             
             movwf ones
             return     
counthundred movlw 0x01
             addwf hpasses
             goto mainhundreds
counttens    movlw 0x01
             addwf tpasses
             goto tenspoint

	end

birdman thank you


next is on jon's scematic and code to drive the 7-seg displays. i simulated his schematic using proteus but haven't seen yet the results, since the code for look-up table is still in the process. i need the look-up table to set correctly the PORTB pins. i'm confident however that what he suggested is the best solution so far i can tell. thank you very much jon i am making a look-up table to properly light up the correct leds. it's your idea also to use the sublw instruction, thank you again. i will look closely how you coded yours and try to learn from it.

i am very grateful for your help guys, i'll be back soon.
 

Attachments

  • scehmatic.JPG
    scehmatic.JPG
    120.8 KB · Views: 557
... With some complex multiplexing and the addition of a couple of BCD to 7 segment LED drivers, you can drive 8 7 segment displays with a single 16F84 ...

**broken link removed**

Hi Jon,

Just wanted to supplement your fine example.

If the design allows for adding driver ICs, you can actually drive a lot more than just eight 7-segment displays on the 'F84. For example, you could use 5 pins to drive 12 displays (3x4, see below), or 6 I/O pins to drive 20 displays (4x5), or 7 I/O pins to drive 30 displays (5x6), and so on. And if the 16F84 had a PWM module you could take advantage of complete fade-to-black PWM brightness control running as a 0% overhead background task.

Happy Holidays everyone. Mike

macmux-3-png.49214
 

Attachments

  • MacMux #3.png
    MacMux #3.png
    31.7 KB · Views: 3,718
Last edited:
Hi wejos,

Here's another way (of many different ways) to convert an 8 bit binary number (0..255) into three BCD digits (0..9);

Code:
;
;  13 words, 3 variables, 10 to 166 cycles     Mike, K8LH
;
btod255
        movwf   ones            ; put WREG (total) into 'ones'
        clrf    huns            ; clear 'huns'
        movlw   -10             ; wreg = -10
resetx  movwf   tens            ; reset 'tens' to -10
div10x  addwf   ones,F          ; ones = ones - 10, borrow?
        skpc                    ; no, skip, else
        goto    b2done          ; branch (we're done)
        incfsz  tens,F          ; increment 'tens', overflow?
        goto    div10x          ; no, branch, else
        incf    huns,F          ; increment 'huns'
        goto    resetx          ; reset 'tens'
b2done  subwf   tens,F          ; fix -10 offset
        subwf   ones,F          ; fix -10 offset
For time critical applications you might use something like the following routine which is about the same size as what you're using now but it converts any binary input, 0 through 255, in precisely 27 cycles;

Code:
;
;  8-bit binary to 3 digit BCD (isochronous)
;
;   input: WREG, 0..255
;  output: huns, 0..2
;          tens, 0..9
;          ones, 0..9
;
;  27 words/cycles (isochronous)
;
    radix    dec

        clrf    huns            ;
        clrf    tens            ;
        addlw   -200            ; W = W - 200
        rlf     huns,F          ; pick up Carry result
        btfss   huns,0          ; borrow? no, skip, else
        addlw   200             ; add 200 back
        addlw   -100            ; subtract 100
        rlf     huns,F          ; pick up Carry result
        btfss   huns,0          ; borrow? no, skip, else
        addlw   100             ; add 100 back
        addlw   -80             ;
        rlf     tens,F          ;
        btfss   tens,0          ;
        addlw   80              ;
        addlw   -40             ;
        rlf     tens,F          ;
        btfss   tens,0          ;
        addlw   40              ;
        addlw   -20             ;
        rlf     tens,F          ;
        btfss   tens,0          ;
        addlw   20              ;
        addlw   -10             ;
        rlf     tens,F          ;
        btfss   tens,0          ;
        addlw   10              ;
        movwf   ones            ;
;
Good luck on your project and happy Holidays...
 
Last edited:
next is on jon's scematic and code to drive the 7-seg displays. i simulated his schematic using proteus but haven't seen yet the results, since the code for look-up table is still in the process. i need the look-up table to set correctly the PORTB pins. i'm confident however that what he suggested is the best solution so far i can tell. thank you very much jon i am making a look-up table to properly light up the correct leds.

For the first design where the PIC decodes hex values into a decimal value on the readout, this lookup table will do the trick -

Code:
;*************************************************************************

TABLE		addwf		PCL,F		;add offset to program counter
		retlw		0x3F		;0 seven segment
		retlw		0x06		;1
		retlw		0x5b		;2
		retlw		0x4F		;3
		retlw		0x66		;4
		retlw		0x6D		;5
		retlw		0x7D		;6
		retlw		0x07		;7
		retlw		0x7F		;8
		retlw		0x6F		;9

;*************************************************************************

For the 2nd design with the BCD to 7 segment decoders, you would write hex values 0x00 - 0x09 to Port B since they have an internal decoder to interpret binary 0-9 into the appropriate number on the readout.

it's your idea also to use the sublw instruction, thank you again. i will look closely how you coded yours and try to learn from it.

i am very grateful for your help guys, i'll be back soon.

Comparisons are done with either SUBLW, SUBWF, XORLW, and XORWF (they're interchangeable).

SUBLW = Subtract W from Literal Value (yes that appears backwards and more than likely they should've made it SUBWL, but this instruction subtracts the value in W from a literal hardcoded value)
SUBWF = Subtract value in W from value in File

The SUBWF instruction requires a designator as to where you want the result of the subtraction operation stored. You have two choices...you can have the result placed in the W register or you can have the result placed in the File Register that you did the subtraction operation on. The syntax for this operation would be -

Code:
		subwf		FILENAME,W	;stores result in W

		;or

		subwf		FILENAME,F	;stores result in FILENAME

Same applies for XORLW and XORWF.

If you need to see if an incoming data value matches a hardcoded one, you perform the subtract operation, then poll the Z flag in the Status register to see if the result of the operation was zero. Set the designator to W if you need to preserve the value located in the file register you're subtracting W against.

Once you perform a subtraction operation, the Z (Zero) flag in the Status register will set if and only if the result of the operation is zero, which can only happen if two matching data values are subtracted against each other. XORLW and XORWF can be interchanged with SUBLW and SUBWF. The reason for this is that XOR (Exclusive OR) means that the two values have to be different in order to return a non-zero result. If the values are identical, they will always return a zero result on an XOR operation. On Inclusive OR (IOR) the values can be either the same or different to return a non-zero result.

Mike said:
Hi Jon,

Just wanted to supplement your fine example.

If the design allows for adding driver ICs, you can actually drive a lot more than just eight 7-segment displays on the 'F84. For example, you could use 5 pins to drive 12 displays (3x4, see below), or 6 I/O pins to drive 20 displays (4x5), or 7 I/O pins to drive 30 displays (5x6), and so on. And if the 16F84 had a PWM module you could take advantage of complete fade-to-black PWM brightness control running as a 0% overhead background task.

Hi Mike. Coming from you that means a lot as I just got into digital electronics, PIC microcontrollers and Microchip assembly programming about 4 months ago. I've been an electronics guru for almost 20 years but it's all been in the world of analog and valve audio amplifiers.

Thanks for that supplement!
 
Last edited:
When ROM is limited I often keep the variable itself as digits, so it is always in the format ready to be displayed. This can be a good system if the variable only needs simple tasks like counting and additions/subtractions etc.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top