Go Down

Topic: 12 LED Charlieplexed Snowfall with AtTiny85 (Read 21960 times) previous topic - next topic

daaf1984

Hello,

I only found one topic about this, but it's done with 20 ports.

What I want to do:
•Create a charlieplexed row of 12 LED's driven by a AtTiny85 chip (PWM).

What I have managed yet:
•Create a working charlieplexed row with some code found on the web
•create a working sketch with 4 (software)PWM pins.

What are my problems:
•Combine chalieplex and the 4 pins S-PWM
•Create an 'animation' of a shooting star/snowdrop with tail and a delayed end drop.
(like this video)

http://www.youtube.com/watch?v=sFrOMbQ4LXU


This are the codes I found:

The falling animation (No Charlieplex)

Code: [Select]
void setup() {
    for (uint8_t pin=0; pin<5; ++pin) {
        pinMode(pin, OUTPUT);
    }
}

uint8_t brightness(const int8_t led, const int8_t pos) {   
    switch (abs(led-pos)) {
        case 0:     return 32;
        case 1:     return 16;
        case 2:     return 6;
        case 3:     return 2;
        default:    return 1;
    }
}

void pulse_width_modulation(const uint8_t pos) {
    for(uint8_t times=0; times<100; ++times) {
        for (uint8_t pass=0; pass<32; ++pass) {
            for (int8_t led=0; led<20; ++led) {
                digitalWrite(led, (brightness(led, pos) > pass));
            }
        }
    }
}

void loop() {
    static uint8_t pos=0;

    while(pos<12) {
        pulse_width_modulation(pos);
        ++pos;
    }
delay(1000);

   pos=0;
}


A code with PWM (no SPWM) Lighting one after an other

Code: [Select]
/*
* Arrays containing the pin numbers used in
* each charlieplexed matrix. In this case, both
* matrices are the same size, and this code will
* not work properly if this is not the case.
*/

int charlie1[4] = { 1, 2, 3, 4};
int numPins = sizeof(charlie1)/sizeof(int);
int dropLed = 0;


void setup() {
  // Set all pins to output-
  for(int i = 0; i < numPins; i++) {
    pinMode(charlie1[i], OUTPUT);
    pinMode(dropLed, OUTPUT);
  }
}





void fadeSingle(int pinArray[],
                int source, int sink,
                int dir, int del) {
  /*
   * Fade a single charlieplexed LED in or out.
   * pinArray[] = Array of PWM pin numbers
   * source = Index of the source pin in the array
   * sink = Index of the sink pin in the array
   * dir = Direction of fade. 0 = Down; 1 = Up.
   * del = Fade delay(microseconds)
   */
  // Set pin modes
  pinMode(pinArray[source], OUTPUT);
  pinMode(pinArray[sink], OUTPUT);

  // Set the sink pin to low straight away
  digitalWrite(pinArray[sink], LOW);

  // Find any other pins in the array, and disable them
  // by setting them to INPUT
  for(int pin = 0; pin < numPins; pin++) {
    if(pin != source && pin != sink) {
      pinMode(pinArray[pin], INPUT);
    }
  }

  // Now fade the source pin in or out
  if(dir > 0) {
    for(int fadeVal = 0; fadeVal < 256; fadeVal++) {
      analogWrite(pinArray[source], fadeVal);
      delayMicroseconds(del);
    }
  } else {
    for(int fadeVal = 255; fadeVal >= 0; fadeVal--) {
      analogWrite(pinArray[source], fadeVal);
      delayMicroseconds(del);
    }
  }
 
 
 
}


void loop() {
  // Fade through all permutation
  allPermsFade();
  //for (int i=0; i>255; i--);
//  analogWrite (dropLed, 255);
//  delay(1000);
//   // fade out from max to min in increments of 5 points:
//  for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) {
//    // sets the value (range from 0 to 255):
//    analogWrite(dropLed, fadeValue);         
//    // wait for 30 milliseconds to see the dimming effect   
//    delay(30);                           
//  }
//  delay(2000);
}



void allPermsFade() {
  /*
   * Loop through all permutations, fading
   * each in then out with a 2ms delay between
   * increments
   */
  for(int i = 0; i < numPins; i++) {
    for(int j = 0; j < numPins; j++) {
      if(i == j) {
        continue;
      }
      fadeSingle(charlie1, i, j, 1, 500);
      fadeSingle(charlie1, i, j, 0, 500);
    }
  }
}


strykeroz

Hi,

