Showing posts with label schematic. Show all posts
Showing posts with label schematic. Show all posts

Sunday, April 15, 2012

Mood Lamp Touch Version 1.0



Horse of a different colour

The finishing touches on this touchy project ended up taking longer than I expected, leaving me with much less time (and patience) to blog about it.



Alterations

Since the last post on it, I modified the touch lamp code to change colours on tap-and-hold. It was a little less error-prone and far more intuitive than detecting fingers at a distance from the touch area.


[ I hate vero board... yes, I still hate it... ]

Frustrations

Moving it to the vero board was relatively painless. What really caused me headaches was the reassembly of the lamp itself. When using capacitive detection, all wires must be very well insulated and accounted for.

Version Cutoff

After having to assemble, test, disassemble, solder, un-solder, assemble, ad-nauseum for a few hours I gave up on trying to fix all of the bugs or not-so-great features of it and called it “Version 1.0”. Eventually the state of it will bug me enough to make version 2. Until then, at least I have my fancy mood lamp touch with colour therapy to relax with.

Alpha Bugs/Shortcomings

  1. The emitter is far too high in the lamp diffuser, creating a bright band of light in the middle of the lamp instead of at the base.
  2. A single RGB module is far too weak to produce enough light to fill a room. More will need to be added.
  3. Occasionally, due to either the vero board wiring or the internal wire arrangement or some other variable in the sensitivity of the code, the lamp will turn itself off instead of change colours when touched and held. It’s not too frequent so it should be ok for now.
  4. The project severely underuses the Atmega328P. Don’t know what I can do about this one, really. Smaller chips could be bought and used but it’s more effort and time (hence more cost). I optimised a bunch of the HSV to RGB code to produce a hex file that was about half the size that it started at… If you’re interested in recreating this, it’s worth mentioning that the hex is under 8K and would easily fit on an ATtiny85 (slightly less wasteful).

Code

Should you want to make this project yourself, here’s the sketch for it. It was thrown together pretty quickly so I apologise for the many ragged edges. You’ll first need to install the CapSense library by Paul Badger.

Note: Because it was easier on the vero, I changed D4 and D5 to D6 and D7. Be sure to change it back if you follow the schematic to the letter.

#include <CapSense.h>

/* colours */

const long cRed     = 0xFF0000;
const long cGreen   = 0x00FF00;
const long cBlue    = 0x0000FF;

const long cYellow  = cRed | cGreen;
const long cCyan    = cGreen | cBlue;
const long cMagenta = cRed | cBlue;

/* shifts */

const short cRedShift   = 16;
const short cGreenShift = 8;
const short cBlueShift  = 0;

int CKI = 2;
int SDI = 3;

boolean touchPresent = false;

boolean isOn = true;

long toggledFromTouchAtTime = 1L;

long touchesBeganAtTime = 1L;
long currentTouchHoldTime = 1L;
long lastTouchHoldTime = 1L;

CapSense   cs_4_5 = CapSense(6,7); 

#define STRIP_LENGTH 1 // Number of RGBLED modules connected
long currentColor = 0L;
long lastColor = 0L;

void setup() {
  pinMode(SDI, OUTPUT);
  pinMode(CKI, OUTPUT);
  cs_4_5.set_CS_AutocaL_Millis(0xFFFFFFFF);
}

void touchesDidBegin()
{
  touchPresent = true;
  touchesBeganAtTime = millis();
  currentTouchHoldTime = 0;
}

void touchesDidContinue()
{
  currentTouchHoldTime = millis() - touchesBeganAtTime;
}

void touchesDidEnd()
{
  touchPresent = false;
  lastTouchHoldTime = millis() - touchesBeganAtTime;
  currentTouchHoldTime = 0;
}

long highestVal = 0;
long red = 0x00;
long green = 0xFF;
long blue = 0x00;
long *modColor = NULL;
boolean addColor;

