I have been experimenting with a PIC 12F508 and have just begun writing my own delay loops in assembler. Nothing fancy yet just toggling an LED connected to GP1 (set as an output) on and off to verify the code.
I finally got my loop to work but I don't understand why it has to be written a certain way for it to work.
I have copied part of the code that doesn't work below I omitted the input / output TRIS setup and configuration bits for clarity.
When the code is written as it is below and dly4 loops back on itself the LED doesn't flash it just stays on solid.
I can't understand why this is because according to the datasheet after the variable count4 reaches 0 the goto dly4 should be skipped. The next instruction goto main_loop should then be executed which returns to the start of the code toggles the led again and the process repeats.
main_loop
movf sGPIO,w
xorlw b'000010' ; toggle LED on GP1
movwf sGPIO
movwf GPIO
movlw .80
movwf count
movwf count2
movwf count3
movwf count4
dly1 decfsz count,f
goto dly1
dly2 decfsz count2,f
goto dly2
dly3 decfsz count3,f
goto dly3
dly4 decfsz count4,f
goto dly4
goto main_loop
END
To make the code work I have to modify the goto at the end of the loop from:
goto dly4 to goto dly1
Why would I want to go back through all four loops again? Wouldn't decrementing the variables from 0 by going through again reset them to 255? Even though the code works with the modification above I can't understand how the loop is even being exited.
Thanks For Any Help In Advance.
Best Answer
Well I did some digging for accurate information. The PIC12F508 is a 33-single-instruction-per-clock device... except for program branches, which take two clocks.
So if the oscillator frequency of this PIC were 4MHz, then the instruction rate is 1MIPS. The period of 1MIPS = 1uS. Each
decfsz
loop takes 80*3 (since there are two instructions and the branch takes two cycles) = 240uS. Four of those total 960uS. That's 0.000960 seconds."Persistence of vision" is a phenomena of human vision which essentially means that if something is moving fast enough, we can't see it and it appears "fluid" or non-jittery. Essentially, anything changing faster than 30 times per second (1s/30 = 0.0333s) is imperceptible to our eyes. So if the LED were toggling at a rate of 0.001s, then we would perceive it as constantly-on, even though it were in fact, blinking really fast.
However, when the final goto is changed to the first loop, remember count is zero, so decrementing it makes it 255. (
decfsz
decrements first, then skips if zero.) So after the initial three loops, this new first loop adds another 255*3 = 765uS. The next two also add 765uS each. But when it gets to the fourth one, it again decrements only once, and loops to the top again. Over and over, 78 more times. This is called a nested loop, and is very common to create larger delays.The bottom line is that the first version does work as intended. But it happens so fast, you can't "see" it. The second version loops many, many times, so is much slower, and behaves in a way we can perceive with our eyes.
Also note that this PIC does have a hardware timer module, TMR0. This can also be used to create delays and intervals, and since it is implemented in hardware, leaves the rest of the device free to do other things while TMR0 increments. It may be a little finicky to setup and use, since it involves interrupts, however they are very useful in real-world applications. I'd recommend trying these also.