www.mikrocontroller.net

Forum: Mikrocontroller und Elektronik Geisterleuchten bei 7-Segment Anzeige


Autor: Geisterlicht (Gast)
Datum:

Hallo,

mit einem ATTINY 2313 habe ich einen vierstelligen 7-Segment
Countdowntimer realisiert.
Der HW-Aufbau sieht so aus: die gemeinsamen Anoden der Stellen hängen
über je einen NPN Transistor mit Kollektorvorwiderstand an VCC und über
je einen Basiswiderstand an den POTD Pins.
Die Kathoden der Segmente sind über je einen Vorwiderstand an die PORTB
Pins angeschlossen (POTB.0=a, ..., POTB.6=g). Mit PORTD.5 frage ich
einen Schalter ab.
Die Wesentlichen Ausschnitte des Codes sind unten angefügt.

Minuten und Sekunden zählen schön runter und werden auch ordentlich
angezeigt. Alle Segmente die eine Zahl bilden sollen, leuchten auch
hell.

ABER! Einige der Segmente, die dunkel sein sollen leuchten trotzdem
schwach mit und zwar in wechselnden wiederkehrenden Mustern.
Wie bekomme ich das Geisterleuchten weg? Liegt es an der SW, ev. in
stellenanzeige() die Port-Initialisierungssequenz optimieren?
Oder hat der Proz ne Macke (ich hab den von Pollin gekauft, vielleicht
ist der sowas wie Zweite-Wahl-Ramsch...)?

Helft mir mal kurz auf die Sprünge, danke!





/************************************************************************/
/*              Initialisierung                      */
/************************************************************************/

void init_bd (void)
{
  // Port Initialisierung:
  // PORTB Ausgang für die einzelnen Segmente, Seg.x leuchtet, wenn
PINx==LO
  // PORTD 0-4 Ausgäne für 7seg Anoden, Pin 5 als Eingang für
Tilt-Schalter
  PORTB  = 0xFF; // Alles auf hi, damit nichts leuchtet!
  PORTD  = 0x10; // Ausgang 0-4 auf lo, damit nichts leuchtet! PD5
pullup ein für tilt_Schalter
  DDRB  = 0xFF; // Alles auf Ausgang
  DDRD  = 0x0F;  // 0-3 auf Ausgang, PD4,5,6 auf Eingang

    /* Timer Initialisierung */
  TCCR1A  = 0;
  TCCR1B  = (1<<WGM12) | (1<<CS12) /*| (1<<CS11) | (1<<CS10)*/;
  TIMSK  |= (1<<OCIE1A);  // Compare Interrupt aktivieren
  OCR1A  = TWAIT_1P0_S;  // Compare-Wert auf eine Sekunde
  sei();
  // Initialisierung der Startwerte
  zustand    = COUNTDOWN;
    minuten    = MAXMINUTEN;
    sekunden  = MAXSEKUNDEN;
  time_cnt  = 0;
  tilt    = 0;
  digit    = 0;
}

/************************************************************************/
/*    Abfrage des TILT-Schalters                              */
/************************************************************************/

void poll_tilt (void)
{ // Abfrage, ob TILT-Schalter gedrückt ist
  if (PIND & (1<<PIND5))
  {
    tilt    = 1;
  }
}

/************************************************************************/
/*  Verwaltung der Zustände, Zeitberechnung und Aktionen    */
/************************************************************************/

void zustandsautomat (void)
{
   bla;
   bla;
   bla;

  // Umsetzung der Dezimal- in Binärzahlen zur Erleuchtung der
LED-Segmente
  for (i = 0; i < ANZSTELLEN; i++)
  {
    bin_out[i] = SEGMENTE[dez_out[i]];  // Binärmuster für Ausgabe
  }
   bla;
}

/************************************************************************/
/*             Ausgabe auf 7-Segmentanzeige        */
/************************************************************************/

void stellenanzeige(void)
{// Ausgabe der Binärwerte auf PORTB und Weiterschalten der Stelle durch
PORTD
  PORTB =  bin_out[digit];
  PORTD = (PORTD & 0xE0) | (1<<digit);

  if (digit < (ANZSTELLEN-1))
  {
    digit++;
  }
  else
  {
    digit = 0;
  }
}

/************************************************************************/
/*              Hauptschleife            */
/************************************************************************/

void bd_loop(void)
{
  // Hauptschleife
  for (;;)
  {
    // Abfrage des Tilt-Schalters
    poll_tilt();
    // Zustände verwalten, Zeit herunterzählen und Binärmuster erzeugen
    zustandsautomat();
    // Anzeige verwalten, Binärmuster auf PORTB, Stellen weiterschalten
    stellenanzeige();
  } // ende Hauptschleife
}


int main( void )
{
  while(1)
  {
    init_bd();
    bangdead_loop();
  }
}
Autor: Karl Heinz Buchegger (kbuchegg) (Moderator)
Datum:

Hier
void stellenanzeige(void)
{// Ausgabe der Binärwerte auf PORTB und Weiterschalten der Stelle durch PORTD
  PORTB =  bin_out[digit];
  PORTD = (PORTD & 0xE0) | (1<<digit);

schaltest du das neue Muster für die Anzeigen schon auf die LED, während
noch die vorhergehende Stelle selektiert ist. Und das siehst du

->

  zuerst die aktuelle Anzeige dunkel schalten
  dann die nächste Stelle selektieren
  dann diese Stelle durch Ausgabe des Musters zum Leuchten bringen
  PORTB = 0x00;  // oder 0xFF je nachdem wie deine LED angeschlossen sind
  PORTD = (PORTD & 0xE0) | (1<<digit);
  PORTB = bin_out[digit];
Autor: Michael M. (Gast)
Datum:

schau dir doch mal das geisterleuchte an...
du wirst die leds der zuletzt gemultiplexten ziffer erkennen
Autor: Bernd (Gast)
Datum:

Mach da mal nen cli (); sei (); davor.

Denke das du die Ausgabe per ISR rausschreibst aber einfach ins Array
schreibst wann du willst ? oder ?

  for (i = 0; i < ANZSTELLEN; i++)
  {
    bin_out[i] = SEGMENTE[dez_out[i]];  // Binärmuster für Ausgabe
  }

Ist nen Schnellschuß... schau halt mal.
Autor: Anja (Gast)
Datum:

Hallo,

bei hoher Taktfrequenz brauchst Du auch noch zusätzlich 2-4 us Delay bis
deine Transistoren tatsächlich ausgeschaltet (Sperrverzögerungszeit)
sind also:

  PORTB = 0x00;  // oder 0xFF je nachdem wie deine LED angeschlossen
sind
  PORTD = (PORTD & 0xE0) | (1<<digit);
  Delay(4 us);
  PORTB = bin_out[digit];
Autor: Falk Brunner (falk)
Datum:

@Anja (Gast)

>bei hoher Taktfrequenz brauchst Du auch noch zusätzlich 2-4 us Delay bis
>deine Transistoren tatsächlich ausgeschaltet (Sperrverzögerungszeit)

Die Sperrverzögerungszeit ist unabhängig von der Taktfrequenz.
Wenn die Schaltstufen was taugen, haben die keine (so hohe)
Sperrverzögerungszeit.

MFG
Falk
Autor: Gast (Gast)
Datum:

Merke: Nur Anfänger halten es für möglich, dass es auch an einer "Macke
im Proz" liegen könnte. Alle erfahrenen Entwickler wissen, dass der
Grund immer im eigenen Programm zu finden ist. Die Frage lautet nie "der
Proz oder der Code?" sondern stets "im Code - nur wo?".
Autor: Anja (Gast)
Datum:

Hallo Falk,

bei niedriger Taktfrequenz ist die Zeitdauer zwischen setzen von PortD
bis setzen PortB eh schon größer als die Sperrverzögerungszeit. Mit 4 us
sollte man dann hoffentlich auf der sicheren Seite sein. Geisterlicht
will ja ausschließen daß es keinen Hardwaredefekt hat.
Autor: Geisterlicht (Gast)
Datum:

Hallo und danke für die Antworten!

Also, wenn ich das jetzt richtig verstehe, muß ich die Segmente erst
ausschalten, bevor ich die Stelle wechsle?

Das ginge mit PORTB = 0xFF (sind ja die Kathoden). Das probiere ich  mal
aus.

Fragen:
@Bernd
Wie ist das gemeint mit sie() und cli()?
Die Anzeige wird in der Hauptschleife ausgegeben. Den Compare-Interrupt
benutze ich, um einen Zeitzähler hochzusetzen, der dann im
Zustandsautomat in der Hauptschleife ausgewertet wird.

@Anja
Ich verwende den internen 8MHz Oszillator. Die Anzeige wird vermutlich
alle ca. 1000 Taktzyklen von Stelle zu Stelle weitergeschaltet. Sollte
das für die BC548 nicht ausreichen?

@Michael M.
Wahrscheinlich hast Du Recht, aber, so schnell kann ich gar nicht
gucken, wie das flimmert ;-)

