C, 7 Segment Anzeige im Multiplex, Atmel Studio

Gast #4824118
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ß
Gast #4824120
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?
Gast #4824123
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.
Gast #4824126
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.
Gast #4824132
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ß
Gast #4824134
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.
Gast #4824346
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!
#4824420
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.
Gast #4824461
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 ...).
#4824952
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren