Sorry, your browser does not support JavaScript! What in the world are you trying to view it with?!!! Header

Christmas Lights

2014-03-20 15:48:22

How many is enough?

2014-03-21 00:57:53

I've always liked watched the Christmas lights on YouTube synced to music. Looking into it the systems controlling most of them are quite expensive. I've just started learning microprocessors so decided to give it a go myself! Good chance to pick up some new skills.

BigW ended up having the cheapest lights, I scored myself 14 sets of 200.

I could design a power supply and control systems but why when it's already right there? Let's crack those cases open and see what's inside! Into the vice!

Image

The glue easily gives way and we get to peak at the inside.

Image

The top half converts AC to DC, the bottom half control the 2 transistors we are interested on the bottom right with the IC sticking through the board on the bottom left.

Image

All wired up! Blue for earth and red and green to the gates on the transistors powering the leds. I didn't show it in these photo but I also cut the tracers between the gates and the IC outputs.

Image

Nice and safe! Everything we need to control the lights. Now to do the rest!!!

Image

Prototype 0.01

2014-03-21 03:23:45

Ahh breadboards and the nightmares you create...
I purchased a kit from Nerdkits.com which uses an ATmega168, to learn a little more I decided to take on this project. I have all the earth's connected to the earth on the breadboard and the gate wires connected to io pins.

