Multiplexed 4 digit 7 segment led display mit Arduino ansteuern

4 Digit 7 Segment LED Display mit Buchstaben und Zahlen

Diese ersten Versuche mit einem 4-Digit-7-Segment-LED-Display sind eine Minimalvariante ohne Transistoren, zusätzliche Shift-Register oder ICs. Auch auf Libraries habe ich verzichtet, um besser zu begreifen, wie die Ansteuerung des Displays funktioniert. Das ermöglicht mir, neben den üblichen Zahlen auch Buchstaben auszugeben (die meisten jedenfalls), was in den Libraries im Normalfall nicht vorgesehen ist. Allerdings verwende ich im Code Teile der Library SevSeg von Dean Reading.

Projektziel

Zahlen und – soweit dies mit einem 7-Segment-Display überhaupt möglich ist – Buchstaben auf einem 4-Digit-7-Segment-LED-Display anzeigen, wobei die anzuzeigenden Zeichen über die serielle Schnittstelle eingelesen werden.

Komponenten

Multiplexed 4 Digit7 Segment LED Display mit 12 Pins, common cathode

Das vorliegende Beispiel verwendet ein multiplexed Display (nur 12 Pins statt 16) in der Variante common cathode, d.h. die 4 Pins für die 4 Zeichen werden an GND und die 8 Pins für die 7 Segmente und den Dezimalpunkt am Strom angeschlossen. Es gibt unzählige LED Displays mit den verschiedensten Verkabelungen, deshalb benötigt man unbedingt das richtige Datenblatt.

  • 1 Arduino UNO R3
  • 1 Steckbrett
  • 1 multiplexed 4-Digit-7-Segment LED Display LN3461AS2B, common cathode, 12 Pins (Bezugsquelle Schweiz, Datenblatt)
  • 4 Widerstände 680 Ohm
  • 12 Jumperkabel M/M
  • ein paar Drahtverbindungen, damit das Display im Kabelsalat nicht total verschwindet

Der Verzicht auf Transistoren führt dazu, dass die Segmente, die eigentlich 1.8 V und 20mA pro Segment schlucken, mit Strom unterversorgt sind und nicht sehr hell leuchten. Für erste Experimente und für eine Anzeige im Dunkeln reicht es aber alle Male.

Multiplexing bedeutet übrigens im Zusammenhang mit diesem Display, dass von den 4 Ziffern immer nur 1 gleichzeitig angeschaltet ist. Macht man das genug schnell, dann wird das träge menschliche Auge übertölpelt und man meint, alle 4 Ziffern gleichzeitig leuchten zu sehen. Wer es genauer wissen will, findet im Web Dutzende von guten Erklärungen, z.B. hier.

Bestückungsplan und Verkabelung

LED Display - Nummerierung der 7 Segmente

Damit die Anzeige funktioniert und nicht einfach Stäbchensalat ausgibt, muss die Verkabelung natürlich genau stimmen. Die Pins des Displays werden wie üblich von 1 unten links über 6 unten rechts bis zu 12 oben links im Gegenuhrzeigersinn nummeriert. Zwischen die 4 Digit-Pins und die zugehörigen Arduino-Pins kommt je ein Widerstand.

Hier meine Verkabelung von Display-Pins mit Arduino-Pins, wie im verlinkten Datenblatt beschrieben. Die Segmente dagegen werden von oben im Uhrzeigersinn mit A bis G bezeichnet, wobei der mittlere Querstrich G ist.

Was Display Pin Arduino Pin Achtung
Digit 1 12 2 680-Ohm Widerstand dazwischen
Digit 2 9 3 680-Ohm Widerstand dazwischen
Digit 3 8 4 680-Ohm Widerstand dazwischen
Digit 4 6 5 680-Ohm Widerstand dazwischen
Segment A (oben) 11 6
Segment B
(rechts oben)
7 7
Segment C
(rechts unten)
4 8
Segment D (unten) 2 9
Segment E
(links unten)
1 10
Segment F
(links oben)
10 11
Segment G (Mittelstrich) 5 12
DP Dezimalpunkt 3 13

