Hello!
Why we use 120 to create a delay of 1ms
In fact, counting is the worst method to implement a delay.
As said above, each instruction needs a certain number of clocks.
Incrementing is quite quick (the i++, j++). Depends on the chip, but
let's say 2 clocks. But at every step of every loop, you also use
comparisons (with 120 and with 500 in your code) which add clocks at
every step. That must be also short. But it's better to compare to 0.
Today's lab: try to write your loop like this: for(j = 120, j > 0 ; j--)
and you will (probably) notice it's faster because it's usually faster
to compare to 0 than to an arbitrary number.
Then at the end of any loop, there is a jmp instruction which is a bit
more costly. You will have a jump everytime your comparison is false
(e.g. everytime i is less than 500) to return to the beginning of the
current loop with incremenation of i, j.
If 1 ms is 120 cycles, then your clock is 120 x 000 x loop_clocks,
this latter being the average number of clock you need to make your
increments.
Drawbacks of this method
1. Very inaccurate
One loop length will depend on where you are in the process. When you are
not at the border of the j interval, for example j = 100, then the loop is short.
j is incremented to 101, then compared to 120, and then there is a conditional jump.
But when you reach the end of the j loop, then you exit the loop,
enter the i loop, increment i, compare with 500, and then do the j loop,
in which case you have to set j = 0, and process with the short loop above.
It's very difficult to calculate the number of clocks you are going to spend.
Not rocket science, but let's say calendar-like science.
2. It just consumes power
In all meanings of this.
It consumes processing power, making additions, comparisons, etc, only for counting.
What a waste! Then it blocks the program flow.
When you block your system by counting, then you cannot do any other work.
That's why the best method (now that I have described the worst, I'm stuck, I have
to describe the best) is the one mentioned by Klaus. Hardware counter. I suppose
he means one of the processor timers because a timer is a counter with fancy features.
And the second meaning of power: the electrical power because the processor is
continuously on.
Every processor I know has internal timers which have hardware counters, and myriads
of settings that I cannot fully describe here, so I will focus only to the timer
interrupt.
You can setup a timer interrupt, which is an event coming from the timer.
This event will call a function which is called an interrupt service routine (ISR).
I will be short on the details, I'm sure you can find sample code for your
particular processor.
So you set the timer to count to a certain value. If your crystal has a frequency
of 32768Hz (RTC), you can use a 16-bit integer value (assuming it's at least
a 16-bit counter). You can also setup the timer so that it counts in a loop, back to 0
after 32767. Then you program it so that every time it reaches 0, the ISR is called.
You can then program it like this (pseudo code)
main() {
set_timer(32767, loop_mode, interrupt);
sleep();
}
void timer_int_routine() {
LED = !LED;
}
And that's it. You don't need a loop, it exists by the timer itself. Note that
your processor will do nothing exceot when it's called. This one would be 1 on and
1s off. And of course you need to implement set_timer, which is processor specific
code. Beside this, it's not recommended to do something in the ISR, but I cannot
explain everything within a single post.
With this implementation
- You will have an accurate timing
- You can do some other work instead of counting loop cycles.
-> With the first method (the one you have implemented), this extra work
would change the timing. With a hardware counter no. Except it the work
takes more than the counter period.
- If you sleep, the processor will consume possible 1% of the power it consumes
with a software counter.
Have fun!
Dora.