Electronics > Microcontrollers

PIC Delay Loop Time Question (ASM)

(1/4) > >>

blewisjr:
I have a delay loop from a Blinking LED tutorial and I am trying to understand the math behind it so I can effectively write my own delay loops.  For some odd reason I can't wrap my head around it.  Right now the delay is 1.579 seconds and I want to make it more accurate by decreasing the delay to 1 second.

I am not looking for an answer on how to do it I can write the code I am trying to understand the equation behind calculating the delay time.
The 2 loops for on and off are labeled as OnLoop and OffLoop.

If you have any tips on a better way to do the looping that is easier to calculate off of feel free to give tips.


--- Code: ---; =============================================================================
; File: blink_test.asm
;
; Date: 3-13-2013
;
; The typical Hello World uC program.
; This is a simple program that uses a timed delay to blink a LED.
; The LED blinks at a rate of 1.579 seconds.
;
; PIC: 16F1829
; Assembler: MPASM v5.49
; IDE: MPLABX v1.70
; Board: Breadboard
; =============================================================================

    ; Include file containing register mappings for PIC16F1829
    #include <p16f1829.inc>

    ; Fuse configurations
    #define CFG_1_1 _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF
    #define CFG_1_2 _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF
    #define CFG_1_3 _IESO_OFF & _FCMEN_OFF

    __CONFIG _CONFIG1, (CFG_1_1 & CFG_1_2 & CFG_1_3)
    __CONFIG _CONFIG2, (_WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _LVP_OFF)

    ; Warning suppression
    errorlevel -302             ; not in bank0 warining

    ; User file registers
    cblock 0x70                 ; start of shared bank memory
        Dly1
        Dly2
    endc

    org 0                       ; start program at address 0

Start:
    banksel     OSCCON          ; move to bank1
    movlw       b'00111000'     ; set internal cpu clock to 500kHZ
    movwf       OSCCON          ; move contents of w to OSCCON
    bcf         TRISC, 0        ; make I/O pin RC0 and output
    banksel     LATC            ; move to bank2
    clrf        LATC            ; clr data latch for PORTC (set bits to 0)

Loop:
    bsf         LATC, 0         ; turn on pin RC0

OnLoop:
                                ; Outer Loop
    decfsz      Dly1, f         ; Decrement Dly1 store back in Dly1
    bra         OnLoop          ; branch to OnLoop
                                ; OnLoop takes 3 instructions per loop
                                ; * 256 iterations = 768 instructions.
                                ; Inner Loop
    decfsz      Dly2, f         ; Decrement Dly2 store back in Dly2
    bra         OnLoop          ; takes 3 more instructions
                                ; per iteration (768+3) * 256 = 197376
                                ; 197376 inst. / 125k inst. per sec = 1.570 sec
    bcf         LATC, 0         ; turn off pin RC0

OffLoop:                        ; same as OnLoop
    decfsz      Dly1, f
    bra         OffLoop
    decfsz      Dly2, f
    bra         OffLoop
    bra         Loop            ; start over

    end                         ; end of code
--- End code ---

Kaluriel:
Looks like two for loops, wrapping around.


--- Code: ---unsigned char Dly1 = 0;
unsigned char Dly2 = 0;

void Sleep()
{
do
{
do
{
--Dly1;
} while(Dly1 != 0);

--Dly2;
} while(Dly2 != 0);
}

void main()
{
while(true)
{
SetLEDOn(true);
Sleep();
SetLEDOn(false);
Sleep();
}
}

--- End code ---

Each loop only takes 3 instructions to execute if it does nothing but decrement, compare to zero, and branch, a total cost of 256 iterations, so 3x256. But the internal one is executed 256x by the outer loop, so the outer loop cost 3x256 instructions plus its own 3 per loop, another 256 times.
Judging by the comment in the code, 125k instructions are executed per second, assuming you haven't changed the clock speed.
So
Inner Loop: 3 instructions x 256 iterations = 768 instructions
Outer Loop: (3 instructions + 768 instructions) x 256 iterations = 197376 instructions

A total of 197376 instructions before both Dly1 and Dly2 are both 0.

If it takes one second to perform 125k instructions, 197376 / 125000 = 1.579008 seconds

brainwash:
You might try to initialize Dly1 with value 162, it is by default initialized to 0 which causes 256 cycles to occur

Kaluriel:
As brainwash said, changing the initial value of Dly1 and Dly2 will change the timing.
(3 + (3 * Dly1)) * Dly2 = timeInSeconds * 125000
Where Dly1 and Dly2 are a number between 0 and 255, with 0 being treated as 256, and the rest being treated as their respective value.

Keep Dly1 as a low number for more precision, and choose Dly2 as your multiplier to scale up to the time you require. Without more loops, 1.5 seconds is your maximum.

blewisjr:

--- Quote from: Kaluriel on March 13, 2013, 07:11:16 pm ---As brainwash said, changing the initial value of Dly1 and Dly2 will change the timing.
(3 + (3 * Dly1)) * Dly2 = timeInSeconds * 125000
Where Dly1 and Dly2 are a number between 0 and 255, with 0 being treated as 256, and the rest being treated as their respective value.

Keep Dly1 as a low number for more precision, and choose Dly2 as your multiplier to scale up to the time you require. Without more loops, 1.5 seconds is your maximum.

--- End quote ---

ok thanks a bunch that is what I was looking for a solid equation.
((3 + (3 * Dly1)) * Dly2) / ips

I was not sure where the delay variables went into the equation and it was messing up my calculations I guess.

I should be able to easily modify the blink speed and get it very accurate.

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version