The code I wrote uses an interrupt timer running at 128khz(If I'm working it out correctly), the function it triggers runs through 64 iterations, turning appropriate lights on for the first iteration, and turning them off at some percentage of the 64 loops representing the brightness percentage. It then resets and sets a new point in the 64 loops depending if the brightness is increasing or decreasing and how fast.

This way I could control each light individually each in there own type of "thread" while the program keeps running. So the basics of it, the more of those 65 loops its on, the brighter is is. ei on 90% of the time is brighter then on 20% of the time.

It works great! but the amount of space is too limiting to do any really interesting long light sequences

#define F_CPU 14745600
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <avr/delay.h>
#include <stdio.h>

//random macros i use to be lazy while testing ^_^
#define _ms(n) (17*n)
#define BTUP() (bit_is_clear(PINC,4))
#define BTDOWN() (bit_is_clear(PINC,5))
#define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define CLEARBIT(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
#define FLIPBIT(ADDRESS,BIT) (ADDRESS ^= (1<<BIT))
#define CHECKBIT(ADDRESS,BIT) (ADDRESS & (1<<BIT))
#define WRITEBIT(RADDRESS,RBIT,WADDRESS,WBIT) (CHECKBIT(RADDRESS,RBIT) ? SETBIT(WADDRESS,WBIT) : CLEARBIT(WADDRESS,WBIT))


//set pins on these which are written to ports
volatile unsigned char portb_write=0b00000000;
volatile unsigned char portc_write=0b00000000;
volatile unsigned char portd_write=0b00000000;

unsigned int const shades=64;  //resolution for brightness. ie for 64 it gives you brigtness levels from 1/64'th to 63/64'ths.
volatile unsigned int tick_count = 0; //interuupt has to loop though the number set in "shades" times to make one cycle. this keeps track of where you are.
volatile unsigned int active_count = 0; //when nothing is set to fade this makes the interrupt code smaller.
volatile unsigned int active_pwm_values[23];  //current ticks to stay on
volatile unsigned int active_pwm_updown[23];  //1= brighter fade up 0v to vss, 0= dimmer fade down vss to 0v
volatile unsigned int active_pwm_cycles[23];  //number of full cycles each pin has been through
volatile unsigned int active_pwm_cycles_per_tick[23]; //cycles at each brightness, rate of change/speed
volatile unsigned int b; //for loops
volatile unsigned int trig = 0; //me testing interrupts, can an interrupt get called a second time if its already running?

//function to setup fades, pin numbers 1-17. 1-5=PORTB pins 1-5. 6-11=PORTC pins 0-5. 12-17=PORTD pins 2-7
//at current settings speed of 1-5 is reasonable, cant be anything u like though....
//brighter, 1= get brighter, 0=get dimmer
//start, start value to fade up or down from ie "shades/2" would start from half brightness
void setfade(unsigned int pin, unsigned int speed, unsigned int brighter, unsigned int start) 
{
    active_pwm_values[pin] = start;
    active_pwm_cycles_per_tick[pin] = speed;
    active_pwm_updown[pin] = brighter;
    active_count++;
}

//The interuupt process!
ISR(SIG_OUTPUT_COMPARE1A)
{
//Turn  pins off when they are at there percentage through a cycle of shades
//turn them all back on at end of cycle, and increase/decrease brightness as appropriate. Check if they need to be removed.

  if (active_count != 0){ //save afew cycles if nothings happening
    //port B
    if (active_pwm_values[1] == tick_count){ //active_pwm_values needs to be checked either way, more efficent to disable pins by setting active_pwm_values to shades+1 outside normal range.
    portb_write &= ~(1<<1);
    }
    if (active_pwm_values[2] == tick_count){
    portb_write &= ~(1<<2);
    }
    if (active_pwm_values[3] == tick_count){
    portb_write &= ~(1<<3);
    }
    if (active_pwm_values[4] == tick_count){
    portb_write &= ~(1<<4);
    }
    if (active_pwm_values[5] == tick_count){
    portb_write &= ~(1<<5);
    }
    
    
    //Port C
    if (active_pwm_values[6] == tick_count){
    portc_write &= ~(1<<0);
    }
    if (active_pwm_values[7] == tick_count){
    portc_write &= ~(1<<1);
    }
    if (active_pwm_values[8] == tick_count){
    portc_write &= ~(1<<2);
    }
    if (active_pwm_values[9] == tick_count){
    portc_write &= ~(1<<3);
    }
    if (active_pwm_values[10] == tick_count){
    portc_write &= ~(1<<4);
    }
    if (active_pwm_values[11] == tick_count){
    portc_write &= ~(1<<5);
    }
    
    
    //Port D pins 2-7
    if (active_pwm_values[12] == tick_count){
    portd_write &= ~(1<<2);
    }
    if (active_pwm_values[13] == tick_count){
    portd_write &= ~(1<<3);
    }
    if (active_pwm_values[14] == tick_count){
    portd_write &= ~(1<<4);
    }
    if (active_pwm_values[15] == tick_count){
    portd_write &= ~(1<<5);
    }
    if (active_pwm_values[16] == tick_count){
    portd_write &= ~(1<<6);
    }
    if (active_pwm_values[17] == tick_count){
    portd_write &= ~(1<<7);
    }
    
    
    
    
    if (tick_count == shades) { //if at end up cycle
      tick_count=0;
      for(b=1;b!= 18; b++){                       // for every pin
        if (active_pwm_values[b] <= shades){            // with a brightness between 0 and shades
          if ((b > 5) && (b < 12)){                //turn fading pins back on to start a new cycle
            portc_write |= (1<<(b-6)); //port c pins 0-5
          }else if (b > 11){
            portd_write |= (1<<(b-10)); //port d pins 0-5
          }else{
            portb_write |= (1<<b); //port b  pin 1-5
          }
           active_pwm_cycles[b]++;                  //increase pins cycle count
          if (active_pwm_cycles[b] > active_pwm_cycles_per_tick[b]){ //check if need to increase/decrease brightness taking speed into account
            active_pwm_cycles[b] = 0;
             if(active_pwm_updown[b] == 0){
              active_pwm_values[b]--;              //decrease brightness
              if (active_pwm_values[b] == 0){          //if dimmer pin ends life turn pin back off and kill it
                active_pwm_values[b] = shades+1; 
                active_count--;
                if ((b > 5) && (b < 12)){
                  portc_write &= ~(1<<(b-6)); //port c pins 0-5
                }else if (b > 11){
                  portd_write &= ~(1<<(b-10)); //port d pins 0-5
                }else{
                  portb_write &= ~(1<<b); //port b  pin 1-5
                }
              }
             }else{ 
              active_pwm_values[b]++;           //increase brightness, this also pushes it to shades+1 which disables it
              if (active_pwm_values[b] > shades){      //if brighter pin ends life its already on just kill it
                active_count--;
              }
             }
          }
        }
      }
    }
    PORTB=portb_write;    //white values to ports
    PORTC=portc_write;
    PORTD=portd_write;
    tick_count++;      //count a tick for cycle!
  }

  return;
}

//setup pins
 void ioinit (void)
{
   DDRB  = 0b00111110; //1= output, 0 = input. 1-5 enable
   PORTB = 0b00000000; //Set PB pins to low
   DDRC  = 0b11111111; //1 = output, 0 = input. 0-5 enable
   PORTC = 0b00000000; //Set PC pins to low
   DDRD  = 0b11111100; //1= output, 0 = input. 2-7 enable
   PORTD = 0b00000000; //Set PD pins to low

}


int main(void)
{

  
  TIMSK1 = _BV(OCIE1A); //Enable Interrupt Timer/Counter 1,Output Compare A
  TCCR1B = _BV(CS10) | _BV(CS11) | _BV(WGM12); //Mode=CTC, 8mhz/64 = 125,000hz or 0.000008 seconds per tick
  OCR1A =8; // triggered interrupt every 0.000008*8 Seconds faster is smoother even with lower shade counts
  ioinit(); //setup pins function
  sei(); //turn interuupts on

//disable all pins by settings to shades+1 outside normal range.
  for(b=1;b!= 18; b++){ 
      active_pwm_values[b] = shades + 1;
      if ((random() % 3) > 1){ //set dimmer/brighter to a random value, was just using to test stuff
      active_pwm_updown[b] = 0;
      }else{
      active_pwm_updown[b] = 1;      
      }
  }

while (1){ //run forever
  
  for (b=1;b!=18; b++){
    setfade(b,1,1,1);
  }
  while(active_pwm_values[1] != shades+1){ //used as triggers to wait untill fade finishes
  }
  
  unsigned int c;
  unsigned int cc;
  unsigned int ccc;

    while(1){
    //random motion function on all pins
      for (b=1;b!=18; b++){
        if (active_pwm_values[b] == (shades+1)){  
          c =(rand() % 15) + 1;
          if ((b > 5) && (b < 12)){
            if (active_pwm_updown[(b-6)] == 1){
              ccc = 0;
              cc = shades-1;
            }else{
              ccc = 1;
              cc = 1;
            }
          }else if (b > 11){
            
            if (active_pwm_updown[(b-10)] == 1){
              ccc = 0;
              cc = shades-1;
            }else{
              ccc = 1;
              cc = 1;
            }
          }else{
            if (active_pwm_updown[(b)] == 1){
              ccc = 0;
              cc = shades-1;
            }else{
              ccc = 1;
              cc = 1;
            }
            
          }
          setfade(b,(c+1),ccc,cc);
        }
      }
      _delay_ms(1000);
    }
  }
}


Image

Now to put on a proto board!

2800 lights on a tree

2014-03-21 03:30:45

A bit of fun, all 14 sets of 200 lights on our little tree.

Who needs decorations?

Image

Revision 0.02

2014-03-21 03:32:45

After making this I'm not sure if it's better or worse then the breadboard, next year I'll look into making pcb's and buying a decent soldering iron! ;)