I really liked the effect in that video and think it will be something worthy to add to the xmas lights display next year.  As per my PM I decided to take a crack at it.

Firstly I found that adding complexity like trying to implement a PWM over the top of charlieplexing on the ATTiny85 introduced flickering in the LEDs that were at lower brightness levels.  For that reason I simplified it to manipulating the duty cycle for each of the LEDs in the "tail" of the animation so they were on for fewer of the charlieplexing cycles.

This code uses 5 ATTiny pins, and drives an array of 20 LEDs.  It uses no additional libraries, and compiles to 1,786 bytes so it would be possible to use the ATTiny45 also.  I've only tested it at 8MHz.  I use the Arduino-Tiny cores.  The "snowflakes" are 5 LEDs long, with diminishing brightness in the tail, and the animation slows toward the bottom where they collapse into each other.  While I think this does a halfway okay approximation of what is in your video, it can be simply tweaked.  Apologies I have no way to video this, but hope you find it useful for adapting to your project.
Code: [Select]
/*
  ____ _                _ _            _           ____   ___                         
/ ___| |__   __ _ _ __| (_) ___ _ __ | | _____  _|___ \ / _ \ ___ _ __   _____      __
| |   | '_ \ / _` | '__| | |/ _ \ '_ \| |/ _ \ \/ / __) | | | / __| '_ \ / _ \ \ /\ / /
| |___| | | | (_| | |  | | |  __/ |_) | |  __/>  < / __/| |_| \__ \ | | | (_) \ V  V /
\____|_| |_|\__,_|_|  |_|_|\___| .__/|_|\___/_/\_\_____|\___/|___/_| |_|\___/ \_/\_/ 
                                |_|                                                   

Charlieplexing 20 LEDs using 5 ATTiny85 pins with fading by
varying the duty cycle of each LED in the 'tail'.

ATTiny85 connections
Leg  Function
1    Reset, no connection
2    D3 GREEN
3    D4 ORANGE
4    GND
5    D0 WHITE
6    D1 BLUE
7    D2 YELLOW
8    +5V

Tested on ATTiny85 running at 8MHz.
*/

// each block of 4 LEDs in the array is groupled by a common anode (+, long leg)
// for simplicity of wiring on breadboard, using a colour code
#define GREEN 0
#define ORANGE 1
#define WHITE 2
#define BLUE 3
#define YELLOW 4

const unsigned long displayTime = 80;         // milliseconds to spend at each focus LED in descent

// pin definitions {GREEN, ORANGE, WHITE, BLUE, YELLOW}
const int charliePin[5] = {
  3, 4, 0, 1, 2};

// Charlieplexed LED definitions (current flowing from-to pairs)
const int LED[20][2] = {
  {ORANGE, GREEN},                            // 0 (GREEN GROUP)
  {WHITE, GREEN},                             // 1
  {BLUE, GREEN},                              // 2
  {YELLOW, GREEN},                            // 3
  {GREEN, ORANGE},                            // 4 (ORANGE GROUP)
  {WHITE, ORANGE},                            // 5
  {BLUE, ORANGE},                             // 6
  {YELLOW, ORANGE},                           // 7
  {GREEN, WHITE},                             // 8 (WHITE GROUP)
  {ORANGE, WHITE},                            // 9
  {BLUE, WHITE},                              // 10
  {YELLOW, WHITE},                            // 11
  {GREEN, BLUE},                              // 12 (BLUE GROUP)
  {ORANGE, BLUE},                             // 13
  {WHITE, BLUE},                              // 14
  {YELLOW, BLUE},                             // 15
  {GREEN, YELLOW},                            // 16 (YELLOW GROUP)
  {ORANGE, YELLOW},                           // 17
  {WHITE, YELLOW},                            // 18
  {BLUE, YELLOW}                              // 19
};

// other
int current = 0;                              // LED in array with current focus
int previous = 0;                             // previous LED that was lit
unsigned long loopCount = 0;                  // used to determine duty cycle of each LED

void setup() {
  randomSeed(analogRead(0));
}

