Hey,
da ich nun mit meinem LED-Cube relativ weit bin bzw. alle Lauflichter
usw fertig programmiert habe arbeite ich nun an einem Interrupt Taster
für den PIC18F4550 Datasheet:
https://ww1.microchip.com/downloads/en/devicedoc/39632c.pdf
Nun mein Problem: In der "Skizzierung" des Chips steht das RB0 bis 2 die
Interrupt Pins sind, wenn man allerdings runter zum Interrupt Kapitel
geht steht dort das die Pins RB4:RB7 die Interrupt Pins wären. Nun zu
meiner Frage wonach sollte ich mich jetzt richten? Und wie würde ich in
folgender .c Datei am besten den Interrupt Befehl einsetzen (Ist bloß
eine Übungsdatei da ich es erstmal verstehen möchte bevor es in meine
Hauptdatei reinkommt).
Habe jetzt im PIC-Controller Buch von Günter Schmitt gelesen das man
theoretisch auch einfach INTCON2bits.INTEDG2 =0; einsetzen kann und
somit je nach Bedarf eine 0 oder 1 einsetzen aber ich vermute das es bei
mir anders sein wird als im Buch, daher frage ich mal nach.
Mit freundlichen Grüßen
RB2:0 sind die Pins zum Auslösen jeweils eines eigenen externen
Interrupts.
RB7:4 lösen ein Input Change Interrupt aus, das für alle Pins das
gleiche ist. Da müsste man dann also noch herausfinden, welcher Pin das
Interrupt ausgelöst hat.
Sebastian R. schrieb:> RB2:0 sind die Pins zum Auslösen jeweils eines eigenen externen> Interrupts.> RB7:4 lösen ein Input Change Interrupt aus, das für alle Pins das> gleiche ist. Da müsste man dann also noch herausfinden, welcher Pin das> Interrupt ausgelöst hat.
Also heißt das das ich RB2:0 zum auslösen benutze aber die Interrupts
auf einen anderen Pin programmieren muss? Und was genau bedeutet Input
Change Interrupt?
Majd A. schrieb:> Sebastian R. schrieb:>> RB2:0 sind die Pins zum Auslösen jeweils eines eigenen externen>> Interrupts.>> RB7:4 lösen ein Input Change Interrupt aus, das für alle Pins das>> gleiche ist. Da müsste man dann also noch herausfinden, welcher Pin das>> Interrupt ausgelöst hat.>> Also heißt das das ich RB2:0 zum auslösen benutze aber die Interrupts> auf einen anderen Pin programmieren muss? Und was genau bedeutet Input> Change Interrupt?
okay was Input change Interrupt bedeutet hat sich erübrigt habe gerade
was dazu im Internet gefunden
Majd A. schrieb:> Also heißt das das ich RB2:0 zum auslösen benutze aber die Interrupts> auf einen anderen Pin programmieren muss?
Nein. Wenn alles korrekt konfiguriert ist:
INT0_ISR bei steigender oder fallender Flanke an RB0
INT1_ISR bei steigender oder fallender Flanke an RB1
INT2_ISR bei steigender oder fallender Flanke an RB2
IOC_ISR* bei steigender und fallender Flanke an RB4, 5, 6 oder 7
Also die ersten drei Pins haben jeweils eine eigene Interrupt Service
Routine, RB7:4 teilen sich eine gemeinsame ISR.
*Interrupt on Change
Sebastian R. schrieb:> Majd A. schrieb:>> Also heißt das das ich RB2:0 zum auslösen benutze aber die Interrupts>> auf einen anderen Pin programmieren muss?>> Nein. Wenn alles korrekt konfiguriert ist:>> INT0_ISR bei steigender oder fallender Flanke an RB0> INT1_ISR bei steigender oder fallender Flanke an RB1> INT2_ISR bei steigender oder fallender Flanke an RB2>> IOC_ISR* bei steigender und fallender Flanke an RB4, 5, 6 oder 7>> Also die ersten drei Pins haben jeweils eine eigene Interrupt Service> Routine, RB7:4 teilen sich eine gemeinsame ISR.>> *Interrupt on Change
Achso okay dann habe ich das nun auch verstanden, danke dir.
Weißt du noch vllt wie ich es am besten in das Übungsprogramm einbinden
kann? Bzw wie ich die definiere?
Habe jetzt im Buch gelesen das ich die erstmal mit #pragma interrupt und
dann den Funktionsnamen, aber habe nicht so ganz verstanden wie ich die
Interrupts auf die einzelnen Ports (RB0) setze oder wie ich sie am Ende
aktiviere (Habe da einen Ansatz nämlich das ich irgendwie die Befehle
aus dem Buch eingebe [INTCON3bits.INT2IF; INTCON3bits.INT1 IF =0; etc.]
aber kann ja nichts eingeben ohne das ich vorher sowas definiert habe
usw .
Fürs Tasten entprellen und Flanken auswerten nimmt man bewährte Lösungen
mit Timerinterrupt.
Den externen Interrupt nimmt man nur zum Aufwachen aus dem Sleep bei
Schaltungen für Batteriebetrieb.
Peter D. schrieb:> Fürs Tasten entprellen und Flanken auswerten nimmt man bewährte> Lösungen> mit Timerinterrupt.> Den externen Interrupt nimmt man nur zum Aufwachen aus dem Sleep bei> Schaltungen für Batteriebetrieb.
Ist ein Timerinterrupt nicht ein Interrupt der nach einer bestimmten
Zeit aktiv wird, oder habe ich das falsch verstanden?
Majd A. schrieb:> Ist ein Timerinterrupt nicht ein Interrupt der nach einer bestimmten> Zeit aktiv wird
Genau deshalb kann er ja entprellen. Entprellen ist quasi ein Zeitglied
als Tiefpaß.
Die Flankenerkennung fällt nebenbei mit ab.
Majd A. schrieb:> Weißt du noch vllt wie ich es am besten in das Übungsprogramm einbinden> kann? Bzw wie ich die definiere?
Wie das mit dem Pin Interrupt funktioniert, kannst du da nachlesen:
http://www.hs-ulm.de/users/vschilli/Mikrocontroller/uCQ/_downloads/uCquick-X_20180413.pdf
5.3.2 INTx Interrupt
Das Gerüst für den Interrupthandler deines Compilers hast du ja schon.
Wie ist das mit dem Bootloader? Benutzt ihr den, oder habt ihr ein
Programmiergerät?
Im verlinkten Dokument wird der neuere XC8 Compiler verwendet, die alte
Beschreibung für den C18 ist aber noch rudimentär enthalten. (13.4.6 C18
Interrupts)
Peter D. schrieb:> deshalb kann er ja entprellen. Entprellen ist quasi ein Zeitglied> als Tiefpaß.> Die Flankenerkennung fällt nebenbei mit ab.
Das Problem ist aber das ich erst etwas unterbrechen will wenn ich den
Taster RB0 drücke denn sonst soll das Lauflicht permanent Leuchten bis
ich es halt wechseln will.
Peter D. schrieb:> Fürs Tasten entprellen und Flanken auswerten nimmt man bewährte Lösungen> mit Timerinterrupt.> Den externen Interrupt nimmt man nur zum Aufwachen aus dem Sleep bei> Schaltungen für Batteriebetrieb.
Das ist korrekt.
So im normalen Betrieb hat das Auswerten von Tastern über ein Interrupt
keine Vorteile. Eher Nachteile, weil beim Prellen des Tasters das
Interrupt mehrfach aufgerufen werden kann und dann auch Prozessorzeit
bei drauf geht.
Majd A. schrieb:> Habe jetzt im Buch gelesen das ich die erstmal mit #pragma interrupt und> dann den Funktionsnamen, aber habe nicht so ganz verstanden wie ich die> Interrupts auf die einzelnen Ports (RB0) setze oder wie ich sie am Ende> aktiviere (Habe da einen Ansatz nämlich das ich irgendwie die Befehle> aus dem Buch eingebe [INTCON3bits.INT2IF; INTCON3bits.INT1 IF =0; etc.]> aber kann ja nichts eingeben ohne das ich vorher sowas definiert habe> usw .
#Pragmas wirst du dafür vermutlich nicht brauchen.
Und du kannst Dinge eingeben, die du nicht definiert hast, weil sie
jemand anders sie bereits für dich in der p18cxxx.h definiert hat.
Dort sind auch die ganzen Registernamen, die in deinem Buch auftauchen,
definiert. Dahinter verstecken sich dann auch nur Registeradressen.
Volker S. schrieb:> Majd A. schrieb:>> Weißt du noch vllt wie ich es am besten in das Übungsprogramm einbinden>> kann? Bzw wie ich die definiere?>> Wie das mit dem Pin Interrupt funktioniert, kannst du da nachlesen:> http://www.hs-ulm.de/users/vschilli/Mikrocontroller/uCQ/_downloads/uCquick-X_20180413.pdf> 5.3.2 INTx Interrupt>> Das Gerüst für den Interrupthandler deines Compilers hast du ja schon.> Wie ist das mit dem Bootloader? Benutzt ihr den, oder habt ihr ein> Programmiergerät?>> Im verlinkten Dokument wird der neuere XC8 Compiler verwendet, die alte> Beschreibung für den C18 ist aber noch rudimentär enthalten. (13.4.6 C18> Interrupts)
Wir arbeiten mit MPLAB IDE und benutzen als Bootloader PICDEM (TM) FS
USB Demo Tool.
Was genau meinst du mit dem Interrupthandler? Ist das unten das Kapitel
wo steht was ich nutzen soll oder ist das die "Skizzierung" des Chips?
Sebastian R. schrieb:> #Pragmas wirst du dafür vermutlich nicht brauchen.
Vermutlich doch.
Interrupthandler sind keine gewöhnlichen Funktionen, sie müssen den
gesamten Kontext sichern und restoren.
Beim AVR-GCC werden sie z.B. über das Schlüsselwort ISR definiert und
beim PIC über #pragma.
Majd A. schrieb:> Wir arbeiten mit MPLAB IDE und benutzen als Bootloader PICDEM (TM) FS> USB Demo Tool.
Ok, dann ist alles klar ;-)
Majd A. schrieb:> Was genau meinst du mit dem Interrupthandler?
Majd A. schrieb:> Das Problem ist aber das ich erst etwas unterbrechen will wenn ich den> Taster RB0 drücke denn sonst soll das Lauflicht permanent Leuchten bis> ich es halt wechseln will.
In einem Interrupt kannst/solltest du aber auch nicht mehr machen, als
ein paar Flags zu setzen.
Wenn du in der main blockierende Funktionen fürs Lauflicht hast, aus
denen du mit Tastendruck rausspringen willst, hilft dir ein Interrupt
auch nicht viel.
Jede Schleife, die du in der Main verwendest, müsste dann als
zusätzliche Abbruchbedingung den Tastendruck haben*.
Ansonsten, wenn dein Lauflicht 10 Sekunden läuft und du danach erst
guckst, ob der Taster gedrückt wurde (auch wenns im Interrupt passiert
ist) ändert sich halt erst nach 10 Sekunden etwas. Oder man muss den
Taster so lange gedrückt halten, bis das Lauflicht durch ist.
Das ist halt die generelle Struktur von deinem Programm. Man sollte dazu
wirklich verstehen, wozu Interrupts da sind, was sie tun und was sie für
einen leisten können.
Wenn man auf Tastendruck ein Lauflicht abbrechen und ein nächstes
starten will, braucht man dafür nicht unbedingt Interrupts. Das
Lauflicht muss nur entsprechend durch die richtigen Bedingungen
abbrechbar sein.
Ein Timer, der eine 1ms oder 10ms Zeitbasis erzeugt, ist nie verkehrt.
Da kann man dann sehr viel (nicht zu viel) machen. Die paar
Mikrosekunden, die er damit beschäftigt ist, einen Counter hochzuzählen
und Taster einzulesen, fallen nicht groß auf.
Peter D. schrieb:> Beim AVR-GCC werden sie z.B. über das Schlüsselwort ISR definiert und> beim PIC über #pragma.
Da haben wir schon mein Problem. Ich habe jahrelang auf AVRs entwickelt
und versuche das jetzt on the fly auf PIC zu übertragen ;)
> Majd A. schrieb:>> Was genau meinst du mit dem Interrupthandler?#pragma code> _RESET_INTERRUPT_VECTOR = 0x000800> void _reset (void)> {> _asm goto _startup _endasm> }> #pragma code>> /*#pragma code _HIGH_INTERRUPT_VECTOR = 0x000808
Achso das ist das Grundgerüst was wir von unserem Lehrer bekommen haben,
könnte ich dann theoretisch nicht einfach diesen Code so umschreiben das
er für mich auf PORTBbits.RB0 liegen würde statt auf dem jetzigen Reset
Button? Würde gerne einen S-Plan davon reinschicken aber leider besitze
ich keine da diese Platine eine Eigeonkonstruktion von unserem Lehrer
ist, könnte eventuell ein Bild von der Platine reinschicken
Sebastian R. schrieb:> Wenn du in der main blockierende Funktionen fürs Lauflicht hast, aus> denen du mit Tastendruck rausspringen willst, hilft dir ein Interrupt> auch nicht viel.>> Jede Schleife, die du in der Main verwendest, müsste dann als> zusätzliche Abbruchbedingung den Tastendruck haben*.
Habe es auch Anfangs so versucht ich lade mal die Powerpoint hoch wo ich
verschiedene Lösungsansätze hatte allerdings hat leider keine wirklich
geklappt. Hatte es bereits mit den Bedingungen versucht, aber ohne
Erfolg er ist dann einfach beide Lauflichter durchlaufen und habe es
halt nicht geschafft eine Bedingung zu programmieren wo er dann das
aktuelle Lauflicht abbricht und direkt zum neuen geht. Ich lade mal eben
die richtige Datei hoch die ich bis jetzt habe (Könnte etwas komisch für
euch aussehen da ich noch ein Anfänger bin) und Lauflicht_6 ist das
Lauflicht zum testen gewesen.
Majd A. schrieb:> Das Problem ist aber das ich erst etwas unterbrechen will
Nö, willst Du nicht. Du willst es abbrechen und das ist nicht die
Aufgabe eines Interrupts. Der Interrupt kann nur ein Flag setzen,
welches dann das Lauflicht auswerten muß.
Ein Interrupt unterbricht nur kurz, d.h. er ist für die Applikation
unsichtbar. Die Applikation macht nach einigen µs genau an der Stelle
weiter, wo der Interrupt sie unterbrochen hat.
Ein Interrupt kann auch abbrechen über setjmp and longjmp, aber das
solltest Du dann keinem ernsthaften Programmierer zeigen. Das ist very
bad style.
Majd A. schrieb:> Hatte es bereits mit den Bedingungen versucht, aber ohne> Erfolg er ist dann einfach beide Lauflichter durchlaufen und habe es> halt nicht geschafft eine Bedingung zu programmieren wo er dann das> aktuelle Lauflicht abbricht und direkt zum neuen geht.
Schau dir mal die Befehle "break" und "continue" an.
Die könnten dir dabei helfen.
Peter D. schrieb:> Ein Interrupt unterbricht nur kurz, d.h. er ist für die Applikation> unsichtbar. Die Applikation macht nach einigen µs genau an der Stelle> weiter, wo der Interrupt sie unterbrochen hat.
weiß ich dann bescheid danke dachte wenn ich den interrupt setze springt
er dann komplett aus der Schleife
Sebastian R. schrieb:> Schau dir mal die Befehle "break" und "continue" an.> Die könnten dir dabei helfen.
break; habe ich schon versucht aber hat nicht ganz so gut geklappt wie
eigentlich erwartet. Denn manchmal blieb er dann bei einem Lauflicht
hängen bzw. das fing dann erst nach einigen Sekunden an es zu
durchlaufen.
Majd A. schrieb:> Achso das ist das Grundgerüst was wir von unserem Lehrer bekommen haben,> könnte ich dann theoretisch nicht einfach diesen Code so umschreiben das> er für mich auf PORTBbits.RB0 liegen würde statt auf dem jetzigen Reset> Button?
Nein, weil das gar nichts mit irgendwelchen Resetbuttons zu tun hat.
Das ist nur ein Umleitung des ResetVectors, damit das Programm im
Bootloader bei einem Reset, bzw beim Anlegen der Versorgungsspannung
weiß, wo es hin springen muss.
Das Interrupt-Gerüst, ist das auskommentierte darunter. Egal, ob du
später einen PIN- oder Timer-Interrupt verwendest, der Code dafür muss
dann da rein!
Überflieg doch einfach mal mein Kapitel über Interrupts, bevor du
weitermachst. Vielleicht wird es dann klarer.
Volker S. schrieb:> Majd A. schrieb:>> Achso das ist das Grundgerüst was wir von unserem Lehrer bekommen haben,>> könnte ich dann theoretisch nicht einfach diesen Code so umschreiben das>> er für mich auf PORTBbits.RB0 liegen würde statt auf dem jetzigen Reset>> Button?>> Nein, weil das gar nichts mit irgendwelchen Resetbuttons zu tun hat.> Das ist nur ein Umleitung des ResetVectors, damit das Programm im> Bootloader bei einem Reset, bzw beim Anlegen der Versorgungsspannung> weiß, wo es hin springen muss.>> Das Interrupt-Gerüst, ist das auskommentierte darunter. Egal, ob du> später einen PIN- oder Timer-Interrupt verwendest, der Code dafür muss> dann da rein!>> Überflieg doch einfach mal mein Kapitel über Interrupts, bevor du> weitermachst. Vielleicht wird es dann klarer.
Aber Interrupts brauche ich ja nicht mehr, wenn ich dadurch nicht direkt
aus einer Schleife springen kann. Brauche dann wohl einen neuen Weg der
mir das direkte unterbrechen ermöglicht allerdings weiß ich jetzt nicht
mehr was.
Vielleicht wisst ihr ja was
Majd A. schrieb:> Vielleicht wisst ihr ja was
Ich bin mal ganz kurz ehrlich: Deine jetzige Code-Struktur ist ziemlich
beschissen.
Man könnte die Zeilen auf etwa 5% dessen reduzieren, in dem man die
Funktionen mit Parameterübergaben ausstattet und ein bisschen
abstrahiert.
In dem Augenblick, in dem du dann Schleifen um Funktionsaufrufe bauen
kannst und nicht mehr alles "diskret" hintereinander schreiben musst,
wird es eigentlich offensichtlich, wo aus welcher Funktion gesprungen
werden muss.
Dann kann es in etwa (Pseudocode) so aussehen:
1
intmain(void)
2
{
3
init_uc();// Init-Zeugs
4
5
// Hauptschleife
6
while(1)
7
{
8
// Lauflicht 1, solange keine Taste gedrückt wurde
9
while(!tastenflag)
10
{
11
lauflicht1();
12
}
13
14
// Lauflicht 2, solange keine Taste gedrückt wurde
15
while(!tastenflag)
16
{
17
lauflicht2();
18
}
19
}
20
}
21
22
voidlauflicht1(void)
23
{
24
for(inti=0;i<4*4*4;i++)
25
{
26
set_single_led(i);// LED an Position i einschalten
27
delay(20);// 20ms bis zur nächsten LED warten
28
reset_single_led(i);// LED an Position i ausschalten
29
30
// Wurde zwischenzeitlich ein Taster gedrückt?
31
if(tastenflag==1)
32
{
33
break;// Aus for-Schleife springen
34
}
35
}
36
}
Idealerweise müsste die Delay-Funktion dann auch noch so aufgebaut sein,
dass man sie mit einem Flag verlassen kann, aber wenn der Benutzer 20,
50 oder 100ms nach einem Tastendruck warten muss, wird ihn das nicht
stören.
Tastenflag kommt dann idealerweise aus einem Timer-Interrupt, das
regelmäßig die Tasten einliest und sich um die Entprellung kümmert.
Volker S. schrieb:> Das direkte Unterbrechen nennt man Interrupt?> Kannst natürlich auch die Versorgungsspannung kurz unterbrechen,> dann nennt man es Power-On-Reset ;-)
Keine Ahnung, mein Lehrer meinte das ich es mit Interrupt machen soll,
daher bin ich davon ausgegangen.
Sebastian R. schrieb:> Deine jetzige Code-Struktur ist ziemlich> beschissen.
Sagte es ja bereits das ich noch Anfänger bin und mich noch nicht an den
Parametern etc. rangemacht habe. Habe mir aber überlegt die einzelnen
Leds zu kürzen in dem ich (void) LED Ebene 1 (Wert1)
dann jenachdem wenn ich ihn benutze immer in die Klammer die Zahl
brauche die ich benötige, würde mir halt 120 Zeilen sparen.
Sebastian R. schrieb:> Idealerweise müsste die Delay-Funktion dann auch noch so aufgebaut sein,> dass man sie mit einem Flag verlassen kann, aber wenn der Benutzer 20,> 50 oder 100ms nach einem Tastendruck warten muss, wird ihn das nicht> stören.>> Tastenflag kommt dann idealerweise aus einem Timer-Interrupt, das> regelmäßig die Tasten einliest und sich um die Entprel
werde es mal jetzt so versuchen danke für deine Hilfe
Sebastian R. schrieb:> Ich bin mal ganz kurz ehrlich: Deine jetzige Code-Struktur ist ziemlich> beschissen.
Oh, das hatte ich noch gar nicht angeschaut. +1 ;-)
Majd A. schrieb:> mein Lehrer meinte das ich es mit Interrupt machen sollVermutlich meinte er sogar, dass du das mit dem PIN Interrupt machen
sollst, weil er das möglicherweise für einen Anfänger am einfachsten und
es als guten Einstieg in das Thema Interrupts hielt!
Jetzt fragst du hier und bekommst leider gesagt, dass man das nicht so
macht ;-)
Volker S. schrieb:> Majd A. schrieb:>> mein Lehrer meinte das ich es mit Interrupt machen soll>> Vermutlich meinte er sogar, dass du das mit dem PIN Interrupt machen> sollst, weil er das möglicherweise für einen Anfänger am einfachsten und> es als guten Einstieg in das Thema Interrupts hielt!>> Jetzt fragst du hier und bekommst leider gesagt, dass man das nicht so> macht ;-)
Jetzt ist leider die Frage wonach ich mich richten sollte. Da ich das
mit dem Interrupt eh nicht so ganz verstehe versuche ich es mal mit dem
break; wieder habe ja sonst in der Zeit eh nichts zu tun außer mir den
Kopf darüber zu zerbrechen.
Es geht auch erst einmal ohne Interrupt.
Wenn man nur nicht entprellt, kann es passieren, dass dann nicht ein
Lauflicht, sondern 2 oder 3 übersprungen werden.
Was mir auffällt: Du hast "Taster_x_betaetigt", diese Variable wird aber
nirgens mit einem Eingangswert beschrieben. Vielleicht funktioniert
deshalb das ganze auch noch nicht. Genau das Beschreiben könnte man im
Interrupt machen. Oder man
Die Quick&Dirty-Lösung zum Entprellen ohne Interrupt könnte so aussehen:
1
...
2
// Taster gedrückt?
3
if(PORTBbits.RB0==1)
4
{
5
delay(20);// 20ms warten
6
7
// Immer noch gedrückt?
8
if(PORTBbits.RB0==1)
9
{
10
break;// herausspringen
11
}
12
}
13
...
Wenn der Taster gedrückt wurde, kann man nach ein paar Millisekunden
(wenn das Prellen durch ist) einfach noch einmal gucken, ob der Taster
immer noch gedrückt ist.
Ist nicht elegant, funktioniert aber erstmal.
Ich denke, für den aller ersten Schritt wäre ein großes Code-Aufräumen
unerlässlich.
Guck dir einfach mal an, wo du viele gleiche Dinge hintereinander
machst. Das kannst du alles in Schleifen verpacken.
Das würde schon mal sehr viel an Code einsparen.
Sebastian R. schrieb:> Was mir auffällt: Du hast "Taster_x_betaetigt", diese Variable wird aber> nirgens mit einem Eingangswert beschrieben. Vielleicht funktioniert> deshalb das ganze auch noch nicht. Genau das Beschreiben könnte man im> Interrupt machen. Oder man
Meinst du mit Eingangswert jetzt den Startwert? Habe halt oben als ich
die Variable erstellt habe die der 0 zugewiesen.
Sebastian R. schrieb:> Wenn der Taster gedrückt wurde, kann man nach ein paar Millisekunden> (wenn das Prellen durch ist) einfach noch einmal gucken, ob der Taster> immer noch gedrückt ist.>> Ist nicht elegant, funktioniert aber erstmal.>> Ich denke, für den aller ersten Schritt wäre ein großes Code-Aufräumen> unerlässlich.>> Guck dir einfach mal an, wo du viele gleiche Dinge hintereinander> machst. Das kannst du alles in Schleifen verpacken.>> Das würde schon mal sehr viel an Code einsparen.
Danke werde ich jetzt machen nur muss jetzt noch auf meinen Partner die
Schulstunde warten das ich erstmal testen kann ob die Lauflichter
überhaupt klappen nicht das ich da einen Fehler drin habe. Er muss halt
jetzt nur noch die Register verbinden
Vielleicht kannst Du Dir hier was abschauen:
Beitrag "AVR Sleep Mode / Knight Rider"
Das Lauflichtmuster steht in einer Tabelle und bei jedem Aufruf wird das
nächste Muster ausgegeben.
Damit ist es auch einfach, zwischen den Aufrufen eine Taste abzufragen
und das nächste Lauflicht auszuwählen.
Peter D. schrieb:> Vielleicht kannst Du Dir hier was abschauen:>> Beitrag "AVR Sleep Mode / Knight Rider">> Das Lauflichtmuster steht in einer Tabelle und bei jedem Aufruf wird das> nächste Muster ausgegeben.> Damit ist es auch einfach, zwischen den Aufrufen eine Taste abzufragen> und das nächste Lauflicht auszuwählen.
Wie man die Lauflichter auswählen kann im anderen Lauflicht weiß ich ja
und es klappt auch nur das Problem ist das er dann beide Lauflichter
gleichzeitig durchführt.
Majd A. schrieb:> Danke werde ich jetzt machen nur muss jetzt noch auf meinen Partner die> Schulstunde warten das ich erstmal testen kann ob die Lauflichter> überhaupt klappen nicht das ich da einen Fehler drin habe.
Ich schätze, da sind noch einige Fehler drin ;-)
Wenn ihr keinen Schaltplan bekommt, woher willst du wissen, wie der
Zustand bei gedrückten Schaltern ist? Oft wird der 0!
Oder z.B. das hier:
1
voidLED_1_1(void)//Befehl für die Hilfsfunktion der 1. LED der ersten Ebene
Was soll denn das machen?
Funktioniert vielleicht auch so, aber beim Schreiben solltet ihr die LAT
Register verwenden und nicht PORT. (#define CLOCK LATBbits.LATB1 usw...)
Wenn das große Aufräumen beginnt, überlegt, ob es nicht einfacher ist,
die kompletten Daten des Würfels als Puffer im Ram anzulegen (8 Byte,
bzw. 2 Bytes pro Ebene) und für ein Update immer alles komplett raus zu
schieben. Für ein geändertes Bild würde so der Puffer verändert, und
dann wieder komplett raus geschoben. (sehe gerade PeterD hat auch schon
etwas derartiges erwähnt)
Volker S. schrieb:> Oder z.B. das hier:void LED_1_1 (void)> //Befehl für die Hilfsfunktion der 1. LED der ersten Ebene> {> Ebene_1 = 1; Data = 1; Clock = 1; Data = 0; for (i=0; i<0; i=i+1)> {Clock = 1;}> }Was soll denn das machen?
Das wird nach hinten hin ja auch noch schlimmer::
1
voidLED_1_16(void)//Befehl für die Hilfsfunktion der 16. LED der ersten Ebene
Majd A. schrieb:> Wie man die Lauflichter auswählen kann im anderen Lauflicht weiß ich ja> und es klappt auch nur das Problem ist das er dann beide Lauflichter> gleichzeitig durchführt.
Das ist Dein Hauptproblem, es fehlt eine Programmstruktur. Du
betrachtest jedes Lauflicht als festen monolithischen Block.
Die Steuerung über eine Tabelle erlaubt es, nach jedem Teilschritt zum
Main zurück zu kehren und z.B. eine andere Tabelle auszuwählen. Der
Programmablauf wird also nicht mehr durch riesige unteilbare Blöcke
bestimmt, sondern nur durch eine Zählvariable, welcher Eintrag als
nächstes ausgegeben werden soll.
Bei einer Textverarbeitung gibt es ja auch nicht millionen Funktionen
für jedes Wort, sondern nur eine Funktion für Textausgabe.
Dein Stil:
Peter D. schrieb:> Bei einer Textverarbeitung gibt es ja auch nicht millionen Funktionen> für jedes Wort, sondern nur eine Funktion für Textausgabe.
Wobei es natürlich schon sinnvoll sein kann, gewisse Aufgaben in
verschiedene Funktionsebenen zu zerlegen. Dadurch kann man die Hardware
ein bisschen abstrahieren und schafft sich kleine, menschenlesbare
Hilfsfunktionen.
Dabei sollte man repetive Aufgaben oder ähnliche Aufgaben so gut wie
möglich abstrahieren. Das heißt nicht, dass es hinterher eine Funktion
mit 50 Parametern für 120 verschiedene Tätigkeiten gibt, sondern alles
sinnvoll strukturiert ist.
Bei einem LED-Cube kann ich mir gut ein paar Basis- und
Debugging-Funktionen vorstellen:
- write_byte(b) - Schreibt 8 Bits übers Schieberegister raus. Dadurch
kann man die 8 Ausgänge von einem Schieberegister wie ein internen Port
behandeln.
- select_layer(0...3) - Damit kann man die Ebene auswählen, in der man
LEDs aktivieren möchte
- write_led(x, y, z, status) - Zum Setzen und Löschen einzelner LEDs.
Status ist dann 0/1, x, y und z die Koordinaten im Cube.
- write_layer(u_int16t daten, layer) - Alle LEDs aus einem Layer
gleichzeitig beschreiben, in dem man den Zustand aller LEDs als
16bit-Wert angibt. Dadurch kann man mit Bitshifting schon viele
Lauflichter erzeugen
- ...
Die Funktionen bauen ganz grob auf der Funktion darüber auf. Wenn sich
die Hardware z.B. ändert, muss man nur die write_byte anpassen, und alle
Funktionen darüber funktionieren wieder wie erwartet.
Aber genau das ist z.B. die Kunst, die man erlernen muss. Welche
Aufgaben kann man abstrahieren, was kann man in Funktionen packen,...