Sunday, July 26, 2009

Game Counter

FInally finished a little project I've been working on - a counter that can be used to record the score or time in games. It can be used as a chess clock or simply to count the number of points up to six players have. I used a proto-shield to layout the components - a piezo-buzzer, a tri-color led, 3 switches (2 with embedded leds) and a serial display from SparkFun as described in an earlier post. It was also the first time I've really laid things out and soldered onto a protoboard. Some lessons learned there.

It's really been a project to test out a number of my library classes and how well they work in a real project. I'll describe and upload each of these in future posts, but for now here's the list of classes used:


1. A buzzer class
2. A tri-color led class
3. A general led class (with fading support)
4. A serial LED display class
5. A button class (with debounce)

All simple stuff really, and my main application class still looks a bit messy. More refactoring needed...

Wednesday, July 22, 2009

A trivial LED class

I needed a simple way of turning an LED on for a while and then coming back to it later to turn it off. In my case I wanted to signal to a user that I had done something (in my case written something to an SD card) but didn't want to interrupt everything else while this was going on. This is how I did this:

First, I created an LED class - I pass in the pin the LED is on in the constructor:


class AMLed
{
private:
 uint8_t _ledPin;
 long _turnOffTime;

public:
 AMLed(uint8_t pin);
 void setOn();
 void setOff();

 // Turn the led on for a given amount of time (relies on a call to check() in the main loop())
 void setOnForTime(int millis);
 void check();
};

