Sunday, February 28, 2010

The Amazing Dr Boardman's Colour Conundrum

"Roll up! Roll up! Try your hand at The Amazing Dr Boardman's Colour Conundrum!"





This is a little game I've been planning on making for quite some time. I finally got round to learning the necessary microcontroller details to pull it together. The basic idea is that that there are two, full colour 'bulbs'. One bulb lights up with a random color and the player tries to match this color by adjusting the RGB values of the second bulb (the bulbs are actually RGB LEDs with ping-pong ball diffusers). When the colors are similar enough then the player 'wins'.

This was quite hard to do for the younger kids, so I added a speaker to the mix & set it so that the sound frequency increased the closer the player got to the correct colour. It's still pretty hard, even with the speaker on.

I added a difficulty switch so that the daring/cocky can turn the speaker off.

Here's a little video of it in action. My 5 year old daughter kindly agreed to walk us through it.





How it was put together

Ingredients:


  • 3 potentiometers (20K ohm - but the absolute value isn't very important)
  • 3 knobs for the potentiometers
  • 8 ohm speaker
  • wooden box (I found this one at Savers)
  • perf board
  • 2 baby food jars
  • 2 ping-pong balls
  • 28 pin DIP socket
  • ATmega8
  • 2 RGB LEDs (common anode)
  • 2 toggle switches (for power and speaker on/off)
  • hook-up wire
Methods

First off drill holes in the ping pong balls, the box and in the baby food lids. Obviously, the size of the holes will depend on what you want to put through them so you'll have to work this out yourselves). Here's the layout I used:


There are 3 holes in a row for the potentiometers, two holes for the LEDs, one hole in the middle for the difficulty switch and one on the side for the power switch.

Next up is to solder leads to the pots. I used speaker hookup cable for the +ve and GND connections and then soldered 3 different coloured wires to the center terminals (I would have used blue instead of black, but I don't have any blue wire). These are going to control the red, green and blue levels of the 'player' RGB LED.


I sanded the LED lenses to make them diffused (I could have just bought diffused lenses... doh!) and then soldered the leads in place. I used some speaker cable again here too to keep things simple (and some heat shrink tubing to prevent shorts).



Then solder the DIP socket onto the perf board. Add the potentiometer leds and the power supply. All the wires were cut to be a little generous in length - I wasn't sure how everything was going to fit so I figured I'd play it safe and allow for wiggle room in the box.

I used one of the IC perfboards because I figured having the central Vcc and GND rails would make life easier as well as the already connected pads around each pin of the uC.



Attach the LEDs to the board:


Then add the speaker and difficulty switch (this just connects/disconnects the speaker from GND rather than being directly controlled by the microcontroller) and test the set-up for shorts, cold solder joints etc.

The LEDs are poked through the holes in the box without the ping-pong balls on (no surprise there). I had them on in the above photos to see how well they worked.

Place everything into the case and hot glue it all securely - I glued the switches and the LEDs in place.

I positioned the uC within easy reach so that I can tweak the software and update easily. Next time I think I'll just add programming headers to the board.



If you're very lucky then you're either artistically gifted or you have a talented partner in crime who can make your project look a hell of a lot better. Lin (my lovely lady and the hostess of filthwizardry.com) had the fabulous idea of creating a Coney Island theme for this game. I take no credit for how good it looks, that was all down to Lin. I think I was going to put it in some old Tea box and leave it at that. Thanks, hon! She was also responsible for the game name. I'm far too British to call myself amazing. Oh, and the American spelling of colour she claims was for symmetry purposes.



I drilled a few holes in the back to increase the apparent volume of the speaker. Also, it took me a while to work out how to keep the lid/base on the box (there were no fasteners built in, the lid was meant to be kept on by gravity). I'd almost given up and was going to attack it with nails when I realised I could simply drill some holes in a couple of washers and screw them into the base... I'm stupidly proud of that little idea. Ah, the little things...



Software

The code is available here on github.com.

The output from each potentiometer is read via ADC. These values are used as the 'player' RGB values and are compared with the 'game' RGB values. I started off using the euclidean distance of the RGB vectors as the difference metric, but - with kid friendly values - it meant that you could sometimes match red to green (and green to blue etc.). I ended up requiring each colour be within a defined distance for a successful match.

When a match is detected we turn off interrupts, flash the LEDs and modulate the speaker sound. Then switch interrupts back on and assign a new colour to the system RGB LED.

It uses double buffered software PWM for the LEDs and standard PWM for the speaker.

The only other trick is that the random seed is stored in EEPROM and incremented each time the uC is booted up. The incremented seed is fed to srand and from there we just use the rand() function. This way the game sequence is different each time (well, different for 256 games in a row anyway).
#include <avr/eeprom.h>
/*
 * Use a variable stored in EEPROM to ensure the random color
 * sequence changes from one game to the next.
 */
void initRand()
{
    uint8_t vSeed = eeprom_read_word(0); // load last stored seed
    srand(++vSeed); // increment and use value as seed
    eeprom_write_word(0, vSeed); //store the new seed for next time
}

Saturday, February 27, 2010

CharliePlexed LEDs

There are quite a few things I've wanted to try out and post about as I've been learning them (it seems like a good way to remember them!). For example, I have a half-written post on AVR ADC (analogue to digital converter - for reading inputs like potentiometers and light dependent resistors), one on using pulse width modulation (PWM), one on using LEDs as light sensors...etc, etc. well, so I don't always get round to finishing what I've started. I'm not sure those posts would even be popular and I've concentrated on real/physical/entertaining projects instead. Of course now I have a load of half written posts for almost finished projects... aaaaannyway, onto the point.

I've heard a lot about charlieplexing since starting out on the electronics adventure & the idea of controlling lots of LEDs from only a few microcontroller pins is very appealing. I've been wanting to make some interesting ways to play with the glow-in-the-dark wall and this has lead me to my first practical use for charlieplexing. I thought that a controllable row of LEDs would open up a lot of possibilities: scan back and forth for a sine wave; all LEDs on for caligraphy; random flash for making star-scapes; POV style message writing; printing patterns - hearts, smileys etc.

So, the problem is that with an ATtiny, if you don't want to mess with the reset pin, you only have 5 I/O pins available. I want to use two pins as input - a potentiometer and a push button. This would leave me 3 pins for controllign LEDs... not much to play with really. That's where charlieplexing comes in. I can control 6 LEDs using these 3 uC pins.

The wikipedia article on charlieplexing is pretty good, so I won't repeat what's already been said. Take a look at the tri-state logic part to see what's going on here. There are a load of Instructables which cover charlieplexing - this one on the theory is worth a read.

In the code below the LEDs are numbered slightly differently than exactly the same as in the wikipedia diagram (I just soldered up a prototype and the wiring is much easier to route with the wikipedia numbering). The trick is that we switch two pins to output and one as a high-impedance input (this is the 'floating' pin that is effectively taken out of consideration). One input is set high (+Vcc) and one is low (0v). Current is sourced by the +Vcc output pin and sunk by the 0v output pin. So, for each LED we have different data direction (DDRxn) and port (PORTxn) register settings.

In order to control the 6 LEDs in the diagram above we use the following settings:

LEDPIN1PIN2PIN3
1+Vcc0vInput
20v+VccInput
3Input+Vcc0v
4Input0v+Vcc
50vInput+Vcc
6+VccInput0v

The code below is just an initial test set-up where we activate LEDs in a scanning pattern (classic 'cylon eye'). It has all the basics necessary to implement the more complex behaviours. Having the structure array hold the PORTB and DDRB values makes controlling individual LEDs very easy. I'm hoping this will scale up to allowing PWM, but I haven't put much thought into that yet.

Hopefully I'll get a chance to make the UV LED gizmo this week and post about the results.

You can download the source-code from github or use the cut and paste options in the top right of the code box below.

/*
* charlieplex_test.c
*
* Running on an ATtiny45.
*
* Here we control 6 LEDs through 3 pins (PB0:2).
*
* In order to illuminate each LED we do the following:
*
* LED1 - PB0 & 2 output PB2 input. PB0 sourcing, PB1 sinking. Pull-up on PB2
* LED2 - PB0 & 2 output PB2 input. PB1 sourcing, PB0 sinking. Pull-up on PB2
* LED3 - PB1 & 3 output PB0 input. PB1 sourcing, PB2 sinking. Pull-up on PB0
* LED4 - PB1 & 3 output PB0 input. PB2 sourcing, PB1 sinking. Pull-up on PB0
* LED5 - PB0 & 3 output PB1 input. PB0 sourcing, PB2 sinking. Pull-up on PB1
* LED6 - PB0 & 3 output PB1 input. PB2 sourcing, PB0 sinking. Pull-up on PB2
*
* This little ASCII diagram shows the wiring and orientation of the 6 LEDs.
* The hyphens ('-') identify the cathode pins of the LEDs.
*
* PB0 ----------------------
*        |   -      |      |
*        1   2      |      |
*        -   |      |      -
* PB1 --------      5      6
*        |   -      -      |
*        3   4      |      |
*        -   |      |      |
* PB2 ----------------------
*
* Only a single LED can be illuminated at any point in time.
*
* Distributed under Creative Commons 3.0 -- Attib & Share Alike
*
*  Created on: Feb 27, 2010
*      Author: PaulBo
*/
#include <avr/io.h>
#include <util/delay.h>

#ifndef F_CPU
#define F_CPU 1000000UL
#endif

#define DELAY_TIME 50
#define N_LED 6

// see class comments for pin setting explanation
// unused pins are set to input with pull-up resistors activated
struct leds {
uint8_t mDdrB;
uint8_t mPortB;
} ledData[] = {
{0b00011011, 0b11100101},
{0b00011011, 0b11100110},
{0b00011110, 0b11100011},
{0b00011110, 0b11100101},
{0b00011101, 0b11100011},
{0b00011101, 0b11100110}
};

int main()
{
uint8_t i;
for(;;)
{
for(i = 0; i < N_LED - 1; i++)
{
DDRB = ledData[i].mDdrB;
PORTB = ledData[i].mPortB;
_delay_ms(DELAY_TIME);
}
for(i = N_LED - 1;i > 0; i--)
{
DDRB = ledData[i].mDdrB;
PORTB = ledData[i].mPortB;
_delay_ms(DELAY_TIME);
}
}
}

Sunday, February 7, 2010

RGB Night-lights


My kids love lights; flashlights, LEDs, house lights, pen-lights, light-up teddy bears, the northern lights... you name it, they love it. I've been playing around with RGB LEDs for another project along with ping-pong ball diffusers and baby jar containers. It occurred to me that I could make a simple night-light with most of the same components & the girls were bound love 'em.

I put it all together on Saturday evening after the girls were in bed. I think I'm getting better at all this as I had the code working and 2 lights put together by midnight. The girls found them in the morning (unfortunately, very early...) and came into our bedroom to play with them. First off, they played some kind of colour matching game where they were shouting (yes, shouting, early, in bed...) "RED! I'm wearing red!", "Blue! My socks are blue!". After a bit of this they moved into their bedroom to make a 'tent' out of a couple of chairs and a duvet (comforter). They played with the lights in there for a while; I'm not sure what they were doing as I was drifting in and out of consciousness.

It's Sunday and I've just put the kids to bed. They wanted to go to bed with their lights right next to them. I declare them a success!


I apologise for the quality of this video. It was taken on an iPhone and I've not been able to get hold of them again to take a proper vid. I'm sure you get the idea though.



Ingredients:



  • ATtiny13
  • RGB LED (common anode)
  • 8 pin DIP socket
  • switch (the ones I used were SPDT)
  • coin cell battery holder
  • coin cell battery
  • baby jar
  • hookup wire (I used stranded 24 AWG).
  • ping pong ball
  • neodymium magnet
I used the magnet to attach everything to the lid of the baby jar. I've not had much luck with hot-glue and lids (metal ones), so I figured this should work better. I decided to put this together free-form (i.e. no perfboard), mainly for space reasons - but also as I like the aesthetics of the free-form projects (like this advent wreath or this programmable led).

First off I realised that the DIP socket would fit nicely onto the side of my coin cell holders:



Then I added the neodymium magnet to the center of the holder:



This was actually a bad idea... these things are very strong and everything you're playing with at this point has some kind of ferrous metal involved. This thing attracted the soldering iron, the solder, cut off leads, pliers, the helping hand... If I do this again, I'd definitely wait until the end to attach the magnets.

Next step was to solder on the RGB LED:



You may notice that the socket has changed orientation. I was planning on attaching wire to the leads of the LED so that it'd be easily positionable. Then I realised that, since I only had a tiny amount of room in the jar, I could leave the LEDs leads in place and bend them to put the LED into the correct position. That meant re-orientating the DIP socket (as seen above).

The LEDs common anode has not been attached at this point. I added some heat-shrink tubing to this lead to insulate it from the others. It has to be bent forward and could easily touch one of the adjacent leads.

Also, I sanded the LED casing to diffuse the light. Without this step there are obvious areas of red/green/blue that shine on the ping pong ball from the LED.

Now all that's left is the final bit of wiring:





I attached the switch to Vcc and added a ground wire from the battery holder to the DIP socket. The wire is bent around the magnet and was, er... "fun" to solder in place. The soldering iron kept 'pinging' onto the magnet just as I was getting into position... like I said before, put the magnet on last!

I decided to house the lights in baby food jars. The only modification was to cut some holes for my switches (I used a Proxxon rotary tool for this).

Here's a few shots of them in working order:


Code:

I'm running the ATtiny at 8MHz. This requires setting the fuse bits because the default setting is to divide the clock by 8. This code uses the same software PWM as the firefly-jar-II I wrote about previously. No other tricks here, other than a hack (in the main method) to increase the duration of the RedToYellow transition. That's just personal taste though & (since I'm fickle) I may remove that section in the future.

Current code is available on github. Here's the code that's running in my kids bedroom at the time of posting:

/*
 * rgb_strobe.c
 *
 * Distributed under Creative Commons 3.0 -- Attib & Share Alike
 *
 *  Created on: Feb 6, 2010
 *      Author: PaulBo
 */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#ifndef F_CPU
    #define F_CPU 8000000UL
#endif

//Hardware definitions
#define RED_LED      PB2
#define GREEN_LED    PB1
#define BLUE_LED     PB0
#define ALL_LEDS    ((1 << RED_LED) | (1 << GREEN_LED) | (1 << BLUE_LED))

//Maximum value for led brightness
#define R_MAX 255
#define G_MAX 255
#define B_MAX 255

#define RED_INDEX   0
#define GREEN_INDEX 1
#define BLUE_INDEX  2

//Cycle States
#define RedToYellow     0
#define YellowToGreen   1
#define GreenToCyan     2
#define CyanToBlue      3
#define BlueToMagenta    4
#define MagentaToRed     5

//set red to max (we start in the RedToYellow state)
volatile unsigned char mRgbBuffer[] = {0,0,0};
unsigned char mRgbValues[] = {255,0,0};
unsigned char mState;

void init_timers()
{
    TIMSK0 = (1 << TOIE0);         // enable overflow interrupt
    TCCR0B = (1 << CS00);          // start timer, no prescale

    //enable interrupts
    sei();
}

void rgbCycle(){
    switch (mState) {
    case RedToYellow:
        mRgbValues[GREEN_INDEX]++;
        if (mRgbValues[GREEN_INDEX] == G_MAX)
            mState++;
        break;
    case YellowToGreen:
        mRgbValues[RED_INDEX]--;
        if (mRgbValues[RED_INDEX] == 0)
            mState++;
        break;
    case GreenToCyan:
        mRgbValues[BLUE_INDEX]++;
        if (mRgbValues[BLUE_INDEX] == B_MAX)
            mState++;
        break;
    case CyanToBlue:
        mRgbValues[GREEN_INDEX]--;
        if (mRgbValues[GREEN_INDEX] == 0)
            mState++;
        break;
    case BlueToMagenta:
        mRgbValues[RED_INDEX]++;
        if (mRgbValues[RED_INDEX] == R_MAX)
            mState++;
        break;
    case MagentaToRed:
        mRgbValues[BLUE_INDEX]--;
        if (mRgbValues[BLUE_INDEX] == 0)
            mState++;
        break;
    }

    //state should never advance beyond 5.
    //It wraps back to 0 when we reach 6
    mState %= 6;
}

int main(void){
    //Set LED pins to output
    DDRB |= ALL_LEDS;

    init_timers();

    while (1) {
        rgbCycle();
        _delay_ms(250);

        //I like the orange state and it only lasts for a second
        //so lets extend it a little bit more
        if(mState == RedToYellow)
        {
            _delay_ms(250);
            _delay_ms(250);
        }
    }
    return 0;
}

/*
 * Timer/Counter overflow interrupt. This is called each time
 * the counter overflows (255 counts/cycles).
 */
ISR(TIM0_OVF_vect)
{
    //static variables maintain state from one call to the next
    static unsigned char sPortBmask = ALL_LEDS;
    static unsigned char sCounter = 255;

    //set port pins straight away (no waiting for processing)
    PORTB = sPortBmask;

    //this counter will overflow back to 0 after reaching 255.
    //So we end up adjusting the LED states for every 256 interrupts/overflows.
    if(++sCounter == 0)
    {
        mRgbBuffer[RED_INDEX] = mRgbValues[RED_INDEX];
        mRgbBuffer[GREEN_INDEX] = mRgbValues[GREEN_INDEX];
        mRgbBuffer[BLUE_INDEX] = mRgbValues[BLUE_INDEX];

        //set all pins to low (remember this is a common anode LED)
        sPortBmask &=~ ALL_LEDS;
    }
    //this loop is considered for every overflow interrupt.
    //this is the software PWM.
    if(mRgbBuffer[RED_INDEX]   == sCounter) sPortBmask |= (1 << RED_LED);
    if(mRgbBuffer[GREEN_INDEX] == sCounter) sPortBmask |= (1 << GREEN_LED);
    if(mRgbBuffer[BLUE_INDEX]  == sCounter) sPortBmask |= (1 << BLUE_LED);
}

Tuesday, February 2, 2010

Jar-O-Fireflies (Mark II)


I really enjoyed the process of making my first 'Jar-O-Fireflies' but I was a little disappointed with the performance (i.e. the software), especially the obvious flicker when the lights were pulsing on and off. I've learned a lot more about how to program the AVR uCs over the last few months (but still just the basics really). So, I decided to re-write the software and make a smaller, battery powered, version. I'm going to make another and put it in an empty Nuttela jar for the girls to use as a night light (I'm sure the girls will help me empty the jar).

The software took a little while to sort out but the hardware, on the other hand, only took about 2 hours to put together. Most of that was due to the fiddlyness of using magnet wire for the LED leads.

Below is a little video of it working. Yes, we have 'pet' ants at the moment - at least it was interested in what was going on...



The parts:
  • some magnet wire
  • coin cell holder (and coin cell to go with it)
  • perf board - I used a board with a semi breadboard layout (see picture below), but it wasn't much more help than a standard one other than having a common power and ground rail to connect everything to.
  • switch (one that fits onto a PCB/perf board)
  • 8-pin dip
  • 5 green LEDs (3mm)
  • ATtiny13

This is the layout I used (for the battery holder, DIP socket and switch):



The trickiest part was soldering the magnet wire onto the LEDs. I used a third-hand to hold all the pieces together. It helps that the magnet wire is quite stiff and bendable even though it's thin.


As you can see from the photo. After soldering on the wire I twisted the two strands together. After doing the 5 LEDs I realised that it'd be really nice to have 2 different colours of wire so that the positive and negative leads were obvious... oops. I ended up testing each pair of wires with my LED tester to determine which lead was positive and which was negative.

Then it's was just a matter of soldering on the LED leads to the board:


Then I glued everything onto the jar lid (using a hot glue gun):



Et voila!



Code
:

I've just started using code.google.com as a code repository. The google site supports subversion source control (and there's a good plug-in for eclipse called subversive). I'd been going back and forth between computers and it was turning into quite a headache trying to get the code in sync. Now I can just push and pull from the code repository.

Here's the location of the firefly code:
http://code.google.com/p/pboardman-avr/source/browse/firefly_jar/firefly_jar.c

Google code is no-more.  I've moved all the code to github.

https://github.com/paulboardman/avr/blob/master/firefly_jar/firefly_jar.c

This may change in the future as I tinker a bit more, so I'm including below the version of the code that was running when I wrote this post. This version required setting the fuse bits for the ATtiny13 to make it run at 8MHz. I also wrote a better software PWM routine (see the Atmel technote: "Low-Jitter Multi Channel Software PWM". Warning: PDF link).

There are a few enhancements that I have in mind like actually using a random number generator for generating random numbers... The reason I didn't was that I had trouble coming up with a method for generating a seed (without a differing seed, the pseudo random number generator would give the same sequence each time the AVR was switched on). My latest project (post forthcoming) saves the seed in EEPROM and increments it each time the AVR is booted up - this way the random number generator produces a different sequence each time. Anyway, here's the code:

/*
 * firefly_jar.c
 *
 * Distributed under Creative Commons 3.0 -- Attib & Share Alike
 *
 *  Created on: Feb 2, 2010
 *      Author: PaulBo
 */
#import <util/delay.h>
#import <avr/io.h>
#import <avr/interrupt.h>

#ifndef F_CPU
    #define F_CPU 8000000UL
#endif

//LED pin definitions
#define LED1    PB0
#define LED2    PB1
#define LED3    PB2
#define LED4    PB3
#define LED5    PB4
#define N_LEDS  5
#define ALL_LEDS (1 << LED1) | (1 << LED2) | (1 << LED3) | (1 << LED4) | (1 << LED5)

//Max value for LED brightness
#define MAX     100

#define PULSE_UP   1
#define PULSE_DOWN 0

volatile unsigned char buffer[N_LEDS];

//counter for use in updateLedState() and pulseLeds()
unsigned char i;

//structure for storing data on each LED
struct ledData {
    unsigned char mBrightness;
    unsigned int  mTime;
    unsigned char mPin;
    unsigned char mPulseDirection;
};

//set up some initial values
struct ledData led_data[] = {
        {0, 1000,  LED1, PULSE_DOWN},
        {0, 10, LED2, PULSE_DOWN},
        {0, 500, LED3, PULSE_DOWN},
        {0, 50, LED4, PULSE_DOWN},
        {0, 150,  LED5, PULSE_DOWN}
};

//return a random time interval from 0 to 255
int getTime()
{
    return TCNT0;//just read the current timer/counter value
}

void updateLedState()
{
    for(i = 0; i < N_LEDS; i++)
    {
        switch(led_data[i].mBrightness)
        {
            case MAX://led is on
                if(--led_data[i].mTime == 0)
                {
                    //decrement the brightness, this puts the LED in a
                    //pulse state
                    led_data[i].mBrightness--;

                    //specify the "down" direction for pulsing
                    led_data[i].mPulseDirection = PULSE_DOWN;
                }
                break;
            case 0://led is off
                if(--led_data[i].mTime == 0)
                {
                    //increment the brightness,this puts the LED in
                    //a pulse state
                    led_data[i].mBrightness++;

                    //specify the "up" direction for pulsing
                    led_data[i].mPulseDirection = PULSE_UP;

                    //set the ON time
                    led_data[i].mTime = getTime() + 1;
                }
                break;
            default: //pulse state
                if(led_data[i].mPulseDirection == PULSE_UP)
                {
                    led_data[i].mBrightness++;
                }
                else
                {
                    if(--led_data[i].mBrightness == 0)
                    {
                        //set the OFF time - make this longer than the on time
                        led_data[i].mTime = (getTime() + 1) * 5;
                    }
                }
                break;
        }
    }
}

void init_timers()
{
    TIMSK0 = (1 << TOIE0);         // enable overflow interrupt
    TCCR0B = (1 << CS00);          // start timer, no prescale

    //enable interrupts
    sei();
}

void init_io()
{
    //set all LED pins as outputs
    DDRB |= ALL_LEDS;
    PORTB &= ~(ALL_LEDS); //off to start
}

void setup()
 {
    init_io();
    init_timers();
}

int main(void)
{
    setup();

    //infinite loop
    while(1)
    {
        updateLedState();
        _delay_ms(10);
    }
}

/*
 * Timer/Counter overflow interrupt. This is called each time
 * the counter overflows (255 counts/cycles).
 */
ISR(TIM0_OVF_vect)
{
    //static variables maintain state from one call to the next
    static unsigned char sPortBmask = ALL_LEDS;
    static unsigned char sCounter = 255;

    //set port pins straight away (no waiting for processing)
    PORTB = sPortBmask;

    //this counter will overflow back to 0 after reaching 255.
    //So we end up adjusting the LED states for every 256 overflows.
    if(++sCounter == 0)
    {
        for(i = 0; i < N_LEDS; i++)
        {
            buffer[i] = led_data[i].mBrightness;
        }
        //set all pins to high
        sPortBmask = ALL_LEDS;
    }
    //this loop is considered for every overflow interrupt.
    //this is the software PWM.
    if(buffer[0] == sCounter) sPortBmask &= ~(1 << led_data[0].mPin);
    if(buffer[1] == sCounter) sPortBmask &= ~(1 << led_data[1].mPin);
    if(buffer[2] == sCounter) sPortBmask &= ~(1 << led_data[2].mPin);
    if(buffer[3] == sCounter) sPortBmask &= ~(1 << led_data[3].mPin);
    if(buffer[4] == sCounter) sPortBmask &= ~(1 << led_data[4].mPin);
}