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.

Project Help and Ideas » 4 digit LED lib

November 13, 2011
by claesz
claesz's Avatar

Hi guys!

I had this 4 digit LED display laying around and decided to write a short lib for it.
alt image text

These displays are available on ebay and elsewhere for less than $1 and are quite useful for displaying time and other numbers.

The display requires 12 pins, but since it runs on interrupt, you can use the pins for other stuff outside the interrupts. Just keep the LOW pin for each digit off.

My display is marked "5461AS" but all the similar looking displays I found on ebay had the same basic structure. The only thing that differed was whether the pin controlling each digit should be LOW or HIGH. This display requires this pin to be LOW and each "line controlling pin" to be HIGH. But depending on your display you may have to switch this around.

Anyway, the library was hammered together in about an hour, so I am sure there is room for improvement. However, it seems to work.

You can use fprintf to display data. Since these displays have no diagonal lines you really cannot display anything other than numbers (letters like "K", "R" and "H" would be impossible), so this lib is limited to numbers and decimal points. You can print f ex "12.00" or "12,00", "1,200", "120,0" or "1234".

I included a LED brightness setting, so you can easily dim or increase the LED light. Might be useful for f ex an alarm clock where you want to dim the light during night hours.

If someone has written a similar lib before, I apologize. If not, hopefully some of you may find it useful.

This is the lib:

#include <stdio.h>
#include "../libnerdkits/delay.h"
#include <avr/interrupt.h>

// You need to define the pins you have used for the LED display.  12 pins in total
// LED pin 12, 9, 8 and 6 control the LOW of each digit. The rest controls each line in the
// digit.  Outside interrupts you can use the other pins for whatever you want, as long as
// 12, 9, 8 and 6 are kept LOW.

#define LEDPN1 (1<<PC0)
#define LEDPO1 PORTC
#define LEDDDR1 DDRC

#define LEDPN2 (1<<PC1)
#define LEDPO2 PORTC
#define LEDDDR2 DDRC

#define LEDPN3 (1<<PC2)
#define LEDPO3 PORTC
#define LEDDDR3 DDRC

#define LEDPN4 (1<<PC3)
#define LEDPO4 PORTC
#define LEDDDR4 DDRC

#define LEDPN5 (1<<PC4)
#define LEDPO5 PORTC
#define LEDDDR5 DDRC

#define LEDPN6 (1<<PC5)
#define LEDPO6 PORTC
#define LEDDDR6 DDRC

#define LEDPN7 (1<<PD6)
#define LEDPO7 PORTD
#define LEDDDR7 DDRD

#define LEDPN8 (1<<PB5)
#define LEDPO8 PORTB
#define LEDDDR8 DDRB

#define LEDPN9 (1<<PB4)
#define LEDPO9 PORTB
#define LEDDDR9 DDRB

#define LEDPN10 (1<<PB3)
#define LEDPO10 PORTB
#define LEDDDR10 DDRB

#define LEDPN11 (1<<PB2)
#define LEDPO11 PORTB
#define LEDDDR11 DDRB

#define LEDPN12 (1<<PB1)
#define LEDPO12 PORTB
#define LEDDDR12 DDRB

int LED5461_char[] = { 0b11111100, 0b01100000, 0b11011010, 0b11110010, 0b01100110, 0b10110110, 0b10111110, 0b11100000, 0b11111110, 0b11100110 }; // defines each number ABCDEGH-DP as defined in datasheet
int LED5461_display[] = {0, 0, 0, 0}; // stores the display data (what to display in digit 1,2,3 and 4 respectively
int LED5461_decimal[] = {0, 0, 0, 0}; // stores the decimal point data (1 = ON, 2 = OFF) for decimal points 1,2,3,4
int LED5461_pos = 0; // Stores the current write position
int LED5461_brightness = 300; // used to set how long the light is kept on for each interrupt

