6-stellige 7-Segment LED Anzeige mit TPIC6B595 Schieberegister

Hallo,

ich habe eine LED Anzeige welche als Zähler funktionieren soll.
Die verwendete Library zählt von der ersten Stelle immer weiter nach hinten und die noch unbenutzten Stellen sind mit “0” gefüllt.

Ich würde das ganze gerne umgekehrt haben.
Es soll von der letzten Stelle angefangen werden zu zählen und es soll immer weiter nach vorne aufrücken. Und die noch unbenutzten Stellen sollen aus sein.

Was muss ich bitte ändern?

Vielen Dank im vorraus!

/*
  Shifter.cpp - Library
  Code for driving multiple common Anode 7 Segment Displays using the TI TPIC6B595 8-Bit Shift Register
  This has been written for use with the Arduino UNO. Roy Fisher
  25.02.2011
  Released into the public domain.

  Connect between shift registers:-
  SRCLRPin, SRCKPin, RCKPin and connect the SEROUT to SERIN of each cascaded shift register
  Make sure the G Pin is grounded
  Make sure SRCLR is tied to 5V
*/

#include "Arduino.h"
#include "Shifter.h"

Shifter::Shifter(int NumOfDigits, int SRCKPin, int SERINPin, int RCKPin)
{
  _NumOfDigits = NumOfDigits;
  pinMode(SRCKPin, OUTPUT);
  _SRCKPin = SRCKPin;
  pinMode(SERINPin, OUTPUT);
  _SERINPin = SERINPin;
  pinMode(RCKPin, OUTPUT);
  _RCKPin = RCKPin;    
}

void Shifter::clear()
{
  int x; 
  digitalWrite(_RCKPin, LOW);  
  // shift out 0's to clear display
  for (x = _NumOfDigits; x >= 0; x--)
    {
      shiftOut(_SERINPin, _SRCKPin, LSBFIRST, 1); 
    }
  digitalWrite(_RCKPin, HIGH);
}

int Shifter::display(int intNumber)
{ // Displays number on display
  int SegmentArray[] = {252, 96, 218, 242, 102, 182, 190, 224, 254, 230};
  String strDisplay;
  int x;
  int res;
  int shiftword;
  if (intNumber < 10)
  {
    strDisplay =  "0" + String(intNumber, DEC);           // using an int and a base
  }
  else 
  {
    strDisplay = String(intNumber, DEC);
  }
  
  digitalWrite(_RCKPin, LOW);
  for (x = _NumOfDigits ; x >= 0; x--)
    {
  res = strDisplay[x] - '0';
  
  shiftword = SegmentArray[res];
  // shift out the bits
  shiftOut(_SERINPin, _SRCKPin, LSBFIRST, shiftword);
  }
  digitalWrite(_RCKPin, HIGH);
}

Hallo,

zeigst du Methoden aus der Lib?
Warum?
Die Lib sollte nur das rausgeben was man ihr sagt.
Das heißt dein Programm musst du ändern, nicht die Lib.

Wenn die TPIC6B595 im Daisy Chain verbunden sind mußte nur den Bitstrom umdrehen.
Aber nicht den kompletten sondern nur die Reihenfolge für die einzelnen Digits.
Die Segmentfolge muss erhalten bleiben nur die Digitzuordnung kehrt sich um.
Also das was du der Lib Methode übergibts muß Digit für Digit umgedreht werden.

Warum spielst Du das nicht mal mit Bleistift und Papier durch, wie in der Schule gelernt?

Umwandlung in Ziffern durch fortgesetzte Division durch 10, Rest jeweils als Ziffer (Digit) merken. Abbruch bei Dividend=0. Für die Digits ein Array der maximalen Länge benutzen, für 16 Bit int reichen also 6 Stellen. Anschließend sind die Digits im Array linksbündig gespeichert und die Anzahl gültiger Stellen bekannt. Die können nun von rechts nach links in die Schieberegister geschoben werden, dabei in die 7-Segment Bitmuster umwandeln. Hört man hier auf, ist die Zahl linksbündig ausgegeben. Andernfalls (rechtsbündig) zuletzt für die übrig gebliebenen Stellen Leerzeichen rausschieben.