I've added 2 shift registers to have more output pins to this version! I now have 16 outputs to work with. Image

I think this will be the last time I try using these type boards, they have a place in the world but this isn't it.

Image

That time of year again!

2014-03-21 03:42:21

I was walking through BigW today and noticed they were starting to sell Christmas lights again! I couldn't stop the urge and ended up with 10 more sets, 6 small trees and a larger tree!

This time around I'm going to do a much better job of it, I've been playing with Teensy 3.0's which are hugely more powerful arm based chips with way more space. I'm also going to make it controllable over a serial wifi connection to program the lights from a PC. My aim is to use 4 shift registers giving me 32 outputs! And to make it more ambitious I'm going to try make my own PCB's, lot to learn!

I decided to learn eagle to make my circuit and board design, as it's free and has a large community of hobbies using it.

Image

There are many great video tutorials on YouTube, I picked it up in no time.

Image

For my first PCB though I'm going to make a small breakout board for the wifly chip I'm using. It has 2mm pitch on the pins which won't fit in a normal breadboard! So I'm going to space them out to 2.54mm

Image

PCB developing!

2014-03-21 04:25:48

The process is pretty simple, you create a png image from the board you design in eagle. Print that onto either transparencies or drafting wax paper which i used with preferable a laser printer.

Image

Next you need some pre sensitized PCB, I sourced mine from kinsten which I'd buy from again!
Put the printed circuit face down onto the PCB so the ink is touching it to get nice sharp edges as close to the board as possible.

Image



Now you need to expose this to UV light, I'm using a large UV LED from ebay powered with my lab power supply. It will depend on your setup, I did many tests of this board and found 140sec gave the best results

Image



Next you develop the photo resist, this removed the green coating that was exposed to UV. You want the copper to come out nice and shiny! It should start to come off after about 30sec.

Image



