Go Down

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

strykeroz

Hi Dave,

I specifically made this turn that last LED off rather than fade it.  That is done by this line:
Code: [Select]
if (current > 19) charlieON(19); else charlieON(current);so rather than the focus LED which is the head of the animation going off the bottom, it stays at 19 until the animation is complete and the tail has collapsed into it.  If you want the head to keep going so the last LED fades, change that line to simply:
Code: [Select]
charlieON(current);
If you want the last LED to fade after the tail goes away, suggest you use the charlieplexing duty cycle to do that.  If the Analogwrite is working that is simply good fortune that the particular ATTiny pin referenced in the array at that point is one of the PWM pins.  That won't work the length of the array therefore since one of the 5 pins used for controlling the LEDs isn't PWM capable.

I'm surprised by your findings on the randomseed().  Analog pin 0 is actually leg 1 on the chip, which is disconnected.  My thoughts were that worst case, even if it always returned the same value as that seed it will still generate a pseudorandom sequence, though it will have a sequence that will repeat every run.  It isn't electrically connected to the LEDs so I need convincing it can be playing a part in flashing any lights.

I am not seeing your issue, as yet.  Will try to break it tomorrow and report back.

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

daaf1984

Quote
I'm surprised by your findings on the randomseed().  Analog pin 0 is actually leg 1 on the chip, which is disconnected.  My thoughts were that worst case, even if it always returned the same value as that seed it will still generate a pseudorandom sequence, though it will have a sequence that will repeat every run.  It isn't electrically connected to the LEDs so I need convincing it can be playing a part in flashing any lights.


analog 0 in actually pin 5 on the Attiny... try it with the fade sketch. :)

I will try tomorrow the thing you said about the fading and also the random generator.

strykeroz

Sorry mate recheck the chart.  pin 5 is DIGITAL 0, see next to pin 1 it says it's D5 and A0, so digital 5 or analog 0.  Pin 5 is not an analog pin, but it's used for AREF.
"There is no problem so bad you can't make it worse" - retired astronaut Chris Hadfield

Coding Badly

Code: [Select]
  randomSeed(analogRead(0));

Did you disable RESET?  If not the pin very likely always reads 1023 because of the internal pullup.

Assuming there is enough Flash available, this is a good way to initialize random...
http://arduino.cc/forum/index.php/topic,66206.msg537783.html#msg537783

If you want a truly random seed...
http://code.google.com/p/avr-hardware-random-number-generation/

strykeroz

Thanks cb.  I hadn't, but then wasn't too concerned if the sequence was repeating each run.  Will definitely check out the EEPROM and entropy methods for my Xmas lights tho.
"There is no problem so bad you can't make it worse" - retired astronaut Chris Hadfield

strykeroz

Hi Dave

Here's a modification, adding in the entropy library to give a random randomseed().  This has both a randomised delay between snowflakes, and a randomised speed of the drop.  I've also added a fade-out for the end after the tail collapses.
Code: [Select]
#include <Entropy.h>
// downloaded from http://code.google.com/p/avr-hardware-random-number-generation/

