Turn on/off random charlieplexed leds - simulate people arriving-leaving

Hi,

welcome all… new and inexperienced, but willing to learn i got a little project…

I’m trying to bring a little extra light in existence :wink: … and for this i am trying this little project.

I have 20 small houses with a led on my wall, and want to connect them to my arduino.
I want to simulate occupants getting home or leaving … by turning lights on or off.

What I am trying to achieve is the following:

At startup i want to turn all lights off (or on)
I want to generate a random number between 1-20 (one of the “houses”)
I want to check the state of that “house” and switch the state of it (if it’s on, turn it off etc)
After a certain delay i want to rerun the loop.

So after a while i will have a some occupants home … and constantly people arriving and leaving.

I’m using charlieplexing to connect the leds (want to us a micro arduino board to hide in one of the houses…)

So far i did some test using 6 leds charlieplexed and got some results … but I’m not there yet!

I started of with the base code from the Arduino Cookbook page 242-243

the current attached code light random leds… but doesn’t keep “on” state of other leds i guess, because only 1 led lights up at a time don’t know why.

thanks for any help!

this is my current code:

byte pins[] = {8,9,10};
const int NUMBER_OF_PINS = sizeof(pins)/ sizeof(pins[0]);
const int NUMBER_OF_LEDS = NUMBER_OF_PINS * (NUMBER_OF_PINS-1);

byte pairs[NUMBER_OF_LEDS/2][2] = { {0,1}, {1,2}, {0,2} };

int ledStates = 0; //holds states for up to 15 LEDs //not sure how this is stored?
int ledNr[6] = {1,2,3,4,5,6}; //nr of led
int ledOnOffCheck[6] = {0,0,0,0,0,0}; //declating array of led states 0 or 1
int refreshedLed;  // the LED that gets refreshed
int counter = 0;


void setup()
{
 Serial.begin(9600); // added this to see what's happening
}

void loop()
{
 Serial.print(counter); // added this to see what's happening
 delay(100); // added this to see what's happening
 Serial.print(ledOnOffCheck[counter]); // added this to see what's happening
 delay(100); // added this to see what's happening
if (counter ++> NUMBER_OF_LEDS-1)
 {
 counter = 0;
 }
if (ledOnOffCheck[counter] == 1)
 { 
lightLed(counter);
 }
 int randLed;
 randLed = random(NUMBER_OF_LEDS); //choses a random led
 if( ledOnOffCheck[randLed]==0) //checks if it has the off state and switches using options following
  {
 ledOnOffCheck[randLed]=1;
  }
 else
  {
 ledOnOffCheck[randLed]=0;
  }
delay(100);

}


void setState( int led, boolean state)
{
  bitWrite(ledStates,led, state);
}

void ledRefresh()
{
  // refresh a different LED each time this is called.
  if( refreshedLed++ > NUMBER_OF_LEDS) // increment to the next LED
     refreshedLed = 0; // repeat from the first LED if all have been refreshed
//  if( bitRead(ledNr[refreshedLed],ledOnOffCheck[refreshedLed]) == 1)
  if(ledOnOffCheck[ledNr[refreshedLed]] = 1)
        lightLed( refreshedLed );
}

// this function is identical to the sketch above
// it lights the given LED, the first LED is 0

void lightLed(int led)
{
 // the following four lines convert LED number to pin numbers
 int indexA = pairs[led/2][0];
 int indexB = pairs[led/2][1];
 int pinA = pins[indexA];
 int pinB = pins[indexB];

 // turn off all pins not connected to the given LED
 for(int i=0; i < NUMBER_OF_PINS; i++)
   if( pins[i] != pinA && pins[i] != pinB)
   {  // if this pin is not one of our pins
       pinMode(pins[i], INPUT);   // set the mode to input
       digitalWrite(pins[i],LOW); // make sure pull-up is off
   }
 // now turn on the pins for the given LED
 pinMode(pinA, OUTPUT);
 pinMode(pinB, OUTPUT);
 if( led % 2 == 0)
 {
    digitalWrite(pinA,LOW);
    digitalWrite(pinB,HIGH);
 }
 else
 {
    digitalWrite(pinB,LOW);
    digitalWrite(pinA,HIGH);
 }
}

