Saturday, 29 December 2012

Rope making machine at BuildBrighton

With Xmas and New Year occupying so much of everyone's time, there's not really been much time for nerding about lately. Well, not for some of us. But thankfully Stephen Cropp from BuildBrighton hasn't been so pre-occupied, and set about 3D-printing this awesome rope-making machine.


It's really quite simple in design. At one end of the table is clamped a central cog, which drives three outer cogs (each spaced 60 degrees apart). By turning the central cog with a handle, all the outer cogs turn the same way and at the same rate.

Steve threads his twine through hooks on these outer cogs to a weighted clip at the other end of the table then cranks the handle...



Sunday, 23 December 2012

Wiegand26 protocol RFID reader

We recently received an RFID reader from eBay for a door tagging/entry system project due to start in the New Year. This one was going to stay on hold for a while, but with a few hours to spare one evening at a BuildBrighton Thursday night, it seemed like the perfect opportunity to have a play about and see what this thing could do.



Firstly, it uses some weird protocol called Wiegand26 rather than the slightly more straight-forward serial/TTL level communications. But the protocol itself seems quite straightforward: the device consists of two data lines - when a zero is transmitted, one line goes low for a few microseconds, while the other stays high and when a one is transmitted, the other line goes low, keeping the first line high.

This seems easy enough. We simply monitor both lines and when one goes low, wait for it to come high again, and add a zero or a one to a binary buffer value. The tricky part comes in detecting the end of the binary stream:

