4x7Seg-Anzeige über 4x ULN2803A und 4x 74HC595N mit Arduino Mega2560 ansteuern

Hallo Leute,
ich bastle seit geraumer Zeit an meinem Arduino-Projekt herum und bin jetzt in einer Sackgasse gelandet in der ich nicht so richtig weiter komme. Deswegen brauche ich euren Rat.

Zum Projekt:
Ich möchte vier 7Seg-Anzeigen über vier ULN2803A und diese über vier 74HC595N ansteuert. (Schaltplan im Anhang)
Ich habe die halbe Schaltung (also nur 2x7Segment) auf einen Breadboard aufgebaut und mit diesem Code getestet.

int taktPin=8; //SH_CP
int speicherPin=9; //ST_CP
int datenPin=10; //DS

void setup(){
  pinMode(taktPin, OUTPUT);
  pinMode(speicherPin, OUTPUT);
  pinMode(datenPin, OUTPUT);
}
void loop(){
  for (int wert=0; wert<65536; wert++){
  sendeBytes(wert);
}}
void sendeBytes(int wert){
  digitalWrite(speicherPin, LOW);
  shiftOut(datenPin, taktPin, MSBFIRST,wert >> 8);
  shiftOut(datenPin, taktPin, MSBFIRST,wert & 255);
  digitalWrite(speicherPin, HIGH);
  delay(20);
}

Jedes Segment der 16 Segmente wurde angesteuert. Schaltung ist also korrekt!

Problem:
Ich möchte Zahlen und Buchstaben auf dem Display darstellen. Deswegen habe ich mir für den Anfang eine 8Bit Wahrheitstabelle erstellt um die passende Dezimal- und Binärzahl für die Zahl auf der 7Segment zu ermitteln.
Bsp: 0 auf ersten 7Seg = 00111111 in Binär = 63 Dezimal

Jetzt habe ich eine 3 auf die 1. 7Seg-Anzeige gebracht (quasi die 1er Stelle).
Das hat auch funktioniert.

Jetzt möchte ich gerne noch eine 1 auf die 2. 7Seg-Anz. (10er Stelle) bringen.
Das funktioniert nicht! Hier der Code:

int taktPin=8; //SH_CP
int speicherPin=9; //ST_CP
int datenPin=10; //DS 
int zahlen[10]={63,6,91,79,102,109,125,7,127,111};  //Zahlen für 7Seg 0,1,2,3,4,5,6,7,8,9,
int buchstaben[5]={119,118,57,118,56}; //Buchstaben für 7Seg A,B,C,H,L

void setup(){
  pinMode(taktPin, OUTPUT);
  pinMode(speicherPin, OUTPUT);
  pinMode(datenPin, OUTPUT);
}

void loop(){
  digitalWrite(speicherPin, LOW);
  shiftOut(datenPin, taktPin, MSBFIRST,zahlen[2]>>8);
  shiftOut(datenPin, taktPin, MSBFIRST,zahlen[4]);
  digitalWrite(speicherPin, HIGH);
  delay(250); 
}

Frage 1: Was mach ich falsch? Wo ist mein Denkfehler?

Frage 2: Muss ich mir eine 16Bit Wahrheitstabelle (später 32Bit) anlegen und mir den Wert heraussuchen der für 13 auf zwei 7Seg steht? Das wären dann aber 89 Zahlen (später 9989) die ich mir neu suchen müsste.

Frage 3: Kann ich nicht einfach, jedes Byte an die Stelle (1er, 10er, 100er, 1000er) senden wo es hin soll?
Bsp: Byte für 3 gehe zum 1.Register und Byte für 1 gehe zum 2.Register

Frage 4: Oder, kann mir nicht die Dezimale 6 und die Dezimale 79 zusammenrechnen sodass am Ende eine 13 auf der 7Seg steht?

Danke

Warum verschiebst Du denn das Byte in shiftOut(datenPin, taktPin, MSBFIRST,zahlen[2]>>8); nochmal um 8 Bit? Du hast doch schon ein Byte?
Im ersten Code wurde das Verschieben gemacht, um an der high-Byte der 2-Byte Integer zu kommen. Deine Werte sind aber alle schon Bytes.
Daher sollte ein shiftOut(datenPin, taktPin, MSBFIRST,zahlen[2]); schonmal reichen.
Mehr hab ich erstmal nicht gesehen.

Ansonsten

Das funktioniert nicht!

