Monday, August 9, 2010

First Surface Mount Soldering Attempt

Last Friday or Saturday, I received the final tools I needed to attempt the surface mount soldering as taught by the tutorial at freetronics.com. Today, I received two SOIC14 ATtiny44 chips to attempt to solder onto an Adafruit Arduino protoshield. Pictured below is an ATtiny44 on my finger to give perspective.



I squirted the syringe of solder paste on the board and tried to line up the chip. As you can see by the image below, I didn't get things lined up quite right.



I wasn't aware that I hadn't gotten the chip lined up before I put it in the oven. In fact, I wasn't aware until I saw the picture. Luckily, the oven sucked the chip right onto the pads. The only thing was that I apparently globbed a little too much paste in a couple of areas.



Though the picture is out of focus, you can see big solder bridges across a set of pins on each side. Solder wick took care of the problem, so I could test. After figuring out that I was misreading the pins on the proto shield and rearranging the wires, I was able to hook up my USBTiny and read the chip type. The chip reported correctly! I was able to upload a simply blinky LED program and blink and LED.



At this point I'm confident that I can do surface mount soldering. However, I consider my first attempt a qualified success because I had to use solder wick to remove excess solder. Now I'm ready to design a new board using surface mount chips!

Saturday, June 19, 2010

Taking Forever to Fix the Garage Door Opener Pt. 2

In Part 1, I admitted several of my failures, at least one of which wasn't very compatible with the boards I was using from Radio Shack. I also noticed that my soldering skills seemed much better when I was soldering on a Printed Circuit Board rather than a prototyping board. I recently purchased a copy of Practical Arduino which gave me some ideas on how to solve a couple of other challenges I had with other projects. My main frustration with the introductory chapter was that it didn't give any good tips on soldering using a prototyping board. What I did find was a rather cool tutorial on surface mount soldering written by the author. That tutorial looked even easier than what I was doing with through the hole soldering. It was also the final push that I needed to try having my own printed circuit board created.

