Inverting a 4-Digit 7-Segment Display

7 segment

This arduino program demonstrates inverting a 4-digit 7-segment display. Upon power-up, the program waits approximately 5 seconds to see if the power is interrupted. If so, the program inverts (toggles) the display. Very simple and hopefully you will find it useful.

Normal Display:
4-Digit 7-Segemnt Display (normal mode)

Inverted Display:
4-Digit 7-Segment Display (inverted mode)

Arduino wired to a 7-Segment Display

Arduino wired to a 7-Segment Display

Warning
I didn’t use any current limiting resisters for the 7-segment display. The display routine relies on the timing of the display function to control the 7-segment brightness. Without the delays, the display and/or the arduino could be damaged.

/* 
  Demonstration: Inverting a 4-digit 7-Segment Display 
  Copyright 2011, all rights reserved.
  James M. Eli
  8/9/2011

  bill of materials:
    (1) arduino 16MHz/5v
    (1) 4-digit 7-segment display
  
  7-segment pin outs:
   LCD - Arduino - Port - LCD function
    1  -  A0  -  Port C0  -  Digit 0
    2  -  A1  -  Port C1  -  Digit 1
    6  -  A2  -  Port C2  -  Digit 2
    8  -  A3  -  Port C3  -  Digit 3
    14 -  D1  -  Port D0  -  Segment A
    16 -  D2  -  Port D1  -  Segment B
    13 -  D3  -  Port D2  -  Segment C
    3  -  D4  -  Port D3  -  Segment D
    5  -  D5  -  Port D4  -  Segment E
    11 -  D6  -  Port D5  -  Segment F
    15 -  D7  -  Port D6  -  Segment G
*/ 

//required to make delay functions work
#define F_CPU 16000000UL //16MHz internal osc 
#include <avr/delay.h>
#include <EEPROM.h>  //add eeprom access

//
//definitions
//

//eeprom addresses
//used to detect off/on cycle within intial 5 seconds of powerup
#define INVERT_STATUS_ADDRESS  0        //byte
#define STARTUP_FLAG_ADDRESS   1        //byte

#define TRUE                   1
#define FALSE                  0
#define OK                     1
#define RESET                  0

//software version
#define SOFTWARE_VERSION       1001

//fill digit with leading zeros
#define LEADING_ZEROS		1

//
//globals 
//

//display status [right-side up = FALSE / inverted = TRUE]
uint8_t invert_status;
//hold number to display
uint8_t d[10];
//7-segment digits
const uint8_t *segment, segment_array[20] = {
  //GFEDCBAx right side up, 0, 1, 2... 7, 8, 9
  0b01111110, 0b00001100, 0b10110110, 0b10011110, 0b11001100,
  0b11011010, 0b11111010, 0b00001110, 0b11111110, 0b11011110,
  //inverted, 0, 1, 2... 7, 8, 9
  0b01111110, 0b01100000, 0b10110110, 0b11110010, 0b11101000,
  0b11011010, 0b11011110, 0b01110000, 0b11111110, 0b11111010
};

//
// 7-segment display routines
//

//output number to digit 0, 1, 2 or 3
void _Display(uint8_t number, uint8_t digit) {
  //turn on corresponding digit
  if (invert_status)
    PORTC &= (uint8_t)~(1<<(3 - digit)); //inverted = backwards
  else
    PORTC &= (uint8_t)~(1<<digit);       //right side up
  if (number < 0 || number > 9)
    PORTD = 0b01111110;                  //landing here is an error
  else 
    PORTD = *(segment + number + ((invert_status) ? 10 : 0));
}

//convert uint32_t to array of digits
void ExtractDigits(uint32_t number) {
  uint8_t i;
  
  i = 0;
  while (number > 0) {
    //pull individual digits from 'number' and stuff into 'd' array
    d[i++] = (int)number%10;
    number /= 10;
  }
#ifdef LEADING_ZEROS
  while (i <= 4) //display needs 4 chars
    d[i++] = 0;  //fill with leading '0's 
#endif
}
void DisplayNumber(uint8_t index, uint32_t number) {
  uint8_t i;
  
  ExtractDigits(number);         //convert UL to byte array
  for (i=0; i<4; i++) {          //total time per loop ~5.5ms@16MHz
    _Display(d[index - i], i);   //light up number
    //this delay controls individual segment on-time/brightness, longer = brighter
    _delay_us(45);               //maximum delay = 768/16 = 48us, hence...
    _delay_us(45);               //we do this twice
    //clear display
    PORTC = PORTC | 0b0011111;   //all digits off
    PORTD = 0;                   //all segments off
  }  
  //this delay controls all segments off-time/brightness, shorter = brighter
  _delay_ms(5);
}

//
//power-up utiliy routines
//

//extract a bunch of stuff from eeprom
void InitEepromData(void) {
  uint32_t temp;
  uint16_t i;
 
  //fetch invert status
  invert_status = EEPROM.read(INVERT_STATUS_ADDRESS);
 
  //fetch startup time flag (flag==TRUE if reset within 5 seconds of powerup)
  if (EEPROM.read(STARTUP_FLAG_ADDRESS) == TRUE)
    invert_status ^= 0x01; //toggle display status
  
  //save status
  EEPROM.write(INVERT_STATUS_ADDRESS, invert_status);
  //set startup flag
  EEPROM.write(STARTUP_FLAG_ADDRESS, TRUE);
  //show software version during startup for a brief ~5 seconds wait
  for(i=0; i<600; i++) {
    DisplayNumber(3, (uint32_t)SOFTWARE_VERSION);
    _delay_ms(1);
  }

  //clear startup flag
  EEPROM.write(STARTUP_FLAG_ADDRESS, FALSE);

}

void setup(void) { 
  //configure ports
  DDRC = DDRC | 0b0111111;	//set data direction for port C (digit 1, 2, 3, 4 & DP)
  PORTC = PORTC | 0b0011111;	//initialize all digits off
  DDRD = DDRD | 0b11111110;	//set data direction for port D (segments A, B... G)
  PORTD = PORTD | 0b00000000;	//initialize all digits off

  //initialize pointer, determines which segments to turn on for each digit 
  segment = &segment_array[0];

  //check for inverting display
  InitEepromData();                      
} 

//
//main loop
//

extern volatile unsigned long timer0_millis;

void loop(void) {
  while(1)
    DisplayNumber(4, timer0_millis/10);	//display a ticking timer
}

About Jim Eli

µC experimenter
This entry was posted in Uncategorized and tagged , , . Bookmark the permalink.

2 Responses to Inverting a 4-Digit 7-Segment Display

  1. Malik Quadri says:

    I have a problem with the inverted form and the normal form, it seems to me that you switched them. The one you used as the inverted form seems to be the one actually meant for the normal form. Can you please check that ? this was really helpful by the way.

    • Jim Eli says:

      Its obvious which way the display is oriented because when in the normal mode, the dots representing decimal points on my display appear at the bottom of the digits. When in the inverted mode, the dots appear at the top of the digits. Does your display have decimal points?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s