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.

how to decrement big numbers?

Status
Not open for further replies.

josi

New Member
Hi! how can i decrement the binary value 1010001011000010101? i'm using a PIc 16F877. my idea is to breack the number into 3 bytes! but if i do that is it still the same number?

this is what i did:

LIST p=16F877
#include <P16F877.inc>
__config _XT_OSC & _PWRTE_ON & _WDT_OFF &_LVP_OFF
;*****Equates**********************************************
status equ 03h
PortD equ 08h
TRISD equ 88h
count1 equ 22h
count2 equ 23h
count3 equ 24h
;******Main Program****************************************
org 10h
bsf status,RP0
movlw B'00000000'
movwf TRISD
bcf status, RP0
start
bsf PortD,0
call delay
bcf PortD,0
call delay
goto start

delay
movlw B'10100010'
movwf count1
movlw B'11000010'
movwf count2
movlw B'00000101'
movwf count3
loop1
decfsz count1,1
goto loop1
loop2
decfsz count2,1
goto loop2
loop3
decfsz count3,1
goto loop3
return
end
 
hi josi,
Is this related to delays.?

Why would you want to decrement a 24 bit number.?:)
 
wont work like that.

10100010 = 162
11000010 = 194
00000101 = 5

Your number was 333,333 to do this i would use the delay generator. Only because its faster :D

Code from:
Code:
delay
	movlw	0x02
	movwf	count1
	movlw	0xBB
	movwf	count2
	movlw	0x01
	movwf	count3
Delay_0
	decfsz	count1, f
	goto	$+4
	decfsz	count2, f
	goto	$+4
	decfsz	count3, f
	goto	Delay_0

	goto	$+2

(i replaced all $+2 with $+4 AND $+1 with $+2)
 
hi atom,
josi has another thread running, regarding calculating delays.?
 
hi Eric! yes this is relayed to delays! all i'm triying to do is to apply a formula! remenber in my previous thread i wanted a 1s delay and i used this formula (XX= (Td-5us)/3), wich gave me the decimal # 333333 (1010001011000010101). I do agree that there other easier way (PIClist etc....) but i need to get this right! coz i'm currently studying and my lecturer want us to implement the delay using the given formula.
 
wont work like that.

10100010 = 162
11000010 = 194
00000101 = 5

Your number was 333,333 to do this i would use the delay generator. Only because its faster :D

Code from:
Code:
delay
	movlw	0x02
	movwf	count1
	movlw	0xBB
	movwf	count2
	movlw	0x01
	movwf	count3
Delay_0
	decfsz	count1, f
	goto	$+4
	decfsz	count2, f
	goto	$+4
	decfsz	count3, f
	goto	Delay_0

	goto	$+2

(i replaced all $+2 with $+4 AND $+1 with $+2)

Thanx atom! as i told eric, i'm fully aware of the generator! and i'll use it! but i need to do it the way my lecturer want (using the stupid formula)
 
hi Eric! yes this is relayed to delays! all i'm triying to do is to apply a formula! remenber in my previous thread i wanted a 1s delay and i used this formula (XX= (Td-5us)/3), wich gave me the decimal # 333333 (1010001011000010101). I do agree that there other easier way (PIClist etc....) but i need to get this right! coz i'm currently studying and my lecturer want us to implement the delay using the given formula.

hi josi, No problem.:)

We are trying to give you the best advice we can, its just sometimes difficult to see what OP's are asking.;)
 
Last edited:
hi josi, No problem.:)

We are trying to give you the best advice we can, its just sometimes difficult to see what OP's are asking.;)
Thnax 4 helping! i'll use the generator for my delays! i jus need to understand them better! as i'm writting my final soon.
 
Thnax 4 helping! i'll use the generator for my delays! i jus need to understand them better! as i'm writting my final soon.

hi,
For long delays, look at loops within loops.

All that means is, suppose you wrote a delay2 loop, say for 100mSecs
and another delay1 loop for 10 counts.

You could place the delay2 loop inside the delay 1 loop, this would give you 10 * 100 mSecs = 1second.

delay1:
load counter 1
del1:

delay2:
load counter 2
del2:
... count down counter2 till zero
goto del2

....count down counter till zero
goto del1

...done

Do you follow.?
 
Last edited:
yeah if i wanted to count to 10,000 i would do.

10000/256 = 39 approx. so i would loop 0-255 39 times.