The design of my board is really quite simple (even though I couldn't get it right). I shared part of the schematic in Part 1, that is, the screw up trying to create an inverter with an NPN transistor. Here is the whole schematic:


This is actually the second iteration of the schematic. The first one didn't have a Vcc net and when I let Eagle autoroute the board, I at least noticed that the 7804 chip didn't have it's power pin connected to anything. To solve that problem, I created a Vcc net and connected it to the 5v net and everything seemed to route like I wanted. Although I wasn't very confident in the design, I shipped it off to BatchPCB anyway so that it might be ready when I got back from vacation.

I got the board on Thursday and started soldering things up. Here's the way it looked when I thought I was done:




Of course, my test program didn't work and I quickly found that I had made the same mistake twice...this time in the form of a printed circuit board! ARGH! Well, At least that mistake wasn't too hard to fix. I needed a resistor between Pin 12 and the base of the transistor, so I soldered one end of a resistor in the hole meant for the base of the transistor and then connected the base lead of the transistor to the other end of the resistor. My pretty board isn't so pretty, but at least that problem was fixed.

Unfortunately, my test program still didn't work. The test program adds a couple of LEDs that I just jumper from the female headers on the shield. The test program doesn't get through the initial indication that all of the parts are there...that is, the program resets. If I disconnect one of the LEDs, the program runs farther before resetting, so I believe that my problem is that I'm shorting power somewhere and the processor resets due to the lack of power.

My initial thought was to verify how the buttons and switches were wired. Using a tutorial by Lady Ada, I found a completely different schematic than what I was using. First there was a 100 Ohm resistor between the +5 rail and the Arduino pin. Second, there was a 10K pulldown resistor between the switch and ground. The tutorial talks about different resistor values and specifically talks about wasting power if you choose too low of a value. I'm not sure how I would rig up both resistors, but I could at least try replacing my 1Ks with 10Ks. I tested the ability of the Arduino to read the state of the switch using my schematic with 10K resistors instead of 1K resistors and it didn't seem to have any problem. So I desoldered the 1Ks for each switch and soldered in 10Ks instead. So now the board looks like this:



It might not be easy to see, but the mess to the left of "Relays" is the resistor soldered into the hole for the base lead of the transistor. That's why the transistor is sitting so high on the board. The 1K resistors have been replaced by 10K resistors except for the one at the top right of the board.

With high hopes, I went back to my test program. It didn't take long for my hopes to be dashed. Right now I'm stuck with two problems that I haven't been able to track down. First, the 10K resistors didn't change the fact that the program resets with what appears to be a power failure. Second, the "down" relay is activated when the program fires up. If I have the relay connector plugged in, the program resets almost immediately. The relay activates and drains the power, then deactivates as the board resets. If I don't plug in the connector for the relays, but do have the connector for the external LEDs that come on when the relays are active, the program runs longer. The "down" LED lights almost immediately upon program startup and stays lit until the program resets...which takes a bit longer without the relay connector plugged in. Long enough, in fact, for me to measure values coming out of the AND gate.

And this is where I have a real problem that I can't figure out. Pins 12 and 13 are both read zero on my volt meter. Pins 1, 2, 4, and 6 all read zero as expected. Pin 5 reads 5 volts as expected. Pin 3 reads 4.7 volts. That's supposed to be the output of the AND gate supplied by Pins 1 and 2. Even stranger is that this pin is supposed to control the 'up' relay. Yet it is the down relay LED that is lit. So part 3 of this mess won't be coming until I figure some things out.

Friday, June 18, 2010

Taking Forever to Fix the Garage Door Opener

We have a commercial garage door opener that opens a 12 ft x 16 ft door on our trailer shed. The opener failed a couple of years ago and the repair consisted of a service call and an over priced part. When the opener failed again last year, I somehow convinced my wife that I could build a circuit board that would take over the job of controlling the opener motor and not have to pay for a service call again. Of course, our door still isn't working.

The process of creating a circuit board using a micro-controller and a couple of relays seemed fairly straight forward. In fact, it still seems straight forward even though I have failed thus far in creating the board. In my first attempt, I purchased an Arduino Pro Mini from Sparkfun, a simple prototyping board from Radio Shack, and various electronic components to be able to read the state of the buttons and limit switches. The Mini has 12 holes on each side in which I soldered male header pins. I made a little socket in which to plug the mini by soldering female headers on the prototyping board.

The garage door opener motor is controlled by switching power on one of two wires. Which wire you switch determines the direction the motor runs and therefore the direction the door moves. I purchased one relay for each wire, but I wanted to make sure that I couldn't activate them both at the same time. The relays are easy to control with an output pin of an Arduino, but rather than wiring a pin to each relay, I decided to put a logic chip in between to make sure that only one relay could be active at a time. I used pin 13 to indicate whether or not I wanted the motor to be active (HIGH means running, LOW means stopped). I then used pin 12 to determine the direction the motor should run (HIGH means up, LOW means down). Pins 12 and 13 are connected to an AND gate with the output of the gate driving the relay that makes the door go up. Pin 13 is also connected to a second AND gate, but I needed to invert the value of Pin 12 before connecting it to the other input. The output of that gate drives the relay that makes the door go down.

I'll stop here to admit that I'm not an EE major, I'm a computer science major. I'm good at programming. Things that may be obvious to an EE major, aren't obvious to me until I screw up good! I purchased a logic chip in a 14 pin DIP package, but I didn't want to waste the board space on an inverter chip, so I contrived a way to use a transistor as an inverter. Again this seems straight forward, but there was some fundamental knowledge that just isn't there for me. Even after I figured it out, I managed to make the mistake again! Here's the diagram of what I did:
The top line in the picture is Pin 12, the one under is Pin 13. The idea was that when Pin 12 was high, the transistor would ground input 6. When Pin 12 was low, the transistor would not connect the collector and emitter and the input on the gate would be high. Unfortunately, I discovered that when Pin 12 was high, all of its current was grounded through the transistor and input pin 2 was pulled to ground. The top AND gate would never yield a high value. Of course, I'm getting ahead of myself because I didn't actually discover this until the second version of the board!

The first problem I had was that I couldn't get my program to upload to the Mini. I built a simple little programming board that contained the same female header that I had built on the prototype board. The "socket" connected the appropriate pins of the Mini to the programming header. Unfortunately, the mini wouldn't take the program. I still have no idea why. So I changed gears and decided to use an Arduino Pro that I had purchased a while back.

The next thing that I have to admit is that I make stupid mistakes while I'm soldering up wires and I have to desolder and re-solder too often. The cheap prototyping boards from Radio Shack don't stand up too well to this and the copper foil they use to connect holes peels up. I had already moved the power supply portion of the board to a different area because I had destroyed a whole section. Most of what I had done would have to be moved now because the foot print of the Arduino Pro is so much bigger than the Mini (as the name would suggest). So I started a new board.

As an example of making stupid mistakes, I didn't wire the 7408 from a diagram but from trying to match the wires on the previous board. However I screwed it up, I managed to swap one of the input pins and one of the output pins on each gate. And wouldn't you know it, the relays didn't work! I actually managed to desolder the wires and wire it up correctly without doing too much damage to the board. It was then that I discovered the problem with the transistor. By the time I got that straightened out, I was having problems with the board resetting and my connectors kept coming apart.

So I ordered polarized connectors that would clip when connected, desoldered the old connectors and soldered in the new ones. The board looked pretty nice from the top...the bottom showed off how many mistakes I had made:



At this point I decided to take the learning experience one step further. I would design my own Arduino shield using Eagle and have a PCB custom made for my project. I'll relate my experience with that in part 2!

Wednesday, August 19, 2009

AirSplat Customer Service

My last blog was about the great customer service we got unexpectedly from Ashley Furniture. Unfortunately, for the last month I have had one of my worst customer service experiences. My son ordered an airsoft gun and bio-degradable BBs from AirSplat on July 7th. Below is an accounting of our interaction. Note that every email exchange has the entire conversation included.

7/14 - Package arrives. BBs are not bio-degradable and the gun is missing a part. We plugged in the rechargeable battery and set off an email to customer support:
I think that I am missing a part the my gun. In the picture on the box
there is an aiming device that goes on the top of the gun. It is a small
cylinder with a small triangular cut out. I think that it is supposed
to be in the box and something that I attach to the gun. There were no
separate packages in the gun's box.

I also think that I was sent the wrong BB's. I ordered biodegradable
BB's and can find no indication on the package that these are, in fact,
biodegradable.

Thanks for your time.
7/15 - We are on vacation and discover that the battery charger doesn't work.
7/16 - received this email from AirSplat customer support:
Thank you for contacting Airsplat.

We sincerely apologize for any inconveniences and are disappointed to learn
of the difficulties you have experienced.
If you like I can have the Optics that are missing sent out for you; the
BB's you received were in fact not the Airsoft Elite 6mm .2g 4000 BIO BB's.

The BB's sent were KSC .25g 3000 6mm, you where not charge $16.00 but rather
$11.00 for the alternative BB's due to the fact that the Airsoft Elite 6mm
.2g 4000 BIO BB's are out of stock.

Thank you for choosing Airsplat and please feel free to contact us with any
additional questions or concerns.
Notice that they offered to send the missing optics if we like!

7/17 - We return home to find the above email. We respond:
I really wanted the biodegradable BB's that I ordered, not the standard
BB. Can you exchange theses for the biodegradable? Since the ones that
I ordered are out of stock, can B2-5000-BIO
<http://www.airsplat.com/itemdesc.asp?ic=B2-5000-BIO>
<http://www.airsplat.com/itemdesc.asp?ic=B2-5000-BIO> be sent instead?

In addition, I have found that the charger for the battery for the gun
doesn't charge the battery. Can a replacement be sent? Please send the
missing Optics for the gun as well.

Thanks
Yes we want the missing optics, that was one of the two reasons we contacted them about the order.

7/20 AirSplat's response:
You actually received what you had ordered. These BBs are in fact
biodegradeable, but are not marketed as such since they take several years
to degrade as opposed to several months.

Please feel free to contact us with any additional questions or concerns.
Are you kidding me? I wonder if that logic would work with a "90 days - same as cash" deal! Notice that they don't even acknowledge the problem with the battery charger or the Optics. So now I'm really aggravated, as my next email shows:

7/22
- It did take two days for me to respond, although if I had responded earlier, it probably would have been profanity laden:
The BBs that were sent were substituted without permission.  We wanted the
BBs that degraded in several months. We wanted 4000 BBs. We wanted .2g
BBs, not .25g. They are not what we wanted and we do not want to pay for
them. Frankly, I find the fact that it was even suggested that we received
what was ordered was ridiculous. You also failed to address the charger
issue. The charger that came does not charge the battery. The LED on the
charger does not light and an electrical meter test on the charger indicates
that the charger is not functioning. Finally, the initial message also
indicated that a gun sight was not shipped in the original package.
Airsplat's first response indicated that the sight could be sent if we
desired. We replied that we would like the sight sent, but have not
received an indication that it was ever shipped.

I noticed a recent Airsplat tweet touting 0% negative feedback on Amazon for
the past 30 days. With customer support like this, I would not expect that
string to last much longer. I will, however, give you a chance to fix this
before breaking the string myself.

7/22 - AirSplat's Response:
Dear Customer,

We will have the Airsplat Bio BBs as well as a replacement charger sent out
to you shortly.


Please feel free to contact us with any additional questions or concerns.
Well, apparently being aggravated gets results! We wait for the shipment, although we don't really hold out any hope that they sent the missing sight.

7/29 - Shipment received. Bio-degradable BBs and a fancy new charger! No gun sight.

Now I'm at least somewhat satisfied, and I figure I'll get back to them on the missing sight. The battery doesn't seem to charge right and we have problems with the gun. We get it to work intermittently but by 8/11 it won't function at all. AirSplat has a 30 day return policy, but this process has been so painful, I mistakenly believe it has been longer.

8/11 - We again contact AirSplat support:
Thank you for sending the replacement charger and BBs.  However, the first
thing that was requested was a sight that was supposed to be with the gun.
You offered to send the sight, but that seems to have been dropped while
handling the other issues. You can find the sight issue at the bottom of
this email thread.

Unfortunately, I am having trouble with the gun. The charger seems to be
charging the battery (a volt meter indicates that the battery has power),
but the gun will not fire. Is there any way the gun can be exchanged?
Although we are beyond the initial 30 days, we did not have the ability to
test the gun because of the charger issues that were only resolved a couple
of weeks ago.
Ok, my sense of time stinks, but they can see from the email history that we have only had the working charger for two weeks:

8/12 - AirSPlat's Reply:
Hello

We are thankful for your patronage with AirSplat.com!

We are sorry to hear of the troubles you have experienced and sincerely
apologize for any inconvenience it may have caused. It is never our
intention to inconvenience our customers.

Regarding your concern, at this time the only offer we would be able to
offer is to have you send the gun in for repair and not charge you the
service fee because the warranty has expired. Please advise. Concerning
the optics that you were missing I believe you are inquiring about the
EG706, correct? If this is the case your gun does come with a sight.

Trust that at Airsplat.com, we take pride in working closely with our
customers to ensure the highest level of service. Please let us know if
there is anything else we may assist with.
Great, you've told me what we discussed in the first email....the gun is supposed to have a sight. It's at least they aren't going to charge for the repair right...but wait, how do we go about getting the repair?

8/15 - Another email to AirSplat:
Considering that we were unable to test the gun due to the charger issue, I
am disappointed that you are strictly adhering to the 30 period while
knowing that it was impossible for us to test the gun without a charged
battery. However, if that is our only recourse, please send us the
information on how to go about sending the gun in for repair.
8/17 - AirSplat's response:
Thank you for the update.

Repair fees are as follows for various models:

1. Full size spring $29.95
2. Full size gas $39.95
3. Full size electric $49.95

Repair fees quoted are for inspection and minor repairs. Major parts or
replacement parts will be additional.

Please feel free to contact us with any further questions.
Oh, and I forgot to mention that each response from AirSplat has this attached to the bottom:
PLEASE EMAIL FROM REGISTERED EMAIL ADDRESS WITH AIRSPLAT.COM & RETAIN ALL
EMAIL HISTORY WITH YOUR ORDER # IN THE SUBJECT LINE TO PREVENT DELAY.
I have yet to figure out why they want all email history retained, because they obviously don't read it! It did make it easier to create the timeline, though.

Tuesday, July 7, 2009

Ashley Furniture Customer Service

Earlier this year, my son wanted to change his room around. Part of the redecoration involved buying a love seat. We found that we liked a couple of different ones. Turned out the more expensive one was going to be cheaper if you factored in the great grocery rebate they offered. If you spent over $500, they gave you $500 in free groceries. The more expensive seat was just over $500 and the cheaper one was just under. What a deal!

The catch is that you get it $50 a month, and they gave you the $50 as a gift card after sending in $100 worth of grocery receipts. Still, it made sense, and we got the better piece of furniture.

Over the next three months, we submitted $300 worth of receipts, but never received a gift card. A week ago, we got an email from the company managing the rebate program saying that they were filing for bankruptcy. In the email, they said not to contact the company from whom we received the rebate as they had no control over the situation. We figured we had lost the $500 and didn't contact Ashley.

Today we received a letter from Ashley Furniture. The letter acknowledged that the company managing the program had declared bankruptcy. They also said that they had found another company to manage the program, and that they would honor the rebates. I was impressed! Not only were they honoring the program, they actively sought us out rather than us having to contact them to ask about it.

It's easy to find negative things on the web related to companies. It's easy to complain. I certainly haven't ever published anything positive about a retailer. But this seemed to be beyond good customer service. I hope that someone who is looking what kind of company Ashley is will find this.

Thursday, March 5, 2009

Nerd Kit Week 2

Well we did get the stoplight operational and we learned some things along the way. The final lesson we learned is that the connections on the solderless breadboard are unstable. More on that later. The first step was to verify that the clock interrupt was working correctly. The ATmega168 has a couple of built in timers that essentially operate independent of the controller CPU. It has lots of options and can be used to generate PCM patterns on the controllers output pins to create a clock signal. Very useful, but got in the way of understanding what I wanted to use it for. Eventually, we figured out the configuration to just use it to interrupt our program.
The oscillator runs at 14.7456 MHz. That means it generates a clock tick 14, 745, 600 times per second. The timer can be set up to increment an internal 8 bit counter every clock tick. When the counter wraps around (256 ticks), an interrupt occurs and the controller executes the interrupt routine specified by the timer overflow vector. That would mean 57,600 interrupts per second. That's exactly 57,599 more interrupts per second than we needed. Luckily the control register for the timer provides a setting such that the timing can be divided by some amount. By setting up the timer to only increment its counter every 256 clock ticks, we get our interrupts down to a managable 225 times per second. Using that method and a simple 8 bit integer, I can accurately determine when a second has passed.
The idea behind our timer was that we had a global value that determined how many seconds were left in whatever cycle we were waiting on. The interrupt would simply decrement that value every second until it reached zero. To prove to myself that the timer was functional, I added an LED to one of the output pins on the controller. If the global timer value was odd, I'd set the pin to high, thus lighting the LED. If the global timer value was even, I'd set the pin low, turning off the LED. After discovering one bad bit combination that I had put in the control register, I did indeed get the LED to flash every other second! Now on to the switches.
The switches turned out to be more confusing. We didn't actually have weight sensing switches, but we did have a 7 position dip switch. The NerdKit came with a project by which you could do binary arithmetic by inputting the number through the position of the switches. In their example, they hooked up the dip switch to ground. So, I hooked up my dip switch to ground. Much to my dismay, once I read the value of the pin, the value seemed to disappear. That made the program think that the switch had been flipped off almost as soon as it was flipped on. Eventually, I randomly tried connecting the switch to +5v instead and the value stayed. Another problem solved, but not really understood. When the switch was connected to ground, the program would light the appropriate green LED, but would almost immediately change to yellow and start the timer. At least the cycles were working right! Once the switch was connected to +5v, the program waited until I flipped the switch back before "pretending" that there was no longer traffic on the sensor.
The program basically worked right the first time. That is, I guess it did, because we saw it do the right things in all of the scenarios we through at it. But I can't get it to repeat. One of the things we did was to display what was going on, including the timer value, on the LCD display. Unfortunately, that doesn't seem to work consistently either. And I didn't write the code for that! What I've discovered is that the connections are "brittle" and the program flakes out when the connections aren't quite right. Especially the power connection itself. So that's led me to soldering. I've purchased a printed circuit board (PCB) that's especially designed for the ATmegax8 series. I'm still waiting on parts, but eventually, we are going to wire/solder our traffic example so that the connections are stable. I'll report back when we finish. Once that's done, we are going to create the LED marquee display that got me interested in this in the first place.

Saturday, February 14, 2009

NerdKit Stoplight Project, Week 1


Unfortunately, I had to leave town on business before the NerdKit arrived. Marshall and I had been discussing the Finite State Machine aspect of the traffic light controller. I put together a simple one just based on timers. It only had a handful of states and the only event that triggered a state change was when the timer expired, which we represented using TX. Our simulation is to be based on the temporary traffic signals that are put in place when they rebuild a bridge and restrict traffic to one lane. The signal allows traffic from both directions to share a single lane to cross the bridge.
Our "requirements" are to include weight sensors at each end of the bridge to signal the controller when traffic is waiting to cross the bridge. We decided that we wanted the traffic to have a maximum wait time of 1 minute. We also decided to assume that it took 15 seconds to get from one side of the bridge to the other at the posted work-zone speed limit. Given a 5 second yellow light, that meant that there would be a green light for a maximum of 40 seconds.
Our initial "weightless" state diagram only cared about the position of the lights. The valid states were INIT, GR, YR, CR, RG, RY, and RC. The letters R, Y, and G in the those states represent the color of the light in one of each direction. The letter C, represents a red light in one direction while we wait for traffic to clear. Although we could have used a single RR state that would work for both directions, I was already thinking ahead to the version with weight sensors.
On Monday morning, I made my trip to the airport. I began to work on the FSM diagram, and quickly realized that I couldn't keep track of everything. So I changed direction and began building a spreadsheet. The spread sheet had four columns: current-state, event, action, new-state. The initial state and initial transitions are easy. You start in the state RRNN which represents a red light in both directions and no traffic on either weight sensor. In my initial attempt, there were 5 events that would cause a state transition: T1, N1, T2, N2, and TX. These events correspond to the weight sensor for direction 1 indicating traffic and no traffic, repeating for direction 2, and finally the timer expiring. So my table looked like this:






































CurrentEventActionNew State
RRNNT1G1,T(40)GRTN
RRNNN1N-AN-A
RRNNT2G2,T(40)RGNT
RRNNN2N-AN-A
RRNNTXN-AN-A


Note that two of the events never make sense. If the weight sensor indicates that traffic is present, the event corresponding to traffic arriving isn't valid. In the initial state, we aren't waiting for a timer to signal anything, so we are simply waiting for traffic to appear. When it appears, we will give that direction a green light. The action column indicates which light and for which direction as well as "T(40)", meaning we're setting a timer for 40 seconds.

Working through the table, I discovered that there were 12 states for one direction. Double that for both directions and add in the initial state yields 25 states. Thus the table consists of groups of five entries for each state. However, every group had two entries that didn’t apply.

For each state, there were two “events” that really couldn’t occur, and if they did occur, they would yield the same state. For example, the state GRTN represents a Green light in direction 1, a Red light in direction 2, Traffic sensed by the weight sensor for direction 1, and No Traffic sensed by the weight sensor for direction 2. The T1 event would indicate the sensor changing from not sensing weight to sensing weight. That change cannot occur without first generating the N1 event representing the sensor changing to no weight. Further, even if the event were possible, the event would not cause a state transition as the state machine is already in the state indicated by traffic sensed in direction 1. Therefore, I changed the meaning of T1 and T2 to mean Toggle, or change in the value of the weight sensor in direction 1 and 2 respectively. I was then able to remove the N1 and N2 events and shrink the table by 50 integers.

That reminds me of a time early in my Bell career when Linda Lahue made fun of me for worrying about saving a couple of bytes in a structure. I had come from a programming environment where we only had 64K of data available to us. I wasn’t used to working on a machine with a whole 32MB memory! Today, that’s tiny! Of course, on a large midrange computer, 50 bytes won’t matter, but programming a microcontroller with a small amount of memory, you had better be in the habit of maximizing your memory usage.

At first, Marshall didn’t understand why the table even had rows for events that didn’t make sense for a given state. Of course, he doesn’t have any programming experience at all, so this was an opportunity to show him how we can write a very generic programming routine that is driven by the data. The first thing I noticed about the action column of my table was that there are only two types of actions listed. The first was an indication of what light was to be turned on. Although I didn’t list it in the table, there was also an implied light that needed turned off. The other type of action was setting a timer. Given that these were the only actions ever described by the table, I came up with the following structure to represent the states and transitions:

struct stateEntry {

uint8_t lightOn;

uint8_t lightOff;

uint8_t timer;

uint8_t newState;

};

Next I created an array of these structures. The array consists of groups of three of these structures, one for each of the possible events. The start of this array looks like this:

struct stateEntry stateTable[] {

/* RRNN */

/* T1 */ { G1, R1, GT, GRTN },

/* T2 */ { G2, R2, GT, RGNT },

/* TX */ { NA, NA, NA, NA },

/* GRTN */

/* T1 */ { Y1, G1, YT, YRNN },

/* T2 */ { NA, NA, NA, GRTT },

/* TX */ { NA, NA, NA, GRTNX }

The comments indicate the current state and the three events. Each of the values in the array has an associated #define associated with it to give it a value. The lightOn and lightOff values are bit masks corresponding to pins on the microcontroller that need to be turned on or off. Those pins will be connected to LEDs representing our traffic lights. In the real world, they could be connected to relays which would actually control the more power hungry traffic signals. The third column is defined to be the timer length for the appropriate condition. GT stands for green timer and would be defined as 40. YT is the yellow timer and is defined as 5. If we decide we want a different period of time for these lights to be on, we can change the definition instead of having to change the value in each state in which they apply.

Once the table is filled in, the program becomes very simple. Assume we have functions to return an event number (0,1,2) corresponding to the events (T1, T2, TX), functions for setting the timer, and functions for turning lights on and off. The get_next_event function would figure out if the timer expired or if one of the weight sensors had changed values and return the appropriate value corresponding to the event. The main loop would then have the following logic:

current_state = RRNN

LOOP: event = get_next_event()

index = (current_state * 3) + event

entry = stateTable[index]

if (entry.lightOn != -1)

toggleLights(entry.lightOn, entry.lightOff)

if (entry.timer != -1)

setTimer(entry.timer)

if(entry.newtState != -1)

current_state = entry.newState

goto LOOP

Notice how simple the main logic is. For any given state, the set of data corresponding to the 3 possible events are grouped together. To get to the appropriate group, multiply the value of the current_state by three. This gets us to the group of three entries that correspond to the current state. Then add the value for the current event to obtain the appropriate entry for the current event. This forces the programming thought to be pushed into data. It’s not that we can’t create a buggy program, but the logic errors are mostly likely to be found in the state model.

There are still some hardware dependent issues to deal with, like how to actually enable the chip to output a current on the appropriate pins, how to make the timer work, etc. Since I didn’t actually have the NerdKit with me, the best I could do was to read lots of documents while I was away. In fact, the first step when I get home is to get used to wiring the pieces together. My first program will probably attempt to use the watch dog timer (part of the microcontroller) to count in seconds and display the count on the provided LCD. Once that works, it will be a short step to getting the traffic controller operational.