void updateCurrentColor()
{
  currentColor = (red << cRedShift) + (green << cGreenShift) + (blue << cBlueShift);
}

void changeColor()
{
  switch(currentColor){

      case cRed:
        // add green
        modColor = &green;
        addColor = true;
      break;

      case cYellow:
        // subtract red
        modColor = &red;
        addColor = false;
      break;

      case cGreen:
        // add blue
        modColor = &blue;
        addColor = true;
      break;

      case cCyan:
        // subtract green
        modColor = &green;
        addColor = false;
      break;

      case cBlue:
        // add red
        modColor = &red;
        addColor = true;
      break;

      case cMagenta:
        // subtract blue
        modColor = &blue;
        addColor = false;
      break;

      default:
      break;
    }

    // modify the colour
    if (addColor){
      *modColor = *modColor + 1;
    } else {
      *modColor = *modColor - 1;
    }

    updateCurrentColor();
}

void loop() {

  long total1 =  cs_4_5.capSense(30);

  // calibrate

  if (highestVal == 0){
    for (int i = 0; i < 100; i++){
      if (highestVal < total1){
        highestVal = total1;
      }
      total1 = cs_4_5.capSense(30);
      delay(10);
    }
  }

  // touch recognition

  if (total1 >= highestVal + 30){
    if (!touchPresent){
      touchesDidBegin();
    } else {
      touchesDidContinue();
    }
  } else if (touchPresent){
    touchesDidEnd();
  }

  // and the colour bit

  if (isOn && currentTouchHoldTime > 500){
    changeColor();
  } else if ((!isOn || (!touchPresent && lastTouchHoldTime < 500)) && (touchesBeganAtTime > toggledFromTouchAtTime + 200)) {
    toggledFromTouchAtTime = touchesBeganAtTime;
    isOn = !isOn;
  }

  if (isOn) {
    updateCurrentColor();
  } else {
    currentColor = 0;
  }

  if (currentColor != lastColor) {
    post_frame(currentColor);
    lastColor = currentColor;
  }

  delay(50);
}

void post_frame (long led_color) {
  for(int LED_number = 0; LED_number < STRIP_LENGTH; LED_number++)
  {
    long this_led_color = led_color; //24 bits of color data

    for(byte color_bit = 23 ; color_bit != 255 ; color_bit--) {
      //Feed color bit 23 first (red data MSB)

      digitalWrite(CKI, LOW); //Only change data when clock is low

      long mask = 1L << color_bit;
      //The 1'L' forces the 1 to start as a 32 bit number, otherwise it defaults to 16-bit.

      if(this_led_color & mask) 
        digitalWrite(SDI, HIGH);
      else
        digitalWrite(SDI, LOW);

      digitalWrite(CKI, HIGH); //Data is latched when clock goes high
    }
  }

  //Pull clock low to put strip into reset/post mode
  digitalWrite(CKI, LOW);
  delayMicroseconds(500); //Wait for 500us to go into reset
}

Tuesday, February 28, 2012

Wireless Reprogrammable PS2 Controller (Part III)

(or how I came to ditch veroboard)

img1s

Okay…

So, in the last post, I was about to build a vero-board model of the WRPC, having successfully demonstrated proof of concept on breadboard.

The reasons I chose veroboard for the next phase was that:

  1. There are a lot of pins on microcontrollers and my drill press isn’t compatible with the 0.8mm bit.
    (read that as: I don’t wanna hand-drill a billion holes)

  2. Less effort than a custom PCB

Point B became more than arguable over the course of development, as you’ll soon read about. For those of you either not on Google+ or just not reading what I post (fine, then!), here’s how the progress reports went:

Drama - Act 1, Scene 1

One fine day on Google+…
Later…
Finally…

Why did it fail?

The veroboard approach failed because either:

  1. I somehow made the tiniest little melt or jumper or something but because of how immensely complicated the back of the board became (because I wanted it to look nice), diagnosing it became impossible (but I still tried).

    OR

  2. Nothing was wrong with the veroboard, even though diagnosis was impossible. There was a mistake in the breadboard to veroboard conversion.

