Steve's blog

A blog about what's going on in Analysis UK...

Build Indicator – Part 2 (The firmware)

This is part 2 of the Build Indicator series. Part 1 – the construction of the hardware is here.

The firmware is written using the Arduino’s own programming language which is much like C/C++, using the IDE provided it’s easy to develop the code and push it down to the Arduino.

I decided that as the Arduino has 13 IO pins it would be a shame not to make these available for 6 build indicators so 6 individual projects could be monitored. I’ve not used OO to implement the code so it’s a little messy with individual arrays for project status, red and green led pins which are indexed based on the project number. I think you can create classes but this has to be done in external C++ files so for a simple application like this I didn’t worry to add that extra complexity.

Serial (RS232) communications is used to send a status message down to the Arduino build indicator to update the project status.

The full Arduino build indicator code can be download here.

License : Please use, copy and modify this code as you wish, all I ask is that you don’t take credit for the bits I wrote. You should ensure it’s fit for purpose before using it.

Variable declaration :


    1 /*


    2   Build Indicator (c) Analysis UK Ltd 2008


    3  *


    4   Digital Pin Assignments:


    5   0 - RX


    6   1 - TX


    7   2 - Project 6 - Green LED


    8   3 - Project 6 - Red LED


    9   4 - Project 5 - Green LED


   10   5 - Project 5 - Red LED


   11   6 - Project 4 - Green LED


   12   7 - Project 4 - Red LED


   13   8 - Project 3 - Green LED


   14   9 - Project 3 - Red LED


   15   10 - Project 2 - Green LED


   16   11 - Project 2 - Red LED


   17   12 - Project 1 - Green LED


   18   13 - Project 1 - Red LED


   19  */


   20 


   21 #define VERSION "1.0"


   22 


   23 // Project not enabled of not connected.


   24 int PROJECT_OFF = 0;


   25 


   26 // Project build failed


   27 int PROJECT_FAIL = 1; // 001


   28 


   29 // Project build good


   30 int PROJECT_GOOD = 2; // 010


   31 


   32 // project building from a failed project.


   33 int PROJECT_BUILDING_FAIL = 5; // 101


   34 


   35 // project building from a good build.


   36 int PROJECT_BUILDING_GOOD = 6; // 110


   37 


   38 // Maximum number of projects.


   39 int maxProjects = 6;


   40 


   41 // Project status codes.  Indexed by project.


   42 int projectStatus[] = {


   43   0, 0, 0, 0, 0, 0};


   44 


   45 // Pins for the Red LEDs.  Indexed by project. 


   46 int redLEDPin[] = {


   47   13, 11, 9, 7, 5, 3};


   48 


   49 // Pins for the Green LEDs.  Indexed by project.


   50 int greenLEDPin[] = {


   51   12, 10, 8, 6, 4, 2}; // pins 0 and 1 reserverd for RS232.