In this case I added some simple setOn/setOff functions (you'd normally simply call digitalWrite functions for this inline in your code). Here's the code for the implementation, I'll describe it after the code:

AMLed::AMLed(uint8_t ledPin) : _ledPin(ledPin), _turnOffTime(0)
{
 pinMode(_ledPin, OUTPUT);
}

void AMLed::setOn()
{
 digitalWrite(_ledPin, HIGH);
}

void AMLed::setOff()
{
 digitalWrite(_ledPin, LOW);
}

void AMLed::setOnForTime(int p_millis)
{
 _turnOffTime = millis() + p_millis;
 setOn();
}

void AMLed::check()
{
 if (_turnOffTime != 0 && (millis() > _turnOffTime))
 {
                _turnOffTime = 0;
  setOff();
 }
}

So when I call setOnForTime I of course turn on the LED but I also record a time in the future when the LED should be turned off. Then, when the check() method is called I check to see whether the current time is greater than the turn off time and turn it off if necessary. I set _turnOffTime to zero so I don't overly exercise that code. Due to the short-circuit nature of C++ the check against millis() is never executed if _turnOffTime is zero.

Back to the code - this is how it would look in a sketch:


AMLED myLED(3);

void setup()
{
}

void loop()
{
   myLED.check();
   if (someEventHappened)
   {
      myLED.setOnForTime(5000);
   }
   // Some other interesting stuff
}

And that's it!

Serial LED4

I bought this LED display from Sparkfun a while back and it was pretty easy to get setup and running with it. But I wanted to create a little class to control it in a standard way (class = "library" in Arduino speak). This is how I did it.

First things first, I looked at the specification from the web site. The device can be controlled through a single wire serial interface so I wired that up on the breadboard with the power and ground all setup and the single serial wire attached to the digital pin 4.

I also saw the NewSoftSerial library which had everything I wanted - I didn't need to worry about how to actually send serial data down pin 4 - I just needed to encapsulated the protocol defined in the data sheet.

So - the first step was to get the class ready with the types of function I wanted (which pretty much emulates what the protocol in the data sheet says). The device is simple - it gives you the ability to put some data on (in chunks of 4 digits) and a couple of control codes for the decimal points and brightness.

Here was my first stab at that:

#ifndef SERIAL_LED_4  
#define SERIAL_LED_4  
  
#include "NewSoftSerial.h"  
  
#define COLON_DISPLAY 0x30  
  
class SerialLED4 : public NewSoftSerial  
{  
public:  
 SerialLED4(uint8_t sendPin);  
 ~SerialLED4();  
  
 void setup();  
 void displayValue(int val);  
 void brightness(uint8_t level);  
 void decimalPoint(uint8_t flags);  
  
private:  
};  
  
  
#endif  

In this case we construct our class (which derives from NewSoftSerial) with the send pin and we have functions to setup the display (if needed) and to display values and adjust the brightness. As for the implementation?

SerialLED4::SerialLED4(uint8_t sendPin) :
 NewSoftSerial(sendPin, sendPin)
{
}

SerialLED4::~SerialLED4()
{
 
}

void SerialLED4::brightness(uint8_t level)
{
print(0x7A, BYTE);
print(level, BYTE);
}

void SerialLED4::decimalPoint(uint8_t flags)
{
print(0x77, BYTE);
print(flags, BYTE);
}

void SerialLED4::displayValue(int val)
{
if (val < 1000)
{
print(0);
}
if (val < 100)
{
print(0);
}
if (val < 10)
{
print(0);
}
print(val);
flush();
}

In this case the NewSoftSerial has a send and receive mode, we simply use the same pin for both (it doesn't matter). And then looking at the protocol the act of displaying and controlling the display is achieved by simply "printing" the value (print is a method in NewSoftSerial). For the display of the value we make sure we send 4 bytes at a time.

And that kind of worked, except that the display sometimes got out of sync (i.e. the 4 digits were offset or rolled around). Not good. So instead of wiring the power pin of the device direct to Vcc I actually wired it to another digital out pin (which seems to provide enough power to the device when HIGH). That way I can add some new methods to powerOn and powerOff the device and to control how it starts up. This is how I did that:

class SerialLED4 : public NewSoftSerial
{
 public:
  SerialLED4( uint8_t sendPin, uint8_t powerPin);
  ~SerialLED4();
  
  void setup();
  void displayValue(int val);
  void powerOn();
  void powerOff();
  
  void brightness(uint8_t level);
  void decimalPoint(uint8_t flags);

 private:
  uint8_t _powerPin;
};

I added a powerPin to the constructor and some new methods to power it on and off. The changes to the implementation are reproduced below:

In the constructor, store the power pin and set it to be an output pin:

SerialLED4::SerialLED4(uint8_t sendPin, uint8_t powerPin) :
 NewSoftSerial(sendPin, sendPin)
{
 _powerPin = powerPin;
 pinMode(_powerPin, OUTPUT);
}

Then in the setup function, call powerOn:

void SerialLED4::setup()
{
 powerOn();
}

Power off is easy:

void SerialLED4::powerOff()
{
 digitalWrite(_powerPin, LOW); 
}

Power on introduces a delay to make sure the device is ready and sets the brightness to be the maximum.

void SerialLED4::powerOn()
{
begin(9600);
flush();
digitalWrite(_powerPin, HIGH);
delay(100);
brightness(0);
}

This now works just fine - here's an example use of the software in my data logger application:

class DLApp
{
private:
 SerialLED4 _ledDisplay;

// blah blah blah

};

DLApp::DLApp(uint8_t ledSend,
    uint8_t ledPower)
: _ledDisplay(ledSend, ledPower)
{

}

void DLApp::setup()
{
 _ledDisplay.setup();
}


// And then somewhere in my application:

// Display current temperature on display
_ledDisplay.displayValue(_temperature);

I'll post a link to the source code for my libraries soon once I've cleaned them up a bit. Then you can use them verbatim.

Welcome

Welcome to the hard-wired blog. This is where I want to tell the world what I've been working on in the world of physical computing.

In this first post I want to tell you how I write code for the Arduino platform (or the ATMega platform but I've been doing this on the Arduino specifically). I started out by downloading the general Arduino sofware and that worked well up to a point, but I'm a software engineer at heart and wanted full control over the build/release/version control process. My development machine is a Mac BTW.

IDE

I use Eclipse as an IDE - with the C++ plug-in. I have a new project for each "program".

Makefile

I copied the standard Makefile from the Arduino software download and "made it work" for me. This involved making the following changes:

############################################################################
# Below here nothing should be changed...

ARDUINO = $(INSTALL_DIR)/hardware/cores/arduino
AVR_TOOLS_PATH = $(INSTALL_DIR)/hardware/tools/avr/bin
SRC = $(ARDUINO)/pins_arduino.c $(ARDUINO)/wiring.c \
$(ARDUINO)/wiring_analog.c $(ARDUINO)/wiring_digital.c \
$(ARDUINO)/wiring_pulse.c \
$(ARDUINO)/wiring_shift.c $(ARDUINO)/WInterrupts.c twi.c
CXXSRC = $(ARDUINO)/HardwareSerial.cpp $(ARDUINO)/WMath.cpp \
$(ARDUINO)/Print.cpp SerialLED4.cpp \
TSens.cpp \
DLApp.cpp

(Famous last words on the "nothing should change below this point"). I simply add my new source code to the dependencies above.

I then make sure that the "builder" for the project is external and make sure that the build directory is the root directory of my project.

(Images to come)

Application

I create one main application class with setup() and loop() methods and instantiate that in my main sketch, delegating the setup() and loop() methods of the sketch to the application. I could of course alter the makefile to do this myself but it works ok. I also include the following in my sketch:

extern "C" void __cxa_pure_virtual() {};

because without it most programs will not link.

Programming using C++

I have the following rules for my C++ classes:

Always include the following at the top

#include <WProgram.h>
#include <WConstants.h>
#include <inttypes.h>

Never use new and delete

Use #define, #ifdef etc. where needed to exclude functionality as desired. This is important if you need to reduce the size of the overall application to remove bloat if your particular program does not need a feature. I reuse a lot of my classes in my projects and this helps a lot while keeping your applications looking consistent. And that leads on to:

Have a standard application_config.h file which is included in all source files that contains those definitions (on or off) to customise your application. You could put it in your makefile but I try not to touch the makefile much other than to add source file dependencies.

Building

Once it's all setup I simply do

make

then

make upload

once the board is connected to the computer. Works a treat. In a future post I'll go through a typical C++ class design and how I approach that.