Go Down

Topic: PWM control of 4 digit Seven Seg LED display (Read 135 times) previous topic - next topic

Mogaraghu

Recently while searching for something else,  came across an interesting code for controlling a 4 digit ( can extend further too ) 7 Seg displays. I was particularly impressed with the brightness control... it worked very well.

The original Author is Nathan Seidle / Sparkfun electronics.  Thanks to the Author ... i have only just cleaned up but no change made to logic.

Thought will share it .. so that some may find it useful. ( Of course it uses many port Pins. But then i tried this out since i was not happy with the SAA1064 IIC chip in terms of brightness control. )

Code: [Select]

/*
  [ CODE SUITABLE FOR COMMON ANODE 7SEG LED DISPLAY ]

  Nathan Seidle //Spark Fun Electronics 2011 // 6-13-2011
 
  This is an example of how to drive a 7 segment LED display from an ATmega
  without the use of current limiting resistors. This technique is very common
  but requires some knowledge of electronics - you do run the risk of dumping
  too much current through the segments and burning out parts of the display.
  If you use the stock code you should be ok, but be careful editing the
  brightness values.

  This code should work with all colors (red, blue, yellow, green) but the
  brightness will vary from one color to the next because the forward voltage
  drop of each color is different. This code was written and calibrated for the
  red color.

  Display brightness :
  Each digit is on for a certain amount of microseconds
  Then it is off until we have reached a total of 20ms for the function call
  Let's assume each digit is on for 1000us
  Each digit is on for 1ms, there are 4 digits, so the display is off for 16ms.
  That's a ratio of 1ms to 16ms or 6.25% on time (PWM).
  Let's define a variable called brightness that varies from:
  5000 blindingly bright (15.7mA current draw per digit)
  2000 shockingly bright (11.4mA current draw per digit)
  1000 pretty bright (5.9mA)
  500 normal (3mA)
  200 dim but readable (1.4mA)
  50 dim but readable (0.56mA)
  5 dim but readable (0.31mA)
  1 dim but readable in dark (0.28mA)

  7 segments
  4 digits
  1 colon
  =
  12 pins required for full control

  15 Nov 2017

  Checkout the code below. Working good. 500 brightness a bit low for Green KingBright LED.
  But 1000 seems to be OK. Tried out on a Mega 2560.

*/
# include <LedFlasher.h>

LedFlasher heartBeat (13, 500, 500);

unsigned long scanMillis, scanInterval = 1000;

int digit1 = 2;  //PWM Display pin 1
int digit2 = 3;  //PWM Display pin 2
int digit3 = 4;  //PWM Display pin 6
int digit4 = 5;  //PWM Display pin 8
int segA = 6;    //Display pin 14
int segB = 7;    //Display pin 16
int segC = 8;    //Display pin 13
int segD = 9;    //Display pin 3
int segE = 10;   //Display pin 5
int segF = 11;   //Display pin 11
int segG = 12;   //Display pin 15