Oder die Methode von Doc_Arduino benutzen, und die Schieberegister von der letzten Stelle her füllen und entsprechend verdrahten. Am Anfang die Anzeige mit Leerzeichen füllen, dann die Digits wie oben beschrieben berechnen und gleich ausgeben. Dann bleibt die Anzeige durch das rechtsbündige Reinschieben gleich rechtsbündig.

Danke für die Tips.

Ich verdrahte das ganze morgen mal andersherum.

Hallo,

naja, ich wollte nicht das zu umverdrahtest. Ich weiß ja nicht einmal wie deine ICs aktuell gekoppelt sind.
Es ist auch praktisch unerheblich ob die im Daisy Chain arbeiten oder alle einzeln direkt angesprochen werden. Ersteres spart nur Leitungen ein. Du solltest dir Gedanken machen wie man die Informationen die zu den Schieberegistern gehen "umdreht". Software ist für Anpassungen gedacht. Ansonsten müßtest du für jeden Leuchteffekt die Hardware abändern. Wäre wenig sinnvoll.

Hallo, jetzt habe ich das ganze umverkabelt.

@Doc_Arduino; Habe ich leider zu spät gelesen.

Jetzt wird es von hinten nach vorne beschrieben aber mit den Dezimalstellen falsch herum.

Wie kann ich das jetzt drehen? :confused:

Dankeeee!

#include <Shifter.h>

Shifter shifter(6, 5, 6, 7);  //Setup Shifter instance with number of digits and pin numbers

void setup()
{
  shifter.clear(); 
}

void loop()
{
  int x;
  
  //shifter.clear(); 
  for (x = 0; x < 999999; x++)
   { 
  shifter.display(x);
  delay(100);
   }
}

Hallo,

hier gab es ein doppeltes Missverständnis.

Auf jeden Fall wieder richtig verdrahten, sonst spielt mein Hirn irgendwann verrückt mit dem mehrfachen umdenken.
Nochmal von vorn.

Du möchtest folgendes ... ?
anzeige.jpg

aus ersten drei Beispielen die unteren machen?

anzeige.jpg

Alles Gut. So lerne ich wenigstens was dazu.

Ganz genau. Die Einer in die erste von rechts / die Zehner in die zweite von rechts / die Hunderter in die dritte von rechts und ... und ... und

Die "Datenleitung" ist jetzt gerade am letzten Schieberegister angeschlossen und von da aus gehe ich mit der Datenleitung von rechts nach links raus und wieder in den das nächste Schieberegister rein.

LG

Hallo,

wir reden irgendwie aneinander vorbei. Ansonsten musst du das ordentlichen aufmalen was jetzt der Stand ist und wie du es haben möchtest.

Ich interpretiere wie folgt. Oberen 3 Zeilen sind Bsp. wie es aktuell ist.
Und die unteren 3 Zeilen sind Bsp. wie du es haben möchtest.
Korrekt oder nicht?
anzeige.jpg

anzeige.jpg

Sorry für die Verwirrung!

Die ober drei Zeilen sind der IST Zustand.

Die unteren drei Zeilen stellen dar wie ich es gerne hätte.

Danke!

Schieberegister.PNG

Dann mußt Du nur das Display zu Anfang mit Leerzeichen füllen (alles aus). Oder in umgekehrter Schieberichtung nachher füllen.

Was muss ich "schicken" um alles aus zu haben?
Und wie kann ich außer wieder alles umzulöten die Schieberichtung umkehren?

Danke!

Hallo,

das ist ja völlig anders wie jemals erträumt. Entweder wird die Lib falsch verwendet oder die ist unbrauchbar. Ich tendiere zu Letzterem. Weil das '-' unterdrückt wird statt Segment g anzuzeigen. Zudem in der aktuellen Darstellung eine Null Ziffer nicht von Leer unterschieden wird.