void LED5461_refresh(d) {
    switch(d) {
        case 1: // digit 1 is LEDPN12
                LEDDDR12 |= LEDPN12; // so set 12 to on
                LEDPO12 &= ~LEDPN12; // and to low
                LEDDDR9 &= ~LEDPN9; // and 9,8,6 to off
                LEDDDR8 &= ~LEDPN8; 
                LEDDDR6 &= ~LEDPN6;
                break;
        case 2:
                LEDDDR12 &= ~LEDPN12; 
                LEDDDR9 |= LEDPN9; 
                LEDPO9 &= ~LEDPN9;
                LEDDDR8 &= ~LEDPN8; 
                LEDDDR6 &= ~LEDPN6;
                break;      
        case 3: 
                LEDDDR12 &= ~LEDPN12; 
                LEDDDR9 &= ~LEDPN9; 
                LEDDDR8 |= LEDPN8; 
                LEDPO8 &= ~LEDPN8;
                LEDDDR6 &= ~LEDPN6;
                break;  
        case 4:
                LEDDDR12 &= ~LEDPN12; 
                LEDDDR9 &= ~LEDPN9; 
                LEDDDR8 &= ~LEDPN8; 
                LEDDDR6 |= LEDPN6;
                LEDPO6 &= ~LEDPN6;
                break;          
    }
    d--; // adjust as digit starts on 1 while array starts on 0.
    if ( LED5461_char[LED5461_display[d]] & (1<<7) ) { LEDPO11 |= LEDPN11; } else { LEDPO11 &= ~LEDPN11; }
    if ( LED5461_char[LED5461_display[d]] & (1<<6) ) { LEDPO7 |= LEDPN7; } else { LEDPO7 &= ~LEDPN7; }
    if ( LED5461_char[LED5461_display[d]] & (1<<5) ) { LEDPO4 |= LEDPN4; } else { LEDPO4 &= ~LEDPN4; }
    if ( LED5461_char[LED5461_display[d]] & (1<<4) ) { LEDPO2 |= LEDPN2; } else { LEDPO2 &= ~LEDPN2; }
    if ( LED5461_char[LED5461_display[d]] & (1<<3) ) { LEDPO1 |= LEDPN1; } else { LEDPO1 &= ~LEDPN1; }
    if ( LED5461_char[LED5461_display[d]] & (1<<2) ) { LEDPO10 |= LEDPN10; } else { LEDPO10 &= ~LEDPN10; }
    if ( LED5461_char[LED5461_display[d]] & (1<<1) ) { LEDPO5 |= LEDPN5; } else { LEDPO5 &= ~LEDPN5; }

    if ( LED5461_decimal[d] ) {  LEDPO3 |= LEDPN3; } else { LEDPO3 &= ~LEDPN3; }

}

ISR(TIMER0_COMPA_vect) {
    //interrupt handler
    int i;
    for(i = 1; i<5; i++) {
        LED5461_refresh(i);
        delay_us(LED5461_brightness);
    }
    LEDDDR12 &= ~LEDPN12; 
    LEDDDR9 &= ~ LEDPN9; 
    LEDDDR8 &= ~LEDPN8; 
    LEDDDR6 &= ~LEDPN6;

}

void LED5461_start() {

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

    sei();

    // set all line pins to output
    LEDDDR1 |= LEDPN1;
    LEDDDR2 |= LEDPN2;
    LEDDDR3 |= LEDPN3;
    LEDDDR4 |= LEDPN4;
    LEDDDR5 |= LEDPN5;
    LEDDDR7 |= LEDPN7;  
    LEDDDR10 |= LEDPN10;
    LEDDDR11 |= LEDPN11;

    // set the 4 chr pins to off
    LEDDDR12 &= ~LEDPN12;
    LEDDDR9 &= ~LEDPN9;
    LEDDDR8 &= ~LEDPN8;
    LEDDDR6 &= ~LEDPN6;

}

int LED5461_print(char line, FILE *stream) {
    if (line == '.' || line == ',') {
        LED5461_decimal[LED5461_pos-1] = 1;
    } else {
        int outp = line - '0';
        LED5461_display[LED5461_pos] = outp;
        LED5461_pos++;
    }
    return 0;
}

void LED5461_home() {
    LED5461_decimal[0] = 0; LED5461_decimal[1] = 0; LED5461_decimal[2] = 0; LED5461_decimal[3] = 0;
    LED5461_pos = 0;
}

Here is an example using the lib:

#define F_CPU 14745600

#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/io_328p.h"
#include "./5461AS.h"

int main() {

    LED5461_start();
    FILE LED5461_stream = FDEV_SETUP_STREAM(LED5461_print, 0, _FDEV_SETUP_WRITE);

    LED5461_brightness = 500;

    while (1) { 
        LED5461_home();
        fprintf_P(&LED5461_stream, PSTR("12,34"));

        delay_ms(1000);

        LED5461_home();
        fprintf_P(&LED5461_stream, PSTR("1,234"));

        delay_ms(1000);

        LED5461_home();
        fprintf_P(&LED5461_stream, PSTR("1010"));

        delay_ms(1000);

        LED5461_home();
        fprintf_P(&LED5461_stream, PSTR("9876"));

        delay_ms(1000);

    }

    return 0;
}
November 13, 2011
by claesz
claesz's Avatar

Don't know why I decided the letter "H" would be impossible to do. It is probably one of the few that would work well :) I meant to say that "H" and "K" would be indistinguishable. At least unless you got really creative.

November 13, 2011
by claesz
claesz's Avatar

As usual I end up having public discussions with myself about my own code. Sorry about that. However I also realized that number "9" in my lib is written without the traditional bottom line (it usually looks like a lower case "g"). If you are a sticker for tradition, just change 0b11100110 to 0b11110110 in the lib code.

November 13, 2011
by Ralphxyz
Ralphxyz's Avatar

Well I enjoy it when I see other people talk to themselves, it re-asures me that I am not alone.

Actually this is a very interesting project, which I can see use for, so thank you for your post.

Ralph

November 13, 2011
by claesz
claesz's Avatar

Thanks! Good to know it is not only me.

Post a Reply

Please log in to post a reply.

Did you know that the Timer/Counter modules on the microcontroller can be configured to output a PWM (Pulse Width Modulation) signal? Learn more...