Hi,
I am editing the first post of this thread to summarize the things learned during the investigation and the solution. I've come across some contradictory information while working on this and that made things very difficult when you don't exactly know what you are doing.
The problem:
I was working on a 5x5 matrix, direct drive, not using any ICs.
The brightness of the LEDs was much lower when being Multiplexed than when plugging them to DC directly.
For this application i really need the LEDs to provide their maximum brightness.
LEDs can usually be fed with higher current when being Multiplexed to compensate for this (check datasheet of your LED).
These are the specs for the LEDs:
Forward voltage: 2.2v
Forward current: 20mA
Forward peak current: 50mA (at 10% duty cycle)
Approach:
I was planning to multiplex both Rows and Columns, so only 1 LED would be on at a time. I've done this in the past and it has worked fine, I managed to get consistent brightness on all LEDs and i was able to control the brightness of each LED individually refreshing it at 60Hz. The LEDs were not displaying their full brightness but that wasn't a problem for that application, they were bright enough.
The first problem I was facing was that Arduino can just provide or sink 40mA on each Pin. I needed 50mA to get the full brightness on the LEDs so I needed an extrenal power supply.
The way to switch bigger currents with Arduino on and off is obviously using transistors as switches and in this case I chose to use an NPN transistor, the 2N3904.
The way an NPN transistor works is current flows from the collector to the emitter when a small current is applied to the base.
Transistors can be used as amplifiers or as switches, in this case as i mentioned before, we want to use them as switches.Nowwhat we want to do is to calculate how much current we need to apply to the base, without damaging the transistor, to have it saturated, or fully ON so that the current of the power supply can flow.
There are a few things that you need to take into account when choosing a transistor:
1 - What's the current that you need, to switch the load ON?
In my case, 50mA
2N3904 supports 200mA of collector continuous current
2 - What's the voltage of the power supply that you are intending to use
In my case 9v, 2N3940 supports 40V Collector-Emitter voltage
3 - What's the gain(hFE) of the transistor?
This is basically a factor of the current that needs to be applied to the base in order to let the current pass from collector to emitter. In my case 100.
So if you take the current that you need to switch the LED ON (50mA) and divide it by hFE, 50mA / 100 = 0.5mA is the current that will need to be applied to the base to let 50mA pass through the collector-emitter.
Can the arduino provide that much current (0.5mA)? Yes! not a problem.
So the 2N3904 is a good choice.
Now how do i feed 0.5mA to the transistor from Arduino. Easy, we know the voltage that Arduino provides, we know the current that we need we are just missing the Resistance to apply Ohms Law.
However, the transistors lose 0.7 volts so we need to account for that. And we also want to make sure that the transistor is saturated so instead of 0.5mA we add a 30% to it.
Ib = 0.5 * 1.3 = 0.65
Rb = (5v - 0.7v) / 0.00065 = 6615 ohms (or the closest one available)
If we have done it right, the voltage across the collector and the emitter of the transistor should be < 0.7v, that means that the transistor is in saturation.
Next issue I was facing... Multiplexing.
The LEDs can be fed with 50mA if a duty cycle of 10%. What does this mean?
The duty cycle is the percentage of time that the LED will be ON in a pulse.
If we are using a pulse of 1ms, the LED can be on for 100 microseconds and has to be off for 900 microseconds. A 10% of the pulse.
This presents a problem, if i am planning to light just one LED at a time and i have a 5x5 matrix, this means that each LED can just be ON for 1/25 of the time, so they will be very dim, i need them to be on by 1/10 of the time.
One easy way to do this (I will work on a better solution later) is to split the matrix in sub-matrices of 10 LEDs.
In my case I did 3 groups,(A=Row1, Row2) (B=Row3, Row4) (C=Row5, DummyRow). I added a dummy row to group C just to keep the code consistent and easier.
Now if I want to refresh my matrix 100 times in 1 second
1/100 = 0.01 seconds = 10 miliseconds is the total time of the pulse
So now to achieve a 10% duty cycle, each LED will be ON for 1ms, then we will switch it off and do the same with the rest of the LEDs.
We will do this on the 3 groups at the same time.
In each iteration of the loop what you do is:
Switch on A-Row1 B-Row1 C-Row1
Switch on Column1
Delay 1 milisecond
Switch off Column1
Switch on Column2
Delay 1 milisecond
Switch off Column2
...
until Column5
Then:
Switch off A-Row1 B-Row1 C-Row1
Switch on A-Row2 B-Row2 C-Row2
Switch on Column1
Delay 1 milisecond
Switch off Column1
Switch on Column2
Delay 1 milisecond
Switch off Column2
...
The code would look something like this:
byte Rows[] = {3,4,5,6,7,-1};
byte Rows1[] = {Rows[0],Rows[1]};
byte Rows2[] = {Rows[2],Rows[3]};
byte Rows2[] = {Rows[4],Rows[5]};
byte Cols[] = {8,9,10,11,12};
void setup()
{
for(byte i = 0; i < sizeof(Rows); i++)
{
pinMode(Rows[i], OUTPUT);
digitalWrite(Rows[i], LOW);
}
for(byte i = 0; i < sizeof(Cols); i++)
{
pinMode(Cols[i], OUTPUT);
digitalWrite(Cols[i], LOW);
}
}
void loop()
{
for(byte r = 0; r < 2; r++)
{
byte prevRow = !r;
digitalWrite(Rows1[prevRow], LOW);
digitalWrite(Rows1[r], HIGH);
for(byte c = 0; c < sizeof(Cols); c++)
{
byte prevCol = c;
if(prevCol == 0)
prevCol = sizeOf(Cols) - 1;
digitalWrite(Cols[prevCol], LOW);
digitalWrite(Cols[c], HIGH);
delayMicroseconds(1000);
}
}
}
Bear in mind that this code is assuming that we are using transistors for both rows and columns. So when the pins are set HIGH, the transistors are ON.
Also 3 LEDs (maximum) will be ON at the same time so we need will need to modify the formulas to calculate the resistors based on the current needed to feed the LEDs (150mA)
In my test i just had 1 LED and 1 transistor controlling the Row.
Plug everything in, upload the code, and boom! It works.
Thanks, any questions do not hesitate to ask.