Now the "official" Wiegand26 protocol involves 26 bits of data (that must be where it gets the -26 part of it's name from!). But some RFID cards and tags use much longer data for better security. Since we don't know much about the tags/cards we're going to use with this reader, we're going to have to assume there could be more or fewer bits of data coming down the wire(s).

So here's the approach:
We're going to set a flag to say whether or not we've started receiving some data.
As soon as one of the data lines changes, we start a timer running to time out after about 500ms.
Every time one of the data lines changes, we reset the timer.
When the timer times out (no activity for 500ms) we see what data we've got in the buffer and spit it out over serial.

We've doing this project in SourceBoost - not because we've fallen out with Oshonsoft, but because the first chip we picked up was one of the 16F1825s we've been using in our earlier audio project, so we stuck with it for ease of use.

This is the bulk of our program:
void main(){
   init();
   timer1Init();
   delay_ms(50);
   startTimer();
   while(1){
      checkforinput();
   }
}

The init routine simply sets up the input/output pins, and for debugging, starts the UART for writing data out over serial so we can debug what's actually going on inside the magic black box:


void init(){
   
   osccon           = 0b11110000;   //32 MHz clock   
   intcon           = 0b11000000;   //global/peripheral ints enabled
   apfcon0          = 0b01000000;   //MOSI on RA4
   option_reg         = 0b10000000; //no weak pull-ups, timer0 at OSC/4/2 = osc/ 8   

   UARTInit();
   ansela            = 0;         //no analog inputs
   anselc            = 0;         //no analog inputs
   trisa=00000000b;
   trisc=00000110b;
   
   porta=0;
   portc=0;
   tmp=0;   
   bitCount=0;
   bufferPointer=0;
   
   // now we pull pins low to activate the beeper and the lights
   // so force them high by default
   porta.2=1;
   portc.0=1;
   
   msCount=0;
   isReading=0;
   empty_buffer();
}

We couldn't be bothered to work out the values/pre-scalers for a 500ms timer, so just copied and pasted some code from another project which kept a 1ms timer, and used that with a counter to decide when 500ms had passed:


void preloadTimer1(){
   //------------------------------------
   // pre-load timer1 with 65172 (0xFE94)
   //------------------------------------
   // 1/22050 = 0.00004535147
   // at 32mhz, fosc=8,000,000
   // and 8m/22050 = 362.812
   // so we want our timer1 to only count up to 363
   // timer1 is a 16-bit timer (0-65535) so we need to
   // preload it with 65535-363 = 65172

   tmr1h=0xfe;
   tmr1l=0x94;
}   

void timer1Init(){
   //-------------------------------------------
   // interrupt on timer1 22050 times per second
   // ------------------------------------------
   pie1.0=1;   // timer1 rollover interrupt on bit zero
   intcon.7=1;   // global interrupts
   intcon.6=1;   // peripheral interrupts
   preloadTimer1();   
}

void startTimer(){   
   t1con.0=1;
}

void stopTimer(){
   // turn off the timer1 T1ON bit
   t1con.0=0;
}

void resumeTimer(){
   // turn on the timer1 T1ON bit
   t1con.0=1;
}

And in our timer interrupt:

void interrupt(void){
   
   // bit zero of pir1 is tmr1 overflow interrupt
   if(pir1.0==1){
      // clear the timer1 interrupt flag
      pir1.0=0;
      // preload timer1 to get the next interrupt to occur in a timely manner
      preloadTimer1();
      msCount++;   
      
      if(msCount>500){
         if(isReading==1){
            flushBuffer();
         }
         msCount=0;
      }         
   }
}


Now every time one of the data lines goes low, we wait for it to come back high, then add a one or a zero to the end of a stream of bits.

void checkforinput(){
   if(portc.2==0){
      // reset the timer if this is the start of a read
      if(isReading==0){msCount=0;}
      // set the flag to say we're reading some data
      isReading=1;
      //data1 has gone low: this is a one
      while(portc.2==0){
         // wait for the line to return high
         tmpBit=1;         
      }
      add_bit();
   }
   
   if(portc.1==0){   
      // reset the timer if this is the start of a read
      if(isReading==0){msCount=0;}
      // set the flag to say we're reading some data
      isReading=1;   
      //data1 has gone low: this is a one
      while(portc.1==0){
         // wait for the line to return high
         tmpBit=0;   
      }
      add_bit();
   }
   
}


To add a bit to the right-most end of the temporary value, we bit-shift all the data in the variable one place to the left, and simply OR the value (1 or zero) to the final result.
Here's an example:

Let's say we've already got the value 001101 in our buffer and we receive a one. First we bit-shift the value one place to the left. This gives us 011010. Now we OR this value with the number one (000001) and the result is 011011. This is the same as just tacking a one onto the end of the bit stream!

void add_bit(){
   tmp=tmp << 1;
   tmp=tmp | tmpBit;
   bitCount++;
   if(bitCount>=8){
      // this is a full byte
      // add it to the buffer
      porta.4=1;
      buffer[bufferPointer]=tmp;
      bufferPointer++;      
      tmp=0;
      bitCount=0;
   }   
}


So all that's left to do now is spit the data out so we can interrogate it:

void empty_buffer(){
   unsigned char i;
   for(i=0; i<=12; i++){
      buffer[i]=0;
   }
   bufferPointer=0;
}

void flushBuffer(){
   unsigned char i;
   
   // send out whatever's in the buffer
   // (first four bytes for a 26-bit protocol)
   isReading=0;
   UARTPrintLn("Buffer contents:");
   for(i=0; i<4; i++){
      tmp=buffer[i];
      UARTPrintNumber(tmp);
      UARTPrintLn(" ");
   }
   
   // reset the buffer for the next read
   tmp=0;
   bitCount=0;   
   empty_buffer();      
}

The reader we're working with has the following pinout:

power
ground
data0
data1
buzzer (low to activate)
led (low = green, high = blue)

So we wired the whole lot up to our PIC 16F1825 microcontroller, dumped some code onto it and read back what came out:


Amazingly, everything worked pretty much the first time out, with the results as follows:


Amazingly, the RFID reader could read a variety of RFID tags. We tried it with some of the phonics owl cards from an earlier BuildBrighton project, as well as the key fobs from the BuildBrighton door entry system, along with some other RFID tags from other people's various places of work. The RFID reader simply read them all and reported back the tag contents!

Now it'd be easy to call it a day and say we can read RFID tags successfully, but there's still the nagging doubt that we're not actually reading data, and just reporting a load of junk. What we needed was some way of confirming the data being read with a known value.
Luckily, the phonics owl cards (and a lot of RFID cards for that matter) have a Wiegand26 value printed onto them. If you have an RFID card with two sets of values, it's the second value (the one with the comma in it) that we're interested in:


What we need to do is compare our read-in value(s) against the Wiegand26 values printed onto the cards. So let's take a look at the actual bitstream from each of the card reads:

card no: 0006304068 096,12612
0000000048
0000000024
0000000162
0000000000
b00110000000110001010001000 (first 26 bits)

card no: 0012225140 186,35444
0000000093
0000000069
0000000058
0000000000
b01011101010001010011101000 (first 26 bits)

card no: 0006348080 096,56624
0000000176
0000000110
0000000152
0000000000
b10110000011011101001100000 (first 26 bits)

We've reported four bytes of data, because 26 bits is just over 3 bytes (3x8 = 24 bits).
In this case, all our fourth bytes are zero, but there's no guarantee that this will always be the case. So let's convert each decimal value to binary  and squash them all together (truncating once we get to 26 bits). Looking at it now, we could have created a single 32-bit value and simply bit-shifted the data 26 times, but then our code wouldn't work with 64-bit (or longer) cards. So by handling the data one byte at a time, we've got more work to do at this end (for validating) but it does mean we've a much more flexible system for future use.

Here's how the Wiegand26 protocol works, with 26 bits of data:



Let's look at the first set of values.
Splitting the byte stream up into groups of bits, we've got

0 01100000 0011000101000100 0

At the minute we're ignoring the parity bits, and are only interested in the "middle" section of the data stream. But already it's looking quite encouraging....

01100000 in decimal is 96
We've a couple of cards that begin with 096 followed by a comma.....
Taking the next group of 16-bits and converting to a single decimal gives us - 12612

That means we've correctly read the RFID data from the top-most card! Yay!
Comparing the values from the other cards, and we find we're accurately reading all the cards using the Wiegand26 protocol. We're not just reading junk, we're actually reading data.

With this in mind, we don't actually have to decode the bit-stream back to Wiegand values every time - we can simply report back the groups of bytes from the different cards, fobs and tags, confident that if we're reading them correctly (we are), the data from each will decode to the actual value on the card (if we need it to) but the parity bits will always give us the same groups of bytes for each card. As long as we have consistency each time a card is presented (i.e. we're not reading junk, we know we're reading the data correctly) we can simply compare the clumps of bytes to a look-up table to make the cards usable.

So to use this RFID reader for a door entry system, for example, it doesn't matter if we record a card as having the Wiegand26 value of 096,12612 or whether it's stored as 48,24,162,0 - each time the card with 096,12612 is presented to the card reader, we should expect to get back the bytes 48,24,162,0.
It's much easier to work with byte rather than splitting them up into bits, so we could just put these four bytes into our look-up table instead of converting back and forth between crazy 26-bit values!

In short, our first quick success for a long time.
After just a few hours of messing about, we've got a fully working RFID reading system.
In future posts, we'll look at writing our lookup table to an SD card and logging each time a card is swiped by writing a log file back to the card, making a completely PC-independent, embedded system!

Thursday, 20 December 2012

Working word clock pcb at last!

Having created a pcb from our earlier design, we've finally had time to sit and work out the pinout. And this time we're delighted to report that it actually works. Each pin on the 24-pin connector performs just one task and the correct combination of power and ground onto the pins causes just one LED to light up at a time. Result!

Here's the pin-out from the earlier pcb. The pins along the bottom need to be pulled to ground, while the pins along the edge should have power applied to them:


So if, for example, we put power onto pin2 and pull pin 23 low (to ground) the single LED in the top left corner of the matrix should light up. Repeat as necessary for each individual pin and we've finally got a fully working, individually addressable LED matrix. Yay!

Source code for the word clock to follow.....

Tuesday, 18 December 2012

Some SD cards don't like SPI mode and low voltages

It's a sad fact that some SD cards work differently to others.
Although there's a set of "standards" that all (most?) SD cards are supposed to adhere to, the degree of variance between cards is huge.

And we've just wasted about a month trying to fix a problem "properly" instead of doing the pragmatic thing and just hacking a solution together.

A while ago we started adapting some noise-playing alarm clocks. We completely replaced the onboard sound chip with one of our own design, which plays uncompressed wavs from an SD card. It took a lot of working out to get the SD card actually readable and when we thought we'd cracked it, put the audio player board back inside the alarm clock and gave it a try.

Incredibly, it worked first time!
And second time.
And third. But not the fourth.
In fact, after just a few plays, the SD card refused to initialise properly.

It all came down to the supply voltage. At 5v, we put the supply through a voltage regulator to give a steady 3.3v out. Everything worked fine. We put the boards into the alarm clocks and ran them off the 3v that 2xAA batteries created. In truth this was sometimes as high as 3.2v.

After just a few plays, the tiny voltage drop in the batteries was enough to stop the SD card from working.
But that's not where the story ends. Because we've spent about a month trying to use different triggering mechanisms, DC-to-DC converters, opto-isolators, PNP transistors and more yet all the time we had a working prototype on the desk. The circuit was exactly the same, we kept going back to the same (rough-and-ready) firmware. But all the time the prototype worked while every new version didn't.

And then we spotted the difference.
The prototype was using a genuine SanDisk micro sd card. The newer boards were using another brand. And that was enough to make a difference! SanDisk cards are pretty robust and can handle a wide range of supply voltages - cheaper, inferior brands can't.

So after a month of trying to build a circuit which is 100% compatible with all brands of SD cards, we've finally given up. And decided to only support a small sub-set of available cards on the market. It's not ideal. But it'll let us get these bloody clocks made up and shipped, hopefully this time of Christmas!!


Monday, 17 December 2012

Another word clock update

Anyone who has tried making a word clock from our previous designs is likely to be as disappointed as we were - they still don't work! This despite us actually reading the datasheet and laying out the pcb accordingly.

The problem this time wasn't that we'd connected the wrong pins (earlier assuming that all the "row" pins were on the top and all the "column" pins were on the bottom) but more that we hadn't identified which pins were which!

The datasheet we found suggested that the pin layout was a little peculiar:


So our latest pcb followed this layout. Without further information, we'd assumed that the pins were numbered

 1   2   3   4   5   6   7   8


 9  10  11  12  13  14  15  16 

None of the pins caused the right LED to light up. Putting power and ground to various pins was lighting up lights, just not the ones we expected. Then something peculiar happened:


Now at no point should putting a single power source onto a single pin cause more than one LED at a time to light up. Something was obviously very wrong! And so began the painful, laborious task of applying 5v power to one pin (through a 220ohm resistor of course) and ground to another, and charting which combinations caused which LEDs to light up.


Our final chart didn't resemble the datasheet in any way - we were grounding pins which the datasheet said were LED anodes, and putting power onto pins that the datasheet said should be pulled to ground. 
Once we'd identified which pin caused which "row" to light up, and done the same to find which pin to ground caused the LEDs in a specific column to light, we stopped filling in the grid and just did some random sample testing to prove our theory. Each test worked fine, so we were confident that we'd correctly identified the row and column pins.

There was no denying the hand-written grids - they were what we'd actually witnessed, datasheet or not. But they just didn't match with the datasheet at all. Just before we binned the datasheet and presumed it belonged to another module, we tried changing the presumed layout of the pins on the board.

We'd assumed they were numbered 

 1   2   3   4   5   6   7   8
 9  10  11  12  13  14  15  16 


when - after much messing about -  it turns out that they're, in fact, numbered 

16  15  14  13  12  11  10   9 
 1   2   3   4   5   6   7   8

Following this layout, suddenly the datasheet made sense!
We could read the pins on the datasheet, work out which LED should light by putting power and ground onto the appropriate pins and then proving this to be correct.

(note the LED module spread over two breadboards: it was simply too large to fit onto a single breadboard for testing!)

This time, everything matched up. We'd finally worked out how to make the LEDs light up in the correct way. But one thing remained - the pcb was, once again, wrong!
A bit of re-work in ExpressPCB and we came up with this:
Word Clock v2

Hopefully, a working PCB. To keep the overall final dimensions small, we're going to connect this to the 40-pin PIC mcirocontroller using a simple ribbon cable (off an IDE hard drive). For now we'll keep the connector in place, to make it easier to breadboard the whole thing up during testing:


Monday, 10 December 2012

Updated word clock PCBs

After making a complete cock-up of the earlier 16x8 word clock (made from two massive 8x8 LED matrices), we've had to revise the layout.

Here's the PCB for the LED face.
Since we're going to be connecting the 40-pin PIC microcontroller via some IDE ribbon cable, joining which pins on the connector to which pins on the LED board(s) isn't really that important - we just need to make sure all the pins from the boards are routed to some kind of ribbon connector:

Clock 8x8 v2

But since the pins for the rows and columns are all over the place, and we've just connected them any-old-how to the ribbon connector, we need some kind of look-up table:


The PCB for the PIC simply puts all the output pins to 0.1" pitched holes on the board.
So all we need to do is wire up the pins on the 24-way clock board connector to the appropriate pins on the PIC, following the table above.

That's the theory anyway.
Whether or not it actually works is another question.......

There's no getting away from it, we screwed up

In this earlier post, we designed a schematic and PCB for our 8x8 LED matrix and didn't really pay attention to the data sheet. Like a bunch of idiots, we just assumed that the pins along one edge were for the "rows" and the other set of pins were for "columns".

So it's no wonder that by sticking voltage across the pins resulting in some really peculiar behaviour. Where we expected the top-left corner LED to come on, one somewhere in the middle near the bottom lit up! The next pin along didn't light the next LED in the row, but one about three places along.


To get the top-left LED to light, we don't simply put power onto the first pin at the top, and ground the first pin on the bottom set - that won't actually light any LED!
Assuming our pins are labelled 1-8 across the top, and 9-16 along the bottom, connecting power to pin 1 and ground to pin 9 doesn't pass through any of the LEDs. If we put power onto pin 1, we need to ground one of either pins 3,4,6,11,13,15 or 16.

With this in mind, we've had to re-draw our schematic (and make a new PCB using a similar layout):

clock_8x8


Friday, 7 December 2012

A quick Xmas-themed project with flashing LEDs!

Here's an idea for an Xmas themed project, using up a few components most people are likely to have floating around. At the heart of it is a 555 timer, which creates a regular "pulse".
We're using this on/off behaviour to drive two transistors - one NPN and one PNP

Xmas Tree Sch

When the 555 timer output goes high, the NPN transistor allows current to flow lighting up LEDs 1-4. At hte same time, the PNP blocks current and LEDs 5-8 go out. When the output goes low, the NPN stops the current flow, making LEDs 1-4 go out, while the PNP makes LEDs 5.8 light up.


Play about with the values of the two resistors, R1+R2, between pins 6+7 on the 555 timer, and the value of the capacitor to create different flashing frequencies.

The 555 timer can sink/source up to 200mA. As this is an untested design, and depending on the voltage of the battery used, a resistor between power and the common LED anodes may be required. The value of this resistor will depend on the power source used

Xmas Tree Pcb

Create two of these PCBs. Cut a slot from the top of the first board, to about the mid-point, and from the bottom to the same point on the second board. The common power supply to the LEDs makes a complete circuit around the outside of the board, so it shouldn't matter if it's cut at the top or the bottom (just not both!)

On the first board only, mount the 555 timer and associated discrete components. On the second board, simply populate with LEDs.

Slot the two boards together. Every LED has two holes alongside it. These are for connecting wires to the corresponding hole(s) on the other board. This creates a complete circuit between all the LEDs.
Don't use straight bits of bare wire - use coloured wire (coloured sleeves) and bend them slightly to make "loops" going across the branches. For a real Xmas feeling, cover in glitter or bits of tinsel.

Connect up a battery and see if it works.
(this design, at the time of writing, is untested!)
Here's the silkscreen/layout:



Wednesday, 5 December 2012

There's no room for the pedantic Grammar Police

Try as I might, I can't bring myself to be happy with a word clock which potentially reads "it is just gone five minutes past six".

The sentence should read "it has just gone five minutes past six". But at the same time, we also need to be able to say "it is nearly quarter to seven", for example. A possible work-around (though still slightly clumsy) is "it's....." which could then be read as it is or it has depending on what follows. But that's still a bit nasty.

The problem is, wherever there's a possibility that one word could be immediately followed (light up) by another, we've had to leave a space (notice how there's a space between "it" and "is" on the earlier example, and between "minutes" and "past" - but not between "half" and "minutes"). Well, if we allow for both "it is" and "it has" there simply aren't enough squares left to spell out all the required times.

Unless we fudge it some other way:


We've had to spell out the word "ten" vertically rather than horizontally. It's a bit of a kludge and I'm still not 100% happy with it. But a bit happier than the nails-on-a-blackboard-sounding "it is just gone....x o'clock".

With this in mind, here's how we're going to write the time, at each of 0-59 minutes past each hour:


Bit-shifting. Shift over.

As part of our word clock made from two 8x8 LED matrix modules, we're trying to work out a way of quickly lighting up columns of 8 LEDs at a time.


Here's how it works: we set (and unset) any number of 8 different pins (connected to the "rows" line). Then we pull one of the 16 columns low, leaving the other column pins high, thus lighting up to eight LEDs in a single column. After a short delay, we then change the eight "row" pins and move along to the next column.

One way of achieving this is to have one single byte variable for the rows data, and a two byte (16-bit) variable for the columns data. If we start by lighting the first column, the two byte variable value would be 0111-1111-1111-1111 (in binary). After changing the row data, we need to make the two-byte variable value 1011-1111-1111-1111

In short, we need to make the zero value "move along" one space to the right.
A really easy way to do this is bit shifting.

We're going to simplify things (although not immediately obvious) by bit-shifting the (binary) value 1000-0000-0000-0000 one place to the right, then sending the inverse value to the column pins (so every 1 becomes a zero and every 0 becomes a one).

The reason for this is because bit-shifting isn't necessarily "circular". When a bit "drops off the end" it doesn't necessarily appear back at the start of the value. Consider a simpler example, the number 0110.
If we bit-shift one place to the right, the number becomes 0011. But if we bit-shift one more place to the right, the number becomes 0001. The trailing one has "dropped off the end" and disappeared - it doesn't appear back at the start of the value.

If we had the initial value 01111111 etc. and bit-shift one place to the right, we end up with 00111111 and not 10111111 (which is what we need). Whereas taking the value 10000000 and bit-shifting one place to the right gives us 01000000 which - when inverted - gives us the value we're after.

Right, that's that cleared up.
First we declare our variable:

unsigned short colData;  (SourceBoost)
Dim colData As Word (Oshonsoft)


Why unsigned rather than signed?
A two-byte signed value is simply a 15-bit value and the very first (leading) bit determines whether the value is positive (leading bit zero) or negative (leading bit one). If we used signed values, the leading bit would need to be toggled from zero to one depending on the position of the zero in the rest of the string. This is more hassle than just inverting an unsigned value (where the leading bit actually makes up part of the value represented by the binary pattern).

Then give our variable an initial value
colData=0x8000;
or
colData=32768;

The hex value 0x8000 is the same as binary value 1000-0000-0000-0000
Now when we need to move onto the next column, we bit-shift the colData value one place to the right:

colData = colData >> 1

This means that the value now becomes 0100-0000-0000-0000
And bit-shifting again:

colData = colData >> 1

returns the value 0010-0000-0000-0000
And so on and son on.

When the column is all the way over to the right, 0000-0000-0000-0001, and we bit-shift once more, we end up with 0000-0000-0000-0000 whereas we want the one to wrap around to the start again.
A simple if statement takes care of this:

If colData = 0 Then colData = 32768 (Oshonsoft)
if (colData==0){ colData = 0x8000;} (Sourceboost)

But as we've already stated, our colData is inverted to what we actually want. We don't want to pull 15 of the 16 columns low, we want only one column low at any one time. So we need to invert the value in the colData variable and put this value onto the output port(s):

tmp = colData XOR 0xFFFF

XOR is an exclusive OR statement:


If either of the bit patterns BUT NOT BOTH are one, the result is a one, otherwise it's zero. So simply XOR-ing our colData value with a load of ones 0xFFFF is binary 1111-1111-1111-1111 inverts the value, turning all the ones to zeros and all the zeros to ones.

Now we put the first (most significant) byte of the two byte variable onto PORTB and the second (least significant) onto PORTD:

Oshonsoft
Dim H As Byte
Dim L as Byte
H = colData.HB
L = colData.LB
PORTB = H
PORTD = L



SourceBoost
unsigned short b;
b=colData;
PORTD=b;  // only the lower 8-bits are put onto the output pins
b = b >> 8;  // move the upper 8-bits eight places to the right
PORTB=b;


The end result is that only one pin is pulled low at any one time.
Every time we use the bit-shift operator, the low pin "moves along" one place to the right, effectively lighting up the next column of LEDs in our matrix.

Heres's a quick guide to bit-shifting and unsigned/signed variables:
http://stackoverflow.com/questions/141525/absolute-beginners-guide-to-bit-shifting

Tuesday, 4 December 2012

Word clock PCBs

These massive 16-pin 8x8 LED matrix modules are easy enough to work with - each row of LEDs has a common pin (so all 8 LEDs in a single row are potentially connected to the power supply) and you simply ground one of eight "column" pins to make the appropriate LED light up.



Although there are load of different driver chips for these display blocks, or we could use shift-registers and the like, we're going to do with the really simple direct-drive method. Basically this means choosing a microcontroller with loads of pins and connecting them directly to the pins on the LED matrix.

Word Clock Sch

To keep our final clock dimensions quite small, we're going to put the microcontroller on the back on the LEDs and use some IDE cable (which conveniently is 0.1" pitch spaced anyway) to connect the two boards:


Word Clock Pcb

Since these modules have a common anode, and you drive the appropriate pin(s) low to make the LEDs switch on, we've connected all the anodes on each "row" together. So each "row" output pin activates up to 16 LEDs at once.

This isn't an ideal way of driving these boards - using something like a Maxim MAX7219 constant current LED matrix driver would be better but two of those at a tenner each and the project starts to get a bit spend-y. Since we're only likely to actually light 3 or 4 LEDs (from a maximum of eight) at any one time, direct drive gives us a cheaper alternative to try out the design and check that everything works properly before committing to some rather expensive components.

We've gone for the PIC 16F877A chip, just because we've a few left over from years and years ago - they're the typical "starter" chip for people getting into PIC programming; loads of pins (it's a 40-pin DIP) and loads of peripherals (UART, SPI, I2C etc). It's probably a bit overkill, and there may be other, cheaper chips out there, but we're just using up what we've got.

We're going to be running the chip off a crystal and use this to keep time as well as provide the instruction clock cycle. We've some 4Mhz and some 20Mhz crystals knocking around - either will do. The idea is to keep an array of values representing the output state of each of the 16 vertical columns in the LED matrix. We'll create a timer interrupt every 1ms and use this for timekeeping (increase a seconds counter every second, when this rolls over to 60, increase a minute counter, when this rolls over to 60, incease an hours counter) as well as to drive the next column of LEDs.

By strobing all 16 columns once every millisecond, we're hoping to create an illusion of an always on display; depending on the results of this, we may strobe the columns every few milliseconds and try to find the optimum balance between the length of time each column remains lit and the "refresh rate": as each column stays on for longer, the LEDs may appear brighter, but the refresh rate (the number of times each column is "drawn" per second) reduces.

Monday, 3 December 2012

More Christmas clocks

Last year we made some clocks for Xmas. This was because of an earlier ill-fated attempt to charlie-plex a load of LEDs (a 9x10 matrix) in order to create a word clock (which failed) and a bingo machine (which later worked, but using shift registers instead of charlie-plexing).

This year, since we've got a cheap audio playing device and having seen Jason's awesome digital led MatrixFaces, we thought that some digital caricatures of friends and family would make great stocking filling gifts. So promptly ordered a load of 8x8 LED matrices and waited until they arrived...


They're supposed to be two-colour (red and green) 3mm matrix blocks but the ones that arrived are massive! They're also single colour, with just 16 pins - one set of 8 pins for the "rows" and one set of 8 pins for the "columns". By driving the appropriate pins high/low you can activate any single LED in the matrix. Drive each of them quickly enough, and using POV (persistance of vision) you create the illusion of many LEDs being lit at the same time.

Which got us thinking back to our (failed) word clock project about a year ago.
Instead of a home-made 9x10 matrix, perhaps there's some way we could squeeze a word clock into an 8x8 matrix and use these ridiculously large (in LED matrix terms) modules to create a ridiculously small (in wall clock terms) erm wall clock...

No matter how we tried to spell out all the words required, we couldn't quite get them all to fit into an 8x8 grid. So what if we put two of these side-by-side?


Well now, a 16x8 LED matrix not only gives us more than enough letters to spell out all the words needed for our word clock, but also solves a little niggling issue we'd previously tried to ignore:

Word clocks with five minute increments are accurate to the last five minute segment. Between five to, and o'clock, say, the clock will always read "it is five minutes to x". Then at the o'clock position, it read "it is x o'clock" until it's five past.

By having a larger matrix (albeit by accident than design) we've got extra lights to add in some extra words. So we've added "nearly" and "just gone". This should make our clock accurate to about two minutes at worst.

  • At 2 minutes to six o'clock, it would read "it is nearly six o'clock".
  • At six o'clock, it would obviously read "it is six o'clock" 
  • At 2 minutes past six, it would read "it is just gone six o'clock"
  • And at 4 minutes past six, it would read "it is nearly five past six"
  • At five past, it reads "it is five past six" 

and so on - each two minute segment before a five/ten/quarter past would have "nearly" at the front, and each two minute segment after a five/ten/quarter past time would have "just gone" added to it. This means that you should be able to work out to within two minutes the actual time on the clock.

It's not millisecond accuracy, but it's a bit better than most word clocks manage!

To make the clock, we're planning a laser-cut face over the LED matrix with the letters as laid out in the spreadsheet above. We may even coat some glass with semi-opaque paint to give a smoked effect, and laser this off. The exact finish has yet to be decided.

Since the two LEDs matrices side-by-side give us a 16x8 grid, we can simply keep track of the current time and convert this into an array of single-byte values, each sent out over a full output port (PORTB for example) on a PIC microcontroller, while pulling the appropriate cathode "column" low to make the corresponding LED(s) light up:


In the above example, we want to light up the words to spell out "it is five minutes past six".
If we highlight the letters required, and at the bottom of every column add up the values of all the "lit" characters, we can see the array of value(s) required to make the LED matrix light up.