Rocks schrieb:> Das angehängte Bild dürfte deine Fragen beantworten
Danke dir erstmal. Leider noch nicht alle. Woher weiß ich dann bei der
LED MAtrix welche Pins welche sind?
War der Gedanke zum ansteuern einzelner LED´s denn richtig?
Stefan schrieb:> Ziel des Projektes sollte ein kleines 4-Gewinnt Spiel sein. Wie steuer> ich denn eine einzelne LED in der Matrix an?
Der Trick ist konzeptionell nicht, dass du eine einzelne LED ansteuerst,
sondern eine komplette Spalte oder Zeile.
Eingen wir uns bei deinem Bild mal auf Spalte.
D.h. mittels C1 Low haben jetzt erst mal grundsätzlich alle LED in
dieser Spalte eine Chance zu leuchten. Alle andern C sind logischerweise
auf High.
Welche LED in dieser Spalte leuchten soll, das bestimmst du mit den
R-Leitungen. Die die leuchten sollen, die kriegen auf ihren R-Leitungen
ein High, alle anderen ein Low.
Und Mulitplexen bedeutet jetzt nichts anderes, als das reihum alle
Spalten durchiteriert werden, und das jeweilige Muster zu dieser Spalte
aus dem Speicher auf die R-Leitungen gegeben wird.
D.h. du hast im Programm ein Array, welches deine LED symbolisiert. Der
Multiplex-Mechanismus stützt sich auf dieses Array und ackert es laufend
durch um Spalte für Spalte dauernd auf die realen LEDs zu schalten.
Will dein Programm die LED Spalte 1/Zeile 7 einschalten, dann setzt es
in diesem Array das bewusste Bit und der Multiplex-Mechanismus ist dafür
zuständig, dass dann eben beim nächsten Durchgang, wenn diese Spalte
wieder drann ist, de entsprechende LED eingeschaltet wird (neben all den
anderen LED dieser Spalte die auch leuchten sollen)
Johann L. schrieb:> Aber ein 4-Gewinnt Spielfeld ist doch nicht 8x8.
:) Wahrscheinlich nicht. Aber spielt das eine Rolle? 4 in einer Reihe
gewinnen :) Ob nun bei 7x6 oder 8x8 oder 200 x 400 ist doch egal.
Stefan schrieb:> Rocks schrieb:>> Das angehängte Bild dürfte deine Fragen beantworten>> Danke dir erstmal. Leider noch nicht alle. Woher weiß ich dann bei der> LED MAtrix welche Pins welche sind?
Steht im Datenblatt und wenn man keines hat dann nimmt man sich einen
220 Ohm Widerstand, +5V und probiert es einfach aus.
Karl Heinz Buchegger schrieb:> Der Trick ist konzeptionell nicht, dass du eine einzelne LED ansteuerst,> sondern eine komplette Spalte oder Zeile.
Danke für deine ausführliche Antwort. Verwirrend finde ich, wenn du
sagst du steuerst die ganze Spalte an. Weil du letztendlich zwar der
Spalte die Möglichkeit gibst zu leuchten (indem du C1 auf Low legst),
dann aber dennoch nur eine LED zum leuchten bringst mit den R-Leitungen.
Klar man könnte dann auch mehr leuchten lassen.
Ok also prinzipiell habe ich es verstanden. Ich bestell mir einfach mal
2 Matritzen und experimentiere damit. Wie ich das ganze in C-Code
verpacke weiß ich zwar noch nicht, aber vielleicht unterstützt du mich
dann nochmal Karl-Heinz.
Zum Controller:
Da ich anscheinend 24 Pins also 3 Ports benötige, sollte ich mir auch
einen Controller (ATMEL) mit 4 Ports z.B. den ATMEGA16 nehmen.
Stefan schrieb:> Karl Heinz Buchegger schrieb:>> Der Trick ist konzeptionell nicht, dass du eine einzelne LED ansteuerst,>> sondern eine komplette Spalte oder Zeile.>> Danke für deine ausführliche Antwort. Verwirrend finde ich, wenn du> sagst du steuerst die ganze Spalte an. Weil du letztendlich zwar der> Spalte die Möglichkeit gibst zu leuchten (indem du C1 auf Low legst),> dann aber dennoch nur eine LED zum leuchten bringst mit den R-Leitungen.> Klar man könnte dann auch mehr leuchten lassen.
Weil ich denke, dass du den Kardinalfehler Nummer 1 machst, wenn es um
eine LED-Matrix geht.
Du zerbrichst dir den Kopf darüber, wie du ein deinem Programm,
meinetwegen in der Hauptschleife, welche Ausgabepins wie einstellen
musst, damit genau diese eine LED leuchten kann.
Diese Fragestellung stellt sich aber in Wirklichkeit gar nicht. Denn für
das Programm, welches dann anhand irgendwelcher Spielregeln eine LED
einschalten muss, sind die Output-Pins völlig uninteressant. Damit hat
dieser Programmteil überhaupt nie zu tun. Dieser Programmteil
hinterlässt seine Ergüsse in Form von 0 oder 1 Bits in besagtem Array.
Und erst der Multiplex-Meachnismus schaufelt dann laufend diese Belegun
auf die tatsächlichen LEDs raus. Für diesen Programmteil ist aber die
LED C1/R7 wiedrrum in keiner Weise speziell. Das einzige was diesen
Programmteil interessiert ist: Jetzt, zu diesem Zeitpunkt ist die Spalte
1 drann. Muss die LED R7 leuchten ja oder nein? Und ein paar
Millisekunden später ist dann die Spalte 2 drann und die Fragestellung
lautet: Muss jetzt, zu diesem Zeitpunkt die LED R7 in dieser Spalte
leuchten ja oder nein? Und ein paar Millisekunden später ist es die
Spalte 3, usw. usw.
Die Dinge sind vollständig entkoppelt:
Der 'Spielteil' deines Programms braucht sich nicht darum kümmern, wie
genau die Portbits stehen müssen und der Multiplexteil kümmert sich
nicht darum, warum eine LED aufgrund der Spielregeln leuchten soll.
Bindeglied zwischen beiden ist dieses Array.
Stefan schrieb:> Wie ich das ganze in C-Code> verpacke weiß ich zwar noch nicht, aber vielleicht unterstützt du mich> dann nochmal Karl-Heinz.
Dann nutze die Zeit bis dahin und beschäftige dich mit Timer.
Denn der ist der Schlüssel zum ganzen Multiplexing.
FAQ: Timer>> Zum Controller:>> Da ich anscheinend 24 Pins also 3 Ports benötige, sollte ich mir auch> einen Controller (ATMEL) mit 4 Ports z.B. den ATMEGA16 nehmen.
Kann zumindest nicht schaden.
Hallo,
ich hab mir jetzt einfach selber mal eine 3x3 Matrix aufgebaut. Leider
ist mir erst jetzt aufgefallen, dass es dann wohl doch nicht so
funktioniert wie ich mir das vorstellte.
Wenn ich z.B. die unterste Zeile in der mittleren Spalte Rot leuchten
lassen will und die darüber liegende LED Grün, dann geht das nicht mit
dem nach Rocks hier geposteten Schaltplan.
Dann leuchtet entweder immer eine Spalte Rot oder Grün. Oder mach ich da
noch etwas falsch?
Ich habe angefangen zu programmieren in C. Bin noch nicht so weit
gekommen.
1
#include<avr/io.h>
2
3
#define Port_Spalt PORTA
4
#define S1 PA0
5
#define S2 PA1
6
#define S3 PA2
7
8
#define Port_Zeile PORTB
9
#define Z1 PB0
10
#define Z2 PB1
11
#define Z3 PB2
12
13
voidled_mat(charmatrix[3][3]){
14
15
//Spalten komplett ausschalten
16
Port_Spalt&=~(1<<S1);
17
Port_Spalt&=~(1<<S2);
18
Port_Spalt&=~(1<<S3);
19
20
for(inti=0;i<1000;i++){
21
22
//Durchlauf durch Zeilen
23
for(intz=0;z<3;z++){
24
25
//Durchlauf durch Spalten
26
for(ints=0;s<3;s++){
27
28
if(matrix[z][s]==1){
29
Port_Spalt|=(1<<s);
30
31
}
32
}
33
Port_Zeile&=~(1<<z);
34
}
35
}
36
}
37
38
intmain(void){
39
40
//Würfel 1
41
charleds[3][3]={\
42
{1,0,1},\
43
{0,1,0},\
44
{1,0,1}};
45
}
Ich wollte erstmal fragen ob die Richtung stimmt. Laut dem Artikel
LED-Matrix schalte ich zunächst alle Spalten aus. Dann leg ich das
Muster in den Spalten fest und schalte zuletzt dann die Zeile ein.
Den Durchlauf durch die Spalten und Zeilen wollte ich mit
verschachtelten for Schleifen machen.
Wo ich mir allerdings absolut nicht sicher bin, ist bei folgender
Syntax:
1
Port_Zeile&=~(1<<z);
Wenn z=0 ist, dann steht da:
1
Port_Zeile&=~(1<<0);
Nimmt er dann vorm Port_Zeile das 0.Bit - also PB0?
Stefan schrieb:> Hallo,>> zu den Bezeichnungen meiner 3x3 Matrix:>
1
> S
2
> 1 2 3
3
> 1 # # #
4
>
5
> Z 2 # # #
6
>
7
> 3 # # #
8
>
> Die Belegung zu meinen ATMEGA 16:>
1
> Anode Rot
2
> S1 - PA0
3
> S2 - PA1
4
> S3 - PA2
5
> Anode Grün
6
> S1 - PA3
7
> S2 - PA4
8
> S3 - PA5
9
> Kathode Rot/Grün
10
> Z1 - PB0
11
> Z2 - PB1
12
> Z3 - PB2
13
>
Wenn du deine Matrix als eine 6*3 Matrix auffasst würdest du dir
leichter tun. Ob du jetzt 6 Spalten hast, die alle rot sind, oder ob von
den 6 Spalten 3 Stück rot und 3 Stück grün sind, ist ja dem Programm
wieder egal.
> //Würfel 1> char leds[3][3] = {\> {1,0,1},\> {0,1,0},\> {1,0,1}};
Wenn du nicht für jede LED einen eigenen char benutzt (unsigned char
wäre sowieso besser), sondern ein Byte pro Spalte reservierst, dann
repräsentiert jedes Bit in einem Byte eine LED in dieser Spalte.
Die Ausgabe auf die eigentlichen LEDs würde davon ungemein profitieren,
denn das hier
Port_Spalt |= (1<<s);
willst du eigentlich nicht haben.
Die Ausgabe der Spalten wäre dann einfach nur das Byte auf den Port
legen, noch den richtigen Spaltentreiber aktivieren und fertig.
> Ich wollte erstmal fragen ob die Richtung stimmt.
Als erster Test kann man das so machen. Im Endeffekt geht das aber
timergesteuert über Interrupts.
> Laut dem Artikel> LED-Matrix schalte ich zunächst alle Spalten aus. Dann leg ich das> Muster in den Spalten fest und schalte zuletzt dann die Zeile ein.
Ja. Sonst gibts Ghosting.
> Den Durchlauf durch die Spalten und Zeilen wollte ich mit> verschachtelten for Schleifen machen.
Das Stichwort lautet: Timer!
Da führt kein Weg drann vorbei.
Und nein, das sind keine ineinandergeschachtelten for-Schleifen.
> Wo ich mir allerdings absolut nicht sicher bin, ist bei folgender> Syntax:>
1
>Port_Zeile&=~(1<<z);
2
>
> Wenn z=0 ist, dann steht da:>
1
>Port_Zeile&=~(1<<0);
2
>
> Nimmt er dann vorm Port_Zeile das 0.Bit - also PB0?
PB0 ist auch nichts anderes als eine profane Schreibweise für ... 0
Da steckt nichts geheimnisvolles dahinter. Irgendwo im io.h gibt es ein
1
#define PB0 0
2
#define PB1 1
3
...
Aber wie gesagt. Die ganze Operation willst du so mit der variablen
Verschieberei nicht machen. Und du brauchst sie auch nicht, wenn du
deine Datenorganisation ordentlich mit Bits und nicht mit Bytes machst.
Vielen Dank für deine schnelle Antwort Karl Heinz.
Karl Heinz Buchegger schrieb:> Wenn du nicht für jede LED einen eigenen char benutzt (unsigned char> wäre sowieso besser), sondern ein Byte pro Spalte reservierst, dann> repräsentiert jedes Bit in einem Byte eine LED in dieser Spalte.> Die Ausgabe auf die eigentlichen LEDs würde davon ungemein profitieren,> denn das hier> Port_Spalt |= (1<<s);> willst du eigentlich nicht haben.
Ok das mit der eindimensionalen Matrix und dann Bytes als Inhalt
verstehe ich. Ich muss ja bei der 3x3 Matrix auch nicht alle Bits des
Ports benutzen.
Karl Heinz Buchegger schrieb:> Das Stichwort lautet: Timer!> Da führt kein Weg drann vorbei.> Und nein, das sind keine ineinandergeschachtelten for-Schleifen.
Das versteh ich noch nicht ganz. Kannst du mir das möglichst einfach und
bildlich erklären :) ?
Warum ist das mit For-Schleifen nicht so gut und mit Timern besser? Mit
denen hab ich noch nicht viel zu tun gehabt. Ich hab mal einen µC mit
einen Timer geweckt. Das war aber auch nur mal so am Rande eines
Projektes.
Wie stell ich mir den Ablauf mit Timern vor? Was sollen die bezogen auf
die Matrix machen?
Karl Heinz Buchegger schrieb:> Wenn du deine Matrix als eine 6*3 Matrix auffasst würdest du dir> leichter tun. Ob du jetzt 6 Spalten hast, die alle rot sind, oder ob von> den 6 Spalten 3 Stück rot und 3 Stück grün sind, ist ja dem Programm> wieder egal.
Achso ich wollte bevor ich mit den Duo Leds arbeite und mich an 4
Gewinnt versuche, doch erstmal nur eine einfarbige Matrix als Würfel
gestalten. ISt zum Anfang sicher nicht schlecht.
Stefan schrieb:> Karl Heinz Buchegger schrieb:>> Das Stichwort lautet: Timer!>> Da führt kein Weg drann vorbei.>> Und nein, das sind keine ineinandergeschachtelten for-Schleifen.>> Das versteh ich noch nicht ganz. Kannst du mir das möglichst einfach und> bildlich erklären :) ?>> Warum ist das mit For-Schleifen nicht so gut und mit Timern besser?
Weil das Multiplexing der Matrix auch dann laufen muss, wenn der µC
gerade irgendwas anderes macht. Zb die Pixel berechnen, die leuchten
müssen um den Zeiger einer Uhr darzustellen.
Und das Multiplexing muss REGELMÄSSIG und GLEICHMÄSSIG laufen. Sonst
flackert deine Matrix wie Sau.
> Mit> denen hab ich noch nicht viel zu tun gehabt.
Dann wirds Zeit
FAQ: Timer> Wie stell ich mir den Ablauf mit Timern vor? Was sollen die bezogen auf> die Matrix machen?
Eine Spalte anzeigen.
Und wenn die ISR das nächste mal aufgerufen wird - die nächste Spalte
anzeigen.
Und beim nächsten Aufruf der ISR, dann eben wieder die nächste.
Reihum. Eine Spalte nach der anderen.
Die leuchtet dann so lange, bis die ISR das nächste mal aufgerufen wird.
Dann wird sie wieder abgeschaltet und die nächste Spalte kommt drann.
Und das ganze so schnell, dass jede Spalte mindestens 50, besser 100 mal
in der Sekunde drann kommt. D.h. bei 6 Spalten sollte die
Spaltenumschaltung ca 300 mal (eher mehr) pro Sekunde erfolgen.
Ich bin auf eine Funktion von dir für Zufallszahlen gestoßen. Wenn ich
die nutze erhalte ich zwar Zufallszahlen, allerdings immer die gleichen
Zahlenfolgen. Das gleiche Problem hab ich auch bei rand()%6+1. Was mache
ich falsch?
Stefan schrieb:> Ich bin auf eine Funktion von dir für Zufallszahlen gestoßen. Wenn ich> die nutze erhalte ich zwar Zufallszahlen, allerdings immer die gleichen> Zahlenfolgen.
Logisch.
Sind ja auch keine echten Zufallszahlen sondern dahinter steckt eine
Formel. Geht man von den gleichen Startwerten aus, dann entsteht auch
immer die gleiche Folge von Zahlen. Diese Folge hat statistische
Eigenschaften von Zufallszahlen.
srand() einmalig am Programmstart aufrufen. Aber auch dazu brauchst du
eine erste Zahl. Die kann man zb im EEPROM speichern und bei jedem
Programmstart um 1 erhöhen, für srand() hernehmen und wieder ins EEPROM
speichern.
Oder man kann den Benutzer bitten, eine Taste zu drücken und die
Drückdauer als Startwert für srand() benutzen.
Karl Heinz Buchegger schrieb:> Die kann man zb im EEPROM speichern und bei jedem> Programmstart um 1 erhöhen, für srand() hernehmen und wieder ins EEPROM> speichern.
Sehr gute Idee, wie ich finde. Bei der Umsetzung hab ich wiedermal
Probleme.
Hier ein Ausschnit vom Programmcode. Die Funktionen zum Schreiben und
Lesen vom eeprom benötigen ein uint8_t als Datentyp. Das stellt aber
einen Konflikt zur Funktion srand da, wie mir die Fehlermeldung
mitteilt.
Wenn ich als erstes einen Wert ins EEPROM schreibe und den dann erhöhe,
habe ich beim nächsten Programmstart das gleiche Problem. Denn dann wird
ja wieder zuerst die gleiche Zahl reingeschrieben.
Stefan schrieb:> myByte = eeprom_read_byte (0x00);> eeprom_write_byte(0x00, myByte+1);> void srand(uint8_t myByte);
Das hier ist kein Funktionsaufruf.
Das ist die Deklaration einer Funktion die ein uint8_t Argument
übernimmt und nichts zurückliefert - ein Funktionsprototyp.
Ein Funktionsaufruf sieht anders aus
srand( myByte );
Sag mal, lest ihr eigentlich keine C-Bücher und seht euch dort mal an,
wie die Syntax von verschiedenen Dingen aussieht, übt mit dem Buch ein
bißchen (ein gutes Buch hat nach jedem Kapitel Übungsbeispiele), ehe ihr
reale Programme schreiben wollt? Das ist schon erschreckend, was du
alles NICHT weißt, aber wissen solltest, wenn du dir zutraust eine
LED-Matrix machen zu können.
(war eine rhetorische Frage - ich kenne die Antwort: Du hast kein Buch.
Business as usual)
Im ganzen Zusammenhang
1
myByte=eeprom_read_byte(0x00);
2
myByte++;
3
eeprom_write_byte(0x00,myByte);
4
srand(myByte);
Und ob ein Byte da so gut ist. Na ja. es gibt ja auch Word-Funktionen
aus dem EEPROM Lager.
1
uint16_tseed;
2
3
4
seed=eeprom_read_word(0x00);
5
seed++;
6
eeprom_write_word(0x00,seed);
7
srand(seed);
Aber wahrscheinlich sind 256 verschiedene Zufallszahlenfolgen für den
Hausgebrauch auch so gut genug.
Hallo,
danke erstmal für deine Unterstützung! Natürlich hab ich kein C-Buch.
Mit dem Funktionsprototypen ist mir allerdings ein Begriff. Damit kann
ich vorab dem Compiler mitteilen, dass weiter unten im Programm eine
Funktion dieses Typs vorhanden ist. Hoffe doch das ich mich da jetzt
noch richtig erinnere.
Ich habe nur im Studium mal C programmiert und das ist auch schon eine
Weile her. Ich arbeite dann mit den Unterlagen, aber wenn man es nicht
regelmäßig nutzt, dann vergisst man gerne auch mal sowas.
Karl Heinz Buchegger schrieb:> Dann wirds Zeit> FAQ: Timer>>> Wie stell ich mir den Ablauf mit Timern vor? Was sollen die bezogen auf>> die Matrix machen?>> Eine Spalte anzeigen.> Und wenn die ISR das nächste mal aufgerufen wird - die nächste Spalte> anzeigen.> Und beim nächsten Aufruf der ISR, dann eben wieder die nächste.> Reihum. Eine Spalte nach der anderen.> Die leuchtet dann so lange, bis die ISR das nächste mal aufgerufen wird.> Dann wird sie wieder abgeschaltet und die nächste Spalte kommt drann.> Und das ganze so schnell, dass jede Spalte mindestens 50, besser 100 mal> in der Sekunde drann kommt. D.h. bei 6 Spalten sollte die> Spaltenumschaltung ca 300 mal (eher mehr) pro Sekunde erfolgen.
Ich habe mir den Artikel über TIMER durchgelesen. Die Idee die Matrix so
anzusteuern gefällt mir. So wie ich es verstehe, läuft parallel zum
Programm immer der TIMER mit und ruft je nach Konfiguration (Takt mit
Vorteiler oder ggf. SW Teiler) zu bestimmten festgelegten Zeiten die ISR
auf. Jetzt kann ich mich erinnern, dass man die ISR vom Code so klein
wie möglich halten soll. Warum kann ich allerdings nicht mehr sagen.
Das Problem was ich sehe, wenn die ISR jetzt aller paar ms aufgerufen
wird und ich pro Aufruf eine Spalte anzeigen lassen will, wie übergeb
ich der ISR mein Array für die Matrix? Oder soll das Array als globale
Variable angelegt werden?
Habe jetzt den Artikel zum Interrupt durchstöbert und bin da auf
folgenden Vorschlag gestoßen.
Global wird eine Variable definiert.
1
volatileuint8_tflag;
Diese wird dann in der ISR gesetzt und im Hauptprogramm wird diese
zurücksetzt und ausgewertet mit einer if-Abfrage.
Das klingt für mich nach einen Weg, da hiermit auch die ISR sehr kurz
gehalten wird.
So es läuft. Du wirst sicher noch etwas im Code finden, was optimiert
werden könnte. Ich bin für jede Kritik dankbar. Vielleicht läuft es auch
nur durch Zufall :)
Was ich nicht so glücklich finde ist die Darstellung der einzelnen
Würfelzahlen, da hier einfach zuviele If-Bedingungen den Speicher
belasten. Wobei das hier bei dem kleinen Programm keine Rolle spielt.
Aber wenn ich jetzt Laufschriften programmieren würde, dann würde das ja
ins Unendliche verlaufen. Das geht sicher anders.
1
#define F_CPU 1000000UL
2
3
#include<avr/io.h>
4
#include<stdlib.h>
5
#include<stdio.h>
6
#include<util/delay.h>
7
#include<avr/interrupt.h>
8
#include<avr/eeprom.h>
9
10
#define Port_Spalt PORTA
11
#define S1 PA0
12
#define S2 PA1
13
#define S3 PA2
14
15
#define Port_Zeile PORTB
16
#define Z1 PB0
17
#define Z2 PB1
18
#define Z3 PB2
19
20
#define PIN_Taster PINB
21
#define TasterWurf PB3
22
23
//globale Variable zur Auwertung bei Interrupts
24
volatileuint8_tisrFlag;
25
//globale Variable für Zeilendurchlauf (veränderbar in der ISR (volatile))
Stefan schrieb:> So es läuft. Du wirst sicher noch etwas im Code finden, was optimiert> werden könnte. Ich bin für jede Kritik dankbar.
Falscher Ansatz
Die ganze Sache mit dem Flag ist zwar in den meisten Fällen korrekt,
hier aber nicht.
1
ISR(...)
2
{
3
aktuelleSpalteabschalten
4
Spaltenzähler1weiterstellen
5
neueSpalteanzeigen
6
}
so geht das.
Und ein _delay_ms hat da drinnen schon gar nichts verloren.
Der ganze Inhalt der ISR sind eine halbe Handvoll Programmzeilen. Mehr
ist das nicht.
Im Grunde deine Funktion led_mat, nur ein bischen umgestellt.
1
ISR(...)
2
{
3
Port_Zeile|=(1<<isrZeile);
4
5
isrZeile++;
6
if(isrZeile>2)
7
isrZeile=0;
8
9
Port_Spalt=leds[isrZeile];
10
Port_Zeile&=~(1<<isrZeile);
11
}
Die Leds leuchten vom Ende der ISR, bis die ISR das nächste mal
aufgerufen wird. Daher werden sie am ANFANG der ISR abgeschaltet, dann
die nächste Konfiguration eingestellt und zum Leuchten gebracht. Während
dann die ISR wieder abgibt und das Hauptprogramm seine nächsten
Berechnungen macht, leuchtet diese eine Zeile. Bis eben dann, ein paar
Milliskunden später, die ISR erneut aufgerufen wird, die leuchtende
Zeile abschaltet und die nächste Zeile leuchten lässt.
> //Matrix komplett dunkel schalten> void matrixAus(void){>> Port_Spalt &= ~(1<<S1);> Port_Spalt &= ~(1<<S2);> Port_Spalt &= ~(1<<S3);> Port_Zeile |= (1<<Z1);> Port_Zeile |= (1<<Z2);> Port_Zeile |= (1<<Z3);> }
Wenn du die LEDs alle aushaben willst, dann schreibst du das in das Leds
Array hinein. Ab sofort bedeutet jede LED, die leuchtet oder nicht
leuchten soll, eine entsprechende Manipulation im Leds Array. Einzig und
alleine die ISR macht sich an den Ports/Portpins zu schaffen, die die
Matrix steuern. Und sonst niemand.
Stefan schrieb:> Das Problem was ich sehe, wenn die ISR jetzt aller paar ms aufgerufen> wird und ich pro Aufruf eine Spalte anzeigen lassen will, wie übergeb> ich der ISR mein Array für die Matrix? Oder soll das Array als globale> Variable angelegt werden?
Exakt
Stefan schrieb:> Jetzt kann ich mich erinnern, dass man die ISR vom Code so klein> wie möglich halten soll.
Das ist etwas zu plakativ vereinfacht dargstellt. Du machst in einer ISR
was du machen musst. Nicht zuviel, aber auch nicht zu wenig. Wenn du
eine Garantie brauchst, dass tatsächlich Code regelmässig ausgeführt
wird, und zwar vollständig ausgeführt wird, dann muss der Code dafür
auch vollständig in die ISR.
zb wird das Weiterschalten einer Uhr komplett in der ISR gemacht. Du
kannst dich nicht drauf verlassen, dass die Hauptschleife in main()
genügend Zeit hat, dass sie alle Sekunden dann die Sekunden überprüft
und gegebenenfalls die Minuten/Stunden/Tage weiterschaltet. Wenn das
Hauptprogramm in einer Schleife hängt, in der sie auf Benutzereingaben
wartet, dann muss die Uhr trotzdem weiterlaufen! Und wenn sich der
Benutzer eine halbe Stunde dafür Zeit nimmt, dann tut er das eben. Aber
deswegen darf die Uhr nicht 1/2 Stunde verlieren, weil in dieser Zeit
das entsprechende Flag nicht abgefragt wurde.
So auch hier: Egal was passiert - die Matrix MUSS weitergeschaltet
werden. Egal was die Hauptschleife gerade kompliziertes berechnet, zb.
den Gegenzug zur einer Benutzereingabe bei 4-gewinnt - die Matrix MUSS
weitergeschaltet werden. Du kannst nicht drauf warten dass die
Berechnung irgendwann fertig wird um dann das Flag abzufragen. Kommt die
ISR dann wird die Matrix weitergeschaltet - ohne Diskussion und ohne
wesentliche Verzögerung.
> (1<<isrZeile)
Das ist eine Operation, die du auf einem AVR nicht haben willst. Denn
die muss der Compiler in Form einer Schleife auflösen, in der er jeweils
um 1 Bit schiebt.
Da bist du mit einem Array von vorgefertigten Bitmustern besser bedient
In deinem Fall kannst du dir auch das gezielte 'Setzen' nur der
Zeilenbits auch sparen, denn wenn du einfach (in deinem Fall) alle 3
setzt, dann sparst du dir dadurch etwas.
1
ISR(...)
2
{
3
Port_Zeile|=0x07;
4
...
bzw. besser in Form der tatsächlich benutzten Portbits ausgedrückt
1
ISR(...)
2
{
3
Port_Zeile|=(1<<PB0)|(1<<PB1)|(1<<PB2);
4
...
wenn du dann mal alle 8 Bits setzen musst, dann kann man überlegen ob
0xFF dann nicht einfacher wäre.
Zudem hat dieses Vorgehensweise dann auch noch den Vorteil, dass du das
bitMask Array nur noch für die Verundung brauchst, also hier
1
Port_Zeile&=~(bitMasks[isrZeile]);
2
}
wodurch du die Möglichkiet kriegst, die boolsche Negierung auch gleich
noch mit ins Array reinzuziehen.
Hallo,
so der Würfel hat mit deiner Hilfe ganz gut geklappt Karl-Heinz. Danke
nochmal.
Meine 8x8 RGB LED-Matrix ist mittlerweile auch aus China eingetroffen.
Ich wollte vorher allerdings nochmal eine einfarbige 5x8 Matrix von
Kingbright TA 12-11 probieren. Wenn ich die zum laufen bekomme, dann
mach ich mich an die 8x8 RGB.
Bei der 3x3 Matrix hat der µC den Strom für die Led´s noch treiben
können. Wenn ich jetzt allerdings schon 5x8 Led´s verwende, ist es
sicherlich besser das ganze mit FET´s oder irgendwelchen
Treiberbausteinen zu realisieren?
Wobei im Datenblatt zum ATMEGA8 steht etwas von 40mA pro I/O.
>DC Current per I\O Pin .......................... 40.0mA
Ich hab versucht einfach den Code für den Würfel zu nehmen und
entsprechend der neuen MAtrix anzupassen. Dargestellt wird bei folgenden
Code der äußere Rahmen, der zunächst in leds steht. Die Änderung in der
while(1) Schleife bekommt der µC allerdings nicht mehr mit. Ich bin
gerade etwas ratlos und seh den Fehler nicht.
1
#define F_CPU 1000000UL
2
3
#include<avr/io.h>
4
#include<stdlib.h>
5
#include<stdio.h>
6
#include<util/delay.h>
7
#include<avr/interrupt.h>
8
9
#define Port_Zeile PORTD
10
#define Z1 PD0
11
#define Z2 PD1
12
#define Z3 PD2
13
#define Z4 PD3
14
#define Z5 PD4
15
#define Z6 PD5
16
#define Z7 PD6
17
18
#define Port_Spalt PORTC
19
#define S1 PC0
20
#define S2 PC1
21
#define S3 PC2
22
#define S4 PC3
23
#define S5 PC4
24
25
26
//globale Variable zur Auwertung bei Interrupts
27
volatileuint8_tisrFlag;
28
//globale Variable für Zeilendurchlauf (veränderbar in der ISR (volatile))
29
volatileuint8_tisrZeile;
30
31
32
//Array für die Matrix
33
charleds[7]={0b00011111,\
34
0b00010001,\
35
0b00010001,\
36
0b00010001,\
37
0b00010001,\
38
0b00010001,\
39
0b00011111};
40
41
42
ISR(TIMER0_OVF_vect)// Overflow Interrupt Vector
43
{
44
45
//Zeile ausschalten
46
Port_Zeile|=(1<<isrZeile);
47
48
//Inkrementieren der Zeilen
49
isrZeile++;
50
51
//Nach der 7.Zeile wieder auf 0 zurücksetzen
52
if(isrZeile>6)
53
isrZeile=0;
54
55
//Spalte festlegen
56
Port_Spalt=leds[isrZeile];
57
58
//Zeile einschalten
59
Port_Zeile&=~(1<<isrZeile);
60
}
61
62
63
64
65
intmain(void){
66
//Datenrichtungen PORTD/PORTC festlegen
67
DDRD=0xff;
68
DDRC=0xff;
69
70
71
//Timer konfigurieren
72
TIMSK|=(1<<TOIE0);// den Overflow Interrupt des Timers freigeben
73
TCCR0=(1<<CS01);// Vorteiler 8, jetzt zählt der Timer bereits