| 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;
 
 | 
 |  |