Also noch Mal danke an alle!
Autor: Geisterlicht (Gast)
Datum:

@Gast

>Merke: Nur Anfänger halten es für möglich, dass es auch an einer "Macke
>im Proz" liegen könnte.

Ja, das merke ich mir. Wollte einen kleinen Scherz machen mit dem
Pollin-Proz :-)
Autor: Anja (Gast)
Datum:

Hallo Geisterlicht,

> Ich verwende den internen 8MHz Oszillator. Die Anzeige wird vermutlich
> alle ca. 1000 Taktzyklen von Stelle zu Stelle weitergeschaltet. Sollte
> das für die BC548 nicht ausreichen?

Ups...
Also: die Wechselfrequenz von Stelle zu Stelle würde ich nicht viel
höher machen als unbedingt nötig: also ca 50-100Hz * Anzahl der Stellen
damit die Anzeige nicht flimmert.
Also bei Dir so maximal 400 Hz bzw. alle 2,5 Millisekunden.
Bei 8MHz / 1000 Zyklen = 8000 Hz wundert es mich nicht daß der Effekt so
stark sichtbar ist.
Ich mache das multiplexen gerne in einer Timer-Interrupt-Routine.
Dann ist auch sichergestellt daß alle Digits gleichmäßig hell leuchten.
Den 1 Sekunden-Timer kann man dann als vielfaches des Multiplex-Taktes
erreichen. z.B. alle 4 Digits * 100 Durchläufe.

BC548 sind Transistoren für Verstärker-Anwendungen und nicht für
Schalter-Betrieb spezifiziert. Eine Sperrverzögerungszeit ist daher in
den Datenblättern nicht angegeben. Was nicht heißt daß man den BC548
nicht für Schalteranwendungen verwenden darf. Das Verhalten ist halt nur
nicht spezifiziert.
Bei Schalteranwendungen verwende ich gerne den 2N2222A der hat dann so
0,25 us Sperrverzögerungszeit bei 150mA Kollektorstrom.
Autor: Gast (Gast)
Datum:

Anjas Bemerkungen sind sehr richtig. Die Multiplexfrequenz sollte nicht
höher sein als für eine flimmerfreie Darstellung nötig. 400 Hz sind ein
guter Wert.

Den Ziffernwechsel würde ich nach folgendem Schema bewerkstelligen:

- Alle Segmente ausschalten
- Den "alten" Transistor sperren
- Evtl. kurz warten (µs-Bereich)
- Den "neuen" Transistor durchschalten
- Das neue Segmentmuster anlegen

Dann sind die Segmente während des Umschaltens stromlos und es sollten
keine Geisterbilder auftreten.
Autor: Da Dieter (dieter)
Datum:

