Hallo liebe Gemeinschaft, ich bin ein blutiger Anfänger was C und Mikrocontroller angeht, und versuche aus schulungszwecken eine 4 stellige 7 Segment Anzeige mit Atmel Studio in Sprache C zu programmieren. Ausgangssituation. Ich habe einen Board (fertigboard) mit 4 stellige 7 Segment Anzeige, einen Controller Atmega32A, 8 Pins (PORTB) für die 7 Segment Anzeige und 4 Pins (PORTA) für jede der 4 Stellen. Ich kann problemlos eine Stelle ansteuern und von 0 bis 9 automatisch durchlaufen lassen, und zwar so: char ledmuster [10]= // Array { 0b11000000, // muster 0 0b11111001, // muster 1 0b10100100, // muster 2 0b10110000, // muster 3 0b10011001, // muster 4 0b10010010, // muster 5 0b10000010, // muster 6 0b11111000, // muster 7 0b10000000, // muster 8 0b10010000, // muster 9 }; #define F_CPU 16000000U #include <util/delay.h> #include <avr/io.h> uint8_t Zaehler=0; int main(void) { DDRA=0b11111111; DDRB=0b11111111; DDRD=0b00000000; while (1) { PORTD=0b11111111; if(PORTD) for (Zaehler=0; Zaehler<=9; Zaehler++) { PORTB=ledmuster[Zaehler]; _delay_ms(1000); } } } Das funktioniert eiwandfrei. Sobald aber 2te Stelle zukommen soll, reicht mein wissen nicht aus wie ich das hinbekommen soll. Ich weiß, dass ich die 4 Pins für jede Stelle einzeln und zeitversetzt ansteuern muss (also im Multiplex), aber ich weiß nicht wie! Ich brauche wenigstens ein Tipp. Ich habe keine Vorstellung wie ich 2 Schleifen gleichzeitig laufen lassen soll, die eine Schleife zählt hoch, die andere zeigt die 4 Stellen an. Bitte um Hilfe, Danke im voraus! Gruß
:
Verschoben durch User
DimiX schrieb: > Ich habe einen Board ... und das kennen wir nicht. Ein Schaltplan wäre durchaus hilfreich sonst wird das hier zum Ratespiel.
DimiX schrieb: > und > versuche aus schulungszwecken eine 4 stellige 7 Segment Anzeige mit > Atmel Studio in Sprache C zu programmieren. Das Ziel ist doch ein Mikrocontroller, nicht wahr? Warum schreibst du hier dann im Bereich "PC-Programmierung"? Du programmierst doch nicht deinen PC um die 7 Segment Anzeige anzusteuern, oder doch?
DimiX schrieb: > Ich weiß, dass ich die 4 Pins für jede Stelle einzeln und zeitversetzt > ansteuern muss (also im Multiplex), aber ich weiß nicht wie! Dann tue das doch, also 1. Pin für Stelle aktivieren 2. zugehörige Ziffer auf Stelle ausgeben 3. Warten (z.B. 5 ms) 4. zurück zu 1. Alle paar Durchläufe, also z.B. jeden 200ten kannst du dann die anzuzeigenden Ziffern ändern. Dein delay(1000) ist Gift für den Programmablauf, weil es den Prozessor für eine ganze Sekunde lahmlegt. Die 5ms bei 3. genauso - eigentlich macht man das mit einem Timer-Interrupt.
Hallo, reicht das als Schaltplan, oder brauchst noch was konkretes? Danke für deine Hilfe! Gruß
Wolfgang schrieb: > Dann tue das doch, also > 1. Pin für Stelle aktivieren > 2. zugehörige Ziffer auf Stelle ausgeben > 3. Warten (z.B. 5 ms) > 4. zurück zu 1. Das hab ich versucht, Nur dann durchläuft das Programm von 0 bis 9999 und wenigen Sekunden durch. Und auf der Anzeigen ist kaum was zu erkennen wie es so schnell durchläuft, dass man nur 4 x 8 sieht. Der soll ja irgendwo zwischen den Zahlen eine Sekunde warte, wie eine Uhr.
7segmentdepp schrieb: > Das Ziel ist doch ein Mikrocontroller, nicht wahr? Es tut mir leid, wenn ich falschen Bereich gewählt habe, ich habe keinen sinnvolleren gefunden. Welchen hätte ich nehmen müssen? Gruß
Wolfgang schrieb: > Dann tue das doch, also > 1. Pin für Stelle aktivieren > 2. zugehörige Ziffer auf Stelle ausgeben > 3. Warten (z.B. 5 ms) > 4. zurück zu 1. > > Alle paar Durchläufe, also z.B. jeden 200ten kannst du dann die > anzuzeigenden Ziffern ändern. Habe das versucht in das Programm einzugeben, so: char ledmuster [10]= // Array { 0b11000000, // muster 0 0b11111001, // muster 1 0b10100100, // muster 2 0b10110000, // muster 3 0b10011001, // muster 4 0b10010010, // muster 5 0b10000010, // muster 6 0b11111000, // muster 7 0b10000000, // muster 8 0b10010000, // muster 9 }; #define F_CPU 16000000U #include <util/delay.h> #include <avr/io.h> uint8_t Zahl1=0b11111110; uint8_t Zahl2=0b11111101; uint8_t Zahl3=0b11111011; uint8_t Zahl4=0b11110111; uint8_t Zaehler=0; uint8_t Zaehler2=0; int main(void) { DDRA=0b11111111; // Port A sind alle Ausgänge DDRB=0b11111111; // Port B sind alle Ausgänge /* Replace with your application code */ while (1) { for (Zaehler=0; Zaehler<=200; Zaehler++) { PORTA=Zahl1; _delay_ms(5); PORTA=Zahl2; _delay_ms(5); PORTA=Zahl3; _delay_ms(5); PORTA=Zahl4; _delay_ms(5); Zaehler++; if (Zaehler=200) { Zaehler2++; PORTB=ledmuster[Zaehler2]; } } } Funktioniert leider nicht! Gruß
DimiX schrieb: > Nur dann durchläuft das Programm von 0 bis 9999 und wenigen Sekunden > durch. Dann hast du die anzuzeigende Zahl bei jedem Durchlauf geändert und nicht nur bei z.B. jedem zweihundertsten. Damit muss das 1/4 Stunde dauern. Immer wenn du über PORTA eine Stelle von deinem Display auswählst, musst du auf PORTB das LED-Muster für diese Stelle ausgeben (Schritt 2). Wenn du PORTB nur bei jedem zweihundertsten Durchlauf änderst, siehst du auf allen Stellen das gleiche Muster.
Egal was ich mache, das funktioniert nicht richtig.
DimiX schrieb: > PORTB=ledmuster[Zaehler2]; Überlege dir mal, was passiert, wenn beispielsweise Zaehler2=12 ist. Was soll dann auf deinem Display dargestellt werden und was musst du dafür wann auf PORTB raus geben?
Vielleicht kannst Du Dir hier Informationen holen: http://mikrocontroller.bplaced.net/wordpress/?page_id=179
In der akt. Fassung des Programms ändert sich deine Anzeige mit dem Takt der CPU - so schnell, wie diese die Schleife halt durchlaufen kann. Logisch, dass du nicht viel erkennen kannst. Für das Ansteuern einer Segementanzeige benötigt man allg. zwei Taktgeber: einen für Änderungen des Displayspeicher (= was angezeigt werden soll) und einen weiteren für die Abbildungsfrequenz des Displayspeichers auf den Segementen. Letzteren kannst du dir sparen; wir sagen einfach so schnell, wie möglich oder er wird über den Controller gesteuert. Bleibt also die Aufgabe den Code für die Anzeige so zu verändern, dass diese nur alle 1/x Sekunden neu beschrieben wird. Viel Erfolg!
Noname schrieb: > Bleibt also die Aufgabe den Code für die Anzeige so zu verändern, dass > diese nur alle 1/x Sekunden neu beschrieben wird. Nein. Das eine ist die Anzeige, das andere ist die Uhr, der Zähler oder was auch immer. Das hat beides gar nichts direkt miteinander zu tun. Für die Anzeige werden nacheinander die 4 Digits angesteuert. Und zwar mindestens so schnell, daß die Anzeige nicht flimmert. Damit alle 4 Ziffern gleich hell leuchten, muß die jeweilige Anzeigezeit immer gleich lang sein. Das steuert man praktischerweise mit einem Timer. Z.B. mit einem 1ms-Takt. In diesem Fall käme jede Ziffer 250 Mal pro Sekunde dran. Das kann man gleich in der ISR des Timer Interrupts erledigen.
1 | #define DIGIT0 PORTB |= (1 << 0)
|
2 | #define DIGIT1 PORTB |= (1 << 1)
|
3 | #define DIGIT2 PORTB |= (1 << 2)
|
4 | #define DIGIT3 PORTB |= (1 << 3)
|
5 | #define DIGITOFF PORTB &= 0xF0
|
6 | #define BLANK PORTA = 0
|
7 | |
8 | volatile unsigend char Ziffer0 = 0; |
9 | volatile unsigend char Ziffer1 = 0; |
10 | volatile unsigend char Ziffer2 = 0; |
11 | volatile unsigend char Ziffer3 = 0; |
12 | |
13 | ISR(Timer-Int) |
14 | {
|
15 | static unsigned char digit = 0; |
16 | |
17 | DIGITOFF; //Das ist wichtig,... |
18 | BLANK; //...sonst leuchten einzelne Segmente nach |
19 | |
20 | switch(digit) |
21 | {
|
22 | case 0: |
23 | PORTA = Ziffer0; |
24 | DIGIT0; |
25 | break; |
26 | |
27 | case 1: |
28 | PORTA = Ziffer1; |
29 | DIGIT1; |
30 | break; |
31 | |
32 | case 2: |
33 | PORTA = Ziffer2; |
34 | DIGIT2; |
35 | break; |
36 | |
37 | case 3: |
38 | PORTA = Ziffer3; |
39 | DIGIT3; |
40 | break; |
41 | }
|
42 | digit++; |
43 | digit %= 4; |
44 | }
|
In der main werden in Ziffer0..Ziffer3 in aller Ruhe entsprechend des Anzeigewertes die Bitmuster eingetragen. Das kann man zyklisch machen oder auch nur wenn sich ein Wert geändert hat.
:
Bearbeitet durch User
In meinem Buch Band 3 kommt ein konkretes Beispiel mit 2 Stellen vor, wenn du das verstanden hast, kannst du es ganz sicher auf 4 Stellen erweitern. http://stefanfrings.de/mikrocontroller_buch/index.html
Thomas E. schrieb: > #define DIGIT0 PORTB |= (1 << 0) Nein. Seine Schaltung hat PNP Transistoren mit Emitter an Vcc Damit braucht er eine aktive 0 um die Stelle anzusteuern.
7segmentdepp schrieb: > Nein. > > Seine Schaltung hat PNP Transistoren mit Emitter an Vcc > Damit braucht er eine aktive 0 um die Stelle anzusteuern. Tatsächlich. Ja, dann ändere das doch, anstatt nur rumzumäkeln. Dazu sind defines doch da.
Thomas E. schrieb: > dann ändere das doch, anstatt nur rumzumäkeln. Ich halte es auch nicht für didaktisch sinnvoll einem Anfänger eine ISR vorzusetzen wo er noch nicht mal weiss wie sie funktioniert und er sich an der Konfiguration des erforderlichen Timers die Zähne ausbeissen wird (werden dürfte ...).
DimiX schrieb: > Ich habe keine Vorstellung wie ich 2 Schleifen gleichzeitig laufen > lassen soll, die eine Schleife zählt hoch, die andere zeigt die 4 > Stellen an. Man muß beide Schleifen entkoppeln, d.h. die eine (Multiplex) muß im Timerinterrupt laufen. Alles andere führt in eine Sackgasse. Um den Timerinterrupt zu lernen, mach erstmal nur ne Blink-LED damit.
Man kann das auch ohne Timer-Interrupt machen, nämlich mit einem Zustandsautomaten.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.