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
:
Verschoben durch User
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?
Achso okay danke ich schaue mir das jetzt die PDF Datei die Volker reinschickte vllt werde ich ja daraus schlauer
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?
1 | #pragma code _RESET_INTERRUPT_VECTOR = 0x000800
|
2 | void _reset (void) |
3 | {
|
4 | _asm goto _startup _endasm |
5 | }
|
6 | #pragma code
|
7 | |
8 | /*#pragma code _HIGH_INTERRUPT_VECTOR = 0x000808
|
9 | void _high_ISR (void)
|
10 | {
|
11 | ;
|
12 | }
|
13 | |
14 | #pragma code _LOW_INTERRUPT_VECTOR = 0x000818
|
15 | void _low_ISR (void)
|
16 | {
|
17 | ;
|
18 | }
|
19 | */
|
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
Das direkte Unterbrechen nennt man Interrupt? Kannst natürlich auch die Versorgungsspannung kurz unterbrechen, dann nennt man es Power-On-Reset ;-)
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 | int main( 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 | void lauflicht1( void ) |
23 | {
|
24 | for(int i = 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.
:
Bearbeitet durch User
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 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 ;-)
:
Bearbeitet durch User
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 | void LED_1_1 (void) //Befehl für die Hilfsfunktion der 1. LED der ersten Ebene |
2 | {
|
3 | Ebene_1 = 1; Data = 1; Clock = 1; Data = 0; for (i=0; i<0; i=i+1) {Clock = 1;} |
4 | }
|
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)
1 | TRISB = 0x00; //Definiert den Port B als Eingang |
sollte man auch noch mal überdenken
:
Bearbeitet durch User
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 | void LED_1_16 (void) //Befehl für die Hilfsfunktion der 16. LED der ersten Ebene |
2 | {
|
3 | Ebene_1 = 1; Data = 1; Clock = 1; Data = 0; for (i=0; i<15; i=i+1) {Clock = 1;} |
4 | }
|
Insgesamt wird dort 16 mal Clock = 1 gesetzt. Das hat mit druch-clock-en eines Schieberegisters nicht wirklich was zu tun.
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:
1 | schreibe_Wie(); |
2 | schreibe_geht(); |
3 | schreibe_es(); |
4 | schreibe_Dir(); |
Richtig:
1 | char* text = "Wie geht es Dir?" |
2 | schreibe(text); |
:
Bearbeitet durch User
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,...
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.