/*
   ____ _                _ _            _           ____   ___                         
  / ___| |__   __ _ _ __| (_) ___ _ __ | | _____  _|___ \ / _ \ ___ _ __   _____      __
| |   | '_ \ / _` | '__| | |/ _ \ '_ \| |/ _ \ \/ / __) | | | / __| '_ \ / _ \ \ /\ / /
| |___| | | | (_| | |  | | |  __/ |_) | |  __/>  < / __/| |_| \__ \ | | | (_) \ 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

// 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

void setup() {
  Entropy.Initialize();
  randomSeed(Entropy.random());
}

void loop() {
  unsigned long loopCount = 0;                          // used to determine duty cycle of each LED
  unsigned long timeNow = millis();                     //
  unsigned long displayTime = 10 + random(90);          // milliseconds to spend at each focus LED in descent
  while(millis()- timeNow < (displayTime+current*2)) {  // animation slows toward end
    loopCount++;
    // the "snowflake" gets full duty cycle.  When it gets to the end, hold it at the end until the tail collapses
    if (current > 19) charlieON(19);
    else charlieON(current);
    // each member of tail has reduced duty cycle, and never get to the final position
    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
    // now fade out the snowflake in that final position #19
    for(int dutyCycle = 3; dutyCycle <= 15; dutyCycle += 3) {
      loopCount = 0;
      timeNow = millis();
      while(millis() - timeNow < (displayTime+current*2)) { // fade out as slow as animation has achieved by now
        loopCount++;
        if(!(loopCount % dutyCycle)) charlieON(19);
        else charlieOFF(19);
      }
    }
    current = 0;
    charlieOFF(19);                          // turn off the remaining (possibly) lit LED
    delay(100 + random(3000));               // and then rinse, repeat...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)
  digitalWrite(charliePin[LED[previous][1]], LOW);   // ensure internal pull-ups aren't engaged on INPUT mode
  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;
}

// --------------------------------------------------------------------------------
// turns off LED #thisLED. 
//
void charlieOFF(int thisLED) {
  digitalWrite(charliePin[LED[thisLED][1]], LOW);   // ensure internal pull-ups aren't engaged on INPUT mode
  pinMode(charliePin[LED[thisLED][0]], INPUT);
  pinMode(charliePin[LED[thisLED][1]], INPUT);
}
New compile size is 3,130 bytes which means we've still got plenty of space on the ATTiny85 if you wanted the display to do more.

Thanks again to Coding Badly for the random links.  I had to use one that was completely internal to the uC since we have no spare legs, and this method will ensure these snowflakes are far more effective where several are side by side.

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

daaf1984

Ah, that was my mistake then...

But You have delivered beautiful work!!

I think I don't need to tweak it, but maybe I will finetune it.
The delay works great, but I like it faster, so I turned the random delay down to 20 ;)

I'm gonna work on a test PCB now and hope to fit it in a clear hose of tube.
I want to make 10 or more :)

Again, THANKS!!



strykeroz

Hi Dave

Glad you've found it useful.  I have put this, and my take on a Larson scanner (Knight Rider's KITT) effect using the same 20-LED charlieplex array up on github.
https://github.com/strykeroz/ATTiny85-20-LED-KITT

Looking forward to seeing your next project update.

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

dtokez

I was wondering about a similar effect I had seen at a shopping centre over christmas. I think there were more LED's than 20 though and the motion looked extremely fluid. I will upload the video I took when I get home

daaf1984


I was wondering about a similar effect I had seen at a shopping centre over christmas. I think there were more LED's than 20 though and the motion looked extremely fluid. I will upload the video I took when I get home


This is possible if you use more pins:

Formula is Number of charlieplexed LED's = N * (N-1)


2 IO Ports allows 2 LEDs, LEDs = 2 * ( 2 - 1 )
3 IO Ports allows 6 LEDs, LEDs = 3 * ( 3 - 1 )
5 IO Ports allows 20 LEDs, LEDs = 5 * ( 5 - 1 )
6 IO Ports allows 30 LEDs, LEDs = 6 * ( 6 - 1 )
7 IO Ports allows 42 LEDs, LEDs = 7 * ( 7 - 1 )
8 IO Ports allows 56 LEDs, LEDs = 8 * ( 8 - 1 )
9 IO Ports allows 72 LEDs, LEDs = 9 * ( 9 - 1 )
10 IO Ports allows 90 LEDs, LEDs = 10 * ( 10 - 1 )
And so on...

Only restriction is you number of IO pins on your IC


dtokez

#25
Jan 08, 2013, 01:52 pm Last Edit: Jan 08, 2013, 03:58 pm by dtokez Reason: 1
Interesting. I don't understand how it works at the moment but I will have to look further into it!

Here is the short video I took of the ones I saw

https://dl.dropbox.com/u/33809233/Movie.mp4

strykeroz

That effect looks awesome.  Since I still had the 20 LED array set up I had a play.  Here's a completely underwhelming 20 LED approximation...
Code: [Select]

// 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

// 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
const unsigned long displayTime = 15;         // milliseconds to spend at each focus LED in descent
const int lineLength = 10;                    // how many LEDs to light maximum


void setup() {
}

void loop() {
 unsigned long timeNow = millis();           //
 while(millis()- timeNow < displayTime) {    // animation slows toward end
   for(int thisLED = current; thisLED > current - lineLength; thisLED--) {
     if (thisLED >= 0 && thisLED <= 19) charlieON(thisLED);
   }
 }
 current++;
 if(current==19+lineLength) {               // start over
   current = 0;
   charlieOFF(19);                          // turn off the remaining (possibly) lit LED
   delay(1200);                             // and then rinse, repeat...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)
 digitalWrite(charliePin[LED[previous][1]], LOW);   // ensure internal pull-ups aren't engaged on INPUT mode
 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;
}

// --------------------------------------------------------------------------------
// turns off LED #thisLED.  
//
void charlieOFF(int thisLED) {
 digitalWrite(charliePin[LED[thisLED][1]], LOW);   // ensure internal pull-ups aren't engaged on INPUT mode
 pinMode(charliePin[LED[thisLED][0]], INPUT);
 pinMode(charliePin[LED[thisLED][1]], INPUT);
}
It just moves a block of lineLength LEDs down the array repeatedly.  If nothing else it proves more than 20 LEDs and an ATTiny85 were used in your video :)

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

dtokez

Yeah I'm not sure how many LED's but I'd think maybe even almost 100?

funkyguy4000

There any more progress on this?
Have you been able to run more than one string?
Accelerate to 88 miles per hour.

strykeroz

I've created a couple of these - one on a test rig and one permanently which became a KITT type Larsson scanner.  To run multiple strands I'll be putting an ATTiny85 at the top of each with Vcc and GND shared across them from a wall wart.  While they'll run independently, the slight randomisation in the speed and delay between falls should create a reasonable effect across the windows at the front of our house.

Measuring up the 4 windows I'll be running these in leads me to think I'll need 30 of them, so 600 white LEDs...the project is approved by the minister for finance and war so it's just a matter of sourcing the bits and dedicating the time.  I'm actually very happy I have a 10 month project window on delivering this one :)

Geoff

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

Go Up