NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Problems with LED Array Display

October 30, 2011
by claesz
claesz's Avatar

Hi!

Just for the sake of practice I wanted to put together my own LED Array Display. Please bear with me; I know there is a great example of such a display under "tutorials", but I wanted to make it from scratch myself and not just copy the code.

Now, the display is 15 x 5. The size is neither here nor there, I know, but I got bored of soldering after 75 LEDs so decided to just go with that. (Yes, I know that at least 16x5 would have made more sense since with 15 I don't get the "free" pin on reverse current). I use 13 pins (8 for columns and 5 for rows.

My code seems to work fine, and is quite short and efficient, I felt. However I am noticing some odd problems:

-First of all I get a pile of warnings on compile. I presume this is related to my declaration of pointers to port addresses. I wanted a code where I could pick and choose pins depending on whatever ports I had available in a project, and I can't think of any other way. Declaring them as const would through up an error since they are being addressed in the script. -Secondly, and my main irritation: For reasons I cannot understand, certain LEDs shine much brighter than others - particularly on the last row. -And thirdly, there seem to be some very faint light in some of the LEDs when they should be completely off.

I am copying in the code below. I would really appreciate it if anyone had any thoughts on those problems mentioned above or just any comment on the code in general. My C skills leave a lot to be desired.

Cheers, Claes.

#define F_CPU 14745600

#include <avr/io.h>
#include <avr/interrupt.h>

#include "../libnerdkits/io_328p.h"
#include "../libnerdkits/delay.h"
#include "./font.h"

#define maxRows 15 // 15 rows on the LED
#define ltrwidth 3 // 3px for letter and one for trailing space 0,1,2,3

//colls pb1-pb5+ pc0-2
//rows pc3-pc5 + pd3-4

int outBuf[20] = { 0b10001, 0b11000, 0b11100, 0b11110, 0b11111, 0b11110, 0b11100, 0b11000, 0b10000, 0b11000, 0b11100, 0b11110, 0b11111,0b11110, 0b11100}; // some test data.  Need only hold 15 entries for this LED. 
char text[100] = "THIS IS JUST A LITTLE TEST OF THE LED THING!";

int itrCounter = 0; // interrupt counter
int startColl = 0; // what coll to start on (scroll)
int startLtr = 0 ; // what chr to start on (scroll)

void updateLED() {

    char *rowRefDDR[5] = {&DDRD,&DDRD,&DDRC,&DDRC,&DDRC};
    char *rowRefPort[5] = {&PORTD, &PORTD, &PORTC, &PORTC, &PORTC};
    int rowRefPin[5] = {PD3, PD4, PC5, PC4, PC3};

    char *colRefDDR[8] = {&DDRB, &DDRB, &DDRB, &DDRB, &DDRB, &DDRC, &DDRC, &DDRC};
    char *colRefPort[8] = {&PORTB, &PORTB, &PORTB, &PORTB, &PORTB, &PORTC, &PORTC, &PORTC};
    int colRefPin[8] = {PB1, PB2, PB3, PB4, PB5, PC0, PC1, PC2};

    int rows = 0;
    int collread = 0; // what coll of a chr to read from outBuf (since alt between pos-neg, neg-pos)
    int ii = 0;

    // First all neg-pos
    for (rows = 0; rows<5; rows++) {
        //turn off all colls
        *colRefDDR[0] &= ~(1<<colRefPin[0]); *colRefDDR[1] &= ~(1<<colRefPin[1]); *colRefDDR[2] &= ~(1<<colRefPin[2]); *colRefDDR[3] &= ~(1<<colRefPin[3]); *colRefDDR[4] &= ~(1<<colRefPin[4]); *colRefDDR[5] &= ~(1<<colRefPin[5]); *colRefDDR[6] &= ~(1<<colRefPin[6]); *colRefDDR[7] &= ~(1<<colRefPin[7]); 
        //turn off all rows
        *rowRefDDR[0] &= ~(1<<rowRefPin[0]); *rowRefDDR[1] &= ~(1<<rowRefPin[1]); *rowRefDDR[2] &= ~(1<<rowRefPin[2]); *rowRefDDR[3] &= ~(1<<rowRefPin[3]); *rowRefDDR[4] &= ~(1<<rowRefPin[4]);

        // turn on this row
        *rowRefDDR[rows] |= (1<<rowRefPin[rows]); // turn on
        *rowRefPort[rows] &= ~(1<<rowRefPin[rows]) ; // set low

        // set the colls
        ii = 0;
        collread = 0;
        while(ii<8) {
            if (outBuf[collread] & (1<<(4-rows))) {  /* turn on */ *colRefDDR[ii] |= (1<<colRefPin[ii]); /*set heigh*/ *colRefPort[ii] |= (1<<colRefPin[ii]);} else { /*already off, do nada*/ }
            ii++; collread = collread+2;
            //delay_ms(500);
        }
        //delay_ms(500);
    }

    // Now all pos-neg
    for (rows = 0; rows<5; rows++) {
        //turn off all colls
        *colRefDDR[0] &= ~(1<<colRefPin[0]); *colRefDDR[1] &= ~(1<<colRefPin[1]); *colRefDDR[2] &= ~(1<<colRefPin[2]); *colRefDDR[3] &= ~(1<<colRefPin[3]); *colRefDDR[4] &= ~(1<<colRefPin[4]); *colRefDDR[5] &= ~(1<<colRefPin[5]); *colRefDDR[6] &= ~(1<<colRefPin[6]); *colRefDDR[7] &= ~(1<<colRefPin[7]); 
        //turn off all rows
        *rowRefDDR[0] &= ~(1<<rowRefPin[0]); *rowRefDDR[1] &= ~(1<<rowRefPin[1]); *rowRefDDR[2] &= ~(1<<rowRefPin[2]); *rowRefDDR[3] &= ~(1<<rowRefPin[3]); *rowRefDDR[4] &= ~(1<<rowRefPin[4]);

        // turn on this row
        *rowRefDDR[rows] |= (1<<rowRefPin[rows]); // turn on
        *rowRefPort[rows] |= (1<<rowRefPin[rows]) ; // set high

        // set the colls
        ii = 0;
        collread = 1;
        while(ii<8) {
            if (outBuf[collread] & (1<<(4-rows))) {  /* turn on */ *colRefDDR[ii] |= (1<<colRefPin[ii]); /*set low*/ *colRefPort[ii] &= ~(1<<colRefPin[ii]);} else { /*already off, do nada*/ }
            ii++; collread = collread+2;
            //delay_ms(500);
        }
        //delay_ms(500);
    }
}

int getChar(char charpos, int subpos) {
    int i = 0;
    // find char
    while (font[i] != 99999) {
        if (font[i] == charpos) {
            return font[i+subpos+1]; //+1 to skip the actual letter
        }
        i++;
    }

    // no match found   
    return (0b11111);
}

void updateBuffer() {
    int rows = 0;
    int ltrs = startLtr;
    int i = startColl;
    while(rows<maxRows) {
        if (text[ltrs] == '\0') { ltrs = 0;  }
        outBuf[rows] = getChar(text[ltrs], i);
        i++; rows++;
        if (i > (ltrwidth)) { i=0; ltrs++;} // move to next letter
    }
}

ISR(TIMER0_COMPA_vect) {
    //interrupt handler
    if (itrCounter == 25) {
        startColl++;
        itrCounter = 0;
        if (startColl == (ltrwidth+1)) {
            startLtr++;
            startColl = 0;
            if (text[startLtr] == '\0') { startLtr = 0;  }
        }
    }
    itrCounter++;
}

void setPorts(){

    DDRC |= (1<<PC0);   // 
    DDRC |= (1<<PC1);   // 
    DDRC |= (1<<PC2);   // 
    DDRC |= (1<<PC3);   // 
    DDRC |= (1<<PC4);   //  
    DDRC |= (1<<PC5);   //

    DDRB |= (1<<PB1);   // 
    DDRB |= (1<<PB2);   // 
    DDRB |= (1<<PB3);   // 
    DDRB |= (1<<PB4);   // 
    DDRB |= (1<<PB5);   //

    DDRD |= (1<<PD3);   //
    DDRD |= (1<<PD4);   //

    DDRD |= (1<<PD2); // TEST

    //Timer interrupt
    TCCR0A |= (1<<WGM01);
    TCCR0B |= (1<<CS02) | (1<<CS00);
    OCR0A = 143;
    TIMSK0 |= (1<<OCIE0A);
}

int main() {
    sei(); // start interrupt handler
    setPorts();

    while(1) {
        updateBuffer();
        updateLED();
    }
    return 0;
}

The font.h file being included is basically just:

const char font[] = 
{   
'A',
0b11111,
0b10100,
0b11111,
0b00000,
'B',
0b11111,
0b10101,
0b01010,
0b00000,
'C',
0b11111,
0b10001,
0b10001,
0b00000,
etc
99999};

If anyone wants to try out the code, just let me know and I'll include the whole file if you need it.

October 30, 2011
by Rick_S
Rick_S's Avatar

Just a quick observation.

It appears from a glance that you are using a timer to determine what letter/column position placement interval?? Confused

Typically in an array like this, the timer is used to determine the row refresh rate. In your program, the rows appear to refresh based on how long it takes the other code running in updatebuffer and the timer to run. Change anything in those and your refresh will change. By making the timer refresh the display, you can set how long of an interval between each row update and do all your other stuff between those. This may be why you see one row brighter than the others...

I'd recommend at least looking over the code for the LED Array project or some of the other iterations here on the forums (I have a post on the forums where I added a lot of extra functions to the basic program) By looking those over, you can see the logic flow in a working program.

BTW, while I see no reason to re-invent the wheel myself, I do commend your attempt. LED Array projects have always been one of my favorite. I have my original NK Scratch built array as well as some pre-made panels with shift registers.

Here is a LINK to several links to some of my NK array info.

Have fun! BigGrin_Green

Rick

October 30, 2011
by claesz
claesz's Avatar

Hi Rick!

Thanks for the link. When I planned the script, I didn't really see the need for a timer interrupt for the LED refresh. Since the script did nothing but handling the LED array, I figured I might as well have it refresh the LED as often as it could. The only thing I put on a timer was the update of the output array (since you need that to control scrolling speed).

However, reading through your comments I realized that I still had updateBuffer() in main(). That obviously was a mistake. Since it only updates the output buffer, it need only change when the content change (basically when there is a scroll movement), so I moved it into the interrupt where it should have been all along.

ISR(TIMER0_COMPA_vect) {
    //interrupt handler
    if (itrCounter == 25) {
        startColl++;
        itrCounter = 0;
        if (startColl == (ltrwidth+1)) {
            startLtr++;
            startColl = 0;
            if (text[startLtr] == '\0') { startLtr = 0;  }
        }
    }
    itrCounter++;
    updateBuffer();
}

That fixed the problem with the brighter LEDs on the last row (basically only those LEDs are left on at the end of the refresh run, and since it then went off and did the buffer update before returning to refresh, they appeared brighter.

Visually the thing appears perfect now. Still can notice a faint light in some of the off LEDs if you use a magnifying glass, though. Seems to me there must be some sort of problem with pins not being turned off entirely.

I'll have a look at the other samples. I am sure they are far superior in both functionality and use of resources. It was just important for me to do this from scratch without having any preconceived notions about how to structure the code.

Post a Reply

Please log in to post a reply.

Did you know that a NerdKit can be used to build an iPhone-controlled R/C car? Learn more...