Please edit your original post and put your code in code tags.

done! … with my humble apologies ! :wink:

Thanks.

I'm reading your code and trying to understand it. It seems more complicated than it needs to be.

What happens if you remove all those Serial.println() and reduce the delay(100) down to delay(1)?

Here is a thread where i charlieplexed 4 x 7 segment displays, so 32 leds. I don't know if it will help.

Paul

rRuben: the current attached code light random leds.. but doesn't keep "on" state of other leds i guess, because only 1 led lights up at a time don't know why.

I think that's intentionally done: Your charlieplexing code sets only one LED to ON at the same time.

If you want to control each LED whether it is ON or OFF, you have to do also time-division multiplexing. Let's say you have 20 LEDs, then you create 20 time slots of 1ms each, one time slot for each LED. 1st LED 1ms ON (or not) 2nd LED 1ms ON (or not) 3rd LED 1ms ON (or not) 4th LED 1ms ON (or not) and so on

Playing all 20 time slots takes 20ms, which means: In one second you can play 50 times 20 time slots of 1ms each= 1000ms. That is a frame rate of "50 frames per second" (50 FPS).

The human eye will not be able to follow the single LEDs switching on and off. If a single LED is switched ON/OFF 50 times per second, it will look as if this LED is ON all the time.

And if 6 LEDs are ON during 6 different milliseconds, 50 times per second, it would look as if 6 LEDs are ON all the time. But actually only one LED is ON at the same time.

So you have to combine charlieplexing (for controlling single LEDs) with time-division multiplexing to make it look as if more than one LED is ON at the same time.

jurs: Your charlieplexing code sets only one LED to ON at the same time.

I'm not sure that is true. The code is over-complex, making it difficult to understand, but is does contain this function:

void ledRefresh()
{
  // refresh a different LED each time this is called.

which sounds to me like it is supposed to multiplex (but not is doing so for some reason, as the OP has found).

Hi,

thanks for the replies :)

PaulRB: What happens if you remove all those Serial.println() and reduce the delay(100) down to delay(1)?