Ist nicht sehr hilfreich. WAS passiert denn? Ok, es passiert ja nicht das erwartete, aber irgendwas passiert ja. Ich vermute, das das erste Segment immer aus bleibt, weil Du immer eine 0 (B00000000) in die Registerkette schiebst und damit keine der LEDs geschaltet werden.
Mario.

Zur Frage 3:
Natürlich kannst du das machen.

z.B. so:

digitalWrite(speicherPin, LOW);
shiftOut(datenPin, taktPin, MSBFIRST,zahlen[4]); // viertes Segment
shiftOut(datenPin, taktPin, MSBFIRST,zahlen[3]); // drittes Segment
shiftOut(datenPin, taktPin, MSBFIRST,zahlen[2]); // zweites Segment
shiftOut(datenPin, taktPin, MSBFIRST,zahlen[1]); // erstes Segment
digitalWrite(speicherPin, HIGH);

Warum das ">> 8" weckgelassen werden muss hat mkl0815 schon erklärt, sollte also klar sein.

Danke für die schnelle Antwort.

int taktPin=8; //SH_CP
int speicherPin=9; //ST_CP
int datenPin=10; //DS 
int zahlen[10]={63,6,91,79,102,109,125,7,127,111};  //Zahlen für 7Seg 0,1,2,3,4,5,6,7,8,9,
int buchstaben[5]={119,118,57,118,56}; //Buchstaben für 7Seg A,B,C,H,L

void setup(){
  pinMode(taktPin, OUTPUT);
  pinMode(speicherPin, OUTPUT);
  pinMode(datenPin, OUTPUT);
}

void loop(){
  digitalWrite(speicherPin, LOW);
  shiftOut(datenPin, taktPin, MSBFIRST,zahlen[2]>>8 );
  shiftOut(datenPin, taktPin, MSBFIRST,zahlen[4]);
  digitalWrite(speicherPin, HIGH);
  delay(250); 
}

Ich dachte wenn ich "shiftOut(datenPin, taktPin, MSBFIRST,zahlen[2]>>8);" sende, wird zahlen[2] um ein Byte nach rechts verschoben. Quasi ins 2. Register und dort als 1 auf 7Seg ausgeben.
Und der Befehl "shiftOut(datenPin, taktPin, MSBFIRST,zahlen[4]);" sorgt dafür, dass zahlen[4] ins 1.Register geschoben wird und an der 1er Stelle eine 3 erscheint

Was aber passiert!!!
Es erscheint eine 4 (soll 3) auf der 7Seg von der 1er Stelle und nichts (soll 1) auf der 7Seg von der 10er Stelle.

@J3RE

Hab ich ja erst auch so gemacht. Aber da kommt immer nur Mist auf die 10er Stelle.

Was aber passiert!!!
Es erscheint eine 4 (soll 3) auf der 7Seg von der 1er Stelle und nichts (soll 1) auf der 7Seg von der 10er Stelle.

Das auf der 10er Stelle nix ausgegeben wird, ist klar, das hatten wir schon erklärt. Du schickst eine 0 und damit wird keine LED eingeschaltet.
Das auf der 1er Stelle ein 4 ausgegeben wird, ist korrekt, denn laut Deinem Code ist Index 0 der Wert für die Zahl 0 und Index 4 der Wert für die Zahl 4:

shiftOut(datenPin, taktPin, MSBFIRST,zahlen[4]);

int zahlen[10]={63,6,91,79,102,109,125,7,127,111}; //Zahlen für 7Seg 0,1,2,3,4,5,6,7,8,9,

Frage 2: Muss ich mir eine 16Bit Wahrheitstabelle (später 32Bit) anlegen und mir den Wert heraussuchen der für 13 auf zwei 7Seg steht? Das wären dann aber 89 Zahlen (später 9989) die ich mir neu suchen müsste.

Du brauchst nicht 9989 Zahlen. Du brauchst die eingeschaltenen Segmente nur einmal für jede Zahl also bei zahlen von 0 bis 9 nur 10 Werte. Diese können dann auf jeder Stelle ausgegeben werden. Um Zahlen zu schreiben hast Du ja auch nur 10 Zeichen und nicht 9999 verschiedenen Zeichen um eine 4-stellige Zahl zu schreiben. Das ist ja das funktionaelle an den arabischen Zahlen.

Ein MAX7219 würde mit weniger Aufwand bis zu 8 Stellen 7-Segmentanzeigen ansteuern.

Grüße Uwe

Danke für eure Hilfe ich hab den Fehler gefunden.
Ein Pin auf den Breadboard hatte sich gelöst und deswegen hat die eine 7Seg immer so komische Dinge angezeigt. Deswegen bin ich vermutlich auch vom richtigen Programmierweg abgekommen. :cold_sweat:

@uwefed

Ein MAX7219 würde mit weniger Aufwand bis zu 8 Stellen 7-Segmentanzeigen ansteuern.

Welche Vorteile würde mir der MAX7219 bringen?
Würde der Programmieraufwand geringer bzw. die Verkabelung?
Ich würde doch die vier 74HC595 einsparen aber die vier ULN2803 bleiben doch?

Warum ich frage ist. Ich will einen analogen Sensor auswerten und dessen Werte darstellen. Der Sensor (US oder IR) soll einen Abstand messen und mir diesen dann in Zentimetern oder Millimetern auf der Anzeige ausgeben.

http://playground.arduino.cc//Main/MAX72XXHardware

Der MAX7219 kann ohne weitere Bausteine außer eines Widerstandes bis zu 8 Stellen 7-Segment Display mit gemeinsamer Kathode ansteuern. Zur Steuerung braucht er 3 Pins.
Die Konversion Zahl-Segmente übernimmt der MAX7219. Du kannst aber auch im Matrix-Modus jedes einzelne Segment ansteuern.

Laut Deiner Zeichnung hast Du Displays mit gemeinsamer Anode.

Grüße Uwe

So richtig kann ich mich nicht mit deinem Vorschlag anfreunden. (Trotzdem Danke!) :wink:

Pro:
-Verkabelung wird einfacher und damit auch Platzbedarf

Kontra:
-Ich benötige trotzdem einen ULN weil ich meine 7Seg´s mit 8,4V bei 20mA betreibe und der Max das nicht verträgt.

Neutral:
-Preis:
6,05€(MAX)+0,35€(ULN)=6,40€
40,31(74HC595)+40,35€=2,64€

arduino-yoda:
So richtig kann ich mich nicht mit deinem Vorschlag anfreunden. (Trotzdem Danke!) :wink:

Pro:
-Verkabelung wird einfacher und damit auch Platzbedarf

Kontra:
-Ich benötige trotzdem einen ULN weil ich meine 7Seg´s mit 8,4V bei 20mA betreibe und der Max das nicht verträgt.
http://www.reichelt.de/index.html?;ACTION=7;LA=3;OPEN=0;INDEX=0;FILENAME=A500%252FSA23-12RT.pdf

Neutral:
-Preis:
6,05€(MAX)+0,35€(ULN)=6,40€
40,31(74HC595)+40,35€=2,64€

Ich verstehe nicht, wieso Du die Displays mit 8,4V betreiben mußt.
Du kannst den MAX7219 nicht mit dem ULN2803 kombinieren.
Grüße Uwe

uwefed:

arduino-yoda:
So richtig kann ich mich nicht mit deinem Vorschlag anfreunden. (Trotzdem Danke!) :wink:

Pro:
-Verkabelung wird einfacher und damit auch Platzbedarf

Kontra:
-Ich benötige trotzdem einen ULN weil ich meine 7Seg´s mit 8,4V bei 20mA betreibe und der Max das nicht verträgt.
http://www.reichelt.de/index.html?;ACTION=7;LA=3;OPEN=0;INDEX=0;FILENAME=A500%252FSA23-12RT.pdf

Neutral:
-Preis:
6,05€(MAX)+0,35€(ULN)=6,40€
40,31(74HC595)+40,35€=2,64€

Ich verstehe nicht, wieso Du die Displays mit 8,4V betreiben mußt. Ok jetzt hab ichs verstanden; Du benutzt Displays mit 4 LED in Serie weil diese ein große Baugröße haben. Da ist der MAX7219 ungeeignet.
Du kannst den MAX7219 nicht mit dem ULN2803 kombinieren.
Grüße Uwe

Ich verstehe nicht, wieso Du die Displays mit 8,4V betreiben mußt.

Forward Voltage per Segment = 7,4V (max. 10V)

Ich nehme 8,4V, weil die Verlustleistung über den Vorwiderstand geringer ist als bei 7,4V und somit auch die Wärmeabgabe.

Du kannst den MAX7219 nicht mit dem ULN2803 kombinieren.

Was kann ich dann machen um mit meinen 8,4V klar zukommen?

Mit dem MAX wirst du nicht auf diese Spannung kommen. Hier mal mein ähnliches Projekt.
http://arduino.cc/forum/index.php/topic,131882
Da habe ich es genauso gemacht wie du es vorhast mit 4 Shieberegisten in "Reihe" mit ULNs dahinter.
Gruß
Der Dani