Forum: Mikrocontroller und Digitale Elektronik Funktion für die 7-Segment Anzeige aufbauen


von Markus (Gast)


Lesenswert?

Hallo,

ich möchte mir eine Funktion für die Ansteuerung von vier 7 Segment 
Anzeigen
erstellen.
Die ganze Schaltung habe ich mit einem Atmega8 und vier Anzeigen 
aufgebaut
und programmiert.
Jetzt möchte ich eine Funktion erstellen, welcher ich eine Zahl übergebe 
und der Atmega diese Zahl an die Anzeige rausspuckt.
Beim multiplexen braucht man bekantlich eine Interrupt Routine und genau 
da liegt mein Problem.
Die ISR kann ich doch nicht in die Funktion schreiben oder?
Der Timer muss ja auch nur einmal initialisiert werden also kann ich es 
auch nicht in die Funktion schreiben.
Wie könnte man so was aufbauen?

Für die Tipp's bin ich sehr dankbar.

von STK500-Besitzer (Gast)


Lesenswert?

Man nehme eine globale Variable, in die man den anzzeigenden Wert 
schreibt.

von Peter D. (peda)


Lesenswert?


von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich habe es in einem Beispiel so gemacht:
http://www.mikrocontroller.net/articles/Pollin_Funk-AVR-Evaluationsboard#Uhr_mit_7-Segment-Anzeige

Die "Zahl" (bei mir Ziffern einer Uhrzeit) wird in der Timer-ISR in ein 
globales Array led7segment_ziffern[] geschrieben, wenn sich die Zahl 
geändert hat.

Meine Multiplexroutine led7segment_multiplex() wird ebenfalls in der 
Timer-ISR regelmäßig aufgerufen.

Die Hardware meiner Uhr ist allerdings etwas "exotisch", weil ich zum 
Einsparen von I/O-Leitungen am µC einen herumliegenden 
BCD-nach-7Segment-Decoder CA3161 von Intersil benutzt habe. Den findet 
man nicht mehr so einfach.

Es ist auch eine Schaltungsvariante mit einem Schieberegister 74HC164 
angegeben. Man kann sicher auch eine Variante mit dem 74xx595 wie im 
AVR-Tutorial: Schieberegister bauen.

von Bernd (Gast)


Lesenswert?

@ Peter, von ADC hat er nix gesagt... hab deinen Code mal überflogen, 
sieht so aus als würde die letzte Stelle "springen", will Sagen, 10 BIT 
reichen für 4 Stellen nicht aus.

Für einen Anfänger ne Zumutung :-)

#define SCALE ((u32) ((65536.0 * MAX_VAL / DECIMALS + 512) / 1024))

Kommt 128000,5 heraus. Linearisiert ist auch nix, ist der Wandler so gut 
?

von Holger T. (holgert)


Lesenswert?

Ich denke, Markus ist erst mal auf der Suche, wie man das pprinzipiell 
löst. Ich würde es so machen:

1. Baue Dir eine Funktion, die Dir für eine gebene 4-Bit Zahl den 
nötigen 7-Segment code in einem Byte zurückgibt (Das ist einfach mit 
einer Tabelle zu lösen)

2. Baue Dir eine Funktion (die Funktion, die Du im Betreff suchst), die 
eine gegebene binäre Zahl (16-bit, kann aber nicht voll ausgenutzt 
werden, da nur 4 digits) in ihre Dezimalstellen zerlegt, codiere die 
erhaltenen 4 BCD-Zahlen mit Hilfe von (1) um und lege die Bitmuster der 
Reihe nach im RAM ab.

Fertig! Wenn ein neuer Wert dargestellt werden soll, gehe zu (2).

Nun wird da noch gar nichts angezeigt, die Werte stehen im RAM.
Das Anzeigen (multiplexen) wird dann (z.B. ale 20ms) in der Timer-ISR 
durchgeführt, indem der Wert aus dem RAM (pointer) in die (richtige 
Stelle der) Anzeige geschrieben wird. Danach ist der pointer neu zu 
setzen.

hoffe, das hilft weiter
-Holger

von Peter D. (peda)


Lesenswert?

Bernd schrieb:
> @ Peter, von ADC hat er nix gesagt... hab deinen Code mal überflogen,
> sieht so aus als würde die letzte Stelle "springen", will Sagen, 10 BIT
> reichen für 4 Stellen nicht aus.

Ja, bei einer Anzeige bis 2000 muß diese natürlich immer um 2 Schritte 
springen, da der ADC ja nur 1024 Schritte hat.
D.h. 2000 / 1024 ist nicht exakt 2, daher:

0000, 0001, 0003, 0005, ... 1994, 1996, 1998


Peter

von Karl H. (kbuchegg)


Lesenswert?

Markus schrieb:

> Jetzt möchte ich eine Funktion erstellen, welcher ich eine Zahl übergebe
> und der Atmega diese Zahl an die Anzeige rausspuckt.
> Beim multiplexen braucht man bekantlich eine Interrupt Routine und genau
> da liegt mein Problem.
> Die ISR kann ich doch nicht in die Funktion schreiben oder?
> Der Timer muss ja auch nur einmal initialisiert werden also kann ich es
> auch nicht in die Funktion schreiben.
> Wie könnte man so was aufbauen?


Jungs. Das ist eine Frage nach einer generellen Vorgehensweise.
Würde mich allerdings auch interessieren, wie ihr das so angeht:

Problem:
Man hat da mehrere Subsysteme, die alle zusammen in eine ISR könnten. 
Zb. Entprellen und Multiplexen.

Die für mich vernünftigste Methode um das Ganze modular zu halten, ist 
es für jedes Subsystem einen InterruptHandler zu schreiben und den dann 
von der gemeinsamen ISR aufzurufen.