For larger i do the same like

100,000/256 = 391 approx. so i would dive that by 256
391 / 256 = 1.52 so i know its 1 1/2 roughly.

now i can make 3 loops 1 for the main 256 then 1 for the second 256 and 1 for the 1/2 256 Like

the below isnt code lol
d1 = 1
d2 = 133 (the 1/2) (256 * .52(remainder) = 133
d3 = 255 (0-255)

A. take 1 off from d3 until 0 then when d3 = 0 (once hits 0 it will reset to 255)
B. take 1 off from d2
C. if d2 = 0 then take 1 off of d1
D. if d2 > 0 then goto A again
E. if d1 = 0 then done!

Something like that.
EDIT It comes out like:
it comes out like (133* 256) + (256 * 256) = 99584 Of course this is me using approx you can fix to make 100,000 Even.
 
Last edited:
For a delay longer than about 10ms I always try to use a timer with IRQ, except if it is not in the main program loop.

Thnax 4 helping! i'll use the generator for my delays! i jus need to understand them better! as i'm writting my final soon.

Create a delay routine with the generator, grap a pen and piece of paper then while trying to figure out what they do in the code, draw a flowchart of it... it will make sense allot quicker.
 
Most of you guys are working way too hard trying to generate precise delays using code produced from those delay generator apps'.

Design a delay loop subroutine with a constant overhead and a constant loop time you'll find you can easily control it to generate precise delays exactly to the cycle.

For example, the following simple 12 word subroutine uses a 4 cycle loop with a minimum 16 cycle overhead (including the calling code). Setup the 'cycle' equate to any value between 16 and 262159 and simulate it using the Stop Watch. As we setup the delay high value for TMRH and the delay low value for W, we subtract the 16 cycle subroutine 'overhead' and then divide the value by the constant loop time (4 cycles). Finally we use a variable entry point into the subroutine to account for delay%4 values of 3, 2, and 1.

Code:
        radix   dec
cycles  equ     150

        movlw   high((cycles-16)/4)+1
        movwf   TMRH
        movlw   low ((cycles-16)/4)
        call    DelayLo-(cycles%4)
        nop                     ; insert Simulator break point here

;                                                                 *
;  Delay(16..262159 Tcy) subroutine   Mike McLaren, K8LH, Jun'07  *
;                                                                 *
;  12 words, 1 RAM variable, 14-bit core                          *
;                                                                 *
Delay.16
        nop                     ; entry point for delay%4 == 3    |B0
        nop                     ; entry point for delay%4 == 2    |B0
        nop                     ; entry point for delay%4 == 1    |B0
DelayLo addlw   -1              ; subtract 4 cycle loop time      |B0
        skpnc                   ; borrow?  yes, skip, else        |B0
        goto    DelayLo         ; do another loop                 |B0
        nop                     ;                                 |B0
DelayHi addlw   -1              ; subtract 4 cycle loop time      |B0
        decfsz  TMRH,F          ; done?  yes, skip, else          |B0
        goto    DelayLo         ; do another loop                 |B0
        goto    $+1             ; burn off 2 cycles               |B0
        return                  ;
Once you've simulated this code and you've got a handle on using this constant loop time / constant overhead delay subroutine it's a simple matter to create a macro wrapper and create "usec" and "msec" constant multipliers based on the clock frequency.

Code:
clock   equ     8               ; clock frequency in Mhz
usecs   equ     clock/4         ; cycles per microsecond multiplier
msecs   equ     usecs*1000      ; cycles per millisecond multiplier

DelayCy macro   cycles
        movlw   high((cycles-16)/4)+1
        movwf   TMRH
        movlw   low ((cycles-16)/4)
        call    DelayLo-(cycles%4)
        endm
Now you've got a precise general purpose delay subsystem. Here's an example of how you might use it;

Code:
;
;  generate a 32 msec 500 Hz "new press" beep
;
BeepTask
        movlw   d'32'           ;                                 |B0
        movwf   Beep            ; set beep counter to 32 msecs    |B0
Beep    movf    PORTA,W         ; read port A                     |B0
        xorlw   1<<Spkr         ; toggle speaker bit              |B0
        movwf   PORTA           ; toggle speaker pin              |B0
        DelayCy(1*msecs-6)      ; delay 1 msec minus 6 cycles     |B0
        decfsz  Beep,F          ; done?  yes, skip, else          |B0
        goto    Beep            ; loop (toggle Spkr pin again)    |B0
I subtracted the 6 cycle loop time in the code above in order to produce an exact 500 Hz tone from the speaker no matter what clock frequency we're using. If I had simply used a 1-msec delay parameter without accounting for the loop time we would get the following tones;

Code:
;    "DelayCy(1*msecs)"            "DelayCy(1*msecs-6)"
;  497.018 Hz --  4 MHz clock    500 Hz tone -- any clock
;  498.504 Hz --  8 MHz clock
;  499.004 Hz -- 12 MHz clock
;  499.251 Hz -- 16 MHz clock
;  499.400 Hz -- 20 MHz clock
The ability to produce isochronous code like that above isn't available in the code loops produced by those delay generator apps'.

There's one CAVEAT I should mention... The delay parameter upper limit when using the 'usec' and 'msec' multipliers is determined by the clock frequency as follows;

Code:
;                                                                 *
;     4 MHz, 1 cycles/usec, 16..262144 usecs, 1..262 msecs        *
;     8 MHz, 2 cycles/usec,  8..131072 usecs, 1..131 msecs        *
;    12 MHz, 3 cycles/usec,  6...87381 usecs, 1...87 msecs        *
;    16 MHz, 4 cycles/usec,  4...65536 usecs, 1...65 msecs        *
;    20 MHz, 5 cycles/usec,  4...52428 usecs, 1...52 msecs        *
;                                                                 *
You can extend the range of the delay subsystem several different ways. One way would be to increase the loop time of the delay subroutine and modify the macro accordingly. Another way would be to use a 24 bit delay subroutine instead of a 16 bit delay subroutine but this would increase the minimum subroutine 'overhead' and your minimum delay. And yet another way to increase the range would be to modify the macro to call the delay subroutine multiple times if necessary but this will use another 4 words of memory for each addtional subroutine call. I showed the latter method in the OP's other thread but I'd like to say that once you need delays of 1 second or more, you should really be handling the delays in an interrupt service routine as a background task.

Regards, Mike
 
hi Mike,
IIUC, the OP has just got to demonstrate to his tutor the method of writing loop delays.

I try to use timers/interrupts for delays for more than a few millisec, I dont want the PIC just idling doing big countdowns.

Never use those delay calcs.:)
 
