Hallo,
ich habe eine Uhr gebaut mit einem Display in der mitte und außenrum im
kreis 60 leds. die leds habe ich mit hilfe einer matrix angesteuert.
wegen der matrix kann ich ja nur eine led auf einmal ansteuern. also hab
ich mir gedacht mulriplex ich das, dass zum beispiel bei 53sec auch 53
leds leuchten. so mein problem ist, dass die leds auch noch bei sehr
hoher frequenz flimmern. ich habe mal gehört, dass das menschliche auge
ab einer frequenz von 50hz die led als durchgehend leuchtend wahrnimmt.
außerdem nimmt bei steigender frequenz die leuchtstärke der leds ab.
kann ich dem irgendwie abhilfe schaffen, dass die led nicht mehr
flimmern und noch einigermaßen hell sind?
mfg tobias
Tobias Domhöfer schrieb:> Hallo,> ich habe eine Uhr gebaut mit einem Display in der mitte und außenrum im> kreis 60 leds. die leds habe ich mit hilfe einer matrix angesteuert.> wegen der matrix kann ich ja nur eine led auf einmal ansteuern. also hab> ich mir gedacht mulriplex ich das, dass zum beispiel bei 53sec auch 53> leds leuchten.
Dafür ist deine Matrix zu groß, siehe unten.
> so mein problem ist, dass die leds auch noch bei sehr> hoher frequenz flimmern. ich habe mal gehört, dass das menschliche auge> ab einer frequenz von 50hz die led als durchgehend leuchtend wahrnimmt.
Ja, kann ich so bestätigen.
> außerdem nimmt bei steigender frequenz die leuchtstärke der leds ab.> kann ich dem irgendwie abhilfe schaffen, dass die led nicht mehr> flimmern und noch einigermaßen hell sind?
Das kommt daher, dass bei zwei LEDs schon näherungsweise die Hälfte der
Rechenzeit in einer Programmschleife für die Ansteuerung der ersten LED
genutzt wird, die zweite Hälfte für die zweite LED. Danach startet das
Programm neu.
Je mehr LEDs du ansteuerst, desto geringer wird das Tastverhältnis.
Steuerst du 2 LEDs an, dann hast du noch ca. 50% Tastverhältnis, bei 50
LEDs bist du noch bei ~2%.
Guten Morgen,
schau dir mal diesen Artikel an:
http://www.mikrocontroller.net/articles/LED-Matrix
dort ist alles beschrieben was du benötigst, sollte dann noch etwas
unverständlich sein dann wieder hier melden :)
Gruß
Ich denke das ist ein Software Fehler. Bei 64 Leds ist das eine 8x8
Matrix. Warum kannst du dort nur 1 LED gleichzeitig leuchten lassen?
Normalerweise können dort 8 gleichzeitig leuchten. Jede Gruppe aus 8
LEDs hat also 1/8 ihrer normalen Helligkeit. Die meisten LEDs kann man
aber mit dem 4 fachen strom im Pulsbetrieb betreiben, damit sind sie
schon nur noch halb so hell wie sie sein könnten, aber das fällt meist
nicht auf.
ja stimmt da hast du recht. ich kann auch 8 geleichzeitiig leuchten
lassen. aber ich bekomme das flimmern nicht raus. villt kann es aber
auch daran liegen, dass ich einen zu großen vorwiderstand drinne habe.
hab 560R gewählt, damit ist die LED noch hell genug und zeit nur einen
strom von ~6mA. wenn ich jetzt das ganze multiplex und die LED nur 1/8
der Helligkeit hat ist das schon ziehmlich dunkel.
also gibt es keine möglichkeit das flimmern rauszubekommen?
was hat denn der ganze C code in der H datei verloren? Der ganze code
ist ja voll von Delays ist ja klar das das nicht sauber geht. Wo wird
überhaupt die LED funktion aufgerufen?
Tobias Domhöfer schrieb:> okay, hier meine Software:> (als dateianhang)
Puh.
Den ganzen Code müsste man ..... entsorgen und neu schreiben.
Und das würde ich an deiner Stelle auch tun. Mit diesem Code kommst du
nicht mehr weiter, du bist in einer Sackgasse.
Konzentrier dich beim neuen Code auf die 8*8 Matrix.
Die muss in einem Interrupt angesteuert werden, jeweils 8 Led bei jedem
Interrupt Aufruf. Beim nächsten Interrupt kommen dann die nächsten 8 LED
drann.
Für das Multiplexen ist es unerheblich, ob eine bestimmte LED
eingeschaltet ist oder nicht, du gehst deine 64 LED in 8-er Gruppen
durch und lässt die entsprechende LED leuchten oder auch nicht, je
nachdem was dein Steuerarray vorgibt. Dieser Mechanismus läuft immer und
ständig.
Und erst darauf aufbauend schaltets du die richtige LED abhängig von der
aktuellen Sekundenzahl ein oder aus, in dem du in diesem Steuerarray die
entsprechende Information einträgst.
Und sowas wie wait oder _delay_ms darf es in deinem ganzen Code, mit
Ausnahme der Hauptschleife nicht geben (mit Ausnahme von ein paar kurzen
_delay_us in den LCD Funktionen)
Und mach dir mal ein paar Basisfunktionen für Standardsachen wie zb
LCD-Ansteuerung und Ausgabe auf LCD; Tastenentprellung. Das ist doch
krank was du da aufführst, indem du alles auf unterster Ebene in die
Hauptschleife mehr oder weniger direkt einbaust.
Kein Wunder, dass du in dieser Sackgasse gelandet bist. Dein Code hat
keine Struktur, keinen Aufbau, keine funktionalen Hierarchien, keine
building Blocks. Das ist ein monolithischer Klotz Code, der unwartbar
und unveränderbar ist. Greif an einer Stelle ein und alles fällt
auseinander.
boah das muss ich erstmal verarbeiten -.-'
ich programmiere erst seit 3 wochen oder so, bin noch nicht so der
meister... ich mein es hat ja alles bestens funtioniert(bis jetzt eben
die multiplexgeschichte).
hab gerade versucht parallel zu den LEDs kondensatoren zu schalten, die
dann die LED für kurze zeit puffern, wenn sie nicht angesteuert wird.
aber das geht leider auch nicht.
dann werd ich mich mal dranmachen den code neuzuschreiben.
Tobias Domhöfer schrieb:> boah das muss ich erstmal verarbeiten -.-'> ich programmiere erst seit 3 wochen oder so, bin noch nicht so der> meister...
das ist schon ok.
keiner ist als Meister zur Welt gekommen.
Aber man muss auch mal sagen (und auch einsehen) wenn man sich in eine
Sackgasse verrannt hat. Bis jetzt hast du noch nie dein Augenmerk auf
Dinge wie Codestruktur bzw. Programmaufbau gelegt. Dir war wichtig, dass
es funktioniert. Nur irgendwann ist dann der Punkt erreicht, an dem man
ohne Aufbau und Struktur nicht mehr weiterkommt (und dazu gehören auch
Dinge wie Codeformattierung - deine ist einfach nur grauenhaft)
Die Techiken, mit denen man ein Baumhaus baut funktionieren bei einem
Einfamilienhaus einfach nicht mehr.
Kontrollier bitte mal, ob ich aus deinem Code den Anschluss der LED
richtig herausgelesen habe:
1
Bit
2
\ D | 7 6 5 4 3 2 1 0
3
B \--+------------------------------------
4
|
5
2 | 54 55 56 57 58 59 0 1
6
B 1 | 2 3 4 5 6 7 8 9
7
i 0 | 10 11 12 13 14 15 16 17
8
t 7 | 18 19 20 21
9
6 | 22 23 24 25 26 27 28 29
10
5 | 30 31 32 33 34 35 36 37
11
4 | 38 39 40 41 42 43 44 45
12
3 | 46 47 48 49 50 51 52 53
die Tabelle ist so zu lesen:
Wenn am D-Port das Bit n (Spalte) auf 1 gesetzt ist UND am Port B das
Bit m (Zeile) gesetzt ist, dann leuchtet die LED mit der Nummer, die am
Schnittpunkt aus Zeile und Spalte eingetragen ist.
Bsp. Ist am Port D das Bit 5 und am Port B das Bit 4 auf 1 gesetzt, dann
leuchtet LED Nr. 40
Deine unregelmässige Tabellenstruktur muss jetzt durch Software
korrigiert werden. Was wir wollen:
Wir wollen ein Array aus 8 Byte, wobei jedes Bit in jedem Byte mit einer
LED korrespondiert. Jedes Byte ist eine komplette Zeile in der Tabelle.
In einem Multiplexschritt geben wir einfach das Byte auf den Port D aus
und setzen im B-Port das zu dieser Zeile gehörende 1 Bit. Somit leuchten
dann die zugehörenden 8 LED (oder auch nicht, je nachdem wie die Bits im
Byte das am D-Port ausgegeben wurde aussehen). Nur muss es jetzt
natürlich eine Vorschrift geben, wie man aus der LED-Nummer die Nummer
des Bytes und die Nummer des zu setzenden Bits innerhalb dieses Bytes
errechnen kann. Und um diese Vorschrift zu finden muss diese Zuordnung
klar sein und am besten irgendwo dokumentiert werden.
Das Ziel ist es
1
uint8_tLeds[8];
2
3
voidSetBit(uint8_tLedNr)
4
{
5
...
6
}
7
8
voidClearBit(utin8_tLedNr)
9
{
10
...
11
}
so mit Leben zu füllen, dass beim Aufruf von
SetBit( 40 );
das Bit 5 in Leds[4] auf 1 gesetzt wird.
Aber um zu wissen, wie diese Umrechnung auszusehen hat muss dies Tabelle
erst mal stimmen.
OK.
Dann lass uns mal mit dem Multiplexen anfangen
Am Anfang steht .... das rechnen.
Wir brauchen eine ISR die so ca. 400 mal in der Sekunde aufgerufen wird.
Warum 400 mal? Weil wir für einen Durchgang durch alle 8 LED-Bänke
logischerweise 8 Zyklen brauchen. Jede LED soll mit 50Hz leuchten, also
50 mal in der Sekunde angesteuert werden. 8 mal 50 sind 400.
Mal schaun.
Du hast eine Taktfrequenz von 4Mhz und wir nehmen den Timer 0, einen 8
Bit Timer. Die ISR möchten wir gerne an den Overflow Interrupt hängen.
Wie müssen daher die Timer Einstellungen sein, damit der Overflow 400
mal in der Sekunde erreicht wird.
Unsere Wunschvorstellung für den Prescaler wäre
1
4000000 / Prescaler / 256 = 400
daraus ergibt sich, dass wir einen Prescaler von
1
4000000 / 256 / 400 = 39
brauchen würden.
Den haben wir aber nicht. Ach ja, ich habe jetzt mal einen Mega16 zur
Entwicklung angenommen, da ich auf die Schnelle nicht gefunden habe,
welchen Prozessor du tatsächlich hast.
Ein Blick ins Datenblatt verrät uns, das Prescaler die in der Nähe
liegen entweder 8 oder 64 sind.
Rechnen wir mal durch, was das für Multplexraten ergeben würde.
1
4000000 / 8 / 256 = 1953 Hz oder für 1 Ledbank -> 244 Hz
2
4000000 / 64 / 256 = 244 Hz oder für 1 Ledbank -> 30 Hz
30 Hz ist ein bischen wenig. Das wird man schon flimmern sehen, also
bleibt uns nicht viel anderes übrig als einen Prescaler von 64 zu
nehmen. Damit flackert dann jede einzelne Led mit 244 Hz und das wird
man mit Sicherheit nicht mehr sehen.
Der erste Teil sieht daher so aus
// damit beim nächsten ISR Aufruf die nächsten 8 Led
27
// angesteuert werden
28
mtpxCnt++;
29
if(mtpxCnt==8)
30
mtpxCnt=0;
31
}
32
33
intmain()
34
{
35
DDRB=0xff;
36
DDRD=0xff;
37
38
TCCR0=(1<<CS01)|(1<<CS00);// Prescaler 64
39
TIMSK|=(1<<TOIE0);
40
41
sei();
42
43
while(1){
44
}
45
}
In der ISR passiert nicht mehr, als das reihum ein anderes Element aus
dem Leds-Array samt zugehörigem Bit am B Port ausgegeben wird. Für die
Bits am B-Port hab ich mir noch ein zusätzliches Array gemacht, wobei
jedes Array Element an der jeweils richtigen Stelle ein 1 Bit aufweist.
Denn um die Leds in Leds[4] (also der 5. Zeile) auszugeben, muss ja laut
Tabelle
1
Bit
2
\ D | 7 6 5 4 3 2 1 0
3
B \--+------------------------------------
4
|
5
2 | 54 55 56 57 58 59 0 1 Leds[0]
6
B 1 | 2 3 4 5 6 7 8 9 Leds[1]
7
i 0 | 10 11 12 13 14 15 16 17 Leds[2]
8
t 7 | 18 19 20 21 Leds[3]
9
6 | 22 23 24 25 26 27 28 29 Leds[4]
10
5 | 30 31 32 33 34 35 36 37 Leds[5]
11
4 | 38 39 40 41 42 43 44 45 Leds[6]
12
3 | 46 47 48 49 50 51 52 53 Leds[7]
das Bit 6 im B-Port gesetzt werden.
Beim ersten ISR Aufruf wird daher Leds[0] am PORTD ausgegeben und an
PORTB wird 0b00000100 ausgegeben, welches laut Tabelle die erste Zeile,
und damit die LEDS 54 bis 1 aktiviert, sofern in Leds[0] das zugehörige
1 Bit gesetzt ist. Und genau das testen wir jetzt erst mal.
Dazu wird die main() geändert
1
intmain()
2
{
3
.....
4
5
while(1){
6
Leds[0]=0x1000000;
7
}
8
}
das müss die Led Nr 54 aufleuchten lassen
1
intmain()
2
{
3
.....
4
5
while(1){
6
Leds[0]=0x0100000;
7
}
8
}
Led Nr 55 leuchtet
wir können auch beide leuchten lassen
1
intmain()
2
{
3
.....
4
5
while(1){
6
Leds[0]=0x1100000;
7
}
8
}
oder alle
1
intmain()
2
{
3
.....
4
5
while(1){
6
Leds[0]=0x11111111;
7
}
8
}
oder nur jede 2.te
1
intmain()
2
{
3
.....
4
5
while(1){
6
Leds[0]=0x10101010;
7
}
8
}
Alles was wir tun müssen ist, in Leds[0] bis Leds[7] das jeweils
richtige Bit auf 1 zu setzen (laut Tabelle) und die ISR sorgt dafür,
dass die zueghörige Led aufleuchtet. Das geht dann auch mit mehreren.
Aber ehe ich da jetzt weiterarbeite, solltest du das erst mal testen
(denn ich programmiere deine Hardware blind und kann daher nicht sagen,
ob das bei dir tatsächlich funktioniert)
Tobias Domhöfer schrieb:> Danke für deine Hilfe. ja ich nutze einen mega16 ;). hab das multiplexen> jetzt mit dem timer2 gemacht. da funzts.> super jetzt läuft alles :)
Ich hoffe mal du hast dir eine schöne Umrechnungsfunktionen gemacht, so
das du schreiben kannst
1
voidSetLed(uint8_tLedNr)
2
{
3
uint8_tmpxNr;
4
uint8_tmpxMask;
5
6
calcMpxNrMask(&mpxNr,&mpxMask);
7
Leds[mpxNr]|=mpxMask;
8
}
9
10
voidResetLed(uint8_tLedNr)
11
{
12
uint8_tmpxNr;
13
uint8_tmpxMask;
14
15
calcMpxNrMask(&mpxNr,&mpxMask);
16
Leds[mpxNr]&=~mpxMask;
17
}
18
19
voidcalcMpxNrMask(uint8_t*Nr,uint8_t*Mask)
20
{
21
...
22
}
räum den Rest vom Code auch auf. zb alles was mit LCD zu tun hat in
Funktionen verpacken. Deine Ausgabefunktionen für Stunden, Minuten,
Sekunden auf dem LCD sind im Grunde alle gleich, hat man eine
Ausgabefunktion die eine Zahl ausgeben kann, kann man die 3 Funktionen
wesentlich vereinfachen. etc. etc.
Tobias Domhöfer schrieb:> wieso hat das nachteile? oder macht man das einfach nicht?
Das ist genau das von dem ich oben geschrieben habe.
Irgendwann bist du an einem Punkt angelangt, an dem ohne vernünftige
Struktur nichts mehr geht.
Ausserdem will man nicht bei jedem neuen Projekt das Rad neu erfinden.
Die LCD Funktionen an einer Stelle beisammen werden dann einfach ins
nächste Projekt übernommen und schon hast du in 10 Sekunden im nächsten
Projekt dein LCD am laufen. Und zwar ohne dass du dir die Einzelteil
erst aus dubiosem Code zusammensuchen musst.