Thursday, January 17, 2013

Simple Signal Solution

The idea for this project came to me a couple of years ago to design a simple and inexpensive solution for three color, bi-directional signaling.  I was sure that microcontrollers could implement the code and drive the LEDs; the problem with this plan was the inexpensive part - that was until the LaunchPads came along. So this is what I call the Simple Signal Solution.

In a simple block signaling system, at the eastern entrance to a block there is a westbound signal, conversely at the western entry to the block there is an eastbound signal. When the block is unoccupied both signals are green.  However if the block is occupied both signals indicate red, the signals in the blocks immediately to the east and west,    in the direction heading towards the occupied block, indicate yellow and the blocks beyond that indicate green.

Hardware Required for this project;
  
  • LaunchPads (MSP430G2553 chip) - 1 for each block
  • LEDs - (2) Red, (2) Yellow, (2) Green for each block or (2) signals with built-in LEDs for each block.
  • Resistors - (6) 270-300 ohm min. (higher to reduce LED brightness) for each block.  
A note about LEDs and resistors.  I know that some folks do not use resistors when driving LEDs with the LaunchPad. I did this too when I first programmed one.  However I left an LED flashing for several days and eventually the LED started to act flaky.  Then I saw on the LaunchPad's schematic that TI uses resistors with the on-board LEDs. If TI thinks that it's necessary, that's good enough for me. 


This project requires several of the available pins on the LaunchPad to be assigned as inputs or outputs.  I made up a table to keep them all straight.

 
Pin Port Assignment Direction Sense





2 P1.0 (and LED1) Eastbound Red Indication Output Active High
6 P1.4 Eastbound Yellow Indication Output Active High
7 P1.5 Eastbound Green Indication Output Active High
8 P2.0 Westbound Red Indication Output Active High
9 P2.1 Westbound Yellow Indication Output Active High
10 P2.2 Westbound Green Indication Output Active High






Pin Port Assignment Direction Sense










15 P1.7 THIS_BLOCK_OCCUPIED Input Active low
14 P1.6 (and LED2) OCCUPANCY_DETECTION_TO_EAST_BLOCK  (Occupancy detection TO next east block) Output Active low
13 P2.5 EAST_BLOCK_OCCUPIED (Occupancy detection FROM next east block) Input Active low
12 P2.4 OCCUPANCY_DETECTION_TO_WEST_BLOCK (Occupancy detection TO next west block) Output Active low
11 P2.3 WEST_BLOCK_OCCUPIED (Occupancy detection FROM next west block) Input Active low



That's a lot of pins to keep straight, but not too bad once you get it all into your head.                                            

The schematic diagram below shows the pins on the LaunchPad  headers and how to interconnect the LaunchPads so that the signals to and from the east and west get to their appropriate pins.


Pin 15 is brought to ground by an external circuit (e.g. a train detector) to tell the LaunchPad that the block is occupied.  Pin 14 outputs the status of it's train detection to the LaunchPad to the east, status from the east is received on pin 11.  Similarly Pin 12 outputs the current block status to the LaunchPad to the west on pin13 and status from the west is received on pin 12.

