Introduction: Tiny Wearable LED Kit - 12 PWM LEDs From a Reprogramable ATtiny85

About: Call me Ugi. Special offer! Make something based on one of my instructables and post a picture for a free 3-month pro membership (while stocks last).

This instructable covers the assembly and use of a Tiny Wearable LED kit.  The kit is useable immediately but is desigend to be hackable and can be reprogrammed to your liking using an ISP programmer or Arduino board and the Arduino IDE.

There are not too many tiny implementations of microcontrollers.  The Arduino lillypad is quite large and expensive and if you want to drive a dozen LEDs you still need to multiplex them.  What we could use is something small and simple that will run for an evening off a minature battery....

Here we are taking advantage of two key features to be able to drive 12 independent LEDs from the five programmable pins of an 8-pin ATtiny85.  Firstly, the tri-state nature of the pins means that any pins not being used can be set to high-impedance (INPUT) so that they are not affected.  That gives us 2 x 3 = 6 pairs of outputs.  Secondly, because LEDs conduct only in one direction, we can put 2 LEDs on each pair of lines to give 12 in all.

Our ATtiny runs happily from a 3v coin cell and because we are driving our 12 LEDs in pulsed mode the overall current draw is quite low.  We can therefore run our complete setup from a CR2032 coin cell for several days continuously.  I haven't tested it to exhaustion but I have run it for 48  hours continuously without any problems.  That was actually off a 2025 which is lower capacity than the 2032.

You could in theory light up to 3 LEDs at the same time using this setup but I worry that the coin-cell would not handle the current so in this I limited myself to pulsing only 1 LED at a time.

Obviously, because we are driving the LEDs one at at time in pulsed mode, if we light a lot of them then they will not be as bright as direct attachment to a coin cell and wouldn't ne hugely visible in bright sunlight.  However, by lighting only a few at a time we can make some impressive looking effects, especially indoors.

This is designed to be "sewable" into clothes or could be worn as a programable badge etc.

I don't have a video of the final version but this is the prototype with the LED mounted lose on the board as a test:

Step 1: The Kit

The Kit:

Your kit should contain:

1 CR2032 Coin Cell
1 CR2032 Coin Cell Holder
1 ATtiny85 AVR microprossor (preprogrammed)
1 Sliding Power Switch
1 Tactile Mode Switch
1 PCB
1 Length of thin Stainless Steel Wire or conductive thread (I only have ss wire)
12 Ultra-bright LEDs

With such a small inventory of parts chosen to be relatively water-tollerant, it shoud be entirely feasable to wash the garment into which the kit is incorporated (remove the battery first obviously) but hand-washing would be advisable and please ensure all parts are fully dry before reinserting the battery.

Your kit does not require any programming, however, if you do wish to reprogram it, you will need the additional programming components included:

1 x 6-way 90' male header
1 6-way female to 6 x 1-way male breakout cable.

These components should allow you to connect your Tiny Wearable LED board to your Arduino or other ISP programmer - see Step 6

Additional Materials Required:

You may find the following useful in assembling and using your kit:

Needle and thread.

Scraps of fabric and/or velcro.

5-minute epoxy, silicone or other sealant.  Nail varnish is ideal for this.

Tools Required:

Soldering iron and solder

Side cutters

Small pliers.

Step 2: Populating the Board

Before we start putting components down on the board, let's have a quick look at what we've got:

The board is about an inch wide by less than 1.5 inches long with only five essential components to solder.  The largest of these is the battery holder and since this is going on the bottom of the board we need to do that last.

Obviously the heart of our device is the ATtiny85 microprocessor, we also have a power switch (sliding switch at the top) a tactile switch for input and a current limiting resistor on that switch.  Positions for the 12 LEDs are on the left of the board but typically not all of these would be needed.  The connections with rings around them are the key ones.

Soldering up the Board

The board pictures are from the first version of the board that I made.  It's much the same but not labeled quite so well.  Please try to imagine that its silkscreen is the same as the printout in the first picture of this step.

Fiirst of all, let's solder in that little resistor.  Clip it tight to the back of the board - we need space for the battery.

Second comes the IC - make sure you have the notch at the bottom.  I have used a socket in some of these but there is no need - AVRs are pretty hard and you'll need to get it really hot to fry it.  Just remember that if it takes more than 1 second (that's longer than you imagine), take the heat away and let it cool before trying again.