This was not the best example, there is still a green tinge on the board.

Image



Now the acid bath! The etchant should be heated to about 50-60C and be continuously agitated. Without these conditions, the reaction will take a lot longer and may undercut the copper around the resist.As the reaction progressed the solution turned a faint blue color. After about 6 minutes the copper not protected by the resist vanished, leaving the traces still covered in green acid resist. Once this looks finished, rinsing the board off in water stops the reaction.

Image



The last step is to remove the resist from our copper traces. An easy way to do this is to expose the board to UV for a couple of minutes and then dip it into the developer solution we used earlier. This final product!

Image



Well that was easy...

2014-03-21 04:26:45

My first PCB! I was very happy I got it first time. I went to drill out the holes on my mill but the drive belt snapped... Try using a hand drill and 0.8mm drillbits, fun times!

Image

There are 2 voltage regulators at the top right, one 5v powers the Teensy, shift registers and the other regulator which is 3.3 and powers the WiFly unit. There is a jumper that allows me to power the shift registers with 3.3v if I ever want to use this for other purposes. The cap's scattered about are to help stabilize power fluctuations. The resistors limit the current drawn from the shift registers.

Image

Yes I can actually solder now, the new Iron helps somewhat too ;) I haven't soldered all the pins on the WiFly so I can remove it for other projects.

Image

It works!!

2014-03-21 20:01:47

Got some code working, testing it out with the help of my trusty Oscilloscope!

/* LED Blink, Teensyduino Tutorial #1
http://www.pjrc.com/teensy/tutorial.html

This example code is in the public domain.
*/
#include<stdio.h>
#include <spi4teensy3.h>
#include <Arduino.h>
#include <sys/stat.h>


IntervalTimer myTimer;
char input_line[200]; //wifi serial buffer, fills untill new line
char c; //Serial1.read switch statments
const int slaveSelectPin = 10; //toggle pin for registers
static unsigned int input_pos = 0; //keep track of input_line current data
int timer; //set Seizure timer
int pos; // track location in buffer while reading
int tmpi; //tmp int
int LsetDetails[3]; //
byte registers[4]; //4 registers, 1 for each shift register
byte tmp; //store register while doing test flash
volatile bool notdisabled = true;

unsigned int shades=128;                          //resolution for brightness. ie for 64 it gives you brigtness levels from 1/64'th to 63/64'ths.
volatile unsigned int tick_count = 0;             //interuupt has to loop though the number set in "shades" times to make one cycle. this keeps track of where you are.
volatile unsigned int active_count = 0;           //when nothing is set to fade this makes the interrupt code smaller.
volatile unsigned int active_pwm_values[32];      //current ticks to stay on
volatile unsigned int pin_direction[32];          //1= brighter fade up 0v to vss, 0= dimmer fade down vss to 0v
volatile unsigned int pin_cycles[32];             //number of full cycles each pin has been through
volatile unsigned int pin_cycles_per_shade[32];   //cycles at each brightness, rate of change/speed
volatile unsigned int b;                          //for loops



void setup() {
  // initialize the digital pin as an output.
  Serial1.begin(19200);
  pinMode (slaveSelectPin, OUTPUT);
  digitalWrite(slaveSelectPin, HIGH); // ~CE is active LOW, so this disables shifting
  // initialize SPI:
  spi4teensy3::init(0,0,0); 
  b = 0;
  for(b=0;b!= 32; b++){                       
    active_pwm_values[b] = shades + 1;
  }
  myTimer.begin(seizure, 25);  // seizure to run... errr... very fast...
  registers[0] =  B00000000;
  registers[1] =  B00000000;
  registers[2] =  B00000000;
  registers[3] =  B00000000;
}

//pin is adress of arrays used in Seizure function
//speed = >0
//brigheter. 1 = up, 0 = down in brightness
//start brightness to start at 0 = off shades = fully on
void setfade(unsigned int pin, unsigned int speed, unsigned int brighter, unsigned int start)
{
  active_pwm_values[pin] = start;
  pin_cycles_per_shade[pin] = speed;
  pin_direction[pin] = brighter; //1 = up
  pin_cycles[pin] = 0;
  active_count++;
  notdisabled = true;

}