[Author's post-script.  I designed this circuit for common cathode LEDs, because that's the way I like to wire mine.  If  you are using commercial signals/signal heads they may come wired as common anode.  If they are, this code will not work.  I'll modify this code for use with common anode signals at a future date.]

You'll notice that just four wires interconnect the LaunchPads; two going east and two going west.  Compare that to the interconnects between the components of the commercial signal systems.  All of the LaunchPads may have to be powered by the same source to make sure that you have a common ground between them OR you have to tie the grounds between the supplies together.

Here's a video of the circuit in action. 






If you are not a programmer, you now have all of the data that you need to grab the code and go.  So here is a link to the code.

Simple Signal Solution


Code Walkthrough

If you are inclined to program, read on as I will walk you through the code.  The code begins with the usual declaration that this will be targeted to the MSP430G2553 processor.  Some loop counters and delay variables are defined as are some short intergers that will be used as logicals (0 or 1) to hold the status of the block occupancies.

The program enters the main program and the watchdog timer is turned off.   Then the input pins for the block occupied status are initialized to input; have resistors connected to them and finally have the resistors set as 'pull-ups'.  The MSP430G2553has internal resistors that can be set as pull-up or pull down.  Since these inputs are active low, the resistors are used to 'pull-up' (make high) the input pins until an external signal pulls them down.  Otherwise the pins would 'float' between high and low and may give false readings.

These block occupied pins are connected to either the train detector for the current block, the output of the LaunchPad to the east or the output of the LaunchPad to the west.  Signals on these pins will be captured and internal variable set based on their state below.

The the output pins are set as outputs; the six pins driving the LEDs are set to high (on) and the two outputs of the current  block's train detection status - OCCUPANCY_DETECTION_TO_EAST_BLOCK and OCCUPANCY_DETECTION_TO_WEST_BLOCK are set to high (the comments mistakenly say 1) which is inactive since these pins are active low.

A delay loop follows for a 'lamp check'.  The LED outputs have been set to the 'on' state above, and the delay loop holds that state for about 2 seconds.


Next we clear the block occupancy variables by setting them to 0, which will be interpreted as a logical false.

This finishes the set up and the program enters an infinite loop that will execute until power is removed.



Next the block occupied status for the current block, the block to the east and the block to the west is determined. If a block is occupied it is set to '1' which will be interpreted as a logical true and if the block is unoccupied; the value is set to '0' which will be interpreted as a logical false.

Next the code signals the blocks to the east and the west whether this block is occupied so that they can set their signals accordingly.

Now the signal-setting logic of the code begins. You can read the comments in the code for yourself.  All combinations of the 3 block occupied variables are tested and the signals set accordingly.

Finally, the signal is latched for a while to provide for some debounce.  The infinite loop then begins again with the clearing of the block occupied variables and the reading of the block status, etc.



Modifications & Extensions


While this code is fully functional as a signal system, it can still benefit from some modifications.  Bashing this code together with Hoffy's IR detector would make for an interesting combination.  Similarly combining this with code for a reflective IR detector would also make a better product.  If you attempt either of these think about including a time delay to latch the 'train detected' signal to account for the inter-car dropout common to all optical detection systems.

You could also include code to control the signals on sidings adjacent to the main.  In fact, the most involved signal complex that you can imagine is probably not beyond the capabilities of this relatively simple microcontroller.  Of course, you may not have enough pins to drive all of those signals!

Enjoy!

In the code listing that follows, I've given up trying to keep proper formatting.  Do you'll have to follow along as best that you can or you can download the properly formatted code from the link above.  Do not try to copy and paste this code.  It will not work!

 


//////////////////////////////////////////////////////////////////////////////

//                                                                         ////

//                                                                         ////

//            SIMPLE SIGNAL SOLUTION                   ////

//                                                                          ////

//            THREE-COLOR, BI-DIRECTIONAL SIGNAL LOGIC        

//                                                                             ////

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





////////////////////////////////////////////////////////////////////////////////////////////

//                                                                                            ////

//            Initialize Logical Variables for Block Occupancy                                 ////

//                                                                                           ////

////////////////////////////////////////////////////////////////////////////////////////////



short int THIS_BLOCK_OCCUPIED;              //if this block is occupied the value is set to

//true (non-zero)

short int EAST_BLOCK_OCCUPIED;              //if the next block to the east is occupied the value

//is set to true (non-zero)

short int WEST_BLOCK_OCCUPIED;              //if the next block to the west block is occupied

//the value is set to true (non-zero)









////////////////////////////////////////////////////////////////////////////////////////////

//                                                                                            ////

//                                 BEGIN MAIN PROGRAM                                        ////

//                                                                                            ////

////////////////////////////////////////////////////////////////////////////////////////////





void main(void){

















WDTCTL = WDTPW + WDTHOLD;  //Stop Watchdog Timer















///////////////////////////////////////////////////////////////////////////////////////////

//                                                                                            ///

//                   Initialize Ports AND Signal Indications                                  ///

//                                                                                            ///

///////////////////////////////////////////////////////////////////////////////////////////









P1DIR &= ~BIT7;               // sets THIS_BLOCK_OCCUPIED pin (Port 1, bit 7) to input

P2DIR &= ~BIT5;               // sets EAST_BLOCK_OCCUPIED pin (Port 2, bit 5) to input

P2DIR &= ~BIT3;               // sets WEST_BLOCK_OCCUPIED pin (Port 2, bit 3) to input

P1REN |= BIT7;                // sets pull-up resistor on THIS_BLOCK_OCCUPIED (Port 1, bit 7) input pin

P2REN |= BIT5;                // sets pull-up resistor on EAST_BLOCK_OCCUPIED (Port 2, bit 5) input pin

P2REN |= BIT3;                // sets pull-up resistor on WEST_BLOCK_OCCUPIED (Port 2, bit 3) input pin





P1OUT |= BIT7;                // sets pull-up resistor on THIS_BLOCK_OCCUPIED (Port 1, bit 7) to pull-up

P2OUT |= BIT5;                // sets pull-up resistor on EAST_BLOCK_OCCUPIED (Port 2, bit 5) to pull-up

P2OUT |= BIT3;                // sets pull-up resistor on WEST_BLOCK_OCCUPIED (Port 2, bit 3) to pull-up









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

P1OUT |= BIT0;



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

P1OUT |= BIT4;



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

P1OUT |= BIT5;



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

P2OUT |= BIT0;



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

P2OUT |= BIT1;



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

P2OUT |= BIT2;



P1DIR |= BIT6;                //sets OCCUPANCY_DETECTION_TO_EAST_BLOCK pin to output and sets it to 1 (inactive)

P1OUT |= BIT6;



P2DIR |= BIT4;                //sets OCCUPANCY_DETECTION_TO_WEST_BLOCK pin to output and sets it to 1 (inactive)

P2OUT |= BIT4;





/////////////////////////////////////////////////////////////////////////////////////////////

//                                                                                            /////

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

//                                                                                            /////

/////////////////////////////////////////////////////////////////////////////////////////////





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

              {



              }

        t=0;













/////////////////////////////////////////////////////////////////////////////////////////////

//                                                                                            /////

//                   Clear Block Occupancy Variables                                           /////

//                                                                                            /////

/////////////////////////////////////////////////////////////////////////////////////////////





THIS_BLOCK_OCCUPIED=0;

EAST_BLOCK_OCCUPIED=0;

WEST_BLOCK_OCCUPIED=0;







/////////////////////////////////////////////////////////////////////////////////////////////

//                                                                                            /////

//                   BEGIN MAIN LOOP                                                         /////

//                                                                                            /////

/////////////////////////////////////////////////////////////////////////////////////////////







while (1)

{













//////////////////////////////////////////////////////////////////////////////////////////////

//                                                                                            //////

//            Read Block Occupancy in This Block, Block to the East                    //////

//                          and Block to the West                                         //////

//                                                                                            //////

//////////////////////////////////////////////////////////////////////////////////////////////





if ((P1IN & BIT7) == 0)                                      //Test Port 1 input, bit 7 and if zero (active low)

{

       THIS_BLOCK_OCCUPIED = 1;                               // set THIS_BLOCK_OCCUPIED to a non-zero value (true)

}

else

{

       THIS_BLOCK_OCCUPIED = 0;                               // set THIS_BLOCK_OCCUPIED to zero (false)

}





if ((P2IN & BIT5) == 0)                                      //Test Port 2 input, bit 5 and if zero (active low)

{

       EAST_BLOCK_OCCUPIED = 1;                               // set EAST_BLOCK_OCCUPIED to a non-zero value (true)

}

else

{

       EAST_BLOCK_OCCUPIED = 0;                               // set EAST_BLOCK_OCCUPIED to zero value (false)

}





if ((P2IN & BIT3) == 0)                                      //Test Port 2 input, bit 3 and if zero (active low)

{

       WEST_BLOCK_OCCUPIED = 1;                               // set WEST_BLOCK_OCCUPIED to a non-zero value (true)

}

else

{

       WEST_BLOCK_OCCUPIED = 0;                               // set WEST_BLOCK_OCCUPIED to zero value (false)

}















///////////////////////////////////////////////////////////////////////////////////////////////

//                                                                                                                                                               ///

//                          SEND LOCAL BLOCK OCCUPANCY STATUS TO BLOCKS EAST AND WEST                                  ///

//                                                                                                                                                               ///

///////////////////////////////////////////////////////////////////////////////////////////////





if (THIS_BLOCK_OCCUPIED > 0)         //local block occupied

{

       P1OUT &= ~BIT6;                   //set OCCUPANCY_DETECTION_TO_EAST_BLOCK to 0 (active)

       P2OUT &= ~BIT4;                   //set OCCUPANCY_DETECTION_TO_WEST_BLOCK to 0 (active)

}

else                                      //local block not occupied

{

       P1OUT |= BIT6;                    //set OCCUPANCY_DETECTION_TO_EAST_BLOCK to 1 (inactive)

       P2OUT |= BIT4;                    //set OCCUPANCY_DETECTION_TO_WEST_BLOCK to 1 (inactive)

}







///////////////////////////////////////////////////////////////////////////////////////////////

//                                                                                                ///

//            Begin Main Signal Logic                                                          ///

//                                                                                                ///

///////////////////////////////////////////////////////////////////////////////////////////////











       if (THIS_BLOCK_OCCUPIED > 0)         //If this block is occupied then set all signals red, clear other indications



              {

                     P1OUT |= BIT0;             //turn on EASTBOUND RED SIGNAL

                     P1OUT &= ~BIT4;            //turn off the EASTBOUND YELLOW SIGNAL

                     P1OUT &= ~BIT5;            //turn off the EASTBOUND GREEN SIGNAL

                     P2OUT |= BIT0;             //turn on WESTBOUND RED SIGNAL

                     P2OUT &= ~BIT1;            //turn off the WESTBOUND YELLOW SIGNAL

                     P2OUT &= ~BIT2;            //turn off the WESTBOUND GREEN SIGNAL

              }



       else if ( (EAST_BLOCK_OCCUPIED > 0) & (WEST_BLOCK_OCCUPIED > 0)  ) //blocks east and west of here are occupied

                                                                             //east and west signals set to yellow

                                                                             //clear other indications

              {

                     P1OUT &= ~BIT0;            //turn off EASTBOUND RED SIGNAL

                     P1OUT |= BIT4;             //turn on EASTBOUND YELLOW SIGNAL

                     P1OUT &= ~BIT5;            //turn off the EASTBOUND GREEN SIGNAL

                     P2OUT &= ~BIT0;            //turn off WESTBOUND RED SIGNAL

                     P2OUT |= BIT1;             //turn on the WESTBOUND YELLOW SIGNAL

                     P2OUT &= ~BIT2;            //turn off the WESTBOUND GREEN SIGNAL

              }





       else if (EAST_BLOCK_OCCUPIED > 0)           //only the block east of here is occupied

                                                 //eastbound is yellow, westbound is green

                                                 //clear other indications

              {

                     P1OUT &= ~BIT0;            //turn off EASTBOUND RED SIGNAL

                     P1OUT |= BIT4;             //turn on EASTBOUND YELLOW SIGNAL

                     P1OUT &= ~BIT5;            //turn off the EASTBOUND GREEN SIGNAL

                     P2OUT &= ~BIT0;            //turn off WESTBOUND RED SIGNAL

                     P2OUT &= ~BIT1;            //turn off the WESTBOUND YELLOW SIGNAL

                     P2OUT |= BIT2;             //turn on the WESTBOUND GREEN SIGNAL

              }



       else if (WEST_BLOCK_OCCUPIED > 0)       //only the block west of here is occupied

                                                 //westbound is yellow, eastbound is green

                                                 //clear other indications

              {

                     P1OUT &= ~BIT0;            //turn off EASTBOUND RED SIGNAL

                     P1OUT &= ~BIT4;            //turn off the EASTBOUND YELLOW SIGNAL

                     P1OUT |= BIT5;             //turn on the EASTBOUND GREEN SIGNAL

                     P2OUT &= ~BIT0;            //turn off WESTBOUND RED SIGNAL

                     P2OUT |= BIT1;             //turn on the WESTBOUND YELLOW SIGNAL

                     P2OUT &= ~BIT2;            //turn off the WESTBOUND GREEN SIGNAL

              }



       else                                      //all blocks clear - all signals green

                                                 //clear other indications

              {

                     P1OUT &= ~BIT0;            //turn off EASTBOUND RED SIGNAL

                     P1OUT &= ~BIT4;            //turn off the EASTBOUND YELLOW SIGNAL

                     P1OUT |= BIT5;             //turn on the EASTBOUND GREEN SIGNAL

                     P2OUT &= ~BIT0;            //turn off WESTBOUND RED SIGNAL

                     P2OUT &= ~BIT1;            //turn off the WESTBOUND YELLOW SIGNAL

                     P2OUT |= BIT2;             //turn on the WESTBOUND GREEN SIGNAL

              }





/////////////////////////////////////////////////////////////////////////////////////////////

//                                                                                            /////

//     Latch the final signal indications for a time to prevent "chatter"               /////

//                                                                                            /////

/////////////////////////////////////////////////////////////////////////////////////////////









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

              {



              }

        t=0;

}



}  //end of main



head.

Tuesday, January 15, 2013

Welder Lighting Effect



My lastest endevor toward the Launchpads for Model Railroading is a welding lighting effect.  This project uses two high brightness LEDs to simulate a welder being used. The wiring for this one is very simple as shown below.

I have left a lot of room for improvement in this project and look forward to seeing many variations.  The code has been clearly notated so that even the most novice of users can modify the fine points of the flash effects

It is possible to just use one LED if the dual LED is too bright for your application.

You can obtain the code, instructions, and schematics at hoffysworld.com

 I have posted this video of the effect, but please note it looks much better live and in person  the flash rate is much faster outside of this video.





 DO NOT COPY AND PASTE THIS CODE AS IT WILL FAIL TO COMPILE. Please use the ZIP file included at hoffysworld.com.


/*
* Welding Visual Effect Version 1.2
* COPYRIGHT © 2013 S.D. "Hoffy" Hofmeister
* http://www.hoffysworld.com
* Provided under a Creative Commons Attribution, Non-Commercial Share Alike,3.0 Unported License
* TARGETED TO MSP430 LANUCHPAD W/MSP430G2553 PROCESSOR
**************************************************************************************************
* Design Notes:
*
* This code uses a random number between 0 and and the defined count
* to select between 10 defined effects for two high brightness LEDs.
*
* This has been designed to use two high brightness white light LEDs in order to make the effect
* more intense but you can operate with one of you choose.
*
* I have purposely left room for a lot of growth and improvement on this project,  have fun!
***************************************************************************************************
* Circuit Pinout:
* PIN 1.0 = Anode of LED #1   > Cathode to Ground
* PIN 1.1 = UNASSIGNED - UART
* PIN 1.2 = UNASSIGNED - UART
* PIN 1.3 = Anode of LED #2 > Cathode to Ground
* PIN 1.4 = UNASSIGNED
* PIN 1.5 = UNASSIGNED
* PIN 1.6 = UNASSIGNED
* PIN 1.7 = UNASSIGNED
* PIN 2.0 = UNASSIGNED
* PIN 2.1 = UNASSIGNED
* PIN 2.2 = UNASSIGNED
* PIN 2.3 = UNASSIGNED
* PIN 2.4 = UNASSIGNED
* PIN 2.5 = UNASSIGNED
***************************************************************************************************
**************************************************************************************************/
#include <msp430g2553.h>
#include <stdlib.h>

volatile long reps = 0;
volatile long t = 0;
unsigned short int res;
//---------------------------------
// Effect Adjustments

// Modify these numbers to alter effect
// XXXXXXXXX_rep = number of flashes
// gapX   = How long LEDs are on
// gapXa  = How long LEDs are off

// Original value comments have been added so you can restore them to the original value

unsigned short int count = 50;  // (must remain higher than 10)  Low number effect more often, higher less often
// number higher than 10 creates a greater number of gaps an pauses between the effects

volatile long one_rep = 20;   //20
int gap1 = 500;           //500
int gap1a = 1000; //1000

volatile long two_rep = 5; //5
int gap2 = 500; //500
int gap2a = 1000; //1000

volatile long three_rep = 10; //10
int gap3 = 500; //500
int gap3a = 1000; //1000

volatile long four_rep = 15; //15
int gap4 = 250; //250
int gap4a = 500; //500

volatile long five_rep = 20; //10
int gap5 = 500; //500
int gap5a = 1000; //500

volatile long six_rep = 5; //5
int gap6 = 250; //250
int gap6a = 500; //500

volatile long seven_rep = 5; //5
int gap7 = 250; //250
int gap7a = 250; //500

volatile long eight_rep = 10; //10
int gap8 = 500; //500
int gap8a = 500; //500

volatile long nine_rep = 20; //20
int gap9 = 250; //250
int gap9a = 500; //500

volatile long ten_rep = 5; //5
int gap10 = 500; //500
int gap10a = 500; //500
//----------------------------------------------
/*
 * Main Code
 */
void main(void){

// Configure Pins and stop Watchdog

WDTCTL = WDTPW + WDTHOLD;  //Stop Watchdog Timer

P1DIR |= BIT0;  //Set Port 1 Pin 0 as Output
P1OUT &= ~BIT0; //Set Port 1 Pin 0 as OFF

P1DIR |= BIT3; //Set Port 1 Pin 3 as Output
P1OUT &= ~BIT3;//Set Port 1 Pin 3 as OFF

//---------------------------------------------
while ( 1 ) { // Continuous Loop

res = (rand() % count); // returns random value

switch (res){  //  switches between each of the ten choices based on the returned number above

case 1:
  for (reps; reps < one_rep; reps++) // repeat choice based on the number of reps set above
  {
  P1OUT |= BIT0;  //ON
  P1OUT |= BIT3;  //ON

  for (t; t < gap1; t++)   //delay loop
  {
  }

  P1OUT &= ~BIT0; //OFF
  P1OUT &= ~BIT3; //OFF
  t=0;  //RESET COUNTER

  for (t; t < gap1a; t++)   //delay loop
  {
  }
  }
  t=0; //RESET COUNTER
  reps=0; //RESET REPS
  break; // Leave choice and get new random number

case 2:
for (reps; reps < two_rep; reps++) // repeat choice based on the number of reps set above
{
P1OUT |= BIT0; //ON
P1OUT |= BIT3; //ON

for (t; t < gap2; t++)   //delay loop
{
}


P1OUT &= ~BIT0; //OFF
P1OUT &= ~BIT3; //OFF
t=0; //RESET COUNTER
for (t; t < gap2a; t++)   //delay loop
{
}

}
t =0; //RESET COUNTER
reps=0; //RESET REPS
break; // Leave choice and get new random number


case 3:
for (reps; reps < three_rep; reps++) // repeat choice based on the number of reps set above
{
P1OUT |= BIT0; //ON
P1OUT |= BIT3; //ON

for (t; t < gap3; t++)   //delay loop
{
}

P1OUT &= ~BIT0; //OFF
P1OUT &= ~BIT3; //OFF
t=0; //RESET COUNTER

for (t; t < gap3a; t++)   //delay loop
{
}
}
t=0; //RESET COUNTER
reps=0; //RESET REPS
break; // Leave choice and get new random number


case 4:
  for (reps; reps < four_rep; reps++) // repeat choice based on the number of reps set above
  {
  P1OUT |= BIT0; //ON
  P1OUT |= BIT3; //ON

  for (t; t < gap4; t++)   //delay loop
  {
  }

  P1OUT &= ~BIT0; //OFF
  P1OUT &= ~BIT3; //OFF
  t=0; //RESET COUNTER

  for (t; t < gap4a; t++)   //delay loop
  {
  }
  }
  t=0; //RESET COUNTER
  reps=0; //RESET REPS
  break; // Leave choice and get new random number


case 5:
  for (reps; reps < five_rep; reps++) // repeat choice based on the number of reps set above
  {
  P1OUT |= BIT0; //ON
  P1OUT |= BIT3; //ON

  for (t; t < gap5; t++)   //delay loop
  {
  }

  P1OUT &= ~BIT0; //OFF
  P1OUT &= ~BIT3; //OFF
  t=0; //RESET COUNTER

  for (t; t < gap5a; t++)   //delay loop
  {
  }
  }
  t=0; //RESET COUNTER
  reps=0; //RESET REPS
  break; // Leave choice and get new random number


case 6:
  for (reps; reps < six_rep; reps++) // repeat choice based on the number of reps set above
  {
  P1OUT |= BIT0; //ON
  P1OUT |= BIT3; //ON

  for (t; t < gap6; t++)   //delay loop
  {
  }

  P1OUT &= ~BIT0; //OFF
  P1OUT &= ~BIT3; //OFF
  t=0; //RESET COUNTER

  for (t; t < gap6a; t++)   //delay loop
  {
  }
  }
  t=0; //RESET COUNTER
  reps=0; //RESET REPS
  break; // Leave choice and get new random number


case 7:
  for (reps; reps < seven_rep; reps++) // repeat choice based on the number of reps set above
  {
  P1OUT |= BIT0; //ON
  P1OUT |= BIT3; //ON

  for (t; t < gap7; t++)   //delay loop
  {
  }

  P1OUT &= ~BIT0; //OFF
  P1OUT &= ~BIT3; //OFF
  t=0; //RESET COUNTER

  for (t; t < gap7a; t++)   //delay loop
  {
  }
  }
  t=0; //RESET COUNTER
  reps=0; //RESET REPS
  break; // Leave choice and get new random number


case 8:
  for (reps; reps < eight_rep; reps++) // repeat choice based on the number of reps set above
  {
  P1OUT |= BIT0; //ON
  P1OUT |= BIT3; //ON

  for (t; t < gap8; t++)   //delay loop
  {
  }

  P1OUT &= ~BIT0; //OFF
  P1OUT &= ~BIT3; //OFF
  t=0; //RESET COUNTER

  for (t; t < gap8a; t++)   //delay loop
  {
  }
  }
  t=0; //RESET COUNTER
  reps=0; //RESET REPS
  break; // Leave choice and get new random number


case 9:
  for (reps; reps < nine_rep; reps++) // repeat choice based on the number of reps set above
  {
  P1OUT |= BIT0; //ON
  P1OUT |= BIT3; //ON

  for (t; t < gap9; t++)   //delay loop
  {
  }

  P1OUT &= ~BIT0; //OFF
  P1OUT &= ~BIT3; //OFF
  t=0; //RESET COUNTER

  for (t; t < gap9a; t++)   //delay loop
  {
  }
  }
  t=0; //RESET COUNTER
  reps=0; //RESET REPS
  break; // Leave choice and get new random number


case 10:
   for (reps; reps < ten_rep; reps++) // repeat choice based on the number of reps set above
   {
   P1OUT |= BIT0; //ON
   P1OUT |= BIT3; //ON

   for (t; t < gap10; t++)   //delay loop
   {
   }

   P1OUT &= ~BIT0; //OFF
   P1OUT &= ~BIT3; //OFF
   t=0; //RESET COUNTER

   for (t; t < gap10a; t++)   //delay loop
   {
   }
   }
   t=0; //RESET COUNTER
   reps=0; //RESET REPS
   break; // Leave choice and get new random number

}  // END switch
}  //END while
}  //END main

Duplicating, Modifying, Extending the Projects

One of the beauties of electronics design and experimentation is that there are usually several ways to solve a problem; and when software is involved, there are almost infinite ways to code a program.  Some solutions are better than others, of course, but every solution is useful for someone.

Therefore, when someone contributes a project to this blog do not let that deter you from doing your own version of the same project or modifying the original project to meet your needs and preferences and then resubmitting your version to this blog.  Your version may be just what someone else needs too.

By the same token, if you have an idea for a new project or modification to an existing one and you don't want to take on the challenge yourself, suggest it to the followers of this blog, via the comments for now.  You never know who will take on the challenge and complete your project.

Friday, January 11, 2013

Quad IR Beam Detector


On the Model Rail Radio Podcast Episode: Model Rail Radio #67: DCC is Not a Solution (to World Peace) [December 8, 2012]

 Terry Terrance introduced his concept on using Texas Instruments MSP430 Launchpads for the development of Open Source / Group Sourced model railroading animation and projects.

 I of course was intrigued by this and just had to throw my hat in the ring and play with this idea.  While I am known to throw myself very deep into projects like this the intention is to develop projects that will be easy for the non technical model railroader to use.  

 I have spent a great chunk of time getting myself familiar to how these little gems work and getting at best a novices understanding on coding in the Code Composer Studio software.  I started playing with the MSP430's in regards to some robotics projects I had pending and moved into developing a project toward Terry's cause.

 My project of choice was to start off making a Quad (4) IR Beam detection project that can be used to detect the presence of trains in four areas.  This would be useful for signaling or triggering other animations.

 Here is a video of my final testing, I would suggest blowing up full screen.

   






 As complicated as this may all appear to those who are not versed with electronics it is certainly not something to be intimidated from.  I am not showing all of these technical details to frighten anyone away, but for the benefit of those who do comprehend it as a whole.

*********************************************************************************************

Moderator's Notes:


In the type of optical detector train detector that Hoffy is describing is best described as an  “Interrupter”.  A light source (lamp, visible or Infrared LED) is aimed across the rails. On the opposite side of the tracks from the light source is some form of photo detector (photovoltaic cell, photo-resistive cell, photodiode or photo transistor). When the train comes along it breaks the beam between the light source and the detector and the train’s presence is detected. Don’t be put off by the technical terms within the parenthesis above; the key concepts are: light source, light detector and breaking the beam.



Figure 1 illustrates the principles. In Fig. 1a the light source shines perpendicularly across the rails and is received at the light detector. The train comes along and breaks the beam, which results in the train being detected. This illustration also points out a shortcoming of the interrupter detector. At each gap between cars, the detector will “drop out” and give a clear indication. This can be addressed in a couple of ways. A delay can be built into the circuit or into the LaunchPad code  to hold the indication for a time to allow the next car to move into position. When the train has finally passed, this delay will time-out and give the clear indication (sounds like a good candidate for customization to me!).

A strictly mechanical method to address the problem is indicated in Fig. 1b. The source/detector pair is set across the rails at an angle such that the largest gap between cars will not expose the detector. Setting up the source/detector pairs in this way avoids any further electronic or software complications.

*********************************************************************************************

 The code is pretty straight forward with not alot of surprises ot complicated processes.  DO NOT COPY AND PASTE THIS CODE FROM THIS POST.  the entire project package is attached below in a zip file. 

/*
* Quad Infrared Detector Version 1.2
* COPYRIGHT © 2013 S.D. "Hoffy" Hofmeister
* http://www.hoffysworld.com
* Provided under a Creative Commons Attribution, Non-Commercial Share Alike,3.0 Unported License
* TARGETED TO MSP430 LANUCHPAD W/MSP430G2553 PROCESSOR
*
* Design Notes:
*
* This code is designed to control 4 IR Sensors and light 4 independent indicator LEDS to signal that an object as been detected.
*
* Distance between Tip ofEmitter and Tip of Detector has only been tested upto 3.5 Inches under incandescant and floroescant
* lighting conditions with no failures.
*
* Circuit Pinout:
* PIN 1.0 = Cathode of IR Receiver #1 > Anode to Ground
* PIN 1.1 = UNASSIGNED - UART
* PIN 1.2 = UNASSIGNED - UART
* PIN 1.3 = Cathode of IR Receiver #2 > Anode to Ground
* PIN 1.4 = Cathode of IR Receiver #3 > Anode to Ground
* PIN 1.5 = Cathode of IR Receiver #4 > Anode to Ground
* PIN 1.6 = Anode of Indicator LED #1 \
* PIN 1.7 = Anode of Indicator LED #2 \ Cathodes to ground
* PIN 2.0 = Anode of Indicator LED #3 /
* PIN 2.1 = Anode of Indicator LED #4 /
* PIN 2.2 = UNASSIGNED
* PIN 2.3 = UNASSIGNED
* PIN 2.4 = UNASSIGNED
* PIN 2.5 = Circuit Power Indicator
*
* PINS 1.1, 1.2, 2.2, 2.3, 2.4 are left open for integration into other projects
*
* Note Anodes for the IR Emitters connect to VCC and Cathodes to Ground
*/


#include   <MSP430 LIBRARY FILE>

void main(void) {

WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer

P2DIR |= BIT5; // Circuit Power Indicator
P2OUT |= BIT5; // Used to Trouble Shooting

//Configure IR Detectors

P1DIR &= ~BIT0; // Port 1 P1.0 (IR Detector #1) as inputP1REN |= BIT0; // Enable Port 1 P1.0 (IR Detector #1) pull-up resistor
P1SEL &= ~BIT0; // Select Port 1 P1.0 (IR Detector #1)

P1DIR &= ~BIT3; // Port 1 P1.3 (IR Detector #2) as inputP1REN |= BIT3; // Enable Port 1 P1.3 (IR Detector #2) pull-up resistor
P1SEL &= ~BIT3; // Select Port 1 P1.3 (IR Detector #2)

P1DIR &= ~BIT4; // Port 1 P1.4 (IR Detector #3) as input
P1REN |= BIT4; // Enable Port 1 P1.4 (IR Detector #3) pull-up resistor
P1SEL &= ~BIT4; // Select Port 1 P1.4 (IR Detector #3)

P1DIR &= ~BIT5; // Port 1 P1.5 (IR Detector #4) as input
P1REN |= BIT5; // Enable Port 1 P1.5 (IR Detector #4) pull-up resistor
P1SEL &= ~BIT5; // Select Port 1 P1.5 (IR Detector #4)

//Configure Outputs
P1DIR |= BIT6; // Port 1 P1.6 (Indicator #1) as output
P1OUT &= ~BIT6; // Port 1 P1.6 (Indicator #1) Set to off State

P1DIR |= BIT7; // Port 1 P1.7 (Indicator #1) as output
P1OUT &= ~BIT7; // Port 1 P1.7 (Indicator #1) Set to off State

P2DIR |= BIT0; // Port 2 P2.0 (Indicator #1) as output
P2OUT &= ~BIT0; // Port 1 P2.0 (Indicator #1) Set to off State

P2DIR |= BIT1; // Port 2 P2.1 (Indicator #1) as output
P2OUT &= ~BIT1; // Port 2 P2.1 (Indicator #1) Set to off State

// Let's Get Down to Business
while( 1 ) // While this value remains equal to 1 the code will loop continuously, there is no code written to
// change this state in this particular program.
{

//Detector #1
if( (P1IN & BIT0) > 0) // When IR Detector #1 detects an object breaking the IR Beam
P1OUT |= BIT6; // Set LED Indicator #1 to ON
else // Otherwise
P1OUT &= ~BIT6; // Set LED Indicator #1 to OFF
//END of Detector #1

//Detector #2
if( (P1IN & BIT3) > 0) // When IR Detector #2 detects an object breaking the IR Beam
P1OUT |= BIT7; // Set LED Indicator #2 to ON
else // Otherwise
P1OUT &= ~BIT7; // Set LED Indicator #2 to OFF
//END of Detector #2

//Detector #3
if( (P1IN & BIT4) > 0) // When IR Detector #3 detects an object breaking the IR Beam
P2OUT |= BIT0; // Set LED Indicator #3 to ON
else // Otherwise
P2OUT &= ~BIT0; // Set LED Indicator #3 to OFF
//END of Detector #3

//Detector #4
if( (P1IN & BIT5) > 0) // When IR Detector #4 detects an object breaking the IR Beam
P2OUT |= BIT1; // Set LED Indicator #4 to ON
else // Otherwise
P2OUT &= ~BIT1; // Set LED Indicator #4 to OFF
//End of Detector #4

} End of While

} // END OF MAIN