Sunday, December 23, 2012

Trafffic Light Sequencer



In this installment I will share the MSP430 code for a traffic light sequencer, but before I do, I believe a few words need to be said about powering the Launch Pad.

TI has designed the Launch Pad to be powered in two ways.  The most straightforward is via the USB connection.  This is how most experimenters will use it.  Your computer puts out regulated 5V on the USB cable.  The Launch Pad converts this 5V to 3V to power the microcontrollers on board (there are more than the one that you are programming).  

If you want to power the Launch Pad on your layout this way I would suggest that you get a USB powered hub with a lot of output ports.  Then get some USB "Male A" to "Female A"  extension cables (sometimes the dollar store has these, if not try All Electronics).  Use  the extensions to connect the hub to your Launch Pad's USB cable.  Now your Launch Pads are powered with no muss, fuss or bother and the cost is not great. Non-powered hubs can be cascaded from your powered hub to feed more Launch Pads. Not a bad option if your layout is not too large.

If your layout is really large or the distances between Launch Pads is long, you may want to run a power bus for the Launch Pads.  This bus must be clean, pure, regulated DC - the output from a spare power pack will not do.  The voltage on this bus must be between 3V and 3.3V and cannot exceed 3.6V.

The Launch Pad documentation tells you which jumpers to disconnect to use external power.  A good power source would be a converted PC power supplyYou may be able to find a wall-wart that puts out 3VDC, but it has to be regulated.  Another inexpensive option, that I have not tried, may be the Philmore MW122A power supply (about $25 but available from MCM Electronics for $19 and when on sale for as little as $15).  This looks like their old battery replacement unit but they claim full regulation and low ripple.  Whatever you use, maintaining regulation over very long runs can be a problem.  I have purchased some inexpensive regulator boards off of e-bay that could be used to take clean but unregulated DC and regulate it to 3V right at the Launch Pads.  I'll let you know how my experiments turn out.

Using external power unfortunately prevents you from using the USB port for a future network of Launch Pads or from potentially controlling your Launch Pads from a central location.  

Enough about power, on to the traffic light sequencer.   

Traffic Light Sequencer

This program uses timing loops just like the alternate flasher, but I have used some different coding structures and the timing loops are of uneven  durations.

First, how do traffic lights operate?  Traffic lights control two intersecting bidirectional streets.  Lets refer to one route as East/West (E/W) and the other as North/South (N/S).  A regular 3-color traffic light then has four states:

E/W - Red            N/S - Green
E/W - Red            N/S - Yellow
E/W - Green         N/S - Red
E/W - Yellow        N/S - Red

And then the cycle repeats.  The green and the yellow cycles will have different durations and the red cycle will be the sum of the green and yellow cycles - so the three signal aspects have three different durations.  My observation of the traffic lights outside of my office indicates that the yellow cycle lasts for about 1/8 as long as the green.

This is all of the information that we need to know to program our traffic light sequencer. The table above tells us which lights to turn on or off for each cycle.  We need to define two timing loop counters - which we will call 'green' and 'yellow'.  We do not need to define one for red since it is the sum of green and yellow.