Working our way out towards the edges of the board, put in the switches next and then the battery.  I bent one side of the switch down to be out of the way, as shown.  You should still have space to add the programing header later but if you know you will be needing it (see later steps) then you could solder that before the battery for greater comfort.

The circuit is extremely simple but chosen so that we don't need to strip the components off the board to re-program it.  The schematic is shown in the last picture.  The important point is that pins 5, 6 and 7 of the chip (that's D0-D2 in Arduino - or I have called them T0-T2 in the schematic, since this is Tiny Arduino) do not have any LEDs between each other.  The LEDs all join these pins to pins 2 and 3.  As a result, there should be no short-circuits when pins 5-7 are used for programming since pins 2 and 3 will remain high impedence.  If we had used more pin combinations then we could have driven more LEDs but they would start to get rather dim anyway because we only drive one at a time and we would have to pop out the chip to program it.

Step 3: A Quick Test

If you have a kit with a pre-programmed ATtiny85 then we are already in shape to try a quick test.

If you don't have a programmed ATtiny and want to test your circuit before you start stitching then skip forward to the programming step, burn the sketch, and then pop back here.  We'll wait..  All done?  Right, let's test...

First, slip your coin-cell into the holder.  The +ve side faces the spring arm and the -ve side goes towards the board.  Slide on the power switch and your ATtiny should now be humming away. But how can we tell?

Grab an LED and slip it into one of the pairs of LED holes.  Any pair of holes, any way round, will do for now.  You should see your LED blink on and off about once each second.  That's the first program in the sketch: half of the LEDs on and half off at any one time. 

If you want to test that each LED position is working correctly, take your LED and test it in each pair of holes.  The polarity doesn't matter at the moment.

Now try a second test:  Put two LEDs in consecutive pairs of holes.  If you turn them so that they have the same polarity then they will flash alternately.  If you reverse one then they will flash together.

If your LEDs behave as described then it looks like your assembled board is working well.  Feel free to press the mode button and switch between modes - you won't break anything - but our kit will look much nicer once we get all the LEDs in place so when you've ready, let's move on.

Step 4: Adding the LEDs - Pt1 - Connections

Before we actually lay our our wires, let's have a look at how the LEDs are connected.  Then we can chose the best wiring scheme for this specific project.

There are 24 pads for adding LEDs placed down the left had side of the board.  If you wanted to drive the LEDs on the board itself then all you need to do is solder one to each pair of pads with the longer (+ve) leg of the LED towards the outside of the board.  If you wanted to add your LEDs to a tie or something then you could do just that. 

Obviously, we could just wire our LEDs up one to each pair of pads in the same way as fitting them to the board but since we want to sew these into something wearable and we don't want to look more like robocop than necessary, we can be a bit more cunning about how we wire them.  Also, the fewer wires we have the less chance that we will short-circuit something.  This is where the rings around the pads come in...