4 digit 7 segment Display LN3461AS2B Steckplatine

Code

Der Code gehört einmal mehr ins Kapitel „Weshalb ich C von ganzem Herzen hasse!“. Er ist sehr lang, besteht aber aus unzähligen fast identischen Schritten und Wiederholungen, da es mir nicht gelungen ist, in C einen Array aus anderen Arrays zusammenzusetzen. Dass es tückisch ist, einen Array als Parameter in eine Methode zu übergeben, darüber habe ich ja in meinem Arduino Cheat Sheet bereits geklagt. Deshalb steht der ganze Code ohne weitere Unterteilung im Loop.

Das Einlesen aus der seriellen Schnittstelle wiederum habe ich bereits im Artikel „Arduino als Uhr“ beschrieben.

/*  4 digit 7 segment LED display common cathode
 *  display shows numbers and letters from the serial interface
 *  without the use of a library
 *  every digit can have a decimal point
 *  decimal point can be entered with . or ,
 *
 * Author: Silvia Rothen, rothen ecotronics, Bern, Switzerland
 * part of the code is from the library SevSeg by Dean Reading
 */
 
boolean DigitOn = LOW;
boolean DigitOff = HIGH;
boolean SegOn=HIGH;
boolean SegOff=LOW;
int DigitPins[] = {2, 3, 4, 5};
int SegmentPins[] = {6, 7, 8, 9, 10, 11, 12, 13};

//looks terrible, but I didn't find a way to copy Arrays or merge them from parts
//N is for numbers and NxP is a number with a decimal point behind
int BLANK[] = {LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW};
int N0[]    = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, LOW, LOW};
int N0P[]   = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, LOW, HIGH};
int N1[]    = {LOW, HIGH, HIGH, LOW, LOW, LOW, LOW, LOW};
int N1P[]   = {LOW, HIGH, HIGH, LOW, LOW, LOW, LOW, HIGH};
int N2[]    = {HIGH, HIGH, LOW, HIGH, HIGH, LOW, HIGH, LOW};
int N2P[]   = {HIGH, HIGH, LOW, HIGH, HIGH, LOW, HIGH, HIGH};
int N3[]    = {HIGH, HIGH, HIGH, HIGH, LOW, LOW, HIGH, LOW};
int N3P[]   = {HIGH, HIGH, HIGH, HIGH, LOW, LOW, HIGH, HIGH};
int N4[]    = {LOW, HIGH, HIGH, LOW, LOW, HIGH, HIGH, LOW};
int N4P[]   = {LOW, HIGH, HIGH, LOW, LOW, HIGH, HIGH, HIGH};
int N5[]    = {HIGH, LOW, HIGH, HIGH, LOW, HIGH, HIGH, LOW};
int N5P[]   = {HIGH, LOW, HIGH, HIGH, LOW, HIGH, HIGH, HIGH};
int N6[]    = {HIGH, LOW, HIGH, HIGH, HIGH, HIGH, HIGH, LOW};
int N6P[]   = {HIGH, LOW, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};
int N7[]    = {HIGH, HIGH, HIGH, LOW, LOW, LOW, LOW, LOW};
int N7P[]   = {HIGH, HIGH, HIGH, LOW, LOW, LOW, LOW, HIGH};
int N8[]    = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, LOW};
int N8P[]   = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};
int N9[]    = {HIGH, HIGH, HIGH, HIGH, LOW, HIGH, HIGH, LOW};
int N9P[]   = {HIGH, HIGH, HIGH, HIGH, LOW, HIGH, HIGH, HIGH};
int MIN[]   = {LOW, LOW, LOW, LOW, LOW, LOW, HIGH, LOW};
//The letters K, M, N, T, V, W, Z are off limits with a 7 segment display
//Some letters like D, G, Q are hard to recognize, as D is like O and G like 6
int A[] = {HIGH, HIGH, HIGH, LOW, HIGH, HIGH, HIGH, LOW};
int B[] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, LOW};
int C[] = {HIGH, LOW, LOW, HIGH, HIGH, HIGH, LOW, LOW};
int D[] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, LOW, LOW};
int E[] = {HIGH, LOW, LOW, HIGH, HIGH, HIGH, HIGH, LOW};
int F[] = {HIGH, LOW, LOW, LOW, HIGH, HIGH, HIGH, LOW};
int G[] = {HIGH, LOW, HIGH, HIGH, HIGH, HIGH, HIGH, LOW};
int H[] = {LOW, HIGH, HIGH, LOW, HIGH, HIGH, HIGH, LOW};
int I[] = {LOW, HIGH, HIGH, LOW, LOW, LOW, LOW, LOW};
int J[] = {LOW, HIGH, HIGH, HIGH, HIGH, LOW, LOW, LOW};
int L[] = {LOW, LOW, LOW, HIGH, HIGH, HIGH, LOW, LOW};
int O[] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, LOW, LOW};
int P[] = {HIGH, HIGH, LOW, LOW, HIGH, HIGH, HIGH, LOW};
int Q[] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, LOW, HIGH};
int R[] = {HIGH, HIGH, HIGH, LOW, HIGH, HIGH, HIGH, LOW};
int S[] = {HIGH, LOW, HIGH, HIGH, LOW, HIGH, HIGH, LOW};
int U[] = {LOW, HIGH, HIGH, HIGH, HIGH, HIGH, LOW, LOW};
int Y[] = {LOW, HIGH, HIGH, HIGH, LOW, HIGH, HIGH, LOW};