Refer to the listing at the end of this post as I walk through the code.  This is not an attempt to teach you how to program in "C" (I'm hardly qualified for that); but simply to explain the workings of the program.

After the declaration of the main program (main.c) come several statements that tell the compiler - the program that executes on your PC and builds the program for the microcontroller - some things that it should do.  One of these is which, of several hundred TI microcontrollers, we want to build a program for (i.e. target).

Then a number of variables are declared.  Variables are numbers whose values, as their name implies, can be changed.  In this program, almost all of them are used as constants; only t's value changes.  The comments after each variable declaration explains its use.  A value of 900,000 in 'green' causes a delay of about 16 seconds for the green lights and the value 112,500 in 'yellow' a delay of about 2+ sec. for the yellow lights.

Under the banner "BEGIN MAIN PROGRAM"  the part of the code that actually executes on the microcontroller begins.  The first job is to turn off the watchdog timer (it's important to do, but I won't explain why now).

Next we set up the pins on the microcontroller.  This involves two operations for each pin.  First, the pin has to be defined as an output; followed by setting the output "on" (that is, telling the microcontroller to put 3V on the pin).  The comments tell you which pin is being set and what it is used for.  Inside of the parentheses is the internal port and bit number that is being used (more on this in another post).

Next under the banner "DELAY WITH ALL SIGNALS ILLUMINATED FOR LAMP CHECK" I do something that is not necessary, but is nice to have.  All of the signals have been turned on by previous code, so I introduce a delay loop of a couple of seconds with all of the lights so that you can do a visual lamp check.  

A word about delay loops.  It is possible to get precise timing out of the microcontroller; but it's an involved process and not required for this prigram.  Approximate times can be established by using loops to count up or down to/from a number and the time it takes the microcontroller to do this counting produces the time delay.  This loop tells the microcontroller to count using the variable 't' as a counter from t=0 to the value of 'start_up_delay', which has been set to a value of 50,000.  After the loop is finished, 't' is set back to zero so that it can be used as a counter in the next delay loop.

Under the banner "BEGIN MAIN LOOP" we begin the part of the program that will execute indefinitely so long as power is applied.  The "while" statement begins an infinite loop; once execution reaches this point everything between this statement and the end of the of the "while" statement will run indefinately.

The first sequence of setting the traffic lights begins after the banner "Begin Sequence E/W - Red  N/S - Green"; like the first state in the table above.  Since the first time through this loop all of the lights will be on after the lamp check, we have to not only turn on the appropriate Red and Green signals, but turn the others off as well.

After the lights have been set, the program enters a delay loop that counts up to the value in the variable "green".  The microcontroller will take about 16 seconds to count up to 900,000; "t" is then reset to zero and we go on to the next sequence.

Here's where this program differs from the alternate flasher program.  In the alternate flasher, the instructions turning the LEDs on were inside of the loop.  So the LEDs were turned on several thousand times while the loop executed.  In this program we set LEDs once and then just idle in the loop while we count up.

The next sequence "E/W - Red   N/S - Yellow" begins with the comment that we  do not have to set the E/W signal to red because it's red already; but we're going to do it anyway.  This makes the code clearer and more self-contained, but could be eliminated if we were running out of code space or time - which we're not. At the end of this sequence, we count up to the value in the variable "yellow", which produces a delay of a little over 2 seconds.

The next two sequences operate in much the same way as the first two.  After the timing loop of the last sequence, the right hand curly brackets closes the "while" statement infinite loop and the program returns to the first sequence.

Here's a video of the circuit in action.  I've made a daughter board to connect six LEDs and resistors (270-300 ohm) to the Launch Pad's pins that I have defined as output. The daughter board obscures the Launch pad which is below the daughter board. The layout of the LEDs follows the layout of the microcontroller's pins and not the arrangement of a traffic light signal head, but you'll see the correct pattern of lights in red, yellow and green.



 



You can download the text file of the code here:

Traffic Light Code
 
If you want to try your hand at modifying this program here are a couple of suggestions.  If you want to have more than three indications on the signal, to add turning arrows for instance, you would add additional states to the state table.  You'd have to define more output pins for the turning arrow LEDs, then add a couple of states where both main signals are red and the E/W then the N/S arrows are illuminated in turn before returning to the green-yellow-red sequence.

If you want to add a third route through the intersection, you will need to add a column to the state table then re-sequence the lights to accommodate the three routes. New output pins will have to be defined for the additional signals for the third route.

For the neurotic, who want the maximum attention to prototype detail, I have two suggestions.  At most intersections one route through the intersection is usually more heavily traveled and is allowed more time on green than the other route.  This would be an easy modification.  Simply define two green and two yellow loop counters - a longer one for the superior route and a shorter one for the inferior route.  Substitute them into the code where appropriate for 'green' and 'yellow' and the timing loops will adjust accordingly. 

The other suggestion is for the (exceedingly neurotic) advanced  programmer.  Build in a 'soft start' and 'gradual fade' for the LEDs to make them look more like incandescent lights. This could be accomplished in two ways. Build a nested timing loop where the LED is on for a short while followed by an off period, followed by a longer on period, shorter off period..., etc. until full brightness is reached.  Full brightness is held for a the duration of the signal and then the process is reversed.  The soft start and gradual fade would be much less than a second each and the loops would probably be only hundreds of counts long at the beginning and end. What you are doing is creating a crude Pulse Width Modulation (PWM).

The other apporach would be to use the on-chip PWM generator to do this function for you. I'll be doing PWM for a future project, so we'll see how this comes out.

These options demonstrate the versatility of the microcontroller.  You can buy a traffic light circuit kit, but it's a fixed green-yellow-red sequence without any ability to add additional lights or routes or modify the timing.

 
This has been a long post with a lot of information. The code for the basic traffic light sequencer follows. Don't cut and paste this into Code Composer Studio as the embedded HTML that allows it to display properly will mess up the compiler. Use the link above to get a text file of the program. (BTW Blogger has really honked-up the indentation this time, and I cannot seem to get it fixed, sorry)


//
//
//
// Traffic Light Sequencer
// COPYRIGHT 2012 T. TERRANCE
//                                
// Provided  under a Creative Commons Attribution, Non-Commercial  
// Share-Alike,3.0 Unported License                          
//
// TARGETED TO MSP430 LANUCHPAD W/MSP430G2553 PROCESSOR
//
//



/*
 * main.c
 */ 
 
#include <msp430g2553.h> //This instruction tells the compiler what microcontroller you are compiling this for.


volatile long t=0;        //Define loop counter t and set it to 0
volatile long green = 900000;   //Define loop counter green and set it to 900,000
volatile long yellow = 112500; //Define loop counter yellow and make it 1/8 of green
volatile long delay=15000;   //Define delay waiting period used to latch the signal indication and set it to 15000
volatile long start_up_delay = 50000;   //Define delay waiting period used to flash all of the signals at start-up and set it to 50000



////////////////////////////////////////////////////////////////////////////////////////////
//                      
//     BEGIN MAIN PROGRAM            
//                      
////////////////////////////////////////////////////////////////////////////////////////////


void main(void){


WDTCTL = WDTPW + WDTHOLD;  //Stop Watchdog Timer


P1DIR |= BIT0;  //sets E/W RED SIGNAL pin #2 (Port 1, Bit 0) to output and set to on
P1OUT |= BIT0;

P1DIR |= BIT4;  //sets E/W YELLOW SIGNAL pin #6 (Port 1, Bit 4) to output and set to on
P1OUT |= BIT4;

P1DIR |= BIT5;  //sets E/W GREEN SIGNAL pin #7 (Port 1, BIT 5) to output and set to on
P1OUT |= BIT5;

P2DIR |= BIT0;  //sets N/S RED SIGNAL pin #8 (Port 2, BIT 0) to output and set to on
P2OUT |= BIT0;

P2DIR |= BIT1; //sets N/S YELLOW SIGNAL pin #9 (Port 2, Bit 1) to output and set to on
P2OUT |= BIT1;

P2DIR |= BIT2; //sets N/S GREEN SIGNAL pin #10 (Port 2, BIT 2) to output and set to on
P2OUT |= BIT2;


/////////////////////////////////////////////////////////////////////////////////////////////
//                      
//  DELAY WITH ALL SIGNALS ILLUMINATED FOR "LAMP CHECK"     
//                      
/////////////////////////////////////////////////////////////////////////////////////////////


for (t; t < start_up_delay; t++)  //delay loop
  {

  }
  t=0;



  /////////////////////////////////////////////////////////////////////////////////////////////
  //                      
  //     BEGIN MAIN LOOP              
  //                      
  /////////////////////////////////////////////////////////////////////////////////////////////



  while (1) // while (1) is always true, so this is an infinite loop
  {

   ///////////////////////////////////////////////////////////////////////////////////
   //     Begin Sequence - E/W Red, N/S Green
   //
   ///////////////////////////////////////////////////////////////////////////////////


   P1OUT |= BIT0;  //turn on E/W RED SIGNAL
   P1OUT &= ~BIT4; //turn off the E/W YELLOW SIGNAL
               P1OUT &= ~BIT5; //turn off the E/W GREEN SIGNAL

               P2OUT &= ~BIT0; //turn off the N/S RED SIGNAL
               P2OUT &= ~BIT1; //turn off the N/S YELLOW SIGNAL
               P2OUT |= BIT2;  //turn on the N/S GREEN SIGNAL

               for (t; t < green; t++)  //delay loop for one green time period
        {

        }
             t=0;

       ///////////////////////////////////////////////////////////////////////////////////
       //     Begin Sequence - E/W Red, N/S Yellow
       //
       ///////////////////////////////////////////////////////////////////////////////////

             //the E/W signals should not have to be reset
             //but do it anyway

       P1OUT |= BIT0;  //turn on E/W RED SIGNAL
       P1OUT &= ~BIT4; //turn off the E/W YELLOW SIGNAL
           P1OUT &= ~BIT5; //turn off the E/W GREEN SIGNAL

                //the N/S red signal should not need to be reset
                //but do it anyway


           P2OUT &= ~BIT0; //turn off the N/S RED SIGNAL
    P2OUT |= BIT1;  //turn on the N/S YELLOW SIGNAL
    P2OUT &= ~BIT2; //turn off the N/S GREEN SIGNAL


         for (t; t < yellow; t++)   //delay loop for one yellow time period
          {

          }
          t=0;


         ///////////////////////////////////////////////////////////////////////////////////
         //     Begin Sequence - E/W Green, N/S Red
         //
         ///////////////////////////////////////////////////////////////////////////////////

         P1OUT &= ~BIT0;  //turn off E/W RED SIGNAL
    P1OUT &= ~BIT4;  //turn off the E/W YELLOW SIGNAL
    P1OUT |= BIT5;   //turn on the E/W GREEN SIGNAL

    P2OUT |= BIT0;   //turn on N/S RED SIGNAL
    P2OUT &= ~BIT1;  //turn off the N/S YELLOW SIGNAL
    P2OUT &= ~BIT2;  //turn off the N/S GREEN SIGNAL


          for (t; t < green; t++)   //delay loop for one green time period
           {

           }
           t=0;


         ///////////////////////////////////////////////////////////////////////////////////
         //     Begin Sequence - E/W Yellow, N/S Red
         //
         ///////////////////////////////////////////////////////////////////////////////////


                           //should not have to reset E/W red signal
                           //but do it anyway

      P1OUT &= ~BIT0; //turn off E/W RED SIGNAL
      P1OUT |= BIT4;  //turn on E/W YELLOW SIGNAL
      P1OUT &= ~BIT5; //turn off the E/W GREEN SIGNAL

                        //should not have to reset any N/S signal
                        //but do it anyway

     P2OUT |= BIT0;  //turn on N/S RED SIGNAL
     P2OUT &= ~BIT1; //turn off the N/S YELLOW SIGNAL
     P2OUT &= ~BIT2; //turn off the N/S GREEN SIGNAL


     for (t; t < yellow; t++)  //delay loop for one yellow time period
            {

            }
          t=0;


  } //close while statement, back to top of infinite loop



} // End Main 
 
 
 





















The LaunchPad for Model Railroading



No, I'm not talking about some cheesy "action" accessory made by Lionel in the sixties.  What I am talking about is a microcontroller development board from Texas Instruments that has the potential for scores of uses on a model railroad.  The Texas Instruments MSP430 Launch Pad (MSP-EXP430G)

A microcontroller is, essentially, a computer system on a single chip, including some hardware that ordinarily would be external to and would have to be connected to a conventional microcomputer.  Today's microcontrollers can be essentially as fast or faster than the '486 generation of microcomputers. Whether you know it or not microcontrollers are embedded into many of the systems model railroaders use today.  They are in each DCC decoder, in the command station and handhelds.  Accessory decoders and the products from Tam Valley Depot are built around them as well.

What's unique about the Launch Pad is that you can buy one from TI for $4.30 - that's not a misprint.  For less than $5 you get a development board, two target microcontrollers and some accessories.  This makes the TI board much cheaper that similar products from the competing microcontroller lines and it's cheap enough that the Launch Pad can be incorporated right into your projects.

What can you do with one?  Among other things, microcontrollers can directly light LEDs therefore they can be used for all manner of things like crossing flashers, traffic light sequencers and signaling systems.  In addition to illuminating the lights, the microcontroller can incorporate the logic to determine which lights to turn on.  You can program one to sequence the lights inside of a building or factory to imply activity inside. The logic for a bi-directional, three color signaling system is created using a surprisingly few lines of code.  In addition, with a few external components the same microcontroller can also detect the presence of the trains.

Turnout control using either stall motor (Tortoise) machines or servos is possible.  There are accessory boards available for the Launch Pad that enable it to store and playback sounds, opening the possibility to add sound sequences to your scenes.  Because the Launch Pad has a USB port on board that is accessible from the target microcontroller, the potential exists for tying many Launch Pads together into a network so that they can be controlled from a central location, or tied into a system like JMRI.

The microcontroller has to be programmed to function. The programming language (C or assembler) and environment is available free from TI.  If you cannot program, don't despair  I'll address that shortly.  Because these can be programmed, you can customize one for whatever functions you need.  Need B&O four-color signalling with all six marker indications (about 37 different signal aspects including flashing)?  You can program that complex signal system into one of these - and in many cases you can do it without additional hardware.

So what if you cannot program?  Well you could learn.  I hadn't programmed anything in almost 25 years before I took to programming the Launch Pad; and I had a couple of projects up and running in two days - including the time it took me to learn the "C" programming language.  I will be trying to cajole some of my buddies at Model Rail Radio to create some tutorials on how to learn and program in C.

For those of you who don't want to program, but want to give this technology a try anyway, I'll be putting up the programs that I create, and hopefully the creations of others, onto a website where people can come to share and use the code created by all.  In this way I hope to foster a community where we can share applications for the TI Lanuch Pad (and other microcontrollers) for model railroad use.

The code below, for an alternate crossing flasher, is the first such submission.  This code is provided under a Creative Commons license, which means that you can use it, modify it and redistribute it with attribution to the original author.  And your modifications must be shared freely. You cannot use it, even if modified, for commercial purposes.

This program will flash the on-board LEDs in an alternate pattern, as used in a RR crossing flasher.  In addition to the on-board LEDs, two of the microcontroller's pins (pins 6 and 7) are toggled so that if you connected a LED with series resistor between the pin and circuit ground, the LEDs will flash as well.

Here's a short video of the program in operation. BTW that's a small travel mouse along side the Launch Pad to give you some sense of it's size.




The program is almost as simple as any program can get. After some set-up formalities, the program is comprised of  two loops inside of an infinite loop.  In the first loop one LED and a pin is turned on and the other LED and a pin is turned off, the loop counts for the duration of the flash.  Then the second loop executes and turns off the first LED and pin while turning on the other LED and pin.  The second loop counts for a similar time to keep these LEDs on.  Finally the outer loop takes over and starts at the beginning; and it will do this indefinitely so long as the circuit is powered up.  It's brute force and inelegant, but it is simple to understand.

A comment about reading the program.  Anything after a // is a comment and is not read by compiler (the compiler converts the statements that are written in the code into a numerical sequence that the microcontroller reads and acts upon).  It's there only for you to read for understanding. 

To use this program you will have to download TI's Code Composer Studio (CCS) and install it on to your computer. You can download the free version - which has some limitations that are not likely to effect the programming that you will do - from this link.

Code Composer Studio

Most likely you'll want the windows version.  Installing this in your machine may require that you sign up for an account with TI; don't worry, no credit card or anything like that is required.

Once you have CCS installed (it takes rather a lot of time to install and wherever you start it), download the code file from my Microsoft Skydrive at this link:

Flasher code

Go to the "File" menu in the upper left, pull it down and choose "Save As";  from save as you will be given an option to download the file.  Open the MS Word file that you download, cut and paste the program into the "main.c" window of CCS.  Do not cut and paste from this blog post, because of embedded HTML characters it will not work.     These instructions will resume below, after the code listing.


//
//      
//
//
//             ALTERNATE CROSSING FLASHER
//
//            COPYRIGHT 2012 T. TERRANCE
//
// Provided  under a Creative Commons, Attribution,  
//       Non-Commercial, Share Alike, 3.0 Unported License
//
//
//      TARGETED TO MSP430 LANUCHPAD          
//      W/MSP430G2553 PROCESSOR
//              
//

/*
 * main.c
 */
#include <msp430g2553.h>


volatile long t=0;            //Define loop counter t and set it to 0
volatile long p=15000;  //Define flash period variable P and set it to 15000



void main(void){



WDTCTL = WDTPW + WDTHOLD;  //Stop Watchdog Timer



P1DIR |= BIT0;  //sets pin 1.0 RED on-board LED for output and turns it on
P1DIR |= BIT6;  //sets pin 1.6 Green on-board LED for output and turns it on
P1DIR |= BIT4;  //sets pin 6 (port 1.4) for output and turns it on
P1DIR |= BIT5;  //sets pin 7 (port 1.5) for output and turns it on


for (;;)  //start infinite loop
{


for (t;  t<p; t++)  // loop 1
{


P1OUT &= BIT0;  //Turn off on-board red LED 0 FOR DURATION OF TIMER 1
P1OUT &= BIT4;  //Turn off pin 6 (port 1.4) FOR DURATION OF TIMER 1
P1OUT |= BIT6;  // TURN ON on-board green LED FOR DURATION OF TIMER 1
P1OUT |= BIT5;  // TURN ON pin 7 (port 1.5) FOR DURATION OF TIMER 1
}


t=0;  //set t to zero


for (t;  t<p; t++)  // loop 2
{
P1OUT &= ~BIT6;  //Turn off on-board green LED for duration of timer 2
P1OUT &= ~BIT5;  //TURN OFF Pin 7 (port 1.5) FOR DURATION OF TIMER 2
P1OUT |= BIT0;   //TURN on on-board red LED FOR DURATION OF TIMER 2
P1OUT |= BIT4;   //TURN ON pin 6 (port 1.4) FOR DURATION OF TIMER 2
}


t=0;  //set t to zero



}  //end of infinite loop



}  //end of main




Creative Commons License
Alternate Flasher by Terry Terrance is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.



The convention for writing C code includes indenting the lines of code to highlight the nested loops.  My original code was so indented, but Blogger took out the tab characters. 
 
Connect your Launch Pad to your computer via the USB cable included with it.  A demonstration program is loaded into the Launch Pad that, coincidentally, causes the on-board LEDs to flash.  You can stop the flashing by pushing the push button nearest the LEDs.

Now in CCS pull down the "Project" menu and click on "Build Project".  The build process will take a few seconds during which a pop up window will appear and then disappear.  After the build has finished go to the "Run" menu and click on "Debug".  A pop-up window will appear complaining about the lack of code to support TI ultra low power mode.  Since we are not developing this project for battery power you can just click on "Proceed" to ignore this warning.  A few more pop-ups will come and go of their own accord.

The code will be loaded onto your Launch Pad automatically.  Once it's loaded the Debug window will appear as the topmost window on your screen.  In the top bar of the debug window at the far right you'll see some controls that look like those on a DVD player: a play button, a pause button and a stop button.  When the play button is green and yellow, you can click on it and the LEDs should start flashing.  Congrats, you've successfully compiled and loaded a program.

Pushing the pause button will pause the program's execution.  Depending on when you hit the pause button, the red or the green LED may stay on; I even once paused the program during the tiny amount of time that both LEDs were off.  Pushing the Stop button will disconnect your computer from the running program.  The program is still running however, and the LEDs will continue to flash until you disconnect the USB cable, thereby removing power.

The program is now loaded into the micro controller and will stay there until replaced by another program.  You can prove this to yourself by disconnecting the Launch Pad, shutting down CCS, then reconnecting the Launch Pad.  The LEDs will begin to flash and continue until disconnected.

For your first foray into modifying a program, change the value of the variable "p" which controls the timing loops.   Make p larger or smaller (in increments of 1000) to change the flash rate.  Rebuild the project as above, load it and see the results.

There are many resources for the TI Launch Pad on line.  There are videos on both the TI website and You Tube; although the ones at TI are hard to find.  There are user groups for the Launch Pad as well as products made to interface to the Launch Pad, they're called "Booster Packs".

I'll be putting up more information on the Launch Pad for model railroads as well as a dedicated website and/or blog.  But for now this entry is running long so I'll end it here.

.