Hallo µC.net Gemeinde,
nach Jahren des mitlesens und ausmärzen meiner Fehler in meinen
Schaltungen, mithilfe der Posts in eurem Forum, habe ich mich nun
dennoch angemeldet, da ich bei meinem aktuellen Projekt, einer 3x5 LED
Matrix im Multiplexbetrieb, wohl einen Fehler drinnen habe, welchen ich
nicht,... finde?
Trotzdem ich einige der Themen mir durchgelesen habe, auf welche auch
öfters verwiesen wird bei diesem LED Matrix Thema, kann ich meinen
Fehler einfach nicht finden.
Nun zu meinem Projekt / Problem:
Ich arbeite mit einem Arduino Mega2560 r3 Bord(µC ist natürlich der
AtMega2560).
Als Programmierumgebung benutze ich das AVR Studio (Atmel Studio 6.1).
Ich habe mir meine Schaltung nach dem Berechnen der Vorwiderstände der
LED, Basistransistorwid,... in Eagle gezeichnet und sie anschließend mal
gelötet, as usual.
(siehe Anhang LED Matrix Eagle sch)
Als SRG nutze ich einen normalen 8bit Zähler (weil ich den zuhause
hatte)
Die Reihen schalte ich mit PNP (Q1 bis Q5).
Die Spalten mit NPN (T1 bis T3).
T4 dient als Schalter um beim Hochzählen des Zählers die LED ausschalten
zu können.
Das Bord sowie die Schaltung versorge ich beim Programmieren über USB.
Beim Normalen Betrieb, um mir um die Versorgungsleistung keine Gedanken
machen zu müssen, über mein Netzgerät und die Strombuchse am Bord.
Die Schaltung funktioniert soweit.
Meines erachtens, ist der Hund wohl in meinem C-Code begraben...
Bevor ich hier lang und breit meinen Code poste wollte ich fragen wie es
üblich bzw sinnvoll ist, ein Hauptprogramm (LED_Matrix) und eine eigene
Header+Source Datei (LED_Matrix_MUX.c & .h) hier im Forum zu posten?
(jeweils ca 150 bis 200 Zeilen)
Zum Code:
Zum Testen der Matrix habe ich anfangs einige "Muster" definiert, welche
im ca 5 Sekundentakt durchlaufen sollten. Dies hat mit meinem Code zum
Multiplexen auch funktioniert, allerdings nur mit einem "_delay_ms(1)".
Es ist mir klar, dass in den meisten Fällen ein "delay" eine schlechte
Art zu programmieren ist, ist zum ausprobieren aber recht praktisch.
Darum wollte ich anschließend das "delay" durch eine Interrupt Routine
ersetzen.
Gesagt getan. Timer initialisiert, ISR usw angelegt.
Doch nun funktioniert der Teil mit dem Multiplexen nicht mehr, der Code
wurde natürlich mit dem Umstellen vom "delay" auf den Timer/ISR
angepasst.
Ich vermute, dass hier der Fehler in meinem Programm ist.
Bisher hatte ich noch nichts mit Timern zu tun, vlt liegt also das
Problem in dessen Config oder daran wie ich die ISR verwende.
Mit meiner ISR setze ich meine eigene Interrupt Variable und zähle eine
Variable zum "Musterwechsel" hoch.
Meine eigene Interrupt Variable nutze ich in meinem Hauptprogramm
(Globale Variable) und in meiner "LED_Matrix_MUX".
Hier eine Frage:
Kann ich eine Varibale, welche im Hauptprogramm als Globale Variable
angelegt ist, in meiner LED_Matrix_MUX.c / .h mittels "extern" ebenfalls
verwenden?
Hierzu sei noch gesagt, dass ich den Timer (genauergesagt die ISR) auch
zum bestimmen der Zeit nutze, wann das Muster gewechselt werden sollte
und das funktioniert.
Als Info noch, was beim Multiplexen passieren sollte und was bei "delay"
und "timer/ISR" wirklich passiert.
Meine Matrix:
LED's
A | B | C
D | E | F
G | H | I
J | K | L
M | N | O
Hier die "Matrix", welche ein "X" darstellen sollte
(Led welche nicht leuchten sollten entfallen)
A | - | C
D | - | F
- | H | -
J | - | L
M | - | O
Matrix mit "delay"
(alter Code)
A | - | C
D | - | F
- | H | -
J | - | L
M | - | O
Matrix mit "Timer/ISR"
(angepasster Code)
A | B | C
D | E | F
- | - | -
J | K | L
M | N | O
Den C Code poste ich, sobald ich die Gepflogenheiten diesbezüglich hier
im Forum erfahren habe ;-)
Danke schonmal für die Mühe, mir helfen zu wollen ;-)
Beste Grüße Phil
Lehner P. schrieb:> ausmärzen
ausmerzen.
Auch wenn es evtl tatsächlich vom März kommt, in den die schlechtesten
Lämmer zu Lammbraten umfunktioniert wurden...
Lehner P. schrieb:> (siehe Anhang LED Matrix Eagle sch)
Bei den Q1...5 ist C und E vertauscht
Lehner P. schrieb:> Kann ich eine Varibale, welche im Hauptprogramm als Globale Variable> angelegt ist, in meiner LED_Matrix_MUX.c / .h mittels "extern" ebenfalls> verwenden?
Wo "im Hauptprogramm"?
BTW: wenn dein Programm nicht funktioniert dann solltest das mal
anhängen.
Lehner P. schrieb:> Matrix mit "Timer/ISR"> (angepasster Code)>> A | B | C> D | E | F> - | - | -> J | K | L> M | N | O> Den C Code poste ich, sobald ich die Gepflogenheiten diesbezüglich hier> im Forum erfahren habe ;-)
Nicht nötig, der Zeiger für Reihen wird richtig angesteuert, aber der
Zeiger für Spalten wahrscheinlich nicht.
@ Lothar Miller
Wer Rechtschreibfehler findet, darf sie behalten, aber Danke Lothar
Miller ;-)
Ja hatte bei den PNP schon so meine zweifel, aber da die Matrix erst
funktionierte, dachte ich wirds schon passen. Werde das ansonsten
ändern.
Ich habe in meinem Main.c die Variable "short InterruptT0var" global
angelegt.
In meiner Matrix.c wollte ich diese Variable ebenso verwenden. Dort habe
ich sie mit "extern short InterruptT0var" angelegt (ebenso im
zugehörigen .h File).
Kann ich so auf den Wert dieser Variable auch in einem Sourcefile
zugreifen?
Oder würde dies nur funktionieren wenn ich diesen Wert übergebe (Bspw
mit einem Pointer)?
@Marc Vesely
Hab mich bei meinem ersten Post vertan, es handelt sich um ein H nicht
um ein X... sry
werde das noch editieren.
Das Problem der Matrix liegt meines erachtens daran, dass in meinem
Aufruf für das Multiplexen, nur der erste Wert angenommen wird.
---------
Ich schreib hier mal meinen Code rein, sollte es nicht passen den Code
so anzufügen, so sagt mir bitte wie es hier im Forum richtig gemacht
wird.
In meinem Source File verwende ich in der switch-case einmal ein
weiteres switch-case und anschließend eine if-else if.
Begründung:
Um auszuschließen, dass es sich hierbei um den Fehler handelt, jedoch
habe ich bei beiden das gleiche Problem, dass eben in der "inneren
switch-case(casecount)" immer nur der erste Aufruf ausgeführt wird...
Liegt dies daran, das meine Variable "InterruptT0var" von mir falsch
verwendet / angelegt wird?
Hier der Großteil des Codes
(die USART Befehle müsst ihr nicht beachten, die hauen hin ;-) )
Hauptprogramm (main)
Hallo,
auf die Schnelle was mir aufgefallen ist:
Der Datentype zu |interruptT0var| ist nicht vollständig und die Timer
ISR kann den Wert nicht ändern.
Stichwort: volatile
Warum wird das Multiplexen der LED nicht in der Timer ISR durchgeführt ?
volantile
Lehner P. schrieb:> @ Lothar Miller Wer Rechtschreibfehler findet, darf sie behalten
Das war kein Rechtschreibfehler, sondern ein Verständnisproblem (so wie
z.B. anderswo "Standart"). Deshalb hatte ich das kurz mal erwähnt...
> Danke Lothar Miller ;-)
Keine Ursache, man lernt nie aus.
> Ja hatte bei den PNP schon so meine zweifel, aber da die Matrix erst> funktionierte, dachte ich wirds schon passen. Werde das ansonsten> ändern.
Ja, denn du betreibst die Transistoren im Inversbetrieb. Das bringt
insbesondere einen Nachteil mit sich, dass die Stromverstärkung nur noch
ca. 10 statt 300 ist. Deine Vorwiderstände sind dafür falsch
berechnet...
BTW:
Lehner P. schrieb:> Das Problem der Matrix liegt meines erachtens daran, dass in meinem> Aufruf für das Multiplexen, nur der erste Wert angenommen wird.
Sage ich doch.
Ohne mich durch deinen Code zu wühlen:
Spalten werden richtig umgeschaltet aber der zugehörige Wert wird
nicht übernommen bzw. aktualisiert.
Zu meinem vorherigen Post:
ich kann ihn leider nicht mehr editieren...
Karl M. schrieb:> Der Datentype zu |interruptT0var| ist nicht vollständig und die Timer> ISR kann den Wert nicht ändern.>> Stichwort: volatile
Was heißt "nicht vollständig"?
Und warum kann eine ISR den Wert einer Variable nicht ändern?
Das "Problem" mit "volatile" sollte ich umgehen können wenn ich in den
Projekt Properties in der Toolchain unter AVE/GNU C Compiler Optimation
den Optimation Level auf "none" setzte oder? Hab ich nämlich dafür so
eingestellt.
Wenn ich in meinem Code "volatile" verwende, ändert sich nichts.
Karl M. schrieb:> Warum wird das Multiplexen der LED nicht in der Timer ISR durchgeführt ?
Wäre meine ISR dann nicht relativ lange? Und sollte man dies nicht
vermeiden?
Lothar M. schrieb:> Ja, denn du betreibst die Transistoren im Inversbetrieb. Das bringt> insbesondere einen Nachteil mit sich, dass die Stromverstärkung nur noch> ca. 10 statt 300 ist. Deine Vorwiderstände sind dafür falsch> berechnet...
Stimmt, die hab ich kervehrt eingebaut... die LED leuchten jetzt auch
generell etwas heller, Danke für den Tipp.
Lothar M. schrieb:> BTW:Antwort schreiben> Wichtige Regeln - erst lesen, dann posten!> ....> * Längeren Sourcecode nicht im Text einfügen,> sondern als Dateianhang
Wird in Zukunft berücksichtigt!
Nun wieder zum Problem:
Die Variable "InterruptT0var", wird in meinem Programm, so wie ich es
wollte, in der ISR geändert.
Das sehe ich, wenn ich mir die Speicherstelle ansehe und daran, dass
wenn ich sie in der ISR auf "0" setze, keine LED mehr leuchten.
Wohl eben, weil ich die Optimation ausgeschaltet habe.
-> main
1
/*
2
* Der Overflow Interrupt Handler wird aufgerufen, wenn TCNT0 von 255 auf 0 wechselt (256 Schritte),
3
* Interrupt Aktion alle (16000000/64)/256 Hz = 976,6 Hz bzw. 1/976,6 s = 1,024 ms
4
*/
5
ISR(TIMER0_OVF_vect)
6
{
7
interruptT0var=1;//Setzen einer eigenen Iterrupvariable
8
autocount++;//Autocount für Musterwechsel
9
TCNT0&=0b00000000;//Rücksetzen des Timer Zählregisters
10
TIFR0=(1<<TOV0);//Löschen des Interrupt Flag Overflow Timer 0
11
}
-> header
1
externshortinterruptT0var;
-> source
1
//Globale Variable zum richtigen Ablauf der "Count" im switch case
2
shortcasecount=0;
3
externshortinterruptT0var;
Mein Problem dürfte also im folgenden liegen:
Mit "casecount", zähle ich eine Variable hoch, welche aussagen sollte,
welche LED im aktuellen Muster eingeschaltet werden sollte.
Was aber nicht passiert...
--> MatrixMux ist die Funktion, welche das "übergebene" Muster an LED
ansteuern sollte, jedoch wird immer nur der erste "Count"
Funktionsaufruf ausgeführt.
Bei Muster H eben die beiden äußeren Spalten, nicht jedoch der zweite
case, die mittlere LED.
1
voidMatrixMux(intMusterNr)
2
{
3
4
switch(MusterNr)
5
{
6
case0:
7
Count(LED12);
8
casecount=0;//Rücksetzten der casecount Variable
9
break;
10
case1://Muster Eckpunkte
11
Count(LEDECKEN);
12
casecount=0;
13
break;
14
case2://Muster H
15
switch(casecount)
16
{
17
case0:
18
Count(LEDI0I);
19
break;
20
case1:
21
Count(LED12);
22
casecount=0;
23
break;
24
}
25
break;
26
case3://Muster X
In meiner Count Funktion, würde ich diese Variable, nach einem
Durchlauf, aber immer um Eins erhöhen...?
1
//Funktion zum Setzten des Zählers für auszugebende Muster
2
voidCount(intcount)
3
{
4
cli();//Interrupt off
5
6
if(interruptT0var==1)
7
{
8
//Ausschalten der LED um die Matrix beim Hochzählen nicht
9
//dauernd alle LED zu beleuchten
10
PORTA=0b00000000;
11
12
//Rücksetzen des Zählers
13
ResetCount();
14
15
//Hochzählen auf den neuen "LED_M" Wert
16
inti=0;
17
for(i=0;i<count;i++)
18
{
19
PORTA=0b00000010;
20
PORTA=0b00000000;
21
}
22
//Wiedereinschalten der LED Matrix
23
PORTA=0b00000100;
24
25
casecount++;//Hochzählen der Variable für die case(MusterNr)
Lehner P. schrieb:>> Stichwort: volatile>> Was heißt "nicht vollständig"?> Und warum kann eine ISR den Wert einer Variable nicht ändern?
ich glaube, er meint
"A variable should be declared volatile whenever its value can be
changed by something beyond the control of the code section in which it
appears, such as a concurrently executing thread."
Info @ all:
Mein Programm läuft jetzt, Danke nochmal an die hilfreichen Antworten!
Mein Fehler lag hier:
In meiner inneren Switch hatte ich die Variable "casecount" nullgesetzt,
natürlich ist das immer passiert, sobald case "0" abgearbeitet worden
war.
1
case2://Muster H
2
switch(casecount)
3
{
4
case0:
5
Count(LEDI0I,interruptT0var);
6
break;
7
case1:
8
Count(LED12,interruptT0var);
9
break;
10
casecount=0;<--Fehler!
11
}
12
break;
Richtiggestellt sieht der Code so aus:
Nun wird die "casecount" Variable erst nach der letzten inneren switch
case Anweisung nullgesetzt.
1
case2://Muster H
2
switch(casecount)
3
{
4
case0:
5
Count(LEDI0I,interruptT0var);
6
break;
7
case1:
8
Count(LED12,interruptT0var);
9
casecount=0;<--Richtig
10
break;
11
}
12
break;
Ich sollte meine Augen eben aufmachen beim lesen und schreiben :-D
Einen gemütlichen "Abend" noch an alle.
PS: Eine Frage hätte ich noch, wie löst man es sauber in der ISR den
neuen Zählerstand auszugeben? Tipps? :-)
Danke Jan,
Jan L. schrieb:> ich glaube, er meint>> "A variable should be declared volatile whenever its value can be> changed by something beyond the control of the code section in which it> appears, such as a concurrently executing thread."
ich dachte er (TE) würde sich mehr mit den MC und C beschäftigen und
diesen Fehler in seinem Programm finden. Er ist nun immer noch
vorhanden.
>Karl M. schrieb:>> Warum wird das Multiplexen der LED nicht in der Timer ISR durchgeführt ?>Wäre meine ISR dann nicht relativ lange? Und sollte man dies nicht>vermeiden?
Ja und ich will ja auch nicht, dass die LED flackern, sondern die LED
mit einer definierten Umschaltzeit "bedient" werden.
Wenn man für die Ausgabe zwei LED Framepuffer verwendet, dauert dise
auch nicht lange. Im Hauptprogramm wird das Muster berechnet und in den
nicht benutzen LED Framepuffer geschrieben, ist das Muster vollständig,
wird der LED Framepuffer umgeschaltet.
Dein gesamtes Programm wird durch diese Maßnahmen strukturierter, besser
lesbar und besser wartbar.
Karl M. schrieb:> Ja und ich will ja auch nicht, dass die LED flackern, sondern die LED> mit einer definierten Umschaltzeit "bedient" werden.>> Wenn man für die Ausgabe zwei LED Framepuffer verwendet, dauert dise> auch nicht lange. Im Hauptprogramm wird das Muster berechnet und in den> nicht benutzen LED Framepuffer geschrieben, ist das Muster vollständig,> wird der LED Framepuffer umgeschaltet.> Dein gesamtes Programm wird durch diese Maßnahmen strukturierter, besser> lesbar und besser wartbar.
Alles klar, dann werde ich meinen Code noch etwas umstrukturieren.
Habt ihr auch Tipps oÄ welchen Normen oder vlt auch Vorschriften oder
Richtlinien solche Codes in der Industrie bzw in Firmen folgen?
Worauf muss man in der Softwareentwicklung bzw Hard&Software Engineering
oder im Bereich der Embedded Software auf soetwas achten?