You will see from the circuit board printout that some of the outside pads have rings around them.  These are the key connections that we will make.  You in fact only need 5 wires (one for each of the pins we are using but in practice it will be easier to wire if we use 8 wires.  These are in two lots of four, where each set of four has one "master" wire and three "slave" wires.  We will wire two LEDs between each combination of a master and a slave.

Let's start with LEDs 0 to 5.  They are marked at the top left of the board.

You will see that LED 0 is marked in bold with a large ring around the + side commection.  That is because this is the "master" wire for this group.  All 6 LEDs will connect to this master - 3 by their +ve side and three by their -ve.

The +ve connections for each of LEDs 1, 3 and 5 also has a ring.  These are where the slave wires join.

It doesn't matter too much if the slave wires short together - the worst that will happen is that the LEDs won't light.  However when laying out the LEDs be sure not to allow any slave wire to touch any master wire.  That will cause a short and could fry our controller.

A rough diagram of how the first 6 LEDs wire up is shown in the second picture.

You can then wire the second group of 6 in exactly the same way.  Assuming that the board will be near the middle with LEDs 0 to 5 going one way and 6 to 11 going the other then it makes sense to wire both halves like this.  Use the wire from LED 6 as the "master" and 7, 9 and 11 as slaves.

However, because the "slave" lines from LED connection points 7, 9 and 11 connect to the same pins as those from 1, 3 and 5, you can use your existing slave wires if you like.  That's shown in the last diagram.

Step 5: Placng the LEDs

How and in which order you place the wires for the LEDs will depend to a good degree on how you are laying them out.  Assuming you have the board in the middle then I suggest running the master wire from LED0 to your furthest LED in one direction but taking it past the positions for the others on the way. 

The slave wire from LED1 then goes out to LEDs 0 and 1 (zero with +ve side to the master, LED1 with +ve side to the slave).  Slave from LED3 goes to lamps 2 and 3 (again +ve side to master is LED2) and the slave from LED5 goes to 4 and 5.  If you have stainless wire then a twist around the LED leg and a dab of solder works well.  A loop in the LED leg tied to with a knot would probably suffice for conductive thread.  So long as you don't short any wires you can test your connections at any time by turning the board back on.  Remember that they should flask alterntely so if you have two together that flash in sync then you probably have the polarity mixed up.

The second sequence on the chip lights the LEDs in a progressive wave so you can use this to check you have your LEDs in the correct order.

Step 6: Programing

If this was a kit then the chip would come pre-flashed with the required firmware.  However if you are making this from parts or want to hack it then you will need the programing parts.

First of all, lets fit the 90-degree pin headers for programing - just slip them in and solder.  As you see, there is just space to fit an iron past the battery holder.

As a programmer, all you need is an Arduino.  I will assume that's what you are using.

For using the Arduino as a programer, follow this 'ible - essentially, join + to 5V, - to Gnd, Rst to D10 and 5, 6, 7 to D11, D12 & D13.  The third picture shows the tiny board with the hookup jumpers added and the forth shows it hooked up to my nano, which lives on a breadboard surrounded by chaos.

By hooking up your 'Tiny as above, you can use your Arduino as an ISP to program the Tiny.  However, to use the Arduino IDE to program your ATtiny85, you need two additional things - the ArduinoISP sketch for your Arduino and core files for your 'Tiny.

The correct Arduino ISP sketch should be available in the Examples menu on the Arduino IDE.  Upload that to your Arduino and put a 10uf capacitor from reset to +5v to disable auto-reset.

To complie for the ATtiny85, you need the appropriate core files.  The best I have tried are at the Tiny Arduino page.  Download from that page and follow the instructions included in the distribution to put the correct files into your "hardware" folder.  When you restart the IDE you will have ATtiny85 - 8Mhz Internal as a board option.  This will use the Arduino ISP as the default programmer so you are ready to rock!

Step 7: Code

I have attached the Arduino "pde" source code file below in the form suitable for use on the ATtiny85.

If you want to use it on a 16 MHz Arduino then simply change the "Loop" constant at the top to 128 in place of 8.  This constant simply makes the code repeat everything a certain number of times.  We are running our ATtiny at 8 MHz but I think the internal clock divider must be set by default because it behaves as if it's running at 1MHz.


To get a suitable speed, multiply this Loop constant up by the speed of your clock (e.g. make it 64 for a '328 running on the internal 8MHz oscillator) etc.  Make sure it's always a multipe of 8 or the code is likely to have trouble.

The attached code is pretty simple and has only 4 modes:

1 - Odd & Even alternating
2 - scanner clockwise
3 - scanner anti-clockwise
4 - "Larsen" type alternating scanner.

You could easily add many more modes and this core code only takes around 1.6K, so you have another 6K+ to play with.

The same code should compile perfectly well for an Arduino without amendment.  On an Arduino, PB0 to PB4 are digital "pins" 8 to 12 respectively.  That is pins 14 to 18 on the actual ATmega328 or '168 chip.  This is quite useful for testing or if you are coding while you wait for parts to arrive.

This is my code:


// Test sketch
// Turn on each LED in turn
// MIT License
// Ugi 2012

// This is to be my standard multiplier so that I can tweak the sketch for different timing and clock speeds.  128 for Arduino
// Make it a multiple of 8!

const unsigned int Loop=8;

// Pins 8 to 12 map to the relevant bits of PORTB on the '328.  Since we will use direct PORTB commands this should work on '328 and ATtiny85

// This uses PORTB direct access - that's pins D0 to D4 on Tiny Arduino or D8 to D12 on normal Arduino
// First set is current pin layout.
// Second set is old version:
//
// Current version:
byte DirMatrix[12]={B10001, B10001, B10010, B10010, B10100, B10100, B01001, B01001, B01010, B01010, B01100, B01100}; // Which pins are output and which are high impedence
byte PolMatrix[12]={B10000, B00001, B10000, B00010, B10000, B00100, B01000, B00001, B01000, B00010, B01000, B00100}; // Which pin is high and which is low for each LED
//
// Old version:                     
//byte DirMatrix[12]={B00110, B00110, B01010, B01010, B10010, B10010, B00101, B00101, B01001, B01001, B10001, B10001}; // Which pins are output and which are high impedence
//byte PolMatrix[12]={B00010, B00100, B00010, B01000, B00010, B10000, B00001, B00100, B00001, B01000, B00001, B10000}; // Which pin is high and which is low for each LED

byte Mode=0; // numbered from zero
const byte MaxModes = 4; // Actual number of modes (so 1 if only Mode 0 defined). If greater than 12 will need to amend ChangeMode()
boolean SwitchMode=false;
boolean ButtonPress=false; // This may now be redundant.

void setup(){

//Serial.begin(9600); // There are some debugging Serial commands remaining but commented out.  They work on Ardu' but not tiny85
//Serial.println("tiny85 test");
//Serial.println("Ugi 2012");


DDRB&=B11100000; // set all pins to high impedence 

}

void loop(){
  switch (Mode){
    case 0:
      OddEvenFlash();
      break;
    case 1:
      Progressive(8,0);
      break;
    case 2:
      Progressive(8,1);
break;
    case 3:
      Larsen(8);
break;
  }
  if (SwitchMode) {SwitchMode=false; ChangeMode();} 

}

// This is the central routine that lights an LED.
// Just takes the LED number (0 to 11)
// uses direct port access for ease and speed
void LightLED(byte LEDno){
  DDRB&=B11100000;  // Set all pins input
  PORTB&=B11100000; // Set all pins low
  PORTB|=PolMatrix[LEDno]; // Set relevant pins high & low
  DDRB|=DirMatrix[LEDno]; // set two relevant pins to output
}

// Checks the status of the button.
// Don't call it too often 'cos it wastes time.
boolean CheckButton(){
  DDRB&=B11100000;  // Set all pins input
  PORTB&=B11100000; // Set all pins low
  PORTB|=B00000100; // Set PB2 high - set internal pullup
  delayMicroseconds(100); // Need to allow to settle Increase if trouble with button press
  //Serial.println(PINB&B00000100);
  volatile boolean press = PINB&B00000100;
  if(!press){ // if pulled down by switch
   while (!press){ // wait until switch released
    //Serial.print("debounce ");Serial.println(PINB&B00000100);
    delay(20);
    press = PINB&B00000100;
   }
   return true;
  }
  return false;
}

// Advances the "Mode" variable.
void ChangeMode(){
Mode++;
if(Mode>=MaxModes) Mode=0;
   //Serial.println(Mode);
   for(byte flash=0; flash<=Mode; flash++){
    LightLED(Mode);
    delay(5);
    DDRB&=B11100000;
    delay(15);
   }
}

// Mode functions defined below....

// OddEvenFlash - designed as the default function.  This flashes odd and even LED alternately.
// Should be useful for debugging the hardware as well as looking OK.
void OddEvenFlash(){
  const unsigned int Timer=300;
  ButtonPress=0;
  boolean Odd=false;
   while(!ButtonPress){
     for(int unsigned time=0; time<(Loop*Timer); time++){
       for (byte LED=0; LED<12; LED+=2){
        LightLED(LED+Odd);
       }
     }
     Odd=!Odd;
     SwitchMode=CheckButton();
     if (SwitchMode){
      //Serial.println("SwitchMode set");
      return;
     }
  }
}


// Progressive Looping
// Sends an "eye" of 4 LEDs around the loop by fading in and out sequentially.
// Second function - again to aid hardware debugging & also looks cool!

void Progressive(byte Increment, boolean Reverse){
byte EyePos[4]={3,2,1,0};
  if (Reverse){
   EyePos[0]=8;
   EyePos[1]=9;
   EyePos[2]=10;
   EyePos[3]=11;
  }
byte EyeInt[4]={64,192,(192-Increment),(64-Increment)};
while(!ButtonPress){
  for (byte Speed=0; Speed<Loop; Speed+=8){ // This should equalise speed for clock freq
   for (byte Pos=0; Pos<4; Pos++){ // light 4 LEDs according to their brightness
    LightLED(EyePos[Pos]);
    //Serial.print(EyePos[Pos], DEC);Serial.print("=");Serial.print(EyeInt[Pos],DEC);Serial.print("  ");
    byte Scrap;
    for (byte Count=0; Count<EyeInt[Pos]; Count++){PORTB&=B11111111;}
   }
   //Serial.println("");

  EyeInt[0]+=Increment;
  EyeInt[1]+=Increment;
  EyeInt[2]-=Increment;
  EyeInt[3]-=Increment;

if(EyeInt[3]<Increment){
  EyeInt[3]=EyeInt[2];
  EyeInt[2]=EyeInt[1];
  EyeInt[1]=EyeInt[0];
  EyeInt[0]=0;
  EyePos[3]=EyePos[2];
  EyePos[2]=EyePos[1];
  EyePos[1]=EyePos[0];

  if(Reverse){
    EyePos[0]--;
    if (EyePos[0]>200){EyePos[0]=11;}
  }
  else{
    EyePos[0]++;
    if (EyePos[0]>11){EyePos[0]=0;}
  }
  SwitchMode=CheckButton();
  if(SwitchMode) {return;}
}

}
}

// Larsen scanner type wave
// Might be able to do this as part of progressive.  I couldn't make it efficient.
void Larsen(byte Increment){
byte EyePos[4]={3,2,1,0};
byte EyeInt[4]={64,192,(192-Increment),(64-Increment)};
boolean Reverse = false;
while(!ButtonPress){
  for (byte Speed=0; Speed<Loop; Speed+=8){ // This should equalise speed for clock freq
   for (byte Pos=0; Pos<4; Pos++){ // light 4 LEDs according to their brightness
    LightLED(EyePos[Pos]);
    //Serial.print(EyePos[Pos], DEC);Serial.print("=");Serial.print(EyeInt[Pos],DEC);Serial.print("  ");
    for (byte Count=0; Count<EyeInt[Pos]; Count++){PORTB&=B11111111;} // hold the LED lit for a time depending upon Eye Intensity
   }
   //Serial.println("");
  }
  EyeInt[0]+=Increment;
  EyeInt[1]+=Increment;
  EyeInt[2]-=Increment;
  EyeInt[3]-=Increment;

if(EyeInt[3]<Increment){
  EyeInt[3]=EyeInt[2];
  EyeInt[2]=EyeInt[1];
  EyeInt[1]=EyeInt[0];
  EyeInt[0]=0;
  EyePos[3]=EyePos[2];
  EyePos[2]=EyePos[1];
  EyePos[1]=EyePos[0];

  if(Reverse){
    EyePos[0]--;
    if (EyePos[0]>200){EyePos[0]=1; Reverse = false;}
  }
  else{
    EyePos[0]++;
    if (EyePos[0]>11){EyePos[0]=10; Reverse = true;}
  }
SwitchMode=CheckButton();
if(SwitchMode) {return;}
}

}

Step 8: Afterword

Attached to this step is the Eagle Schematic and board file for any keen folk who fancy having them Fab'ed.  This is the final version as described throughout this 'ible.  I have not had these made by the prototype worked well, as you can see from the video.  This version should be programable without removing any of the LEDs.

As a rough guide to the cost:


£0.30 1 CR2032 Coin Cell
£0.60 1 CR2032 Coin Cell Holder
£1.30 1 ATtiny85 AVR microprossor (preprogrammed)
£0.20 1 Sliding Power Switch
£0.10 1 Tactile Mode Switch
£0.50 1 PCB (assuming 8 on an 80*100mm board)
£2.00 5M conductive thread (more expensive option)
£0.65 12 Ultra-bright LEDs

Total £5.65 all in.

Prices based upon e-bay suppliers getting up to 10 boards worth, except for PCB which is based on 80 boards.  The conductive thread and the battery holder have clear scope for bulk discount!

Overall, I think this is a cute minature microprocessor kit suitable for beginners or those wanting to move from Arduino to stand-alone boards.  Its minimal soldering and low parts count makes it cheap and quick to make.