Monday, July 7. 2008Build 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. Thursday, July 3. 2008Build Indicators revisited![]() 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. ![]() 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). ![]() 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. ![]() ![]() Pull out the led fitted into the tree using the cable. This is no longer needed. ![]() 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. ![]() 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. ![]() 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. ![]() 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. ![]() 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. ![]() ![]() 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. ![]() 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! ![]() Next it’s just a matter of screwing everything together. ![]() ![]() 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).
(Page 1 of 1, totaling 2 entries)
|
CalendarQuicksearchI'm Reading...My BookSwap.ws Wish List.About Face 3
Practical C# Charts and Graphics Programmers at work Smart client deployment with ClickOnce Pattern recognition and machine learning The long tail Mastering regular expressions RSS and Atoms in Action: Building Applications with Blog Technologies Naked conversations Mastering regular expressions ArchivesTop Exitswww.GoDaddy.com (53)
www.BookSwap.ws (48) www.Dollars2Pounds.com (25) www.DVDSwap.ws (18) www.CDSwap.ws (16) www.LazyLoad.com (13) www.DinnerTimer.com (10) news.sky.com (9) channel9.msdn.com (8) www.AnalysisUK.com (8) Syndicate This BlogBlog AdministrationCategories |
