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
}

Advertisements

About Jim Eli

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

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s