void loop() {
  loopCount=0;
  unsigned long timeNow = millis();
  while(millis()- timeNow < (displayTime+current*2)) {  // animation slows toward end
    loopCount++;
    if (current > 19) charlieON(19); else charlieON(current);
    // each member of tail has reduced duty cycle
    if(!(loopCount % 3)) if(current-1 >=0 && current-1 < 19) charlieON(current-1);
    if(!(loopCount % 6)) if(current-2 >=0 && current-2 < 19) charlieON(current-2);
    if(!(loopCount % 9)) if(current-3 >=0 && current-3 < 19) charlieON(current-3);
    if(!(loopCount % 12)) if(current-4 >=0 && current-4 < 19) charlieON(current-4);
  }

  current++;
  if(current==23) {                          // start over
    current = 0;
    charlieON(-1);                           // all off
    delay(random(3000));                     // after a short pause
  }
}

// --------------------------------------------------------------------------------
// turns on LED #thisLED.  Turns off all LEDs if the value passed is out of range
//
void charlieON(int thisLED) {
  // turn off previous (reduces overhead, only switch 2 pins rather than 5)
  pinMode(charliePin[LED[previous][0]], INPUT);
  pinMode(charliePin[LED[previous][1]], INPUT);
  // turn on the one that's in focus
  if(thisLED >= 0 && thisLED <= 19) {
    pinMode(charliePin[LED[thisLED][0]], OUTPUT);
    pinMode(charliePin[LED[thisLED][1]], OUTPUT);
    digitalWrite(charliePin[LED[thisLED][0]], LOW);
    digitalWrite(charliePin[LED[thisLED][1]], HIGH);
  }
  previous = thisLED;
}
Thanks for the inspiration, hope you find this useful.  For the BoM I used 20x blue 5mm LEDs, 5x 100 Ohm resistors, a 0.1uF capacitor for decoupling, the ATTiny85 and a nest of wires.

Cheers ! Geoff
"There is no problem so bad you can't make it worse" - retired astronaut Chris Hadfield

strykeroz

I started to construct a diagram in Fritzing to explain how the wiring for the above worked, but it soon became as covered in wire as the real thing.  So, attached is a diagram showing just the green and orange channels and I hope it's easy enough to extrapolate from there.

Each group of 4 LEDs shares a direct connection to one pin without a resistor, with the 4 anodes linked.  Then the other legs are connected via a resistor to the other colours in the sequence green, orange, white, blue, yellow (always in this order, but omitting of course the colour that the anodes are).

So the green group has green to the anodes, then the cathodes in left to right sequence are orange, white, blue & yellow.  The orange group has orange to the anodes, with green, white, blue & yellow to the cathodes left to right.  White group's cathodes are sequenced green, orange, blue & yellow; the blue group's cathodes go green, orange, white & yellow; and the yellow group's cathodes go green, orange, white & blue.

I found colour coding made setting out the breadboard very simple, but repetitive.  I started with the row of 20 LEDs, each with the flat side to the right.  Once constructed a simple sketch walking the LEDs down the array on the Uno was used to test it, then I moved the connections to the ATTiny85 on the breadboard.

HTH, Geoff

"There is no problem so bad you can't make it worse" - retired astronaut Chris Hadfield

daaf1984

Hi Geoff,

Wow, thanks for this new years gift :)

I will build it right away to test it.

But I think your fritzing scheme is not quite right...
I only see 2 resistors and only two lines are connected to the Attiny, but I think I will find out.

Ok, I'm gonna bring down my breadboard, LED's an my wires down and try it out.

Thanks!!

Dave

daaf1984

Sorry, It was early...

I didn't read it very well. ;)

You just made 2 'lines'


daaf1984

Hi,

IT WORKS! :D

Video:

http://www.youtube.com/watch?v=CQZCV_FX3-E

Speed = 30 in the video

Thank you SOOOOOOOO much!
I'm now trying to set a random speed... But I can't get it to work right now. But tonight I will try again. I have to go to work now...

Next step: Make a PCB and order tons of white-blue Leds ;)


strykeroz

Hi Dave

Glad you liked it.  As my first taste of charlieplexing I have to admit this is already giving me ideas for new things to try.  I like your idea of randomising the speed too.  Still trying different effects here, and I'll have to try this with 5 RGB LEDs too.

Please update this thread when you get the PCBs.  

All the best with your project ! Geoff
"There is no problem so bad you can't make it worse" - retired astronaut Chris Hadfield

daaf1984

Hmm...

I'v noticed a problem...

After about 20-30 runs (falls)I have a 'bounce back' at the bottom.
I include the video here..

Do you have an idea or someone else?

http://www.youtube.com/watch?v=sVCDoIFEWkU

Thanks, Dave

strykeroz