Ungefähr so
1
#include "keys.h"
2
#include "multiplex.h"
3
4
ISR( ... )
5
{
6
  handleKeyInterrupt();
7
  handleMultiplexInterrupt();
8
}

Die Alternative, nämlich in der ISR jeweils den Code aus den beiden 
Interrupt Handlern zusammenzukopieren, find ich nicht so prickelnd.

Interrupt Handler ist kein allzugrosses Problem. Belibt noch den Timer 
zu konfigurieren. Im Idealfall hätte ja jedes Subsystem seinen eigenen 
Timer. Nur spielts das hardwaremässig nicht. Bleibt also nur in den 
sauren Apfel zu beissen und die Timerinitialisierung aus dem Keys-Modul 
bzw. Multiplex-Modul rauszunehmen und in main() zu verschieben.

Der absolute Idealfall wäre ja sowas
1
#include "keys.h"
2
3
int main()
4
{
5
  uint8_t leftKey  = RegisterKey( PIND, PD1 );
6
  uint8_t rightKey = RegisterKey( PIND, PD2 );
7
8
  while( 1 ) {
9
    if( KeyPressed( leftKey ) )
10
      ...
11
12
    if( KeyPressed( rightKey ) )
13
      ...
14
  }
15
}

Das also der ganze Timer und ISR Mechanismus für die Tasten aus main() 
rausgehalten wird. Mir ist schon klar, dass das deswegen nicht 
funktioniert, weil da nun mal kein BS drunter liegt, welches einen Timer 
bzw. ISR virtualisiert. Aber mit der Alternative
1
#include "keys.h"
2
#include "multiplex.h"
3
4
ISR( ... )
5
{
6
   ...
7
   Code für die Key-Behandlung
8
   ...
9
   Code für die Multiplexbehandlung
10
}
11
12
int main()
13
{
14
  Timer aufsetzen für Keys und Multiplexing
15
16
  while( 1 )
17
    ...
18
}

bin ich auch nicht so glücklich (auch wenn ich noch nichts besseres 
gefunden habe). Vor allem der Teil 'Timer aufsetzen' in main() tut mir 
in der Seele weh.

von Markus (Gast)


Lesenswert?

Hallo und danke für die Antworten.
Sorry, dass ich mich nicht gemeldet habe, war gestern den ganzen Tag 
unterwegs.

@Karl Heinz Buchegger,
du sprichst mir aus der Seele.

Da ich noch relativ unerfahren in C bin.
Wieviele Variablen kann ich einer Funktion übergeben?
Die Idee mit dem Interrupt Handler finde ich gar nicht mal so schlecht.
Das ist ja nur eine weitere Funktion die im Interrupt aufgerufen wird, 
muss ich jetzt dieser Funktion die Variablen übergeben oder reicht es 
die Variablen Global zu deklarieren?

Ich stelle mir das so vor:
In der ISR wird eine Funktion mit einem Pointer aufgerufen, der Pointer 
übergibt bei jedem Aufruf eine Zahl von 1 bis 4, also wird bei jedem 
Aufruf
die Zahl um eins erhöht.
Die Zahl soll die Aktuelle anzeige signalisieren.

Jetzt wird in der main (Endlosschleife) eine andere Funktion aufgerufen,
welcher die Schritt- Variable übergeben wird.
Je nach Schritt wird hier die jeweilige Anzeige aufgerufen.

Dadurch wird die ISR schnell abgearbeitet und die meiste Arbeit erledigt 
die main Schleife.
Den Timer muss man natürlich vor der Endlosschleife initialisieren.

@Peter Dannegger
Sorry, aber durch den Code blicke ich nicht durch, das liegt aber mit 
sicherheit an meiner Unerfahrenheit. Ich brauche noch etwas Zeit bis ich 
soweit bin.

Weitere Anregungen sind erwünscht?

von Karl H. (kbuchegg)


Lesenswert?

Markus schrieb:

> Da ich noch relativ unerfahren in C bin.
> Wieviele Variablen kann ich einer Funktion übergeben?

Soviele du willst.

> Das ist ja nur eine weitere Funktion die im Interrupt aufgerufen wird,
> muss ich jetzt dieser Funktion die Variablen übergeben oder reicht es
> die Variablen Global zu deklarieren?

Müssen tust du gar nichts. Du bist der Chef. Was du für richtig hältst, 
ist Gesetz.

> Ich stelle mir das so vor:
> In der ISR wird eine Funktion mit einem Pointer aufgerufen, der Pointer
> übergibt bei jedem Aufruf eine Zahl von 1 bis 4, also wird bei jedem
> Aufruf
> die Zahl um eins erhöht.
> Die Zahl soll die Aktuelle anzeige signalisieren.

Wozu das ganze?
Damit hast du ja wieder ein Implementierungsdetail, nämlich die Anzahl 
der Anzeigen, aus dem Multiplexmodul nach aussen getragen. Bei welcher 
Anzeige man steht, kann der Mulötiplexhandler genausogut bei sich 
speichern.

> Jetzt wird in der main (Endlosschleife) eine andere Funktion aufgerufen,
> welcher die Schritt- Variable übergeben wird.
> Je nach Schritt wird hier die jeweilige Anzeige aufgerufen.

Wer sagt dir, dass dort dieselbe Anzahl an Schritten gefragt ist?

Das Problem in der Programmierung ist meistens:
Eine Speziallösung ist einfach zu machen. Man muss nicht auf viel 
aufpassen. Schwierig sind allgemeine Lösungen, die nach Möglichkeit so 
gestaltet sind, dass man sie in ein neues Projekt einfach nur 
dazukopieren (im Idealfall als Library einlinken) muss und alles läuft.

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.