Hallo, Ich bin seit längerem dabei gewisse Werte auf 7 Segment Anzeigen wiederzugeben und komme soweit langsam voran. Mein letzter Erfolg war die Auswertung eines Temperatursensors KTY81 und berechung der Temperatur, welche dann auf 2 7 Segment Anzeigen wiedergegeben wurde, was aber nicht sehr zufriedenstellend ist da ich die Anzeige mit Hilfe von delay Timern realisiert habe und daher ist ein Flackern und auch ein nachglimmen der Segmente zu sehen. Welches ich durch den Einsatz von Interrupts lösen will. Da ich aber noch nie mit Interrupts etwas programmiert habe muss ich mal ein paar Basics hier fragen. Ich habe mir bereits den Artikel hier über Interrupts durchgelesen und soweit verstanden. Jetzt bin ich bei der Umsetzung und möchte gerne wissen ob ich soweit alles richtig verstanden habe? -------------------------- Also: (so möchte ich es realisieren, falls möglich) 2 Stellige 7 Segment Anzeige läuft im Multiplexbetrieb an einem MSP430G2553. Wenn das Programm startet erscheint auf der Anzeige 00. Dann wird durch einen TimerInterrupt die Anzeige unterbrochen und der ADC gelesen und ausgewertet, dann der Wert zurück an die Anzeige übergeben. Der TimerInterrupt soll nach meinem Überlegen her nur alle 3-5 Sekunden (muss ich noch versuchen was besser ist) einsetzen, so dass die Anzeige nicht dauernd hin und her springt zwischen Werten. Und das alles läuft while(1) :) -------------------------- Habe ich dass damit so richtig verstanden, dass der Interrupt die Anzeige unterbrechen soll, oder läuft das alles doch anders ab? Falls es noch wichtig ist, die 7 Segment Anzeigen haben eine Gemeinsame Kathode welche über 2 MOSFETs gesteuert wird. Danke euch Gruß
Robert I. schrieb: > wiedergegeben wurde, was aber nicht sehr zufriedenstellend ist da ich > die Anzeige mit Hilfe von delay Timern realisiert habe und daher ist ein > Flackern und auch ein nachglimmen der Segmente zu sehen. Welches ich > durch den Einsatz von Interrupts lösen will. Gut > Also: > (so möchte ich es realisieren, falls möglich) > > Wenn das Programm startet erscheint auf der Anzeige 00. Nope > Dann wird durch einen TimerInterrupt die Anzeige unterbrochen und der > ADC gelesen und ausgewertet, dann der Wert zurück an die Anzeige > übergeben. Genau anders rum. Der Anzeige Code ist der zeitkritische. Der gehört in den Timer-Interrupt! Den ADC Teil kannst du ruhig in der Hauptschleife lassen. Dort ist er gut aufgehoben Deinen Timer stellst du so ein, dass er ca. 150 bis 200 mal in der Sekunde die ISR aufruft. Das ist so ein Kompromiss, weil du anscheinend 2 Anzeigestellen hast. Da in jedem ISR Aufruf immer die nächste Stelle eingeschaltet wird, leuchtet jede Stelle daher 75 bis 100 mal in der Sekunde auf, was normalerweise ausreicht, dass das Bild ruhig steht. Wenn du zu den Menschen gehörst, die da immer noch ein Flackern wahrnehmen, dann gehst du eben mit der ISR AUfruf-Frequenz noch etwas höher, auf vielleicht 300 oder 400 Aufrufe. Aber spätestens dann sollte die Anzeige stehen wie eine Eins. Man kann auch noch höher gehen, aber das bringt dann nichts mehr. In der ISR wird dann gemacht (Pseudocode, da ich die MSP Syntax nicht kenne, wie dort die Hardware angesprochen wird bzw. wie man Interrupt-Funktionen vereinbart)
1 | volatile uint8_t Digit[2]; // die auszugebenden Muster für die Anzeige |
2 | |
3 | ISR( ... ) // Interrupt Funktion, vom Timer aufgerufen |
4 | { |
5 | static uint8_t Stelle; |
6 | |
7 | bisherige Anzeige komplett abschalten (alle Kathoden auf 'aus') |
8 | |
9 | Stelle++; |
10 | if( Stelle == 2 ) |
11 | Stelle = 0; |
12 | |
13 | Das Muster für Digit[Stelle] ausgeben |
14 | Die Anzeige Stelle durch Schalten der zugehörigen Kathode aktivieren |
15 | } |
Die ISR macht also nichts anderes als die Anzeige erst mal komplett abdrehen, danach bestimmen welche der beiden 7_segment_anzeigen als nächstes mit Leuchten drann ist. Sie legt dann das Leuchtmuster für die LEDs auf die Ausgänge und aktiviert mit der gemeinsamen Kathode genau diese Stelle. Diese eine jetzt eingeschaltete 7-Segment-Anzeige leuchtet dann vor sich hin, bis der nächste Interrupt kommt, wo sie abgeschaltet wird und die nächste (in deinem Fall: die andere der beiden) 7-Segment Anzeigen beschickt und aktiviert wird. Und so geht es immer reihum. 150-200 mal in der Sekunde wechselt die Anzeige, einmal leuchtet die eine, dann die andere. Und da das timergestützt funktioniert, passiert es auch dann, wenn in deiner Hauptschleife gerade irgendwas gerechnet wird. Die Rechnung wird dann einfach unterbrochen, die Anzeige umgeschaltet und dann kann die Rechnung weitergeführt werden -----> nichts flackert, weil die Anzeige regelmässig im Takt umgeschaltet wird. Wichtig: Im Array Digit hast du bereits das komplette Muster für die ANzeige gespeichert. Wenn du die Zahl 23 ausgeben willst, dann steht daher in Digit[0] schon die 'umgewandelte' 2, also die Portbelegung, welche LED leuchten sollen und welche nicht. Die ISR soll sich da nicht mehr damit rumschlagen, welche LED leuchten müssen, wenn an einer Stelle eine 4 aufleuchten soll. Die ISR schaufelt nur noch LED-Muster an die Anzeige, kümmert sich aber nicht darum, was diese Muster darstellen. Wenn dein Hauptprogramm in Digit[1] ein Muster hinterlässt, welches einfach nur ein einsames '-' (also den mittleren Querstrich) anzeigen lässt, dann gibt die ISR das auch genau so aus. Und wenn das Hauptprogramm alle 3 Querstriche als leuchtend in Digit[1] einträgt, dann gibt die ISR auch das genau so aus. In der Hauptschleife kannst du dann nach Herzenslust rechnen oder sonstige Dinge tun. Der Timer, bzw. die Interruptroutine sorgt dafür, dass deine Anzeige dauernd sauber sichtbar ist. Um die musst du dich dann soweit nicht mehr kümmern. Wenn du eine neue Zahl hast, die auszugeben ist, dann schreibst du die entsprechenden LED Muster in Digit[0] bzw. Digit[1] und damit ist die Sache für die Hauptschleife erst mal erledigt - die ISR sorgt dann schon dafür, dass das ganze dann auch auf den 7-Segment Anzeigen sichtbar wird. Sinnvollerweise wird man sich natürlich eine Funktion machen, die eine 2-stellige Zahl entsprechend aufbereitet
1 | uint8_t ledPattern[12] = { .... die Bytes, welche für die Ziffern |
2 | 0 bis 9 auszugeben sind, sowie |
3 | ein Pattern für |
4 | * leer |
5 | * Error (zb. 'E') |
6 | };
|
7 | |
8 | void output( uint8_t number ) |
9 | {
|
10 | if( number > 99 ) |
11 | {
|
12 | Digit[0] = ledPattern[10]; // leer |
13 | Digit[1] = ledPattern[11]; // Error |
14 | }
|
15 | else
|
16 | {
|
17 | Digit[0] = ledPattern[ number / 10 ]; |
18 | Digit[1] = ledPattern[ number % 10 }; |
19 | }
|
20 | }
|
:
Bearbeitet durch User
Hallo, ich organisiere das normalerweise so: Timeinterrupt in der Grössenordnung 1..2 ms, der schaltet jeweils die Anzeige 1 Stelle weiter und gibt den entsprechenden 7SegmentCode aus. Ist eine Matrixtastatur dran, wird die ebenso in dieser ISR weitergeschaltet und abgefragt, und mit der üblichen Software entprellt. Das muss aber nicht so oft passieren, jeder 2. oder 4. Aufruf reicht für die Tastatur (abzählen). Ebenso kann man den ADC in der ISR abfragen, ebenfalls über einen Zähler nur ein paarmal in der Sekunde, weil man sowieso nicht schneller kucken kann. Für solche Fälle ist es durchaus üblich, dass in dieser Timer-ISR alles Wesentliche erledigt wird und in main nur die Initalisierung erfolgt und die Endlosschleife nur Dinge geringer Priorität erledigt, wie etwa die Verarbeitung der eingegeben Befehle. Das muss ja nicht schnell sein, weil das Eintippen sowieso Sekunden braucht. Nicht persönlich nehmen, aber der User hat die geringste Priorität. Obige Angaben reichen übrigens für bis zu 8 Digits. Georg
Uhm. Ich schreibe jede ms meine kompletten 4 Ziffern aufs 7-Segment. Und alle Minute kommt dann noch auslesen des RTC-Chips dazu ;) Also 1000 mal wirklich erst an- und dann ausschalten. Spart offenbar gut Strom, nach 4 Wochen ist mein Akku noch > halbvoll ;)
Robert I. schrieb: > Habe ich dass damit so richtig verstanden, dass der Interrupt die > Anzeige unterbrechen soll Nö, es ist genau umgekehrt. Die schnellen Sachen gehören in den Interrupt, also das Multiplexen. Der Mensch ist da sehr empfindlich, auch ein Flackern alle 3s stört ihn. Der ADC und die Ausgabewandlung kommen ins Main. Mehr als 2..5 Messungen je s kann der Mensch eh nicht verarbeiten. Daher ruhig noch ein Delay ins Main (200..500ms), damits ergonomisch ist. Falls das Main noch anderes machen soll, dann im Timerinterrupt alle 200..500ms ein Flag setzen, damit das Main den ADC anstoßen kann.
Danke euch vielmals für die Antworten. @Karl Heinz : Besonderen Dank an dich , ist eine mega Hilfe wie du das geschrieben hast. Besten Dank.
:
Bearbeitet durch User
Ach ja noch was. Gibt es eigentlich im allgemeinen große Unterschiede in der Programmierung wenn man ein Batteriebetriebenes Gerät verwirklichen will ? Gruß
Robert I. schrieb: > Ach ja noch was. > > Gibt es eigentlich im allgemeinen große Unterschiede in der > Programmierung wenn man ein Batteriebetriebenes Gerät verwirklichen will > ? Batteriebetrieben und 7-Segment-LED Anzeigen beissen sich grunsätzlich. Der Hauptstrom geht in die Anzeige. Die paar mA, die du beim µC sparen kannst, machen das Kraut nicht wirklich fett. Wenn du die Anzeigedauer deiner Anzeigen halbierst, zb so
1 | ...
|
2 | static uint8_t Stelle; |
3 | |
4 | bisherige Anzeige komplett abschalten (alle Kathoden auf 'aus') |
5 | |
6 | Stelle++; |
7 | if( Stelle == 4 ) // <---- 2 fiktive Stellen, in denen einfach nichts |
8 | Stelle = 0; // leuchtet |
9 | |
10 | if( Stelle < 2 ) |
11 | {
|
12 | Das Muster für Digit[Stelle] ausgeben |
13 | Die Anzeige Stelle durch Schalten der zugehörigen Kathode aktivieren |
14 | }
|
15 | }
|
dann bringt das erst mal am allermeisten, dafür wird aber auch die Anzeige dunkler. Aber natürlich gibt es auch bei einem µC Möglichkeiten, wie man sparen kann. Man kann den µC "schlafen legen". Dann verbraucht er nur noch winzigste Mengen an Strom, wacht 200 mal in der Sekunde auf um die Anzeige zu multiplexen und sich danach wieder schlafen zu legen. Aber eines nach dem anderen. Sleep Modi werden (genauso wie Watchdog) erst zum Schluss eingebaut. Erst mal muss der Rest funktionieren.
:
Bearbeitet durch User
Robert I. schrieb: > Gibt es eigentlich im allgemeinen große Unterschiede in der > Programmierung wenn man ein Batteriebetriebenes Gerät verwirklichen will > ? Nö, zuerst kümmert man sich nur um die Funktionalität. Später kann man analysieren, ob und wo sich Strom sparen läßt. Z.B. größere Vorwiderstände/Tastverhältnis für die LEDs (= dunkler), Ausschaltfunktion nach xx Minuten. Beitrag "AVR Sleep Mode / Knight Rider"
Robert I. schrieb: > Gibt es eigentlich im allgemeinen große Unterschiede in der > Programmierung wenn man ein Batteriebetriebenes Gerät verwirklichen will > ? ja, wenn die MCU nichts zu tun hat, ab in einen der Sleep-Modes, aus dem sie mit einen weiteren Timer oder einen anderen (vielleicht externen Interrupt, z.B. Taste betätigt) geweckt wird. Und wenn deine 7-Segmentanzeigen aus LEDs bestehen, dann auch hier die Anzeige ausschalten, wenn keiner drauf schaut...
lowpower schrieb: > Und wenn deine 7-Segmentanzeigen aus LEDs bestehen, dann auch hier die > Anzeige ausschalten, wenn keiner drauf schaut... Vieeel besser: LCD verwenden. Georg
Wenn eine Laufzeit von geschätzt 2 Monaten reicht (Akku ist nach einem Monat jetzt von 4,0xV auf 3,72V gefallen), geht das auch mit 1000 Mal die Sekunde kurz Aufblinken lassen. Ist bei Sonneneinfall nicht lesbar, aber bei Bewölkung schon.
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.