|
|
View previous topic :: View next topic |
Author |
Message |
Slicko
Joined: 29 Dec 2011 Posts: 5
|
Controlling an LED matrix |
Posted: Thu Dec 29, 2011 3:33 pm |
|
|
Just wondering if anybody has any advice with regard to controlling an LED matrix via a PIC16F877A or similar device.
I'm still in the learning stages with C and am trying to write a program that will control an LED matrix. It doesn't really matter what size at the moment, i'm just starting with the basics and working my way up.
Lets presume a 5x5 matrix.
The basic code i've got so far is below. I've used the Switch Case statement to achieve it, which isn't what I wanted to do. I want code that will allow me to create an array of the 'font' arrays that contain the coordinates of needed LEDs. I know you can't put an array inside an array in C, but are there different methods that achieve the same result?
Code: |
#include <16F877A.h>
#include <stdio.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
char length;
int i = 0x01;
const char font_1[] = {'A',2,0x03,0xc0}; // random coordinates atm
const char font_2[] = {'B',3,0x07,0x38,0xc0};
const char font_3[] = {'C',2,0x08,0x10};
void col_drive() {
if(i==0x20) { // checks whether it's completed one whole scan
i = 0x01;
output_c(i);
}
else
output_c(i);
i = i<<1; // bit shifts left, so next pin will be active
delay_ms(2);
}
void main() {
while (TRUE) {
char count;
char letter = 'B'; // the letter to be displayed
switch(letter) {
case 'A':
length = font_1[1]; // checks how many columns it uses
for (count = 0; count <= (length-1); count++) { // outputs the number of columns required, using length
output_b(font_1[count+2]); // outputs the coordinates to B
col_drive(); // activates next column
}
for (count=(length); count <= 4; count++) { // makes sure the remaining unused columns are blank
output_b(0x00);
col_drive();
}
break;
case 'B':
length = font_2[1];
for (count = 0; count <= (length-1); count++) {
output_b(font_2[count+2]);
col_drive();
}
for (count=(length); count <= 4; count++) {
output_b(0x00);
col_drive();
}
break;
case 'C':
length = font_3[1];
for (count = 0; count <= (length-1); count++) {
output_b(font_3[count+2]);
col_drive();
}
for (count=(length); count <= 4; count++) {
output_b(0x00);
col_drive();
}
break;
default:
for (count=0; count <= 4; count++) {
output_b(0xff);
col_drive();
}
break;
}
}
} |
I've also got a feeling that this method of controlling the matrix wont allow, or will at least make it very difficult to output other letters / numbers after the initial one on a wider display / matrix. Also, will scrolling text on the display also require a completely different approach?
Cheers for any help
Last edited by Slicko on Fri Dec 30, 2011 6:57 am; edited 2 times in total |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Thu Dec 29, 2011 4:07 pm |
|
|
this kind of application is usually done with multiplexing of the led on states - often with SPI for row/column addresses and a set of decoders --
and is much more complex in the time domain than what you have done so far.
ALSO - the "font" is best described by an array of bit mapped values - not quasi rendered as you have tried so far -a it will consume too many clock cycles when you try tos cale it up
you might show a SCHEMATIC - so we can see what is going on in the BIG picture. |
|
|
Slicko
Joined: 29 Dec 2011 Posts: 5
|
|
Posted: Thu Dec 29, 2011 4:42 pm |
|
|
Thanks for the reply,
Yeah I know the final thing will be much more complicated than what I have so far, I'm just not sure how to get to that point yet.
really basic schematic of just the port b and port c outputs to the LEDs:
Also with this obviously a LOW bit at any of the B pins would signify that it's on so the LEDs on that row can switch on.
So far most things i've found on the internet just give you pre-made source code which i'm sure will work, but it doesn't help me understand it. So far it's been a bit of a trial and error task
EDIT: Oh and I found this page as an example of people who have already done it. I've downloaded their source code but my knowledge of C isn't great yet so I'm finding it pretty difficult to follow / work out how they've achieved what they have. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19535
|
|
Posted: Fri Dec 30, 2011 2:58 am |
|
|
The big problem with what you show, is the lack of any series resistors.
Assuming red LED's, Vf will typically be perhaps 2.2v. Output high voltage, and low voltage will be being limited by the PIC 'maxima' at something like 25mA. Potentially not good for the PIC, pulling either the -ve drive or +ve drive (depending on which one current limits first....), outside their recommended drive range......
Best Wishes |
|
|
Slicko
Joined: 29 Dec 2011 Posts: 5
|
|
Posted: Fri Dec 30, 2011 6:19 am |
|
|
I didn't include anything in the schematic but the basic pin connections. In reality you'd have series resistors to set the current and use transistors as switches with the emitters connected to supply voltage, base connected to each of the PICs C pins, and emitters connected to the corresponding LED matrix column. In a 5x5 matrix this means the maximum current draw at any time would be around 125mA.
It isn't really the schematic design i'm worried about, it's just the software for driving it. the code I've got in my first post should be sufficient in creating an image on the matrix, but isn't very accurate, and will start taking up LOOOTS of space once more characters / images are coded into it.
Is it better to use interrupts? How would I go about making and using an array of bitmapped values? |
|
|
Slicko
Joined: 29 Dec 2011 Posts: 5
|
|
Posted: Fri Dec 30, 2011 11:21 am |
|
|
I've realised I can do it using a multi-dimensional array.
I can place all the 'fonts' in a separate fonts.h file and then the for loop in main can search through and grab the right one. I presume after this I can modify it to accept more characters per scan than the one?
Code: | char length;
int fontn = 2; // number of fonts in the font array -1
int i = 0x01;
int a;
const char fonts[3][5] = {
{'A',2,0x03,0xc0},
{'B',3,0x07,0x38,0xc0},
{'C',2,0x08,0x10},
};
void col_drive() {
if(i==0x20) {
i = 0x01;
output_c(i);
}
else
output_c(i);
i = i<<1;
delay_ms(500);
}
void main() {
while (TRUE) {
char count;
char letter = 'B';
for (a = 0; a<=fontn; a++) {
if(letter == fonts[a][0]) {
length = fonts[a][1];
for (count = 0; count <= (length-1); count++) {
output_b(fonts[a][count+2]);
col_drive();
}
for (count=(length); count <= 4; count++) {
output_b(0x00);
col_drive();
}
}
}
}
} |
|
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
Matrix driving |
Posted: Sun Jan 01, 2012 5:21 am |
|
|
Matrix basics,
You're right, you need to use transistors to drive enough current through your LED matrix (emitter to power rail, base (via resistor) to PIC and collector to LED matrix). As already said, you essentially multiplex the drives. I usually use pnp devices with current limiting resistors to drive the anodes of each row to the +5V rail, and npn's to drive the cathodes in columns to the 0V ground rail.
Suppose you have an 8*8 matrix and you want say 10mA average current through a lit LED. Each column is only on ~10% of the total time, therfore each LED passes ~100mA when lit. If all the LEDs in one column are lit then the npn device for that column needs to handle 800mA easily. In other words all the column drivers have to handle the 800mA, and the row drivers & limit resistors 100mA. The whole thing soon scales up to very big currents requiring careful attention to supply decoupling etc. You may find that you get problems with turning bipolar transistors off fast enough (charge storage effect). In that event, you either use Baker clamps or migrate to FETs.
It's easier to get a stable display by using a timer driven interrupt. Suppose you interrupt at say 1kHz. After 8 interrupts the pattern for the 8*8 matrix repeats. Your display should then update at 125Hz without visible flicker. Using an interrupt in this way frees up the PIC to do other jobs. Let's assume that all the rows are driven from one port and all the columns from another port. The column data is simply 0x80, 0x40, 0x20 ....0x01 repeat from 0x80. The row data is stored in an 8 element array row_data. The row_data array is a mimic of the LED matrix display. You pass all the row_data and column_data to the display in byte sized chunks.
Sequence for interrupt goes:-
1) Turn off all columns
2) Send new_row_data to row port.
3) Send new_column_data to column port.
4) Look up the next new_row_data from row_data array so that new_row_data is ready for the next pass.
5) Work out the next new_column_data again ready for next pass.
6) Any other tasks then leave.
The dead time between activating each column avoids leakage from one column to the next.
You could let main do the looking up processes 4 & 5.
The main loop looks after the row_data array.
You can scroll the image horizontally by shifting the data in the row_data array.
For the above I've assumed that row_data[0] is output when column 0 is active etc.
You could also achieve scrolling by outputting row_data[0] when in column 1 is active, then column 2 etc. This way you're using the row_data array as a circular buffer. Looking after the relationship between row_data and column_data is more complex, but is a lot faster than shifting data around in the row_data array. (Probably helps to have the more elements in the array than columns.)
You appear to be only considering expanding to a wider matrix. For a wider matrix you use a bigger row_data array, a higher interrupt frequency, and may have to go to external decoders to drive the extra columns. For a large matrix the peak current through the LEDs can be quite substantial, its important that the column drivers don't get stuck. It's worthwhile to check drivers before actually connecting to the LED matrix, or try using seriously larger value limit resistors for testing (there's only one per row).
Good luck (and happy new year).
Mike |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sun Jan 01, 2012 5:59 am |
|
|
Quote: | I can place all the 'fonts' in a separate fonts.h file and then the for loop in main can search through and grab the right one. | The idea is good and flexible but has the disadvantage that it is a bit slow. Your text to be displayed will be an ASCII string, so why not use the ASCII number as a direct index into your font array?
Similar projects have been done many times in the past. Searching the web should give you some useful websites. Keywords to search for are: dot matrix ULN2803
Here is a link to a thread where free programs for font creation are discussed: http://www.ccsinfo.com/forum/viewtopic.php?t=44497 |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9240 Location: Greensville,Ontario
|
|
Posted: Sun Jan 01, 2012 6:43 am |
|
|
Be sure to use a HIGH current power supply !! As pointed out, current demands are huge for LEDs compared to the PIC. Something like a regulated 'wallwart' good for 4 AMPS would be a good choice.
Also add good 'filtering' caps., ie: .001mfd, .1mfd, 10mfd, near PIC as well as each driver transistor.
If you don't, 'noise' from switching the LEDS can (and will) cause the PIC to 'go funny'.... |
|
|
Slicko
Joined: 29 Dec 2011 Posts: 5
|
|
Posted: Sun Jan 01, 2012 1:45 pm |
|
|
Thanks for all the feedback / advice. I need to order some components and I'll get on with testing the code, and let you know how I get on
I mainly need to get more confident with C, so I'm still reading a lot trying to learn as much as I can.
Happy new year! |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|