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.
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.
@ 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
?
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
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
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
intmain()
4
{
5
uint8_tleftKey=RegisterKey(PIND,PD1);
6
uint8_trightKey=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
CodefürdieKey-Behandlung
8
...
9
CodefürdieMultiplexbehandlung
10
}
11
12
intmain()
13
{
14
TimeraufsetzenfürKeysundMultiplexing
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.
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?
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.