Adding to the scheduler

Scheduler:Traffic Light With Walk

Since the scheduler example for a traffic light of a week or two ago had nothing to do in the background, this next example uses the idle time to watch for a button push. The program is Figure 13.5, flowcharted in Figure 13.4. I add two buttons to be used by pedestrians to request a walk cycle. The scheduling of the light cycle will still happen in the real-time interrupt as before. I set up two flags (bits in walk) to keep track of anyone pushing the button (which comes in as a logic 0). By ORing the port with the variable, if the button was pushed previously, the logical OR will simply keep a 1 in that bit position. No matter how many people push the button, there will be just one walk cycle, and the bit can be cleared when the walk is actually provided. It is cleared by & ~0x02, which is a more understandable way of getting the 0xfd to clear that bit from a 1 to a 0. When a walk bit is detected, the switch expression substitutes a different pointer to give a walk instead of a normal light cycle. [This is very crude, and you would want a DON’T WALK light and perhaps a flashing period before the walk cycle ends. Also you would want to coordinate with turning cars, and so on. A true traffic light program is significantly more complicated than this.]

There are at least three options for keeping track of users pushing the walk buttons:

  1. Polling in the main routine is the easiest way to recognize walk requests. This is the solution I have chosen to show here.
  2. The buttons could be scanned in the scheduler interrupt itself—add another counter and once every 40th interrupt, perhaps, read the buttons. If there were much else for the processor to do, this would be the preferred solution because long background tasks (in main()) would not alter the button scanning.
  3. The buttons could be tied to external interrupts. There are at least two of them, and they could be made edge-triggered so the software would interrupt whenever a button is pushed. This is a bit wasteful of hardware and has limited expansion capability—there aren’t many external interrupts. Besides, it is a waste of hardware when it can be done easily by the earlier methods.

Flowchart: Traffic Light With Walk

Traffic Light With Walk Buttons
#define uchar unsigned char
#define uint unsigned int
#define LEDS P1
#define WLKBTNS P3
uint countdown; uchar index,walk;
code struct{uint delay;uchar pattern;}cycle[]=
//(0)=—R,–Y-; (1)=-G–,—R; (2)=–Y-,—R;
{5000,0×14}, {3000,0xc1},{5000,0x1c}};
//(3)=—R,-G–; (4)=WG–,—R; (5)=—R,WG–;

void initialize(void){
WDTCN = 0x07; WDTCN = 0xDE;//Disable WDT WDTCN = 0xAD;
XBR2 = 0x40;//enable crossbar
P1MDOUT = 0xFF;//P3 push-pull out
OSCICN = 0x04;//enable int oscillator
countdown=1;//start at once
walk=0;//none pending
index=3;//lead to first state
TMOD=0x10;//tmr1 16-bit
TR1=1;//enable timer 1
IE=0x88;//enable timer1 int

void msecint (void) interrupt 3 using 1{
uchar i;
if(–countdown==0){ //end of delay
switch(index){//override for walk
case 1:if((walk&0x02)==0){
walk&=~0x02; i=4;
case 3:if((walk&0x01)==0){
walk&=~0x01; i=5;

void main(void){
walk=walk | WLKBTNS;

Communication by Shared Variable With the first solution I must get the value of walk to the scheduler from the main (background) program; in a formal sense you can say the two tasks communicate. In effect communication is by shared variablewalk is global and can be accessed by both the interrupt and the main program. Later chapters will go into other communication methods.

For the pattern going to the LEDs I arbitrarily chose to position the walk lights as the most significant bits of the nibbles.

Although the interrupt in this stoplight example has grown more complicated, the basic approach has not changed. The program flow never waits in the interrupt function. Rather, it moves through and returns to the main as quickly as possible.

Related posts: