Hallo!
Bin ziemlich neu, sowohl was Programmierung anbetrifft als auch µC. Im
Moment experimentiere ich mit einem AtMega8 und möchte einen einfachen
Zähler von 00 bis FF in Endlosschleife auf zwei 7-Segment-Anzeigen per
Multiplexing darstellen. Der Controller läuft auf 16 MHz. Mit der
Einstellung des 16-Bit Timers flackert das zwar ziemlich, aber das ist
zunächst nicht mein Problem. Das Multiplexing funktioniert ansonsten
schon ganz ordentlich.
Was nicht richtig funktioniert, ist das Zählen. Er geht mal links 3
weiter, dann mal rechts 5, oder auch mal eine Zeit lang richtig. Deshalb
vermute ich, dass die Interrupts irgendwie die Zählroutine durcheinander
bringen. Was kann ich da machen? Oder ist da noch irgendein grausamer
Fehler drin?
1
#include<avr/io.h>
2
#include<util/delay.h>
3
#include<avr/interrupt.h>
4
5
// Bits für 7-Segment-Matrix mit gemeinsamer KATHODE
6
7
#define ZERO 0b00111111 // ; 0: a, b, c, d, e, f
8
#define ONE 0b00000110 // ; 1: b, c
9
#define TWO 0b01011011 // ; 2: a, b, d, e, g
10
#define THREE 0b01001111 // ; 3: a, b, c, d, g
11
#define FOUR 0b01100110 // ; 4: b, c, f, g
12
#define FIVE 0b01101101 // ; 5: a, c, d, f, g
13
#define SIX 0b01111101 // ; 6: a, c, d, e, f, g
14
#define SEVEN 0b00000111 // ; 7: a, b, c
15
#define EIGHT 0b01111111 //; 8: a, b, c, d, e, f, g
Lothar Glorius schrieb:> Oder ist da noch irgendein grausamer> Fehler drin?
Ja. Die Zeitmessung wird in der main() erledigt, das
Multiplexen/Anzeigen im Timerinterrupt. Eine präzise Zeitmessung sollte
innerhalb des Timerinterrupts stattfinden. Der Timer sollte natürlich
entsprechend eingestellt werden.
Lothar Glorius schrieb:> Was nicht richtig funktioniert, ist das Zählen.
Oh, ja äh, die Mainloop bleibt jetzt "leer" und der Timer macht alles
alleine... Platz für mehr Kreativität!
mfg mf
PS: dir ist klar, dass dein "data" immerzu im RAM liegt?
Ich hab mal versucht zu skizzieren, wie man das umgeht.
Aber gut, wenns jetzt läuft...
50Hz ist schon recht langsam für Multiplex, wirkt noch etwas unruhig.
Man muß ja auch nicht jedesmal das Division-Unterprogramm aufrufen,
zumal es 98 mal unnütz erfolgt (es wird der gleiche Wert berechnet).
Der Timer gibt besser nur die Digits aus. Das Berechnen und nach
7-Segment wandeln macht in aller Ruhe das Main. Dann hat man Luft für
Erweiterungen.
Peter
hallo :)
eine frage...wie schalte ich den port c. sprich die massen von der
anzeige.?
mit transistor.? wenn ja welchen.?
danke schonmal. :)
mfg. johannes
C_anfänger schrieb:> hallo :)>>> eine frage...wie schalte ich den port c. sprich die massen von der> anzeige.?
Du hast Anzeigen mit gemeinsamer Kathode (Masse)?
> mit transistor.? wenn ja welchen.?
Wie immer:
+------------+
|
Gerät
|
µC >------- Transistor
|
-------------+----- Masse
in diesem Fall ist der Transistor ein NPN
+------------+
|
µC >-------- Transistor
|
Gerät
-------------+----- Masse
in diesem Fall ist der Transistor ein PNP Typ
(wobei es je nach Spannung notwendig sein kann,
einen Hochsetzsteller für den PNP zu verwenden)
Also: Auf welcher Seite von der Last sitzt der Transistor
schaltet er nach Masse durch? Ja -> NPN
schaltet er die Spannung? Ja -> PNP (event. Hochsetzsteller)
MaWin schrieb:> Der Inhalt von c1 ändert sich doch.> Nimm eine zusätzliche Variable digit mit den Werten 0 und 1.
wie soll man das verstehen.? eine neue variable wofür.?
Und das allgemeine Schema lautet:
Halte den Multiplex Mechanismus unabhängig von allem anderen. Wenn
dessen Steuerung in sich geschlossen ist und niemand anderer extern
drann rumpfuscht, kann auch nix passieren.
Und gegen das Flackern. Nun ja, die Timerfrequenz mit einem kleineren
Vorteiler hochdrehen, soll da schon gewirkt haben.
Lothar Glorius schrieb:> ISR(TIMER0_OVF_vect){> if(digit == 0){> PORTD = *c0;> digit = 1;> }> else{> PORTD = *c1;> digit = 0;> }> PORTC ^= (1 << PC0);> PORTC ^= (1 << PC1);>> }
Gibts eigentlich einen Grund, warum du hier mit einem Pointer hantierst?
Lass doch den unsigned char c0 gleich direkt das auszugebende Muster
beinhalten. Was immer das auch sei.
Dann kannst du im Grundzustand zb auch mal in deiner Anzeige 2 '-'
anzeigen lassen, oder die Anzeige blinken lassen, oder nach dem
Einschalten eine kleine coole Animation, in der nacheinander alle
Segmente kurz ein und wieder ausgeschaltet werden, oder ....
Je weniger die Multiplex-Routine von irgendwas anderem abhängt, umso
besser. Und noch weniger abhängig als "Da gibt es 2 Variablen, die das
auszugebende Muster beinhalten" geht nicht mehr. Ob du dann bei deiner
Zahlenzerlegung gleich das entsprechende Muster ablegst oder einen
Pointer auf das Musterbyte im Array, ist auch schon egal.
1
voidOutNumer(uint8_tnr)
2
{
3
c0=data[nr/10];
4
c1=data[nr%10];
5
}
Die Digit-Steuerung hätt ich explizit gemacht. Wenn dir da was
durcheinander kommt, tauschen die Digits wieder ihre Plätze.
Jau, das hört sich gut an. War halt nur ein erster Test, da ich auch
noch ziemlich neu in der Materie bin und obendrein froh, dass ich was
mit Pointern hinbekomme. Die nächste Vorteilerstufe war viel zu schnell
(von Takt/8 auf Takt), habe als schnelle Hilfe dann doch den 8-bit Timer
mit Takt/1024 genommen, das sieht schon etwas besser aus. CTC wäre
optimal einzustellen, da hatte ich mich aber noch nicht eingelesen.
Für die nächste Anwendung würde ich so einen Zähler auch schon ganz
anders machen, dank der Anregungen hier im Forum. Ich wollte nur dem
Gast noch eben etwas mit dem Problem im Code meines ersten Postings
helfen.