int value =0;

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void setup()
{
  Serial.begin(9600);
  heartBeat.begin();
 
  pinMode(segA, OUTPUT);
  pinMode(segB, OUTPUT);
  pinMode(segC, OUTPUT);
  pinMode(segD, OUTPUT);
  pinMode(segE, OUTPUT);
  pinMode(segF, OUTPUT);
  pinMode(segG, OUTPUT);

  pinMode(digit1, OUTPUT);
  pinMode(digit2, OUTPUT);
  pinMode(digit3, OUTPUT);
  pinMode(digit4, OUTPUT);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void loop()
{
  heartBeat.update();
 
  if ( millis() - scanMillis > scanInterval)
  {
  scanMillis = millis();
  value++;
  }
  displayNumber(value);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

// Digit Order : MSB Leftside = D4; LSB Rightside = D1.
// Each digit is lit up for a specific (programmable)  duration of microseconds,
// and then switched off. Like this all four digits are done in succession.
// Then a wait of 20ms ensues to repeat the above process.

void displayNumber(int toDisplay)
{
#define DISPLAY_BRIGHTNESS  1000
#define DIGIT_ON  HIGH
#define DIGIT_OFF  LOW

  long beginTime = millis();

  for (int digit = 4 ; digit > 0 ; digit--)
  {
    switch (digit) {
      case 1:
        digitalWrite(digit1, DIGIT_ON);
        break;
      case 2:
        digitalWrite(digit2, DIGIT_ON);
        break;
      case 3:
        digitalWrite(digit3, DIGIT_ON);
        break;
      case 4:
        digitalWrite(digit4, DIGIT_ON);
        break;
    }

    lightNumber(toDisplay % 10);              //Turn on the right segments for this digit = remainder which is unit place digit
//    int result = toDisplay % 10;
//    Serial.println ( result) ;
    toDisplay /= 10;

    delayMicroseconds(DISPLAY_BRIGHTNESS);    //Display digit for fraction of a second (1us to 5000us, 500 is pretty good)

    lightNumber(10);                          //Turn off all segments
    digitalWrite(digit1, DIGIT_OFF);          //Turn off all digits
    digitalWrite(digit2, DIGIT_OFF);
    digitalWrite(digit3, DIGIT_OFF);
    digitalWrite(digit4, DIGIT_OFF);
  }

  while ( (millis() - beginTime) < 20) ;     //Wait for 20ms to pass before we paint the display again
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void lightNumber(int numberToDisplay)         //Given a single number, turns on those segments.... if 10, turn OFF
{
#define SEGMENT_ON  LOW
#define SEGMENT_OFF HIGH
  switch (numberToDisplay)
  {
    case 0:
      digitalWrite(segA, SEGMENT_ON);
      digitalWrite(segB, SEGMENT_ON);
      digitalWrite(segC, SEGMENT_ON);
      digitalWrite(segD, SEGMENT_ON);
      digitalWrite(segE, SEGMENT_ON);
      digitalWrite(segF, SEGMENT_ON);
      digitalWrite(segG, SEGMENT_OFF);
      break;

    case 1:
      digitalWrite(segA, SEGMENT_OFF);
      digitalWrite(segB, SEGMENT_ON);
      digitalWrite(segC, SEGMENT_ON);
      digitalWrite(segD, SEGMENT_OFF);
      digitalWrite(segE, SEGMENT_OFF);
      digitalWrite(segF, SEGMENT_OFF);
      digitalWrite(segG, SEGMENT_OFF);
      break;

    case 2:
      digitalWrite(segA, SEGMENT_ON);
      digitalWrite(segB, SEGMENT_ON);
      digitalWrite(segC, SEGMENT_OFF);
      digitalWrite(segD, SEGMENT_ON);
      digitalWrite(segE, SEGMENT_ON);
      digitalWrite(segF, SEGMENT_OFF);
      digitalWrite(segG, SEGMENT_ON);
      break;

    case 3:
      digitalWrite(segA, SEGMENT_ON);
      digitalWrite(segB, SEGMENT_ON);
      digitalWrite(segC, SEGMENT_ON);
      digitalWrite(segD, SEGMENT_ON);
      digitalWrite(segE, SEGMENT_OFF);
      digitalWrite(segF, SEGMENT_OFF);
      digitalWrite(segG, SEGMENT_ON);
      break;

    case 4:
      digitalWrite(segA, SEGMENT_OFF);
      digitalWrite(segB, SEGMENT_ON);
      digitalWrite(segC, SEGMENT_ON);
      digitalWrite(segD, SEGMENT_OFF);
      digitalWrite(segE, SEGMENT_OFF);
      digitalWrite(segF, SEGMENT_ON);
      digitalWrite(segG, SEGMENT_ON);
      break;

    case 5:
      digitalWrite(segA, SEGMENT_ON);
      digitalWrite(segB, SEGMENT_OFF);
      digitalWrite(segC, SEGMENT_ON);
      digitalWrite(segD, SEGMENT_ON);
      digitalWrite(segE, SEGMENT_OFF);
      digitalWrite(segF, SEGMENT_ON);
      digitalWrite(segG, SEGMENT_ON);
      break;

    case 6:
      digitalWrite(segA, SEGMENT_ON);
      digitalWrite(segB, SEGMENT_OFF);
      digitalWrite(segC, SEGMENT_ON);
      digitalWrite(segD, SEGMENT_ON);
      digitalWrite(segE, SEGMENT_ON);
      digitalWrite(segF, SEGMENT_ON);
      digitalWrite(segG, SEGMENT_ON);
      break;

    case 7:
      digitalWrite(segA, SEGMENT_ON);
      digitalWrite(segB, SEGMENT_ON);
      digitalWrite(segC, SEGMENT_ON);
      digitalWrite(segD, SEGMENT_OFF);
      digitalWrite(segE, SEGMENT_OFF);
      digitalWrite(segF, SEGMENT_OFF);
      digitalWrite(segG, SEGMENT_OFF);
      break;

    case 8:
      digitalWrite(segA, SEGMENT_ON);
      digitalWrite(segB, SEGMENT_ON);
      digitalWrite(segC, SEGMENT_ON);
      digitalWrite(segD, SEGMENT_ON);
      digitalWrite(segE, SEGMENT_ON);
      digitalWrite(segF, SEGMENT_ON);
      digitalWrite(segG, SEGMENT_ON);
      break;

    case 9:
      digitalWrite(segA, SEGMENT_ON);
      digitalWrite(segB, SEGMENT_ON);
      digitalWrite(segC, SEGMENT_ON);
      digitalWrite(segD, SEGMENT_ON);
      digitalWrite(segE, SEGMENT_OFF);
      digitalWrite(segF, SEGMENT_ON);
      digitalWrite(segG, SEGMENT_ON);
      break;

    case 10:
      digitalWrite(segA, SEGMENT_OFF);
      digitalWrite(segB, SEGMENT_OFF);
      digitalWrite(segC, SEGMENT_OFF);
      digitalWrite(segD, SEGMENT_OFF);
      digitalWrite(segE, SEGMENT_OFF);
      digitalWrite(segF, SEGMENT_OFF);
      digitalWrite(segG, SEGMENT_OFF);
      break;
  }
}


PaulRB

I would not use that design. I believe that not limiting the instantaneous current could shorten the life of both the led segments and the Arduino pins.

Mogaraghu

I would not use that design. I believe that not limiting the instantaneous current could shorten the life of both the led segments and the Arduino pins.
Hmmm.. but is it not the way that PWM always works ? The amplitude is constant and only the Mark Space ratio varies ?

Delta_G

#3
Nov 15, 2017, 04:45 pm Last Edit: Nov 15, 2017, 04:46 pm by Delta_G
Hmmm.. but is it not the way that PWM always works ? The amplitude is constant and only the Mark Space ratio varies ?
Right, so during the HIGH periods you are pulling way too much current off the Arduino pin.  That will burn it out. 

This guy is measuring the average current and thinking that it is constant.  It is not. 
If at first you don't succeed, up - home - sudo - enter.

Mogaraghu

Ok I get it ... thanks to both of you for the warning.

So looks like I need to go back to the time trusted shift registers... saw a good one from PaulRB here : http://forum.arduino.cc/index.php?topic=510644.0

I guess that would the safe method. Do you have a link to the code that suits this circuit ... I only then have to modify it for 4 digits.  Will save time to close out the project.. Thanks.

Wawa

A MAX7219 chip can control eight 7-segment displays.

Search for "MAX7219 7 segment" on ebay.

8-digit 7-segment displays are ~$2 shipped, and several boards can be daisy-chained if needed.
Leo..

Go Up