Geisterlicht schrieb:
> @Gast
>
>>Merke: Nur Anfänger halten es für möglich, dass es auch an einer "Macke
>>im Proz" liegen könnte.
>
> Ja, das merke ich mir. Wollte einen kleinen Scherz machen mit dem
> Pollin-Proz :-)

Achso, ja als Pollinkunde is das was anderes. Da darf man dann auch an
der gelieferten Hardware zweifeln ;)
Autor: Hannes Lux (hannes)
Datum:

> Den Ziffernwechsel würde ich nach folgendem Schema bewerkstelligen:

> - Alle Segmente ausschalten
> - Den "alten" Transistor sperren
> - Evtl. kurz warten (µs-Bereich)
> - Den "neuen" Transistor durchschalten
> - Das neue Segmentmuster anlegen

Ich mach's immer anders herum:

- Alle Digits ausschalten (irgendeines wird wohl ein gewesen sein)
- Digit-Index hochzählen und begrenzen
- Neues Segment-Bitmuster holen und ausgeben (kostet aufgrund der
  Positionierung im Array etwas Zeit, die hier parasitär als
  Verzögerung wirkt)
- Neues Digit einschalten

Da ich oftmals aufgrund der Vereinfachung der Platine Segment-Leitungen
und Digit-Leitungen wild durcheinander auf die Portpins zweier Ports
verteile, sieht es meist noch etwas anders aus (ASM):

- Ausgabe einer 16-Bit-Konstante an beide Ports, die alle Digits und
  Segmente deaktiviert (2 mal LDI/OUT), während der folgenden Schritte
  dürfen sich die Transistoren "erholen"
- Digit-Index hochzählen und begrenzen (Ring, Anzahl der Digits)
- Pointer auf SRAM-Array (und Index) positionieren (2 x LDI, ADD, ADC)
- Segment-Bitmuster aus Array holen (2 mal LDD)
- Digit-Bitmuster aus Array holen (2 mal LDD)
- Beide Bitmuster miteinander verknüpfen (2 x OR, AND, je nach
  Schaltung)
- Bitmuster ausgeben (2 x OUT)

Das Bereitstellen der Segment-Bitmuster für jedes Digit erledigt die
Mainloop bereits beim Ermitteln des anzuzeigenden Wertes. Die
Digit-Bitmuster wurden beim Initialisieren aus dem Flash ins SRAM-Array
kopiert. Die Multiplex-Routine läuft selbstverständlich im
Timer-Interrupt. Durch Nutzen eines Index' für mehrere
SRAM-Lese-Zugriffe (2 Bytes Segment-Bitmuster, 2 Bytes Digit-Bitmuster)
über LDD bleibt der Code schlank und schnell. Meist sind auch noch 4
Exklusiv-Register für ISRs drin (2 obere, 2 untere), das spart dann
etliche PUSH und POP.

...
Autor: Bernd Wiebus (Gast)
Datum:

Hallo Gast.

> Merke: Nur Anfänger halten es für möglich, dass es auch an einer "Macke
> im Proz" liegen könnte. Alle erfahrenen Entwickler wissen, dass der
> Grund immer im eigenen Programm zu finden ist. Die Frage lautet nie "der
> Proz oder der Code?" sondern stets "im Code - nur wo?".

Nö. Als ich so Anno 97 das erste mal mit Microcontrollern rumgemacht
habe,
habe ich mir prompt durch irgendeinen Schluss zwischen Leiterbahnen die
Ausgangsports abgeschossen (Ein Zweig des Totempfahls).
Allerdings konnte ich am Oszilloskop die Pins noch um 0,2V wackeln
sehen, in dem Rythmus, in dem es geplant war.....insofern war alles
klar.

Ich hab auch erstmal mit dem kaputten IC weitergemacht, bis ich soweit
war, das ich von der SW alles so hatte wie ich wollte......warum ein
zweites IC riskieren?

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel




Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder GIF-Format hochladen.
Siehe Bildformate
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net