void seizure(void)
{
  if (notdisabled){ //save afew cycles if nothings happening

  if (active_pwm_values[0] == tick_count){ //turn bit off to get brightness, makes it a percentage of shades. ie turn off on tick 16 of 32 shades, half brigntness.
    registers[0] &= ~(1<<0); //off
  }
  if (active_pwm_values[1] == tick_count){
    registers[0] &= ~(1<<1);
  }
  if (active_pwm_values[2] == tick_count){
    registers[0] &= ~(1<<2);
  }
  if (active_pwm_values[3] == tick_count){
    registers[0] &= ~(1<<3);
  }
  if (active_pwm_values[4] == tick_count){
    registers[0] &= ~(1<<4);
  }
  if (active_pwm_values[5] == tick_count){ 
    registers[0] &= ~(1<<5);
  }
  if (active_pwm_values[6] == tick_count){
    registers[0] &= ~(1<<6);
  }
  if (active_pwm_values[7] == tick_count){
    registers[0] &= ~(1<<7);
  }

  if (active_pwm_values[8] == tick_count){ 
    registers[1] &= ~(1<<0);
  }
  if (active_pwm_values[9] == tick_count){
    registers[1] &= ~(1<<1);
  }
  if (active_pwm_values[10] == tick_count){
    registers[1] &= ~(1<<2);
  }
  if (active_pwm_values[11] == tick_count){
    registers[1] &= ~(1<<3);
  }
  if (active_pwm_values[12] == tick_count){
    registers[1] &= ~(1<<4);
  }
  if (active_pwm_values[13] == tick_count){ 
    registers[1] &= ~(1<<5);
  }
  if (active_pwm_values[14] == tick_count){
    registers[1] &= ~(1<<6);
  }
  if (active_pwm_values[15] == tick_count){
    registers[1] &= ~(1<<7);
  }

  if (active_pwm_values[16] == tick_count){
    registers[2] &= ~(1<<0);
  }
  if (active_pwm_values[17] == tick_count){
    registers[2] &= ~(1<<1);
  }
  if (active_pwm_values[18] == tick_count){
    registers[2] &= ~(1<<2);
  }
  if (active_pwm_values[19] == tick_count){
    registers[2] &= ~(1<<3);
  }
  if (active_pwm_values[20] == tick_count){
    registers[2] &= ~(1<<4);
  }
  if (active_pwm_values[21] == tick_count){
    registers[2] &= ~(1<<5);
  }
  if (active_pwm_values[22] == tick_count){
    registers[2] &= ~(1<<6);
  }
  if (active_pwm_values[23] == tick_count){
    registers[2] &= ~(1<<7);
  }

  if (active_pwm_values[24] == tick_count){
    registers[3] &= ~(1<<0);
  }
  if (active_pwm_values[25] == tick_count){
    registers[3] &= ~(1<<1);
  }
  if (active_pwm_values[26] == tick_count){
    registers[3] &= ~(1<<2);
  }
  if (active_pwm_values[27] == tick_count){
    registers[3] &= ~(1<<3);
  }
  if (active_pwm_values[28] == tick_count){
    registers[3] &= ~(1<<4);
  }
  if (active_pwm_values[29] == tick_count){
    registers[3] &= ~(1<<5);
  }
  if (active_pwm_values[30] == tick_count){
    registers[3] &= ~(1<<6);
  }
  if (active_pwm_values[31] == tick_count){
    registers[3] &= ~(1<<7);
  }
  tick_count++;      //count a tick for cycle!
  if (tick_count > shades) { //if at end up cycle
    tick_count=0;
    for(b=0;b!= 32; b++){                       
      if (active_pwm_values[b] <= shades){  //shades is off for this pin if greated then shades
        pin_cycles[b]++;                  //increase pins cycle count
        if (pin_cycles[b] > pin_cycles_per_shade[b]){                              //change brightness or disable
          pin_cycles[b] = 0;
          if(pin_direction[b] == 0){ //if going down
            active_pwm_values[b]--;  //decrease brightness
            if (active_pwm_values[b] == 0){             //if 0 disable
              active_pwm_values[b] = shades+1;
              active_count--;
              if (active_count < 1){
                notdisabled = false;
              }
            }
          }else{
            active_pwm_values[b]++;           //increase brightness, this also pushes it to shades+1 which disables it from the shader
            if (b > 23){                                //otherwise turn them on for the next cycle 
              registers[3] |= (1<<(b-24)); //on
            }else if  ((b > 15) && (b < 24)){
              registers[2] |= (1<<(b-16));
            }else if ((b > 7) && (b < 16)){
              registers[1] |= (1<<(b-8)); 
            }else{
              registers[0] |= (1<<b); 
            }
            if (active_pwm_values[b] > shades){      //if brighter pin ends life its already on just kill it
              active_count--;
              if (active_count < 1){
                notdisabled = false;
              }
            }
          }
        }else{
          if (b > 23){                    //otherwise turn them on for the next cycle 
            registers[3] |= (1<<(b-24)); //on
          }else if  ((b > 15) && (b < 24)){
            registers[2] |= (1<<(b-16));
          }else if ((b > 7) && (b < 16)){
            registers[1] |= (1<<(b-8)); 
          }else{
            registers[0] |= (1<<b); 
          }
        }
      }
    }
  }
  digitalWriteFast(slaveSelectPin, LOW);
  spi4teensy3::send(registers, 4);
  digitalWriteFast(slaveSelectPin, HIGH);
  }
  return;
}

