Charlieplexing at 38KHz?

Hi everyone,

I'm making a light barrier and have so far successfully charlieplexed enough LEDs for the task. Each one is on for 1ms before the next in the chain. Problem is, I need each one to be on for that short amount of time and also "hum" at 38khz. Is there a way to do that? Here is the code:

#define LED_0 PB0
#define LED_1 PB1
#define LED_2 PB2
#define LED_3 PB3
#define LED_4 PB4


void setup()
{
   pinMode(LED_0, INPUT);
   pinMode(LED_1, INPUT);
   pinMode(LED_2, INPUT);
   pinMode(LED_3, INPUT);
   pinMode(LED_4, INPUT);

}

void loop()
{
   set_pins(LED_0, LED_1); //1
   delay(1);
   set_pins(LED_1, LED_0); //2
   delay(1);
   set_pins(LED_0, LED_2); //3
   delay(1);
   set_pins(LED_2, LED_0); //4
   delay(1);
   set_pins(LED_0, LED_3); //5
   delay(1);
   set_pins(LED_3, LED_0); //6
   delay(1); 
   set_pins(LED_0, LED_4); //7
   delay(1); 
   set_pins(LED_4, LED_0); //8
   delay(1); 
   set_pins(LED_1, LED_4); //9
   delay(1); 
   
}

void set_pins(int high_pin, int low_pin)
{
   reset_pins();
   pinMode(high_pin, OUTPUT);
   pinMode(low_pin, OUTPUT);
   digitalWrite(high_pin, HIGH);
   digitalWrite(low_pin,LOW);
}

void reset_pins()
{
   pinMode(LED_0, INPUT); 
   pinMode(LED_1, INPUT);
   pinMode(LED_2, INPUT);
   pinMode(LED_3, INPUT);
   pinMode(LED_4, INPUT);
   digitalWrite(LED_0, LOW);
   digitalWrite(LED_1, LOW);
   digitalWrite(LED_2, LOW);
   digitalWrite(LED_3, LOW);
   digitalWrite(LED_4, LOW);
}

Many thanks!

This will generate the 38khz you require on pin 11.
All done in setup().

const byte IR_LEDpin = 11;

void setup() {
  pinMode (IR_LEDpin, OUTPUT);
  TCCR2A = _BV (COM2A0) | _BV(WGM21);
  TCCR2B = _BV (CS20);
  OCR2A =  209; // ~209 = ~38kHz | ~219 = ~36kHz
}

void loop() {
}

Use a single >=150ohm resistor from this pin to all anodes of the IR LEDs.
Then connect each cathode to individual output pins that you switch on/off in sequence.
3-pin IR receivers are not that fast, so you might have to use small delays between switching.
Leo..

Thanks Leo, I'm just figuring out how to incorporate that one.

I'm using an ATTINY85, so I am limited to only being able to multiplex them so I cannot use just one pin for the signal. If I had 9 separate pins to use it would be dead easy.

Also, the way the receiver bar is working is interesting in that I will have all of the 58038 receivers in range of all of the separate outputs so all of the receivers are receiving all the time, it's just the point of the source that changes, if that makes any sense.

Why do you use t85? If you are not limited by space you may use something to add more outputs. Such as HC595 and PWM the OE pin at 38kHz?

I would need at least 18 outputs if I was to assign each LED to its own pin. Space is limited with this idea anyway.

The other solution would be rather simple - if the NE555 IR modules were still being made. They were cheap enough in bulk that I could just address each one separately anyway. That would be a simple solution for sure.

So if I have 1 of these NE555 modules and want to charlieplex the LEDs, is there a way to somehow control the pulse this way and still address the LEDs correctly?

Why not add a MAX7219? 3 control signals (plus power, Gnd) will control up to 64 LEDs.

I need each one to be on for that short amount of time and also “hum” at 38khz.

So you need it to “hum” during the 1ms that it’s on? 38 cycles worth of on/off, 13.2us each?
That should be easy enough. Charlieplexing works by figuring out the cathode and anode of the target LED, and leaving all the other pins in a high-impedence state. Toggling either of the selected pins, or moving it back to high-impedance state, will turn off the LED.

// loop over LEDs...
cathode = deriveCathode(ledNum);
anode = deriveAnode(ledNum);
DDRx = 0; // All pins to input (everything off)
PORTx = 0;   // All ON pins to GND
DDRx = anode | cathode;  // enable outputs.
for (byte i=0; i<38; i++) {
  PORTx |= anode;  // anode high - light the LED.
  delayMicroseconds(13);
  PORTX &= ~anode; // anode low - LED off.
  delayMicroseconds(13);
}
// next LED.

Or something like that.

Thanks,

I'm going to give this one a go. I'm still quite new to Arduino and when verifying the sketch I had an "undeclared cathode" error

cathode = deriveCathode(ROW_1);
anode = deriveAnode(ROW_6);

I am naming the wire coming from each pin as a "ROW_x"

How do I declare a cathode/anode if the above modification isn't working?

Thanks heaps

My program was only partial. At some point you’d have to have declared “anode” and “cathode” something like:

void loop() {
   int anode, cathode;
   // :
   anode = deriveCathode(ROW_1);

If you’re a beginner, perhaps using PORTx isn’t the best idea. But digitalWrite() is slowish (~8us last time I checked), which will make deriving the timing trickier.

The “derive” functions must be created, and can take argument(s) other than pin numbers. In the example, I was assuming some sort of linear array of LEDs, but the last charlieplexing I actually wrote was a dot-matrix, so I had my derive functions take X and Y values (it was in assembly language, so it’s probably not useful. But it’s published here, with a bit of theory attached.)