Post Number: 3
Votes: 0 (Vote!)
|Posted on Sunday, 01 May, 2005 - 08:31 pm: ||
Based on the "time-base interrupt" technique outlined by Stewart in this thread
I've wrote some code for the 16F877, controlling eight LEDs, which I made complex enough to see how far I could go:
LED 0 blinks once with a certain ON time
LED 1 same as above with a different ON time
LED 2 blinks for a certain number of times with equal ON-OFF periods
LED 3 blinks for a certain number of times with different ON-OFF periods
LED 4 blinks for a certain number of times with equal ON-OFF periods
LED 5 blinks continuously with equal ON-OFF periods
LED 6 blinks continously with different ON-OFF periods
LED 7 blinks continuously with equal ON-OFF periods
The main loop consists of nine tasks continuously CALLed: one for the keyboard and one for each LED. Each LED is activated by pressing a different key in the keyboard. Time base is 2 msec and on/off periods range from 250 msec to 1500 msec.
Basically I can say that it worked from the first try demonstrating his point. Later, after experimenting for a while I've started to wonder about the following points:
a) A keyboard debouncing delay (I use 25 msec) requires just one 8-bit counter to be decremented while a 1500 msec delay demands three 8-bit counters. How to cope with VERY LONG delays and a VERY SMALL time-base? I asume here, that I also need VERY SHORT delays what precludes the use of a LONG time base.
b) With many of the delays requiring two or three (BTW, why not four or five?) 8-bit counters each, I've found that the time spent by the ISR just in checking and decrementing counters, could ammount up to one tenth of the time base period.
Isn't that excessive?
What if I have many other tasks to serve?
Is it any simple trick to reduce the number of counters? PLease consider that delays are most of the time, non time-related to each other!
c) With only TMR0 interrupt enabled, it's an event that repeats after an exact amount of time. The LEDs' blinking periods, since they affect each other, are essentially not exact. I assume then than whatever other event I want to occurr at an exact moment, could not! Let's say that if I want a pin going high for 6 msec, exactly, every 25 msec, exaclty what I could only get is just ABOUT that.
Should I consider that "exact" periods of wahtever, should be in fact, just periods "within a certain tolerance"?
d) What if other interrupts are enabled?. Being unable to assign any priority to TMR0 interrupt (16F877) the 2 msec time base would become not an exact occurrence anymore!
I couldn't follow Stewart's pseudo code very well regarding flags. I work in assembler so whatever comes from C language is hard for me to understand. Sorry about that![&:]
Comments of any kind are much appreciated. If at all possible please follow the order of the points as stated above. That would help me in understanding this new subject. Thanks also for that.
Post Number: 4
Votes: 0 (Vote!)
|Posted on Monday, 02 May, 2005 - 12:30 pm: ||
A couple of thoughts.
If you want an output to change at an exact time, you could use the PIC's CCP (Capture/Compare/PWM) module (section 8 in my copy of the datasheet).
The CCP can be set up so that when Timer1 reaches a 16 bit value of your choice an output port goes high or low, as set by you. This is in hardware, so happens at an exact time.
The CCP would simultaneously generate an interrupt. Your code would respond to the interrupt by reprogramming the CCP for the next edge.
The main limitation is that you can only control one output port: Port C2.
My current project - a wireless temperature logger - has to do lots in real time.
I have an interrupt routine called every 125us. The interrupt routine does the stuff that is REALLY time critical, such as decoding the wireless link.
The interrupt routine also contains 5 nested counters which divide down to 10ms, then 1s, then count seconds, minutes and hours.
Inside the interrupt routine, when each counter reaches its limit I set a flag, e.g.
Outside the interrupt routine I have a loop which goes round checking all of the flags. For example, if the main loop spots that SecondEvent is set then it CALLs a routine called OncePerSecond which does whatever needs doing and clears the flag.
If I need to do something say every 10 seconds then to avoid complicating the interrupt routine I use a divide by 10 counter inside the OncePerSecond routine.
Hope this helps.
Post Number: 6
Votes: 0 (Vote!)
|Posted on Monday, 02 May, 2005 - 07:59 pm: ||
Thanks for replying. I am just realizing the possibilities that interrupts give but also their LIMITATIONS.
a) I was ingenuous thinking that whatever it was, all would repeat on and on at an exact required moment.
b) It's clear that whatever I need to repeat in an exact time frame must be done by hardware (running independent from the background code) located whether inside or outside of the micro itself.
c) I was ingenuous to expect to have a LED blinking exactly 350 msec OFF - 1500 msec ON when it is just needed for saying something to the user. Looking for precision here (now I know) is pure nonsense.
d) TMR0 by itself, triggering an interrupt may achieve an exact occurrence every so xxx msec. The existence of any other interrupt, or worst than that, any section of code disabling interrupts, makes precission / exactness to go haywire.
e) Your example was enlightening and up to now, the sole concrete example I've got.
My next step, still blinking the eight LEDs of reference, will be to explore:
1 - the combination of what someone called "slow", "fast" and "very fast" time bases each one being a multiple (* 256) of the previous one.
2 - your example which is pretty close to above.
That way I expect to have one 8-bit counter, only, for each type of delay just by using a reasonable time base for all of them and selecting the most appropriate of the three time-bases so generated.
For the moment it's not clear to me what part of each procedure is to be done inside the foreground code (ISR) and what inside the background code (main).
Will take time. I will try to post about results and concrete conclusions.
Additional comments always welcome. Gracias for posting in reply.
Post Number: 10
Votes: 0 (Vote!)
|Posted on Sunday, 08 May, 2005 - 01:04 am: ||
It took little work to get it up and running.
Since I had only LEDs, all turning on/off with delays in the hundreds of msec range, I set up two time bases: 5 msec directly from TMR0 and 50 msec, also inside the ISR from a counter decremented continuously from 10 to 0.
The thread in charge of checking what delay counter had to be decremented, is in the main code what keeps ISR to a real minimum.
Let's say that I got the concept proved satisfactorily. I am now exploring ADC and PWM together.
Thanks for your help.