Forum: Mikrocontroller und Digitale Elektronik C, 7 Segment Anzeige im Multiplex, Atmel Studio


von DimiX (Gast)


Lesenswert?

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
von 7segmentdepp (Gast)


Lesenswert?

DimiX schrieb:
> Ich habe einen Board

... und das kennen wir nicht.

Ein Schaltplan wäre durchaus hilfreich sonst wird das hier
zum Ratespiel.

von 7segmentdepp (Gast)


Lesenswert?

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?

von Wolfgang (Gast)


Lesenswert?

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.

von DimiX (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,
reicht das als Schaltplan, oder brauchst noch was konkretes?
Danke für deine Hilfe!
Gruß

von DimiX (Gast)


Lesenswert?

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.

von DimiX (Gast)


Lesenswert?

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ß

von DimiX (Gast)


Lesenswert?

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ß

von Wolfgang (Gast)


Lesenswert?

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.

von DimiX (Gast)


Lesenswert?

Egal was ich mache, das funktioniert nicht richtig.

von Wolfgang (Gast)


Lesenswert?

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?

von BlaBla (Gast)


Lesenswert?

Vielleicht kannst Du Dir hier Informationen holen:
http://mikrocontroller.bplaced.net/wordpress/?page_id=179

von Noname (Gast)


Lesenswert?

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!

von Dieter F. (Gast)


Lesenswert?


von Thomas E. (thomase)


Lesenswert?

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
von Stefan F. (Gast)


Lesenswert?

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

von 7segmentdepp (Gast)


Lesenswert?

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.

von Thomas E. (thomase)


Lesenswert?

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.

von 7segmentdepp (Gast)


Lesenswert?

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 ...).

von Peter D. (peda)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.