Electronics > Microcontrollers
PIC Delay Loop Time Question (ASM)
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
Go to full version