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.
Man nehme eine globale Variable, in die man den anzzeigenden Wert schreibt.
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 | 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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.