The arrays redLEDPin and greenLEDPin represent the pins to use for the red/green leds and are indexed on the project number (i.e. project 0's red led is on pin 13). The array projectStatus holds the status of the project and again is indexed by the project number.

Setup:


   54 // run once, when the sketch starts


   55 void setup()                   


   56 {


   57   // Initialise the ports for output to drive the LEDs


   58   for (int i=0; i<maxProjects; i++) {


   59     pinMode(greenLEDPin[i], OUTPUT);    // sets the digital pin as output for the green/blue part of the tri color LED


   60     pinMode(redLEDPin[i], OUTPUT);      // sets the digital pin as output for the red part of the tri color LED


   61   }


   62 


   63   // Setup Serial communications


   64   Serial.begin(57600);


   65 }




The setup method iterates through all the projects setting up the pins designated as led’s for output and then sets up serial communications at a baud rate or 57,600. Fortunately the Arduino takes care of the difficult serial comms bits for us.

Main Loop:


   67 // Main loop, runs over and over again


   68 void loop()                   


   69 { 


   70   // Check and Read settings from PC


   71   ReadCommands();


   72 


   73   // Update the LED's to indicate project status'


   74   UpdateLEDs();


   75 


   76   // Idle.      


   77   Idle();


   78 }


   79 




The loop method is the main application loop that the Arduino will enter once setup is complete and will keep repeating.

Within loop we call 3 basic methods, ReadCommands() which will check the serial port for commands from the host, UpdateLEDs() which will update the leds based on the project status and Idle() which just inserts a small delay but can be used for other background tasks.

The comms protocol is a fairly simple one. All messages should start with a byte value of 2 and terminate with a byte value of 3 so the Arduino can easily know when a instruction has been received.

To update a project status send the ascii string “@P[x]=y” with x being the project number 1-6 and y being the status (0, 1, 2, 5, 6).

To query the version number of the firmware send ?V.

I’ve stolen the comms protocol from another project I’m working on with the Arduino that has more commands and queries so I’ve based all commands where the Arduino has to do work on the @ character and all queries on the ? character to help separate out the commands and queries.

RS232 Message handling:


   86 // Read commands sent from the PC


   87 void ReadCommands()


   88 {


   89   // Check if serial data available, if so then read this in


   90 


   91   // Read all from the serial port until no more bytes available looking for the


   92   // start byte (1) of a message.


   93   while (Serial.available()) {


   94     //read the incoming byte:


   95     int incomingByte = Serial.read();


   96 


   97     // Start identifier.  STX


   98     if (incomingByte == 2) {


   99       // Found start byte now read in until we get the end of message byte.


  100       ReadSeialCommand();


  101       return;


  102     }


  103   } 


  104 }


  105 


  106 // Read a command from the serial port.  Read until the read byte


  107 // is an end of message (new line) indicator.


  108 void ReadSeialCommand() {


  109   // Expect maximum of 25 bytes (normally 6)


  110   byte buffer[25];


  111   int index=0;


  112 


  113   while (true) {


  114     if (Serial.available()) {


  115       // read the incoming byte:


  116       int incomingByte = Serial.read();


  117 


  118       // Terminating byte


  119       // Wait for ETX (End of text - transmision)


  120       if (incomingByte==3) {


  121         ProcessRequest(buffer);


  122         return;


  123       }


  124       else {


  125         buffer[index] = incomingByte;


  126         index++;


  127       }


  128 


  129       // Check for buffer overflow and give up if it has.


  130       if (index>25) {


  131         Serial.print("Error:Buffer Overflow.\n\r");


  132         return;


  133       }


  134     }


  135   }


  136 }


  137 


  138 void ProcessRequest(byte request[]) {


  139 


  140   boolean processed = false;


  141 


  142   // Check for Query commands (? at the start)


  143   if (request[0] == 63) {


  144     // Query


  145     processed = ProcessQuery(request);


  146   }


  147   else if (request[0] == 64) {


  148     // Set (@P[x]=0) - Set Project x = status.


  149     processed = ProcessSetValue(request);


  150   }


  151 


  152   if (!processed) {


  153     Serial.print ("Error:Unknown Request.\n\r");


  154   }


  155 }


  156 


  157 boolean ProcessQuery(byte request[]) {


  158 


  159   boolean processed = false;


  160 


  161   switch (request[1]) {


  162   case 86: // ?V - version


  163     processed = SendVersion();


  164   default:


  165     Serial.print ("Error:Unknown Query.\n\r");


  166   }   


  167   return processed;


  168 }


  169 


  170 boolean ProcessSetValue(byte request[]) {


  171 


  172   boolean processed = false;


  173   byte command = request[1];


  174   // Allow ascii version of the fan number.


  175   //Position 2 should be [


  176   byte project = request[3] - 48; // 48 = 0


  177   //position 4 should be ]


  178   //position 5 should be =


  179   //position 6 should be the raw value.


  180   byte value = request[6];


  181 


  182   switch (command) {


  183   case 80: //@P[x]=y Set project x status y.  y is ascii version of the status (0-9).  so subtract 48.


  184     processed = SetProjectStatus((int)project, (int)value - 48);


  185     break;


  186   default:


  187     Serial.print ("Error:Unknown set command.");


  188   }


  189 


  190   return processed;


  191 }


  192 


  193 boolean SendVersion() {


  194   Serial.print ("Version=");


  195   Serial.print (VERSION);


  196   Serial.print ("\n\r");


  197   return true;


  198 }


  199 


  200 // Set the status for the project.


  201 boolean SetProjectStatus(int project, int status) {


  202 


  203   if (projectStatus[project-1] != status) {


  204     projectStatus[project-1] = status;


  205 


  206     // Build failed.  Flash the red LED briefly to get attention.


  207     if (status == 1) {


  208       digitalWrite(greenLEDPin[project-1], LOW);


  209 


  210       for (int i=0; i<6; i++) {


  211         digitalWrite(redLEDPin[project-1], HIGH);


  212         delay(100);


  213         digitalWrite(redLEDPin[project-1], LOW);


  214         delay(100);


  215       }


  216     }


  217   }


  218 


  219   return true;


  220 }


  221 




The method ReadCommands() will read the input buffer until it receives the start byte then call ReadSerialCommand() which reads the rest of the command into a buffer until it received the end byte. I’ve limited the buffer to 25 bytes which should be plenty and if this overflows then we just abandon it. Their is no timeout between receiving the start and end bytes so this could cause a problem if the end byte is not received.

Notice in the method SetProjectStatus() that the project index used is -1 from the project value sent. When sending commands the first project is project 1 however the Arduino uses 0 based arrays.

In SetProjectStatus() if the project state changes to be failure (value 1) then the red led is flashed 6 times to draw attention to the indicator.

Project State Indication:


  222 boolean UpdateLEDs() {


  223 


  224   for (int i=0; i<maxProjects; i++) {


  225     int greenLEDStatus = LOW;


  226     int redLEDStatus = LOW;


  227 


  228     switch (projectStatus[i]) {


  229     case 0: // NC


  230       // No acton


  231       break;


  232     case 1: // Fail


  233       redLEDStatus = HIGH;


  234       break;


  235     case 2: // Good


  236       greenLEDStatus = HIGH;


  237       break;


  238     case 5: // Building from a Fail build


  239     case 6: // Building from a good build


  240       greenLEDStatus = HIGH;


  241       redLEDStatus = HIGH;


  242       break;


  243     default:


  244       redLEDStatus = HIGH;


  245       break;


  246     }


  247 


  248     // Determine project LED pins and set them appropriatly.


  249     digitalWrite(redLEDPin[i], redLEDStatus);


  250     digitalWrite(greenLEDPin[i], greenLEDStatus);


  251   }


  252 }




In the method UpdateLEDs() we update the led status based on the project status.

If you are wondering what happened to status codes 3 & 4 I’ve used a bit based project status. 0001 (1) is fail, 0010 (2) is good, 01xx is building so 0101 (5) is building from a previously failed state and 0110 (6) is building from a good previous good state.

If you want to use indicators other than leds for your project state then you can update the UpdateLEDs() method with another way to indicate the project status (maybe a LCD panel?).

That’s basically the firmware, not much to it, the Arduino does most of the work for us which is the best bit!

To program the Arduino connect it up, install the drivers (my Vista x64 and Vista x86 installs got the drivers from Windows Update without a problem and also installed the VCP virtual com port drivers). Open up the IDE, ensure the board and serial port are correct and load the build indicator firmware, then hit the upload to I/O board button.

In the next entry I’ll talk about the PC application to drive the Arduino.

Build Indicators revisited

Arduino controlled X-Mas tree.

Some time ago I posted about a USB Snowman build indicator, the problem with the first version was the USB IO board I used, its availability was limited and the output was designed as a current sink rather than source, so some modifications had to be made to the board, which isn’t really ideal.

Recently I came across the Arduino project, an open source hardware solution and one of the little Diecimila boards provides a perfect base for revisiting the build indicator. The SnowMan is still in use at home and I wanted one for work as well so I figured Id make another build indicator based on the Arduino.

Arduino Diecimila.

The 13 IO pins can sink or source up to 40mA which is ideal for driving the tri-color led used by the build indicator. The led requires 2 current sources and has a common cathode. The Arduino has a USB interface that provides normal serial port communications to the host PC so interfacing is easy as well.

This time instead of a snowman I decided to use a Xmas tree. They are very similar, basically a lump of plastic with a 5MM LED mounted inside. The Arduino provides multiple IO ports of which I’m using only two and the intention here is to provide some common functionality so that the device could be easily adapted to other forms of build indication (Switching relays, multiple project build indicators, other led’s, buzzers etc).

X-Mas tree as new.

Removing the base and replacing the led is a simple job, either use a flat screwdriver or use the cable exit to push off the base off.

X-Mas tree from underneath.

X-Mas tree base removed.

Pull out the led fitted into the tree using the cable. This is no longer needed.

X-Mas tree led removed.

Now glue the base onto the top of the box the tree is to be mounted on. Previously I used a black ABS box but this time I’m using a ice blue box and this has worked out much better for aligning the parts and seeing the led’s on the Arduino board (RX/TX when programming), and also appeals to the inner geek a little more now that the workings can be seen.

Plastic case with X-Mas tree base glued in place.

Drill a hole through the middle of the base so that it will line up with the middle of the x-mas tree. This is best done with the base stuck to the box as it holds it in place and ensures every thing lines up. The hole should be about 7-8mm so that the LED + resistors pass thought easily.

Hole through Xmas tree base and case.

Now we need to prepare the led. Using a standard Tri-Color led (I’ve used Red + Green) we need to fit a current limiting resistor to the supply legs. One for the red and one for the green component of the led.

Using the datasheet for the led the voltage drop across the red Led is about 2V, this leaves a drop of 3V across the current limiting resistor as it’s driven from a 5V source. I’m going to drive the Led’s at 30mA, so we will need a 100R resistor for the red Led.

The green led has a different voltage drop across it (3.4V) so we need to do the same calculation for that and again aim to drive it at 30mA which means we need a 53R resistor, as I only had a 56R resistor to hand I’ve used that which gives us about 29mA current flow.

The data sheet gives luminous intensity for both red and green at 20mA and the green is much brighter than the red so we may wish at a latter date to play around with the drive current to get a better balance when both red and green are on.

Trim the red and green legs of the led fairly short but leave enough to solder on the resistors and attach these. Next connect a cable to the other side of the resistors and to the common pin on the led. If you prefer you can attach the resistors to the Arduino connector and solder the cable directly to the led.

The Tri-color led.

I used 2 core screened cable as this happened to be what I had to hand and as it turns out by tinning the screen and soldering to the led common pin gives a good sturdy way to physically push the led into the socket in the tree (and pull it out again!). I also put a bit of heat shrinking around the connections to prevent them shorting out.

Led with resistors and wires connected.

Now we need the connection to the Arduino board, the led is connected to pins 12, 13 and GND. This is easy as they are all close together and as an added bonus the Arduino already uses an onboard led on pin 13 for status when starting up which means that the tree flashes when the Arduino is starting up, it’s easy to use other pins if you prefer.

I’ve used a standard 0.1" Molex connector (The type used for 3 pin PC fans), the PCB version is ideal, but soldering the led connecting wire to the PCB side and plugging it into the header in the Arduino rather than mounting it on a PCB.

Connector for the led to Arduino controller.

Led connector plugged into the Arduino.

Note that in the photo’s the red cable is actually for the green led and the blue one is for the red led. It doesn’t really matter a great deal which way round they go as long as you get the correct resistor matched up with the appropriate led. However the default in the firmware is that the red led is on pin 13 and green on pin 12.

Next drill some holes in the base of the box and mount the Arduino. Note that one hole is smaller than the others so I ended up using only 2 mounting points due to my lack of any 2mm bolts.

Arduino mounting points.

The advantage of using a translucent box is finding the place to drill a hole of the USB connector. I elected to use a cone drill and just have a circular cut out for the USB cable to go through, it doesn’t look all that professional but it was quick and it worked a treat!

Hole for the USB connector

Next it’s just a matter of screwing everything together.

X-Mas tree build indicator assembled.

A Green X-Mas tree.


I put 6 small feet on the base of the box as well. Why 6? With sticky feet one always falls off (especially with commercial products!) and then it rocks, with 6 you still have some stability to the device if one falls off.

Now all that’s needed is a little firmware to run the Arduino and some software for the PC to put it to use but that’s going to have to be the subject of the next posting(s).