//Array of pointers for the 4 digits
int* lights[4];

//char array coming from the serial interface
//4 numbers or chars, 4 optional decimal points, 1 end-of-line char
char incoming[9] = {}; 

void setup() {
  Serial.begin(9600);

  for (byte digit=0;digit<4;digit++) {
    pinMode(DigitPins[digit], OUTPUT);
  }
  for (byte seg=0;seg<8;seg++) {
    pinMode(SegmentPins[seg], OUTPUT);
  }
  //initialize display with 1.234
  lights[0] = N1P;
  lights[1] = N2;
  lights[2] = N3;
  lights[3] = N4;
}

void loop() {
  //read the numbers and / or chars from the serial interface
  if (Serial.available() > 0) {
    int i = 0;
    //clear the array of char 
    memset(incoming, 0, sizeof(incoming));
    while (Serial.available() > 0 && i < sizeof(incoming) - 1) {
      incoming[i] = Serial.read();
      i++;
      delay(3);
    }
    Serial.println(incoming); 
    
    //tmp is for the incoming string and counter for the 4 digits
    int counter = -1;
    for (int tmp = 0; tmp < 9; tmp++) {
      counter++;
      switch(incoming[tmp]){
        case '0': 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            lights[counter] = N0P;
            tmp++;
          } else {
            lights[counter] = N0; 
          }
          break;
        case '1': 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            lights[counter] = N1P;
            tmp++;
          } else {
            lights[counter] = N1; 
          }
          break;
        case '2': 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            lights[counter] = N2P;
            tmp++;
          } else {
            lights[counter] = N2; 
          }
          break;
        case '3': 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            lights[counter] = N3P;
            tmp++;
          } else {
            lights[counter] = N3; 
          }
          break;
        case '4': 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            lights[counter] = N4P;
            tmp++;
          } else {
            lights[counter] = N4; 
          }
          break;
        case '5': 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            lights[counter] = N5P;
            tmp++;
          } else {
            lights[counter] = N5; 
          }
          break;
        case '6': 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            lights[counter] = N6P;
            tmp++;
          } else {
            lights[counter] = N6; 
          }
          break;
        case '7': 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            lights[counter] = N7P;
            tmp++;
          } else {
            lights[counter] = N7; 
          }
          break;
        case '8': 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            lights[counter] = N8P;
            tmp++;
          } else {
            lights[counter] = N8; 
          }
          break;
        case '9': 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            lights[counter] = N9P;
            tmp++;
          } else {
            lights[counter] = N9; 
          }
          break;
        case '-':
          lights[counter] = MIN; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        //with letters the decimal point is ignored!
        //if you need it, just write AP, BP etc with HIGH in the last position
        case 'a': //falls through to the next case
        case 'A': 
          lights[counter] = A; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'b': //falls through to the next case
        case 'B': 
          lights[counter] = B; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'c': //falls through to the next case
        case 'C': 
          lights[counter] = C; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'd': //falls through to the next case
        case 'D': 
          lights[counter] = D; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'e': //falls through to the next case
        case 'E': 
          lights[counter] = E; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'f': //falls through to the next case
        case 'F': 
          lights[counter] = F; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'g': //falls through to the next case
        case 'G': 
          lights[counter] = G; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'h': //falls through to the next case
        case 'H': 
          lights[counter] = H; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'i': //falls through to the next case
        case 'I': 
          lights[counter] = I; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'j': //falls through to the next case
        case 'J': 
          lights[counter] = J; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'l': //falls through to the next case
        case 'L': 
          lights[counter] = L; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'o': //falls through to the next case
        case 'O': 
          lights[counter] = O; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'p': //falls through to the next case
        case 'P': 
          lights[counter] = P; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'q': //falls through to the next case
        case 'Q': 
          lights[counter] = Q; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'r': //falls through to the next case
        case 'R': 
          lights[counter] = R; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 's': //falls through to the next case
        case 'S': 
          lights[counter] = S; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'u': //falls through to the next case
        case 'U': 
          lights[counter] = U; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;        
        case 'y': //falls through to the next case
        case 'Y': 
          lights[counter] = Y; 
          if (tmp  < 8 && (incoming[tmp + 1] == '.' || incoming[tmp + 1] == ',')) {
            tmp++;
          } 
          break;       
        case 1 ... 43: counter--; break;//special chars are ignored 
        //44 to 46 are , - .
        case 47: counter--; break;//special chars are ignored 
        //chars between Z and a
        case 91 ... 96: counter--; break;//special chars are ignored 
        case 123 ... 127: counter--; Serial.println("above 122"); break;//special chars are ignored 
        
        default: lights[counter] = BLANK;
      }
    } //end for
    
    //show the input values
    for (int y = 0; y < 4; y++) {
      Serial.print(y);
      Serial.print(": ");
      for (int z = 0; z < 8; z++) {
        Serial.print(lights[y][z]);
      }
      Serial.println("");
    }
  } //end if, i.e. reading from serial interface

  //This part of the code is from the library SevSeg by Dean Reading
  for (byte seg=0;seg<8;seg++) {
    //Turn the relevant segment on
    digitalWrite(SegmentPins[seg],SegOn);

    //For each digit, turn relevant digits on
    for (byte digit=0;digit<4;digit++){
      if (lights[digit][seg]==1) {
        digitalWrite(DigitPins[digit],DigitOn);
      }
      //delay(200); //Uncomment this to see it in slow motion
    }
    //Turn all digits off
    for (byte digit=0;digit<4;digit++){
      digitalWrite(DigitPins[digit],DigitOff);
    }

    //Turn the relevant segment off
    digitalWrite(SegmentPins[seg],SegOff);
  } //end of for
}

Demo

Auf dem Screenshot sieht man Arduino mit Steckbrett, Verkabelung und LED Display.

Arduino mit 4 digit 7 segment LED Display LN3461AS2B

Im Video zeige ich, wie man mit Eingaben in der seriellen Schnittstelle Zahlen- oder Buchstabenfolgen auf dem LED Display anzeigen kann.

Comments are closed.