#8
Jan 04, 2013, 12:42 am Last Edit: Jan 04, 2013, 03:36 am by strykeroz Reason: 1
Yes, I think I have an idea...might have cut one too many lines out of the code.  Will see if I can reproduce tonight, and send an update.

Edit: have been running mine here for 38mins so far with that problem not showing up.  I do sometimes see odd things from ATTiny projects where the power isn't decoupled - do you have a 0.1uF cap between VCC & GND on yours?  Also there are notes about charlieplexing that mention the current limiting resistors are critical to ensure stray LEDs don't light - did you use something other than the 100R that I used on my blue LEDs for your green array?
"There is no problem so bad you can't make it worse" - retired astronaut Chris Hadfield

strykeroz

#9
Jan 04, 2013, 04:26 am Last Edit: Jan 04, 2013, 04:48 am by strykeroz Reason: 1
Hi Dave

That's roughly an hour and a half now running without that anomaly showing here.  I'll keep it going...

Geoff
"There is no problem so bad you can't make it worse" - retired astronaut Chris Hadfield

strykeroz

Hi Dave,

Here's something you can try.  This is the extra line I took out as it didn't have a negative impact on my array, but it might be causing your issue.
Code: [Select]
/ --------------------------------------------------------------------------------
// turns on LED #thisLED.  Turns off all LEDs if the value passed is out of range
//
void charlieON(int thisLED) {
  // turn off previous (reduces overhead, only switch 2 pins rather than 5)
  digitalWrite(charliePin[LED[previous][1]], LOW);   // <-- ADD THIS LINE
  pinMode(charliePin[LED[previous][0]], INPUT);
  pinMode(charliePin[LED[previous][1]], INPUT);
  // turn on the one that's in focus
  if(thisLED >= 0 && thisLED <= 19) {
    pinMode(charliePin[LED[thisLED][0]], OUTPUT);
    pinMode(charliePin[LED[thisLED][1]], OUTPUT);
    digitalWrite(charliePin[LED[thisLED][0]], LOW);
    digitalWrite(charliePin[LED[thisLED][1]], HIGH);
  }
  previous = thisLED;
}
I suspect the reason you're seeing what you're seeing is that even though the pin that was previously set high is now in input mode, that would have it with the internal pull-up resistor on, so rather than being a true high impedance mode, it would have a small +ve signal.  If the LED and resistors are matched as they are for my blue array, there wouldn't be enough current to cause an issue but if the resistor value is slightly mismatched a signal would still get out enough to run an LED dimly.  Your video seems to show the LED being run as bright as the head of the animation so that's probably not the reason...but it's worth trying perhaps.

Let me know how you go
Geoff
"There is no problem so bad you can't make it worse" - retired astronaut Chris Hadfield

funkyguy4000

I was looking for this exact thing! Bump so I can receive updates!
Accelerate to 88 miles per hour.

daaf1984

Hi Geoff,

First of all I think it's funny that you help me out from the other end of the world.
Thanks again!

I added the line and i'v made a static delay of 500mS, so it runs fast a high number of falls en let it run for 10 minutes now.
It still works! :D

So the extra line worked!

Thanks!!!

Dave

strykeroz

Hi Dave

I'm glad that has you all sorted out now.

Shout out again when you have your project in a more permanent way - very much looking forward to seeing what you do with it.

Cheers ! Geoff
"There is no problem so bad you can't make it worse" - retired astronaut Chris Hadfield

daaf1984

Hi Geoff,

I thought the problem was solved, but it isn't...
But I think, I'v found the problem.

It's the Random function, and probably Randomseed (analogRead, 0);

0 is also used as D0 out. So I have to make a separate random generator.
Still have to find out, but there is a lot on the web about that.

If I skip the random function and just use 'delay' there is no problem.


I also added something:
The last led fading out, instead of just turning of.

I just fooled arround with the code and it doesn't make sence to me why its working, but is IS working.

Fist of all, add 'void fade' :

Code: [Select]
void fade (int thisLED){

    digitalWrite(charliePin[LED[10][1]], LOW);
    for(int fadeVal = 0; fadeVal< 255; fadeVal++) {
      analogWrite (charliePin [LED[19][0]],fadeVal);
      delay (2);
 
  }
}


Then add this line here:

Code: [Select]

  current++;
  if(current==23) {                          // start over
    fade(current-1);  // <----- ADD THIS LINE
    current = 0;
    charlieON(-1);                           // all off
    //delay(random(3000));              // after a short pause (commented this line temporary and used
delay(2000);                                 // delay instead
}




Greets, Davy


Go Up