Tja dann musst du mindestens die display Methode umschreiben. Oder suchst dir eine anständige Lib. Jede für das 595er Schieberegister sollte eigentlich passen.

Wenn selber machen, leg eine neue Methode an und benenne sie meinetwegen displayRechts.
Das SegmentArray sieht übersetzt wie folgt aus.
SegmentArray.jpg
Die Bit-Segment-Reihenfolge entspricht der 4. Zeile.

Also welcher Segmentsummenwert entspricht alle Segmente "aus"?
Ich würde die Anzahl der linken Leerstellen ermitteln und diese entsprechend mit "leeren" Segmentwert auffüllen. Weil du musst ja unterscheiden können zwischen erforderlicher Null am Ende oder "leerer" führender Null.

shiftOut schiebt "nur" nacheinander den Segmentsummenwert hintereinander raus. Wobei LSBFIRST die Bitreihenfolge für das jeweilige Digit festlegt. Also wie herum die Segmentbits rausgetaktet werden. Daran musste nichts ändern. Nur zur Info was passiert.

Für Serial.print Trockenübungen hier eine Funktion.

void formatiereByte (byte data)
{
  Serial.print(F("data: "));
  for (char i=7;i>=4;i--) {
    Serial.print( (data >> i) & 0x01);
  }
  Serial.print("'");
  for (char i=3;i>=0;i--) {
    Serial.print( (data >> i) & 0x01);
  }
  Serial.println();
}

Wenn du das alles selbst verstehen möchtest, wovon ich ausgehe, dann musst du dich erstmal mit der Funktionsweise von Schieberegistern und Bit schubsen auseinandersetzen. Wie man die Bits in Einklang bekommt das alle an der richtigen Stelle landen. Deine Schieberegister sind in einer Reihe gekoppelt, Daisy Chain, dass heißt du musst immer alle 6 Digits in einem Rutsch durchtakten. Stelle dir das alles bildlich vor, male es auf oder nutze Excel oder ...

An der Schieberichtung musst gar nichts ändern! Das hast du dir seit Threadbeginn falsch vorgestellt womit die Missvertändnisse begannen. Erst ab #9 ist das Problem klar. Die Reihenfolge der Ziffern stimmt weiterhin. Nur das alles nach rechts geschoben werden muss je nach Anzahl der Ziffern vom dargestellten Wert. Das ist der springende Punkt den du verstehen musst. Vergiss den Begriff "umdrehen".

SegmentArray.jpg

Hallo allerseits.
Ich habe es dann ganz ohne Library gelöst.
Vielen Dank für eure Mühe!

Hier meine Lösung:

const int  pinLatch     = 7; // Dieser Pin geht LOW wenn der 595 zuhören soll
    const int  pinClock     = 5; // Clock
    const int  pinData      = 6; // Über diesen Pin werden die Bits geschoben

    int pinSignal           = 2;
    bool impulse            = 0;
    
    byte digits [10]; // Definitions der 7-bit Werte für die Darstellung
    long numberToDisplay = 0; // Zahl die dargestellt werden soll
    const int registers = 6; // Anzahl der verwendeten Schieberegister
    byte registerArray [registers]; // Array of numbers to pass to shift registers

    void setup() {
      pinMode (pinLatch, OUTPUT);
      pinMode (pinClock, OUTPUT);
      pinMode (pinData, OUTPUT);

      pinMode(pinSignal, INPUT);  
      attachInterrupt(digitalPinToInterrupt(pinSignal), Interrupt, FALLING);  
     
    
     
      // Setup the digits array
      // a = 1 b = 2 c = 4 d = 8 e = 16 f = 32 g = 64
      digits [0] = 8 + 4 + 2 + 1 + 32 + 16;
      digits [1] = 4 + 2;
      digits [2] = 1 + 2 + 64 + 16 + 8;
      digits [3] = 1 + 2 + 64 + 4 + 8;
      digits [4] = 32 + 64 + 4 + 2;
      digits [5] = 1 + 32 + 64 + 4 + 8;
      digits [6] = 1 + 32 + 64 + 16 + 8 + 4;
      digits [7] = 1 + 4 + 2;
      digits [8] = 8 + 4 + 2 + 64 + 32 + 1 + 16;
      digits [9] = 8 + 4 + 2 + 1 + 32 + 64;
    } // setup

    
    void loop()
    {
     
    // for (long i = 0; i <= 999999; i++) {
    // numberToDisplay = i;
    //delay(100);
        
    // numberToDisplay = 188;

    // numberToDisplay kommt aus der Interrupt funktion
     
      if (numberToDisplay < 10)
      {
       registerArray [0] = digits [numberToDisplay];
      }
      else if (numberToDisplay < 100)
      {
        registerArray [1] = digits [numberToDisplay / 10];
        registerArray [0] = digits [numberToDisplay % 10];
      }
      else if (numberToDisplay < 1000)
      {
        registerArray [2] = digits [numberToDisplay / 100];
        registerArray [1] = digits [(numberToDisplay % 100) / 10];
        registerArray [0] = digits [numberToDisplay % 10];
      }
      else if (numberToDisplay < 10000)
      {
        registerArray [3] = digits [numberToDisplay / 1000];
        registerArray [2] = digits [(numberToDisplay % 1000) / 100];
        registerArray [1] = digits [(numberToDisplay % 100) / 10];
        registerArray [0] = digits [numberToDisplay % 10];
      }
      else if (numberToDisplay < 100000)
      {
        registerArray [4] = digits [numberToDisplay / 10000];
        registerArray [3] = digits [(numberToDisplay % 10000) / 1000];
        registerArray [2] = digits [(numberToDisplay % 1000) / 100];
        registerArray [1] = digits [(numberToDisplay % 100) / 10];
        registerArray [0] = digits [numberToDisplay % 10];
      }
      else if (numberToDisplay < 1000000)
      {
        registerArray [5] = digits [numberToDisplay / 100000];
        registerArray [4] = digits [(numberToDisplay % 100000) / 10000];
        registerArray [3] = digits [(numberToDisplay % 10000) / 1000];
        registerArray [2] = digits [(numberToDisplay % 1000) / 100];
        registerArray [1] = digits [(numberToDisplay % 100) / 10];
        registerArray [0] = digits [numberToDisplay % 10];
      }

      sendSerialData (registers, registerArray);
//       }
    } // loop


void Interrupt()
{
    numberToDisplay++;
}


    // Simple function to send serial data to one or more shift registers by iterating backwards through an array.
    // Although registers exists, they may not all be being used, hence the input parameter.
void sendSerialData (
      byte registerCount,  // How many shift registers?
      byte *pValueArray)   // Array of bytes with LSByte in array [0]
    {
      // Signal to the 595s to listen for data
      digitalWrite (pinLatch, LOW);
     
      for (byte reg = registerCount; reg > 0; reg--)
      {
        byte value = pValueArray [reg - 1];
       
        for (byte bitMask = 128; bitMask > 0; bitMask >>= 1)
        {
          digitalWrite (pinClock, LOW);
       
          digitalWrite (pinData, value & bitMask ? HIGH : LOW);
           
          digitalWrite (pinClock, HIGH);
        }
      }
      // Signal to the 595s that I'm done sending
      digitalWrite (pinLatch, HIGH);
    }  // sendSerialData

Hallo,

prima und schön das es nun funktioniert.

Hallo,

nach näherer Betrachtung kannst du die Ziffern im digits Array schon bei der Initialisierung definieren und damit konstant machen. Desweiteren solltest du dir noch folgende Fragen stellen. Was passiert wenn deine darzustellende Zahl überläuft, also plötzlich wieder kleiner wird oder anderweitig sich zu kleiner ändert? Was passiert wenn deine darzustellende Zahl negativ ist? Wurde das getestet?

Desweiteren solltest du dich für numberToDisplay mit volatile und atomic beschäftigen.
Und wenn du weiter Energie reinstecken möchtest kannste die Codezeilen-Dopplungen optimieren.