You decrement a big number by adding -1 (aka 0xFFFFFF for the 24 bit case) to it. Remember to propagate the carry after the first addition. It is trivial to make this process run in constant time.
 
To answer the original question, the way to decrement a big number on a pic is to use the subtract instruction,
Code:
        movlw   1		;we are going to subtract 1
        subwf   LowByte,F	;subtract 1 from Least Significant Byte
        btfss	STATUS,C	;was there a borrow
        subwf   MiddleByte,F	;yes, so subtract 1 from next significant byte
        btfss	STATUS,C	;repeat for more
        subwf   HighByte,F	;significant bytes

	;the carry flag will now be clear if [U]ALL[/U] bytes are 0xff.

You can, of course, repeat the above for any number of bytes.

Mike.
 
Last edited:
Thnx guyz! i got another 1s delay routine from my tutor but i don't know how i got it! i'll try all the other stuff that u guyz gave me!

delay
movlw 05h ;SET DELAY FOR 1 SEC
Movwf count2

Loop
decfsz count0,1

Goto Loop

Decfsz count1,1

Goto Loop

Decfsz count2,1

Goto Loop

Return
end
 
To answer the original question, the way to decrement a big number on a pic is to use the subtract instruction,
Code:
        movlw   1               ;we are going to subtract 1
        subwf   LowByte,F       ;subtract 1 from Least Significant Byte
        btfss   STATUS,C        ;was there a borrow
        subwf   MiddleByte,F    ;yes, so subtract 1 from next significant byte
        btfss   STATUS,C        ;repeat for more
        subwf   HighByte,F      ;significant bytes

    ;the carry flag will now be clear if [U]ALL[/U] bytes are zero.
You can, of course, repeat the above for any number of bytes.

Mike.
Hi Mike,

Are you sure about that carry flag statement?

Mike
 
Hi Mike,

Are you sure about that carry flag statement?

Mike

Well spotted. edit, it should be when it rolls over. I'll get it right eventually. I'll edit the original post to stop future confusion.

Mike.
 
Last edited:
Status
Not open for further replies.

Latest threads

Back
Top