well .. i added the serial.print line only to see what my code was sending to the arduino, and the delay to see if it really lighted random leds (otherwise they'd all be blinking/on at the same time!)

jurs: I think that's intentionally done: Your charlieplexing code sets only one LED to ON at the same time.

yes, i understood that, but the code below (copied it from the arduino cookbook) does the time-division multiplexing ... i managed to light different leds at the same time (or visually at least) .. but theres something not right with the way i control my on/off state array i think.

if i use this code :

byte pins[] = {8,9,10};
const int NUMBER_OF_PINS = sizeof(pins)/ sizeof(pins[0]);
const int NUMBER_OF_LEDS = NUMBER_OF_PINS * (NUMBER_OF_PINS-1);

byte pairs[NUMBER_OF_LEDS/2][2] = { {0,1}, {1,2}, {0,2} };

int ledStates = 0; //holds states for up to 15 LEDs //not sure how this is stored?
int ledNr[6] = {1,2,3,4,5,6}; //nr of led
int ledOnOffCheck[6] = {1,0,1,0,1,0}; //declating array of led states 0 or 1
int refreshedLed;  // the LED that gets refreshed
int counter = 0;


void setup()
{
  Serial.begin(9600); // added this to see what's happening
}

void loop()
{
  Serial.print(counter); // added this to see what's happening
//  delay(100); // added this to see what's happening
  Serial.print(ledOnOffCheck[counter]); // added this to see what's happening
//  delay(100); // added this to see what's happening
 if (counter ++> NUMBER_OF_LEDS-1)
  {
  counter = 0;
  }
 if (ledOnOffCheck[counter] == 1)
  { 
 lightLed(counter);
  }
 }

it turns on the leds that are stated "1" in the array. So I think what I'm doing wrong is changing the values of that array .. in my code :

int ledOnOffCheck[6] = {0,0,0,0,0,0}; //declaring array of led states 0 or 1

and this is supposed to manipulate it :

  int randLed;
  randLed = random(NUMBER_OF_LEDS); //choses a random led
  if( ledOnOffCheck[randLed]==0) //checks if it has the off state and switches using options following
   {
  ledOnOffCheck[randLed]=1;
   }
  else
   {
  ledOnOffCheck[randLed]=0;
   }

but there's something not right..

I found my counter working wrong to… this code seems to fix this :

  if (counter < NUMBER_OF_LEDS)
   {
    counter = counter+1;
   }
  if (counter == NUMBER_OF_LEDS)
   {
    counter = 0;
   }

but it doesn’t solve my more then 1 led on/array issue…

rRuben: well .. i added the serial.print line only to see what my code was sending to the arduino, and the delay to see if it really lighted random leds (otherwise they'd all be blinking/on at the same time!)

yes, i understood that, but the code below (copied it from the arduino cookbook) does the time-division multiplexing ... i managed to light different leds at the same time (or visually at least) .. but theres something not right with the way i control my on/off state array i think.

No delay() in the code ==> no problems With delay() in the code ==> has got problems

So the problem is?

Persistence of vision by using time-division multiplexing can work only if you play at least 20 frames per second.

But if you add 3 times delay(100) in your code, this is 300ms delay() total in the loop() function, and the highest frame rate you might get is 3.33 FPS. While 20 FPS or more flashing single LEDs seems to be "steady lighting of all LEDs", a frame rate of 3.33 is just "blinking single LEDs".

Well yes, i understand that the delay is countering the persistence of vision .. i just added these to see if the code for switching on/off state is/was working. If i don't add a delay.. all lights blink at the same time .. so i'm doing something wrong with the turning on/off declaration. I will check how to use a timer to led the random on/off activator happen only every x seconds.. .. to be continued ;)

I’ve re-written it for you. Hope that’s OK. Your code was too complex to get my head around, it was easier to start from scratch.

#define LED_COUNT 6
#define PIN_COUNT 3

const byte ledPin[PIN_COUNT] = {8, 9, 10};

//variables for led control
byte anodePin = 0;
byte cathodePin = 1;
byte currentLed = 0;
unsigned long ledStates = 0;

//variables for timing
unsigned long lastRefresh = 0;
unsigned long lastChange = 0;

void setup() {
  for (byte i = 0; i < PIN_COUNT; i++) pinMode(ledPin[i], INPUT);
  }

void loop() {
  unsigned long timeNow = millis();

  //time to refresh next led?
  if (timeNow - lastRefresh > 2) {
    lastRefresh = timeNow;
    
    //switch off previous led
    pinMode(ledPin[cathodePin], INPUT);

    //move to next led
    if (++currentLed >= LED_COUNT) currentLed = 0;

    //move to next cathode but check not using same pin for cathode and anode!
    if (++cathodePin == anodePin) ++cathodePin;

    //if all cathodes done, move to next anode
    if (cathodePin >= PIN_COUNT) {
      cathodePin = 0;

      //switch off current anode
      digitalWrite(ledPin[anodePin], LOW);
      pinMode(ledPin[anodePin], INPUT);

      //move to next anode, check if all anodes done
      if (++anodePin >= PIN_COUNT) {
        //return to start
        anodePin = 0;
        cathodePin = 1;
      }

      //switch new anode on
      pinMode(ledPin[anodePin], OUTPUT);
      digitalWrite(ledPin[anodePin], HIGH);
    }

    //check if new led should be on
    if (bitRead(ledStates, currentLed)) {
      //switch new cathode on
      pinMode(ledPin[cathodePin], OUTPUT);
      digitalWrite(ledPin[cathodePin], LOW);
    }
  }

  //time to change a random led?
  if (timeNow - lastChange > 1000) {
    lastChange = timeNow;

    //flip a random bit to switch a led on or off
    ledStates ^= bit(random(LED_COUNT));
  }

}

Awesome .. it works!

I'll take a closer look at your code later on to learn something ;) !

I just have to change the code to be able to work with 20 leds now ;)

I was wondering .. since this works with persistence of view .. and only 1 led is actually on at any given time .. this uses only the power for 1 led .. so no worries there .. correct?

Thanks again for the trouble !

I'll try to upload a little animation once the project is finished !

and only 1 led is actually on at any given time .. this uses only the power for 1 led

Yes. Is it bright enough? If not, how are the leds and series resistors connected? It may be possible to get a little more current through. If that's still not bright enough, you will need a few transistors, like the circuit i linked to.

I really appreciate the help provided!