img2s

As it turns out…

When I finally caved and rebuilt the breadboard circuit with new parts (I will desolder and harvest the veroboard later), it did have an error. It didn’t make much sense to me at the time (and at time of writing, I’m just accepting it for now) but somehow connecting the second ground pin on the Atmega when pin 8 was already grounded caused an issue with reprogramming the board with the Wixel. If you’re interested, compare the schematic from the original post with the one below.

img3s

What I learned (VERO == UGLY)

Only use veroboard for circuits that will be out of sight or those that you don’t care how they look. If you try to get clever and reverse-wire a vero, it will only come back and bite you in the arse.

img5s

Onwards and Upwards

Once I threw out the vero idea, rebuilt the breadboard (and spent hours tracing down the source of the error), I was ready to arrange the PCB. After a few hours of rework, here’s the completed design courtesy of Fritzing:

img6s

Smaller than the vero model and much sexier.

I have included a full set of breakout header traces for both microprocessors and space for two stabilizing capacitors on the regulator, should I desire to add them.

Press-n-Peel

img7s

Now, the main reason I wanted to avoid a custom PCB for a prototype in the first place was because of all the dicking around with transferring a design to the board itself.

To that end (and because UV boards are bloody expensive), I bought some Press-n-Peel film from techniks.com. I have tried several different ways of PCB transfer, but I will have to say that provided you’re willing to do a bit of trial and error (like any method) with your printer settings, iron heat and method, Press-n-Peel film will give you the best PCB-making experience for your buck.

It took me 5 attempts to work out the correct combination of printer setting, iron heat and method but after those five attempts, I had this:

img8s

You’ll notice some minor touch ups because for this one (funnily enough) I used an imperfect piece of film. Murphy can eat my shorts as usual. Anyhow, it was only a short, soft scrub from that to this (custom type/art was added post-Fritzing in Inkscape, but more on that later):

img9s

And after all the etching and glazing…

img10s

…and all the drilling work (which I’m not that good at by hand) I realised…

img11s

…that I’d printed the bloody thing out BACKWARDS.

img12s

Well! Isn’t this just a full-on bag of …. F…un ….

Nevermind.

While it did massively increase the complexity of the soldering job (I soldered the microcontrollers on the reverse side) and changed the overall look of the finished board, I still managed to pull it off without losing it (somehow). I even held it together when my soldering iron died in the middle of it (I fixed it again).

The final (hardware) product

After this very very long and dramatic journey, with more twists and turns than I could even be bothered writing about (yes, there were more), here it is - the finished hardware:

img13s img14s img15s img16s img17s

Afterthoughts

I have written myself a reminder to do this, so I’ll get to it when I can spare another moment… I am going to post the settings that worked best for me with the Press-n-Peel film because I didn’t find that many articles that were very helpful about it online.

Until then…

Sunday, February 19, 2012

Wireless Reprogrammable PS2 Controller (Part II)

Standalone Migration

I’ve spent several hours over the weekend arranging the schematic and new Vero board version of the PS2 Controller project, as well as freeing it from the Arduino tether. The controller now functions completely standalone exactly as it did when hooked up to the Arduino.

There are many benefits of migrating to a standalone from an Arduino-based project.

Some of these are:

  1. Reduced project cost (chips and resonators are WAAAY cheaper than an entire Arduino board)
  2. Freeing up your Arduino for another project
  3. Reduced physical footprint

img1t

Vero and Schematic Diagrams

In the first post I promised that I would publish the schematic once I was happy with it and I’m making good on that. This is version 1.0 of the Wireless Reprogrammable PS2 controller in both Vero and Schematic forms.

img2t img3t

Next Steps

From here, I will be making the Vero version, assembling the controller as one unit and designing and implementing ABE’s menu system, so there are more posts to look forward to yet. :)