Hallo zusammen, hab ein Problem damit mehreren Auswahltastern zu sagen was sie machen sollen. Will zum Beispiel an Port B eines ATMEGA 8 einen Taster drücken und dann soll z.B. ein Lauflicht an PIN D starten. Wollt das ganze mit einer switch case Anweisung machen. Hab auch schon meine erste Idee fertig und im AVR Studio funktioniert das auch alles in der Simulation Wunderbar, aber das wars auch. In der Praxis ist alles für die Katz und es passiert nix. Hier mal ein Auszug: ------------------ test=PINC; switch (test) { case 0x02: goto knight; break; case 0x04: goto knight2; break; case 0x08: goto knight3; break; default: goto anfang; ------------------- vielleicht hat ja wer noch eine andere Idee wie man das machen kann. Und vielleicht auch eine Möglichkeit die in der Praxis klappt.
Vielleicht noch das Problem der prellenden Tasten? Und "goto" ist ganz böse...
Wenn Du in C mit goto arbeitest, brauchst Du Dich wegen gar nix zu wundern... Abgesehen davon: Wie sind die Taster an Port B angeschlossen? Ich vermute mal Low-Side...
Einen Funktionsaufruf??? Es gibt unter normalen Umständen keine einzige Anwendung für goto, die nicht auch anders gelöst werden könnte (vielleicht von ganz wenigen sehr exotischen Beispielen abgesehen). goto ist höchst unsauber, da es irgendwo hinspringt und man hinterher nicht mehr weiß, wo man vorher war. Du solltest wirklich mal C-Grundlagen pauken... Abgesehen davon hatte ich oben schon mal gefragt, wie die Taster denn überhaupt angeschlossen sind... Davon hängt nämlich ab, wie die Abfrage zu machen ist!
will es ja lernen, so ist es ja nicht. ist nur schwer sowas auf eigene Faust zu machen. die Taster sind wie folgt angebunden: http://www.mikrocontroller.net/articles/Bild:Active_Low.gif
Ah, genau so hab ichs mir gedacht. Da steht was von 'Active Low'... wenn Du aber abfragst, ob Dein Pin '1' ist, macht das wenig Sinn, es sei denn, Du willst wissen, ob Dein Taster NICHT gedrückt ist. Die Abfrage muss also invertiert werden.
...Ach ja, wenn Du an Port B einen Taster drückst und PINC einliest, bringt Dir das ganze auch recht wenig... Müsste also mindestens test = PINB heißen
sowas hab ich mir auch schonmal gedacht. Hab somit auch schon mal die Abfrage invertiert, leider auch kein Ergebnis. Genau das selbe Problem. In der Simulation geht alles und danach in der Praxis auf dem Board nix. Auch wenn ich alles auf Active High aufbaue, es kommt nix raus. Vielleicht ist das Problem ja das goto. oder ein prellender Taster. Muss man sehen wie ich ihn entprellen kann.
Bei mir in ASM schaut das so aus main: sbis pina, 7 rcall main1 sbis pina ,6 rcall main2 sbis pina, 5 rcall main3 sbis pina,4 rcall main4 rjmp main Habe die Pullups eingeschalten und ziehe mit einem Drehschalter den entsprechenden Pin gegen Masse. Man kann auch die Pullups deaktivieren und mit dem Drehschalter auf 5V hochziehen, dann muss man das SBIS in SBIC ändern, vielleicht kannste das ja in C einbinden
goto ist eigentlich immer ein Problem. Meide es wie die Pest. Wie oben schon gesagt: Es gibt eigentlich immer eine sauberere Lösung, und die ist in jedem Falle vorzuziehen. Du kannst Deine Funktionen ja auch direkt in die switch-Anweisung reinschreiben. Solange das nicht zu viel Code ist, bleibt das auch noch einigermaßen übersichtlich.
"goto" wird nicht gerne genommen, weil es den optischen Programmfluß unterbricht (schlechter lesbar). Ansonsten ist es nicht "böse", wenn Dein Programm logisch stimmt. Das Problem bei ner Taste ist, daß man sie erst ausmaskieren muß, d.h. alle anderen Bits sind egal:
1 | #define KEY0 1 // Portpin 1
|
2 | #define KEY1 5 // Portpin 5
|
3 | |
4 | unsigned char input = ~PINB; |
5 | |
6 | if( input & 1<<KEY0 ){ |
7 | // mache was
|
8 | }
|
9 | if( input & 1<<KEY1 ){ |
10 | // mache was
|
11 | }
|
12 | // usw.
|
Dann kann es immer noch sein, daß Dein Taster prellt (Mehrfacherkennung) oder Du gerade losgelassen hast (keine Erkennung), wenn die Abfrage erfolgt. Daher bietet sich dafür der Timerinterrupt an (1..8 Tasten, siehe Codesammlung). Peter
@Peter: Ich halte goto deshalb für 'böse', weil es einen großen Vorteil der Programmiersprache C (Stichwort strukturierte Programmierung) völlig aushebelt. Ich programmiere schließlich u.a. deshalb in C, damit ich übersichtlicheren Code erhalte, den man auch bei größeren Projekten noch entziffern kann. Die Verwendung von goto macht genau diesen Vorteil zunichte... Deshalb ist (und bleibt voraussichtlich auch) goto das wahrscheinlich einzige C-Schlüsselwort, das ich noch nie in einem Programm verwendet habe. Ansonsten hast Du natürlich recht. Die Methode mit der Abfrage ohne Maskierung haut dann daneben, wenn mehrere Tasten gleichzeitig gedrückt werden oder wenn an irgendeinem anderen Pin des Ports irgendwas anderes passiert. Gruß Johnny
Um mal das Gezetere über den 'goto' (das ich im Übrigen teile) in einen praktischen Vorschlag umzuwandeln. Du kannst das so machen: while( 1 ) { /* das ist eine Endlosschleife */ test = PINC; /* Pins einlesen */ switch( test ) { /* die Pins sind active Low */ /* d.h. wenn der Taster an Pin 2 */ /* gedrueckt wird, dann geht Bit 2 */ /* auf 0 */ case 0b11111101: /* Pin2 */ knight(); /* rufe die Funktion knight auf. */ break; case 0b11111011: /* Pin 4 */ knight2(); break; case 0b11110111: /* Pin 8 */ knight3(); berak; default: ; /* keine Aktion notwendig */ } } Jetzt liegt es an dir die Funktionen knight(), knight2() und knight3() zu schreiben. Ach ja: Besorg Dir unbedingt ein Buch über C-Programmierung. Ich weiss, es gibt Unmengen an Online-tutorials im Web. Kauf Dir trotzdem ein Buch. Es hat schon seinen Grund, warum die meisten Tutorials nicht über 20 Seiten hinauskommen, ein Buch aber mindestens 150 Seiten hat :-) Im Übrigen: als Nachschklagewerke zum 'neben der Tastatur liegen' sind Bücher unschlagbar. Mal ganz davon abgesehen, dass man sich in einem Buch auch Notizen machen kann.
@Karl Heinz, ein sehr schönes Beispiel, wie man es genau nicht machen darf ! Damit beziehst Du alle Pins ein, auch die, die gar keine Tasten sind, sondern vielleicht fröhlich in der Gegend rumfloaten. Ein Funktionieren wäre dann purer Zufall. Der einzig zuverlässige Weg, einzelne Eingänge zu erkennen, ist das UNDieren des jeweiligen Bits. Peter
hey, eure ideen sind super und ich werd sie morgen mal ausprobieren, wenn die Zeit ist. Ein gutes Buch, für den kleinen Anfänger, wäre super, wenn man wüsste welches sich lohnen würde. Also irgendwelche Ideen? Preis ist nur eine zweitrangige Sache bei der Sache. @Peter danegger was meinst du genau mit undieren? Meinst du das schreiben (so vielleicht: (PIN B 1 & PIN B2) weis gerade nicht genau wie es richtig ist. oder wie meinst du es?
@Peter mea culpa Du hast natuerlich recht. Wo hatte ich nur meine Gedanken? @Hubert Also Hubert. Es gibt da mehrere Möglichkeiten. Eine simple ist zb: Bevor du die Auswertung machst, musst du zunaechst mal alle anderen Bits, an denen kein Taster hängt in einen definierten Zustand bringen. Jetzt mach ich mir das einfach und setzte die einfach 1, dann brauch ich im Rest vom Pgm nichts zu ändern. test = PINC; test = test | 0b11110001; switch( test ) { ... ist eine Möglichkeit. Ne andere wäre, wie Peter Dannegger völlig richtig anmerkt, mit einem UND die relevante Bitposition 'heraus- ziehen' und damit weiterzuarbeiten. Dann müsste man den switch-case durch eine if-elseif Leiter ersetzen. Es führen halt viele Wege nach Rom.
"was meinst du genau mit undieren?" Das, was mein erster Beitrag macht. Peter
@Hubert Das würde dann so aussehen: while( 1 ) { test = PINC; if( ( test & 0x02 ) == 0 ) /* Pin 2 */ knight(); else if( ( test & 0x04 ) == 0 ) /* Pin 4 */ knight2(); else if( ( test & 0x08 ) == 0 ) /* Pin 8 */ knight3(); } > Ein gutes Buch, für den kleinen Anfänger, wäre super, > wenn man wüsste welches sich lohnen würde. Mit dem 'Klassiker' kann man nie was falsch machen: Kernighan & Ritchie, Programmieren in C http://www.amazon.de/exec/obidos/ASIN/3446154973/303-4552141-8104214
wenn du den WINAVR nimmst, geht die abfrage auch einfacher - nämlich mit dem Makro: bit_is_clear(): Und else-if Ketten sind (angeblich) besser auf Controllern, daher mein Vorschlag: if( bit_is_clear(PINB, 0) ) function0(); else if ( bit_is_clear(PINB, 1) ) function1(); else if ( bit_is_clear(PINB, 2) ) function2(); cu joern
Ist "bit_is_clear" nicht auch bei der letzten grossen "Reinigungsaktion" des WinAVR mit entsorgt worden (so wie "inp" und "out")? Die Schreibweise mit "(1<<x)" ist auch C-konformer und damit übertragbar; nicht jeder Compiler liefert "bit_is_clear" mit (hat Jörg ja schon durch das Erwähnen von WinAVR eingeschränkt). @Marcor: Master of abo?
so, hab heut schon ein wenig herumexperimentiert, leider ohne ein wirkliches praktisches Ergebnis nur in der Simulation funktioniert es toll. Nun bin nun dabei alle "goto" Anweisungen zu killen, welches viele Änderungen bei meinem Lauflicht erfordern, aber wenn "goto" böse ist dann ist es böse und ich werde es killen. Vielleicht ist es ja das Problem. Kann mich auch wage dran erinnern das mir mein Lehrer sowas von "goto" auch mal erzählt hat. Das es "unsauber sei" usw.
es geht, ich glaubs ja nicht. Aber meinen Fehler hab ich nicht gefunden. Hab nun erstmal es ganz einfach gemacht und gesagt wenn ich Taste drücke geht Licht an und bleibt erstmal an, wenn ich eine andere Taste drücke geht die andere Lampe an. Nun hab ich es erweitert und es geht auch. Ich danke euch für die vielen Beispiele und im Endeffekt hat mir der Vorschlag von Karl Heinz Buchegger weitergeholfen. Aber allen anderen auch ein großes Lob, denn nun wird sich ein Buch gekauft in nächster Zukunft und fleißig gelernt. Und dann finde ich auch Lösungen gegen "goto"
Hmmm... So unterschiedlich ist das... In ASM gibt's eigentlich fast nur "Goto" (rjmp, jmp) und "Goto wenn" (brxx) zur Realisierung von Schleifen und Verzweigungen... Da kann doch "goto" garnicht so "böse" sein... ;-) Duck & wech... ...
@Hannes: goto schon... aber seine ASM-Familie mögen wir alle, auch wenn mancheiner mit der Familie nicht gut zurecht kommt (es handelt sich wohl um Sprachbarrieren [wie zwischen Mann und Frau...])
brxx würde ich eher damit in Basic programmieren "if a = x then gosub" dann landet man nach diesem Unterprogramm wieder am Anfang. Ich verstehe deswegen Peter voll und ganz wenn man nach einem Dutzend gotos nicht mehr richtig weiß wo man eigentlich ist.
> brxx würde ich eher damit in Basic programmieren "if a = x then > gosub" > dann landet man nach diesem Unterprogramm wieder am Anfang. Nix GOSUB, 'brcs label1' verzweigt nach 'label1:' ohne sich wie bei GOSUB (RCALL, CALL) die gegenwärtige Adresse zu merken, es ist also ein 'IF Carryflag=thrue then goto label1'. Mir ist klar, dass die Hochsprachen mächtige Befehle für die übersichtliche Gestaltung von Schleifen und Verzweigungen zur Verfügung stellen und das man diese auch konsequent nutzen sollte wenn man die Vorteile der Hochsprache ausschöpfen will. Daher sollte man schon auf GOTO verzichten. In ASM ist die Denkweise aber nunmal etwas anders, etwas näher an der Hardware, und da gibt es keine Schleifenbefehle, da muss man eben mit RJMP oder JMP (GOTO) zurück springen, bei Schleifen mit Abbruchbedingungen auch mit BRxx. Dass mein Beitrag als Scherz zu verstehen war, kann man übrigens am 'Duck & wech' erkennen. ...
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.