Well, i think it's gonna be bright enough because they will be enclosed in tiny houses .. the houses will provide the darkness to make the leds visible.. or at least i hope they will, otherwise i will have to mod it ;) I'm using 120r resistors. The leds and resistors came from those mood-light-houses , along with a 3x1.5v LR44 batteries.

I was wondering something else to .. i saw that you had a project where you simulated candle light with charlie plexed leds .. would that be hard to implement to run as an alternate program with 20 leds?

either way thanks again!

here is the 6 led test version by the way (higher speed switching) .. PaulRB's code in action ;) https://vid.me/dCg4

OK, i managed to make my semi-final installation with all 20 leds!
It seems all the leds are working.

The only thing i got now is that the leds are flickering… so the persistence of view timing might be to low… i don’t know if i can speed up the cycle ?

I adjusted the code for the 6 leds like this to work with 20:

#define LED_COUNT 20
#define PIN_COUNT 5

const byte ledPin[PIN_COUNT] = {6, 7, 8, 9, 10};

//variables for led control
byte anodePin = 0;
byte cathodePin = 1;
byte currentLed = 0;
unsigned long ledStates = 0;

//variables for timing
unsigned long lastRefresh = 0;
unsigned long lastChange = 0;

void setup() {
  for (byte i = 0; i < PIN_COUNT; i++) pinMode(ledPin[i], INPUT);
  }

void loop() {
  unsigned long timeNow = millis();

  //time to refresh next led?
  if (timeNow - lastRefresh > 2) {
    lastRefresh = timeNow;
    
    //switch off previous led
    pinMode(ledPin[cathodePin], INPUT);

    //move to next led
    if (++currentLed >= LED_COUNT) currentLed = 0;

    //move to next cathode but check not using same pin for cathode and anode!
    if (++cathodePin == anodePin) ++cathodePin;

    //if all cathodes done, move to next anode
    if (cathodePin >= PIN_COUNT) {
      cathodePin = 0;

      //switch off current anode
      digitalWrite(ledPin[anodePin], LOW);
      pinMode(ledPin[anodePin], INPUT);

      //move to next anode, check if all anodes done
      if (++anodePin >= PIN_COUNT) {
        //return to start
        anodePin = 0;
        cathodePin = 1;
      }

      //switch new anode on
      pinMode(ledPin[anodePin], OUTPUT);
      digitalWrite(ledPin[anodePin], HIGH);
    }

    //check if new led should be on
    if (bitRead(ledStates, currentLed)) {
      //switch new cathode on
      pinMode(ledPin[cathodePin], OUTPUT);
      digitalWrite(ledPin[cathodePin], LOW);
    }
  }

  //time to change a random led?
  if (timeNow - lastChange > 25000) {
    lastChange = timeNow;

    //flip a random bit to switch a led on or off
    ledStates ^= bit(random(LED_COUNT));
  }

}

rRuben: The only thing i got now is that the leds are flickering.. so the persistence of view timing might be to low.. i don't know if i can speed up the cycle ?

First try to use same timing for every cycle.

The millis() timer is bad for accurate timing as millis() is sometimes increasing by one and sometimes by two.

Better try timing with 2000 microseconds instead of 2 milliseconds:

 if (timeNow - lastRefresh >= 2000) {
    lastRefresh += 2000;
...

and replace millis() by micros() in your code:

 unsigned long timeNow = micros();

If you really need to speed things up, use 1000 or 500 instead 2000 microseconds.

If you want the change logic depend on the time multiplexing, you'd also have to adjust the timing from milliseconds to microseconds:

  //time to change a random led?
  if (timeNow - lastChange > 25000000L) { ...

Thanks!

Flickering was still there at 2000 micros.. adjusted it to 500.. Working!

This part :

 if (timeNow - lastRefresh >= 500) {
    lastRefresh += 500;
...

This was video flickering at 2000ms (nothing fancy, but hey ;)) https://vid.me/cs0c

This is a somewhat final version of my project.. quite happy with it ;) .. thanks to all for helping! (the video is in real time so only 1 light pops out after 29 seconds.. sorry it ain't an action movie (that's why we got starwars. ;)) .. i wanted to make one with shorter time lapse.. but didn't get to it yet!)

https://vid.me/JN2x