Ken Johnson
Joined: 23 Mar 2006 Posts: 197 Location: Lewisburg, WV
|
Single-task background (main loop) priority scheduler; |
Posted: Wed Sep 26, 2007 9:08 am |
|
|
A clean, simple-looking main() loop makes your code easier to understand and maintain. Rather than numerous flags and several if-statements, I use the following code, with the added benefit that "tasks" to be executed are prioritized (but NOT pre-emptive). Hope this is self-explanatory. Comments appreciated.
Ken
Code: |
// Filename: Work.h Copyright © 2007 K & N Co.
// Created: Sep 21, 2007 by Ken Johnson
// Purpose: Single-task background (main loop) priority scheduler;
// Designed for and tested with the CCS PIC Compiler;
// May be freely used, copied, modified, etc;
#if !defined (WorkHeaderIncluded)
#define WorkHeaderIncluded // Include this stuff only once;
typedef unsigned int16 WORK; // Bit flags tell the main loop what to do;
// Lower bit numbers are higher priority;
// You can make this int8, or even int32 if you need to;
// Use this macro to set one or more Work flags:
#define SetWork(flags) Work |= ((WORK) (flags))
#define ClrWork(flags) Work &= ~((WORK) (flags))
// (You probably don't need ClrWork)
// This macro returns the highest-priority bit (lowest bit number) from x:
#define loBit(x) ((x) & (~(x)+1))
static WORK Work; // This is the one and only WORK variable;
WORK GetWork (void)
// Returns the highest-priority bit (if any) of Work, after clearing that bit;
// Returns 0 if no bits are set;
{
WORK work; // Working copy of Work;
work = Work; // Copy;
work = loBit (work); // Pull off the lo-bit (if any);
if ( work ) { // If we pulled off a bit, clear it:
// Depending on Compiler/Processor, you may need to disable interrupts here;
Work ^= work; // This is "atomic" where I've tested it (several PIC18xxxx);
// Re-enable interrupts if disabled;
}
return work;
}
#if 0 // Sample pseudo-code:
#define W_ZEROWORK 0x0000 // There's nothing to do;
#define W_TIMER 0x0001 // Highest priority work to be done;
#define W_RXDATA 0x0002
#define W_DEBOUNCE 0x0004 // Lowest priority work to be done;
void RxISR (void)
{
// read uart and stuff byte in buffer
SetWork (RXDATA); // Work bits may be set in an ISR;
}
void TimerISR (void)
{
// Clear timer interrupt;
SetWork (W_TIMER);
}
void DoTimer (void)
{
// Maybe every n calls:
SetWork (W_DEBOUNCE); // Work bits may be set in background loop;
}
void main (void) // My main() code always looks like this:
{
Initialize (); // Initialize PIC, etc;
for ( ;; ) switch (GetWork) ) {
// These are alphabetized (one of my habits),
// but *processed* by priority:
case W_DEBOUNCE: DoDebounce (); break;
case W_RXDATA: DoRxData (); break;
case W_TIMER: DoTimer (); break;
case W_ZEROWORK: MaybeSleep (); break;
}
}
#endif // end of sample code
#endif // WorkHeaderIncluded;
|
|
|