// the loop() methor runs over and over again,
// as long as the board has power

void loop() {
  while( Serial1.available() >0){
    c = Serial1.read();
    switch (c){
      case '
':   // end of text        
        pos = 1;
        switch (input_line[0]){
        case 'L' :          // L11nx pos5 
          if (input_pos > 4){
            //Serial1.print( "Turning on light : " ); 
            notdisabled = false;
            while(input_line[pos] != 'n'){
              tmpi = (input_line[pos] -48) * 10 + (input_line[pos+1] -48);
              if ((tmpi >=0) && (tmpi < 33)){
                //Serial1.print( tmpi );
                //Serial1.print( ',' );
                setfade(tmpi, 1, 1, shades); //turn on
              }else{
                //Serial1.print( "ERROR turning on pin : " );
                //Serial1.println( tmpi );           
              }
              pos = pos + 2;
              if (pos >= input_pos){
                //Serial1.println( "ERROR wrong size :L1" );
                goto bailout; //get out of loop something broke
              }
            }
            pos++;
            //Serial1.print( "Turning off light : " );
            while(input_line[pos] != 'x'){
              tmpi = (input_line[pos] -48) * 10 + (input_line[pos+1] -48);
              if ((tmpi >=0) && (tmpi < 33)){ 
                //Serial1.print( tmpi );
                //Serial1.print( ',' );
                setfade(tmpi, 1, 0, 1); //turn off
              }else{
                //Serial1.print( "ERROR turning off pin : " );
                //Serial1.println( tmpi );           
              }
              pos = pos + 2;
              if (pos >= input_pos){
                //Serial1.println( "ERROR wrong size :L2" );
                goto bailout; //get out of loop something broke
              }
            }
          }
          else{
            //Serial1.println( "ERROR too short :L3" );
            goto bailout; //get out of loop something broke
          }
          break;





        case 'F' :            //F0001x091000
          input_pos = input_pos - 6; //save working out +- in every loop
          notdisabled = false;
          while(input_line[pos] != 'x'){  
            //LsetLights[tmpi] = (c -48)* 10 + (Serial1.read() -48);
            pos++;
            pos++;
            if (pos > input_pos){
              //Serial1.println( "ERROR wrong size :F" );
              goto bailout; //get out of loop something broke
            }
          }
          LsetDetails[0] = (input_line[pos+1] -48)* 10 + (input_line[pos+2] -48);
          LsetDetails[1] = (input_line[pos+3] -48);
          LsetDetails[2] = ((input_line[pos+4] -48)* 100) + ((input_line[pos+5] -48) * 10) + (input_line[pos+6] -48);
          //Serial1.print( "Lights : " );
          while( pos > 2){
            pos--;
            pos--;
            //Serial1.print( ((input_line[pos] -48)* 10 + (input_line[pos+1] -48))  ); 
            //Serial1.print( "," );
            setfade(((input_line[pos] -48)* 10 + (input_line[pos+1] -48)), LsetDetails[0], LsetDetails[1], LsetDetails[2]); //pin,speed,bright,start
          }
          //Serial1.print( "Speed     : " );
          //Serial1.println( LsetDetails[0] ); 
          //Serial1.print( "Direction : " );
          //Serial1.println( LsetDetails[1] ); 
          //Serial1.print( "Start     : " );
          //Serial1.println( LsetDetails[2] );
          break;




        case 'H' : 
          Serial1.println( "You pressed H for test =D" );
          notdisabled = false;
          tmp = registers[3];
          registers[3] =  B11111111;
          digitalWriteFast(slaveSelectPin, LOW);
          spi4teensy3::send(registers, 4);
          digitalWriteFast(slaveSelectPin, HIGH);
          delay(200);
          registers[3] =  B00000000;
          digitalWriteFast(slaveSelectPin, LOW);
          spi4teensy3::send(registers, 4);
          digitalWriteFast(slaveSelectPin, HIGH);
          registers[3] = tmp;
          break;
        case 'T' :
          if (input_pos != 4){
            Serial1.println( "ERROR wrong size :T" );
            goto bailout; //get out of loop something broke
          }
          timer =  ((input_line[pos] -48)* 100) + ((input_line[pos+1] -48) * 10) + (input_line[pos+2] -48);
          myTimer.end();
          if(!myTimer.begin(seizure, timer)){
            Serial1.println( "ERROR setting myTimer" );
          }
          Serial1.print( "Timer set to : " );
          Serial1.println( timer );  
          break;
        case 'S' :
          if (input_pos != 4){
            Serial1.println( "ERROR wrong size :S" );
            goto bailout; //get out of loop something broke
          }
          shades = ((input_line[pos] -48)* 100) + ((input_line[pos+1] -48) * 10) + (input_line[pos+2] -48);
          if ((shades > 500) || (shades < 5)){
            Serial1.print( "ERROR setting shades to : " );
            Serial1.println( shades );              
            shades = 32; 
          }
          Serial1.print( "Shades set to : " );
          Serial1.println( shades );
          break;     
        default:           
          if ((input_line[0] != '') && (input_line[0] != '
')){ 
          Serial1.print( "Unknown input: " );
          tmpi = 0;
          while(tmpi < input_pos){
          Serial1.print( input_line[tmpi] );

          tmpi++;
          }
          Serial1.println('.');
          }
          break;
        }
        bailout: //break from nested loops... easier then many many more conditions 
        if (active_count > 0) {
          notdisabled = true;
        }
        input_line[0] = '';
        // reset buffer for next time
        input_pos = 0;  
        break;

      case '
':   // discard carriage return
        break;

      default:
        // keep adding if not full ... allow for terminating null byte
        if (input_pos < 100)
        input_line [input_pos++] = c;
        break;
    } 
  }    
}

/*

test tada
turn all on  L0001020304050607080910111213141516171819202122232425262728293031nx   
turn all off Ln0001020304050607080910111213141516171819202122232425262728293031x
fade all speed 5
F0001020304050607080910111213141516171819202122232425262728293031x050128

*/


Image

I connect to it with putty over a serial connection. The WiFly is very easy to setup and connect to, there are many tutorials online. With this setup I just send strings in the format. Everything between L and n get turned on, everything between n and x get turned off, so in this case it turns on pins 11 22 33 01 02 03 and turns 15 16 17 off

L112233010203n151617x

To fade lights I use the format F010203x020128

The pin numbers are between F and x, the 2 digits after x are the speed, the next digit is 0 or 1 representing darker and brighter, the last 3 represent the starting brightness. In my example it will set pins 01 02 03 to 128 which is max brightness with my settings, it will dim until there off with a speed of 2.

All setup

2014-03-21 20:39:38

Turns out leaving the lights in the tree from last Christmas was not the best idea....

Some had been attacked by the whipper snippier, others from falling branches. I spent most of a day working out all the faults and trying to solder them up! But here it is! In pretty average quality too as the tripod for my camera is currently been fixed.

I had auto hotkey, a macro program, pasting lines of text into the putty terminal. Not the best solution but I was running out of time! As I was working in huge text files there are heaps of mistakes in my sequences, it's also very hard to edit and find where the mistakes are as they are huge. They end up looking like this.

Sleep 1000
SendInput F13x010064{Enter}
Sleep 300
SendInput F13x010064{Enter}
Sleep 300
SendInput F13x010064{Enter}
Sleep 300
SendInput F13x010064{Enter}
Sleep 300
SendInput F13x010064{Enter}
Sleep 100
SendInput F15x010064{Enter}
Sleep 100
SendInput F18x010064{Enter}
Sleep 100
SendInput F10x010064{Enter}
Sleep 100
SendInput F26x010064{Enter}
Sleep 100
SendInput F1318112615x010064{Enter}


Next year I'll do something tidier and make up a little PC app to control them, maybe store the files on a SD card that the teensy can read from and update over wifi.