Hallo, ich möchte mit drei Tastern eine switch case Verzweigung üben. -Taster1 soll PA3 schalten -Taster2 soll PB1 schalten -Taster3 soll PA7 schalten und später soll es dann eine FMS werden, aber dazu will ich erstmal den grundliegenden switch case kennenlernen. da ich aber nicht wirklich etwas bei google finde, und mit dem avr tutorial hier im forum alleine nicht weiter komme bitte ich euch um hilfe. Als anfang will ich an PA3 eine LED über PA0 einschalten. doch das bereitet mir schon riesige probleme. so wie ich das verstanden habe arbeitet das ganze über variablen und habe folgendes probiert. da kommt dann gleich eine riesen fehlerliste. kann mir hier bitte jemand den richtigen einstieg zeigen? /* * switch_case.c * * Created: 11.08.2016 08:37:07 * Author: Huber */ #include <avr/io.h> int main(void) { //Ausgänge festlegen DDRA|= (1<<PA3)|(1<<PA7); DDRB|= (1<<PB1); //Eingänge festlegen pullups PORTA|= (1<<PA0)|(1<<PA1)|(1<<PA2); int AUF = PA0; // hier dachte ich, wenn ich jetzt PA0 drücke, dann geht PA3 an,Wo ist mein dekfehler? switch (AUF) { case 1: PORTA|=(1<<PA3); // Anweisungen für diesen Zweig,variable == break; default: // Anweisungen wenn keine der oben definierten Bedingungen erfüllt ist break; } while(1) { //TODO:: Please write your application code } }
:
Bearbeitet durch User
Huber M. schrieb: > int AUF = PA0; // hier dachte ich, wenn ich jetzt PA0 drücke, Das funktioniert so nicht, denn du musst ja das PIN Register von Port A, also PINA erstmal einlesen. denkbar wäre bei negativer Logik (Pin wird vom Taster auf low gezogen):
1 | #define PINMASK (1<<PA0)|(1<<PA1)|(1<<PA2)
|
2 | |
3 | uint8_t n = ~PINA; // lese Pins invertiert |
4 | n &= PINMASK; // ausmaskieren unbenutzter Pins |
5 | switch (n) { |
6 | case (1 << PA0) : // Taster 0 gedrückt tue was |
7 | break; |
8 | case (1 << PA1) : // Taster 1 gedrückt |
9 | break; |
10 | case (1 << PA2) : // Taster 2 gedrückt |
11 | break; |
12 | case ((1 << PA0) | (1 << PA1)) : // zwei Taster gleichzeitig gedrückt |
13 | break; |
14 | }
|
zugegeben, das auslesen der Pins ist mit der Maskiererei eine Zeile länger, aber damit vermeidet man unnötige Seiteneffekte. Man kann auch bei negativer Logik bleiben (also die Pins nicht invertieren), aber dann wird das switch case etwas unübersichtlicher. Es gibt viele Wege nach Rom und das werden hier sicher auch einige noch anmerken.
:
Bearbeitet durch User
ok, so ungefähr hatte ich mir das vorgestellt, nur erstmal ohne invertieren. damit ich das ganze von grundauf richtig verstehe. Jetzt habe ich das mal aus dem Tutorial Mehrfachabzweigung raus kopiert.Es wären auch noch ein paar beispiele aufgeführt, aber alle in Asembler. Und davon verstehe ich garnix. wie bekomme ich nachfolgendes dazu, dass mir im case1 PA0 (eingang) PA3 (Ausgang) schaltet. Am besten für den anfang, wenn das mit int= möglich ist. switch (variable) { case 1: // Anweisungen für diesen Zweig, wenn variable == 1 break; case 17: // Anweisungen für diesen Zweig, wenn variable == 17 break; case 33: // Anweisungen für diesen Zweig, wenn variable == 33 break; case 9: // Anweisungen für diesen Zweig, wenn variable == 9 break; case 22: // Anweisungen für diesen Zweig, wenn variable == 22 break; default: // Anweisungen wenn keine der oben definierten Bedingungen erfüllt ist break; }
[c] switch (variable) { case 1: // Anweisungen für diesen Zweig, wenn variable == 1 PORTA |= (1<<PA3); break; case 17: // Anweisungen für diesen Zweig, wenn variable == 17 break; case 33: // Anweisungen für diesen Zweig, wenn variable == 33 break; case 9: // Anweisungen für diesen Zweig, wenn variable == 9 break; case 22: // Anweisungen für diesen Zweig, wenn variable == 22 break; default: // Anweisungen wenn keine der oben definierten Bedingungen erfüllt ist break; }
1 | switch (variable) { |
2 | case 1: // Anweisungen für diesen Zweig, wenn variable == 1 |
3 | PORTA |= (1<<PA3); |
4 | break; |
5 | case 17: // Anweisungen für diesen Zweig, wenn variable == 17 |
6 | break; |
7 | case 33: // Anweisungen für diesen Zweig, wenn variable == 33 |
8 | break; |
9 | case 9: // Anweisungen für diesen Zweig, wenn variable == 9 |
10 | break; |
11 | case 22: // Anweisungen für diesen Zweig, wenn variable == 22 |
12 | break; |
13 | default: // |
14 | break; |
15 | }
|
es tut mir wirklich leid, aber ich bringe es nicht zum laufen. Ich check den Anfang schon nicht. Hab mir zich videos etc. angesehen gelesen. Ich weiss was es machen soll, aber ich kanns einfach nicht umsetzen. Selbst wenn ich den geschriebenen code von mathias sch. ein kopiere. Aber jetzt noch mal zum letzten was mache ich den hier falsch? /* * switch_case_1.c * * Created: 11.08.2016 12:41:22 * Author: Huber */ #include <avr/io.h> int main(void) {//Ausgänge festlegen DDRA|= (1<<PA3); //Eingänge festlegen PORTA|= (1<<PA1); int n= (1<<PA1); switch (n) { case 1: // Anweisungen für diesen Zweig, wenn variable == 1 PORTA |= (1<<PA3); break; case 17: // Anweisungen für diesen Zweig, wenn variable == 17 break; case 33: // Anweisungen für diesen Zweig, wenn variable == 33 break; case 9: // Anweisungen für diesen Zweig, wenn variable == 9 break; case 22: // Anweisungen für diesen Zweig, wenn variable == 22 break; default: // break; }
oh, hier nochmal /* * switch_case_1.c * * Created: 11.08.2016 12:41:22 * Author: Huber */ #include <avr/io.h> int main(void) {//Ausgänge festlegen DDRA|= (1<<PA3); //Eingänge festlegen PORTA|= (1<<PA1); char n= (1<<PA1); switch (n) { case 1: // Anweisungen für diesen Zweig, wenn variable == 1 PORTA |= (1<<PA3); break; case 17: // Anweisungen für diesen Zweig, wenn variable == 17 break; case 33: // Anweisungen für diesen Zweig, wenn variable == 33 break; case 9: // Anweisungen für diesen Zweig, wenn variable == 9 break; case 22: // Anweisungen für diesen Zweig, wenn variable == 22 break; default: // break; } while(1) { //TODO:: Please write your application code } }
Dein Problem ist... du ließt den Pin nicht ein, zumindest nicht so wie du das denkst: Huber M. schrieb: > int n= (1<<PA1); damit schreibst du bloß in die Variable n ein 0b0000010... da wird kein Pin abgefragt oder sonstwas. Matthias S. schrieb:
1 | #define PINMASK (1<<PA0)|(1<<PA1)|(1<<PA2)
|
2 | |
3 | uint8_t n = ~PINA; // lese Pins invertiert |
4 | n &= PINMASK; // ausmaskieren unbenutzter Pins |
5 | switch (n) { |
6 | case (1 << PA0) : // Taster 0 gedrückt tue was |
7 | PORTA |= (1<<PA3); // <--- Deine Anweisung |
8 | break; |
9 | case (1 << PA1) : // Taster 1 gedrückt |
10 | break; |
11 | case (1 << PA2) : // Taster 2 gedrückt |
12 | break; |
13 | case ((1 << PA0) | (1 << PA1)) : // zwei Taster gleichzeitig |
14 | gedrückt |
15 | break; |
16 | }
|
Das ist das in welche Richtung es geht. In PINx liegen die aktuellen Zustände der Pins und nicht in PAx. Desweiteren hat dein gesamtes Programm einen fundamentalen Fehler. Es läuft einmal durch und das wars. Du brauchst eine Dauerschleife.
1 | /*
|
2 | * switch_case_1.c
|
3 | *
|
4 | * Created: 11.08.2016 12:41:22
|
5 | * Author: Huber
|
6 | */
|
7 | |
8 | |
9 | #include <avr/io.h> |
10 | |
11 | #define PINMASK (1<<PA0)|(1<<PA1)|(1<<PA2)
|
12 | |
13 | int main(void) |
14 | {
|
15 | //Als Ausgang definieren
|
16 | DDRA |= (1<<PA3); |
17 | |
18 | //DDRA wäre sowieso 0b00001000 somit PA01,1,2 auf Eingang aber um
|
19 | //es nochmal zu zeigen wie auf Eingang gestellt wird:
|
20 | DDRA &= ~((1<<PA0) | (1<<PA1) |(1<<PA2)); |
21 | |
22 | //Hier wird NICHT auf Eingang gestellt, sondern der Pullup gezogen!
|
23 | PORTA|= (1<<PA0) | (1<<PA1) | (1<<PA2); |
24 | |
25 | while(1) // Die Dauerschleife! |
26 | {
|
27 | uint8_t n = ~PINA; // lese Pins invertiert |
28 | n &= PINMASK; // ausmaskieren unbenutzter Pins |
29 | switch (n) { |
30 | case (1 << PA0) : // Taster 0 gedrückt tue was |
31 | PORTA |= (1<<PA3); // <--- Deine Anweisung |
32 | break; |
33 | case (1 << PA1) : // Taster 1 gedrückt |
34 | break; |
35 | case (1 << PA2) : // Taster 2 gedrückt |
36 | break; |
37 | } // Ende der Dauerschleife |
38 | }
|
Das dürfte funktionieren, habs aber nicht getestet nur runtergeschrieben.
Arbeite das https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial mal bis einschliesslich Kapitel 9 durch. Dann kannst Du auch Deinen Switch-Case programmieren :-) Dir fehlen schlicht alle Grundlagen - die musst Du Dir halt erst mal erarbeiten.
Danke dir, jetzt kann ich das langsam nachvollziehen, aber es gibt nur noch ein Problem. Beim kompilieren kommt noch ein fehler. kann aber nicht sehen was fehlen würde oder zuviel da wäre. Ich bekomme bald nen Nervenzusammenbruch :-). Error 1 expected declaration or statement at end of input C:\Dokumente und Einstellungen\Huber\Eigene Dateien\Atmel Studio\6.2\GccApplication16\GccApplication16\GccApplication16.c 38 1 GccApplication16
@dieter.f. da hast du schon recht. Da bin ich ja dabei, aber ich wollte das mit den case üben. Da ich eine Alternative zur if Anweisung brauche. Und mit interrupts habe ich auch kein problem. Ich wollte schon länger den case switch verstehen. Ich tu mich nur leichter, wenn sich was bewegt auf meiner platine :-)
:
Bearbeitet durch User
Setz noch ne Klammer drann ( } ) dann gehts... :-) Die hab ich bei der Switch Case vergessen:
1 | /*
|
2 | * switch_case_1.c
|
3 | *
|
4 | * Created: 11.08.2016 12:41:22
|
5 | * Author: Huber
|
6 | */
|
7 | |
8 | |
9 | #include <avr/io.h> |
10 | |
11 | #define PINMASK (1<<PA0)|(1<<PA1)|(1<<PA2)
|
12 | |
13 | int main(void) |
14 | {
|
15 | //Als Ausgang definieren
|
16 | DDRA |= (1<<PA3); |
17 | |
18 | //DDRA wäre sowieso 0b00001000 somit PA01,1,2 auf Eingang aber um
|
19 | //es nochmal zu zeigen wie auf Eingang gestellt wird:
|
20 | DDRA &= ~((1<<PA0) | (1<<PA1) |(1<<PA2)); |
21 | |
22 | //Hier wird NICHT auf Eingang gestellt, sondern der Pullup gezogen!
|
23 | PORTA|= (1<<PA0) | (1<<PA1) | (1<<PA2); |
24 | |
25 | while(1) // Die Dauerschleife! |
26 | {
|
27 | uint8_t n = ~PINA; // lese Pins invertiert |
28 | n &= PINMASK; // ausmaskieren unbenutzter Pins |
29 | switch (n) { |
30 | case (1 << PA0) : // Taster 0 gedrückt tue was |
31 | PORTA |= (1<<PA3); // <--- Deine Anweisung |
32 | break; |
33 | case (1 << PA1) : // Taster 1 gedrückt |
34 | break; |
35 | case (1 << PA2) : // Taster 2 gedrückt |
36 | break; |
37 | } // <---- Die Schleife hatte gefehlt. |
38 | } // Ende der Dauerschleife |
39 | }
|
Für die Abfrage einzelner Bits ist switch/case nicht geeignet, da die Nachbarbits mit eingehen. Außerdem ist kein Mensch in der Lage, aus CPU-Sicht 2 Tasten gleichzeitig zu drücken (innerhalb 50ns) oder loszulassen. In der Regel ist eine direkte Portabfrage auch nicht sinnvoll, da Tasten oftmals entprellt werden müssen, bevor man sie auswerten kann. Die Entprellroutine kann dann auch ein Intervall für Gleichzeitigkeit bereitstellen (z.B. 500ms). Oder für lang/kurz drücken.
Danke nochmal für die Mühe.Es ist rüber gespielt. Gehe ich jetzt recht der Annahme, wenn ich an PA0 einen Taster (0,1uf entprellt) anschliesse, diesen betättige,dann sollte PA3 einschalten? Es funktioniert nämlich nicht. Ja ich habe die Hardware überprüft verkabelung usw. mehrmals, wenn ich es mit ner if Anweisung mache gehts. Es muss doch nur noch ne Kleinigkeit sein, aber welche?
Huber M. schrieb: > wenn ich es mit ner if Anweisung mache gehts. Damit hast Du schön bewiesen, welches Werkzeug das richtige dafür ist. Warum willst Du unbedingt das falsche nehmen?
weil ich endlich mal mit der Switch Case anweisung arbeiten will. Und ich will das ja dann mal ausweiten, wenn ich einmal den PA3 eingeschaltet bekomme.Wie ich anfangs ja schon schrieb, will ich mich in ferner Zukunft an eine state machine ran arbeiten. -Aber es müsste doch jetzt eigentlich funktionieren. Kann sich keiner vorstellen, warum das nicht geht. Habe an PA0 nen Taster dran und an PA3 eine LED, aber es tut sich nichts, ja die Led ist nicht defekt, oder die anderen komponenten, es liegt nur an mir und diesem Code. /* * switch_case_1.c * * Created: 11.08.2016 12:41:22 * Author: Huber */ #include <avr/io.h> #define PINMASK (1<<PA0)|(1<<PA1)|(1<<PA2) int main(void) { //Als Ausgang definieren DDRA |= (1<<PA3); //DDRA wäre sowieso 0b00001000 somit PA01,1,2 auf Eingang aber um //es nochmal zu zeigen wie auf Eingang gestellt wird: DDRA &= ~((1<<PA0) | (1<<PA1) |(1<<PA2)); //Hier wird NICHT auf Eingang gestellt, sondern der Pullup gezogen! PORTA|= (1<<PA0) | (1<<PA1) | (1<<PA2); while(1) // Die Dauerschleife! { uint8_t n = ~PINA; // lese Pins invertiert n &= PINMASK; // ausmaskieren unbenutzter Pins switch (n) { case (1 << PA0) : // Taster 0 gedrückt tue was PORTA |= (1<<PA3); // <--- Deine Anweisung break; case (1 << PA1) : // Taster 1 gedrückt break; case (1 << PA2) : // Taster 2 gedrückt break; } // <---- Die Schleife hatte gefehlt. } // Ende der Dauerschleife }
:
Bearbeitet durch User
Ich habs mal eben im Simulator getestet und es funktioniert so wie erwartet. Allerdings wird PA3 ja nur einmal im ganzen Programm auf high gesetzt und dann nie wieder zurück. Um es besser zu testen, kannst du in ein anderes 'case' mal PA3 &= ~(1<<PA3); einsetzen, um den Pin wieder auszuschalten. Peter D. schrieb: > Für die Abfrage einzelner Bits ist switch/case nicht geeignet, da die > Nachbarbits mit eingehen. Doch, ist ja oben schon gemacht worden. Deswegen werden auch die Pins mit Knöpfen maskiert. Switch-Case ist immer dann sinnvoll, wenn nur eine Funktion aus vielen ausgeführt werden soll. Das kann auch zur Verriegelung von Tasten oder für Mehrfachkombinationen benutzt werden. Wenn man so einen Buttoninterpreter baut, sollte man ihn allerdings nicht mit der vollen Tektfrequenz durchrennen lassen, sondern mit ein paar ms Intervall. Dann klappt das schon recht gut.
Guten Morgen, ok, das was du hier beschreibtst, soll es auch irgendwann mal werden. und zwar soll es am Gartenteich eine Schiebetür nach oben und unten mit drei Sensoren immer auf den mittleren Pegel-Stand gehalten werden, je nach Wasserstand.Aber dazu muss ich die switch case verstehen.Und da bin ich noch weit entfernt.
Matthias S. schrieb: > Switch-Case ist immer dann sinnvoll, wenn nur eine Funktion aus vielen > ausgeführt werden soll. Genau. Tasten sind aber unabhängig voneinander, daher nimmt man if. Z.B. eine Taste klemmt oder hat ne Zinnbrücke und schon suchst Du ewig und 3 Tage, warum die andere Taste nicht mehr funktioniert. Programmieren heißt nicht nur, es wird schon irgendwie funktionieren, sondern es funktioniert immer zuverlässig und Fehler oder Defekte lassen sich schnell debuggen und finden.
ah, ok, dann werd ich es mir mit if else auf schreiben. Trotzdem Danke für die Mühe, denn ich wollte schon länger mit case switch basteln. Jetzt läuft es ja soweit zum testen. zitat.:Programmieren heißt nicht nur, es wird schon irgendwie funktionieren, sondern es funktioniert immer zuverlässig und Fehler oder Defekte lassen sich schnell debuggen und finden. Genau das will ich mir erarbeiten. Ich habe eigentlich genaue Vorstellung davon wie es funktionieren soll, nur bin ich auch auf der Suche mit welchen Code, und meinen noch wenigen Fähigkeiten ich das umsetzen soll. Jetzt bin ich dem ganzen schon wieder ein Stück näher. Ich habe einen Frequenzumrichter eine Platine mit relais und diversen stift leisten bestückt, die in ein Alugehäuse passt. Und die ich mit dem avr mk2 isp programmieren kann. Muss nur noch meinen Algoryhtmus da rein bringen :-) Ps.: jetzt erstmal zwei wochen Urlaub
:
Bearbeitet durch User
Huber M. schrieb: > Ps.: jetzt erstmal zwei wochen Urlaub Ja, nach der Strapaze auch verdient. "C" zehrt unheimlich an den Reserven des Benutzers. :) mfG Paul
switch/case ist ideal für Statemachines und darin kann man dann z.B. Ereignisse abfragen:
1 | switch( state ){ |
2 | case STATE_X: if( key_pressed( KEY_UP )) |
3 | state = STATE_Y; |
4 | break; |
5 | case STATE_Y: |
6 | // usw.
|
7 | }
|
Ereignisse deshalb, weil nur selten der Zustand interessiert, sondern oft das Ereignis, daß gerade jemand drauf gedrückt hat. Es gibt zu jedem Werkzeug dazu passende Aufgaben (und umgekehrt).
Guten tag mal wieder, ich dachte jetzt habe ich die Logik der case verzweigung endlich mal richtig verstanden, das ich es selbstständig schreiben kann. Und vor allem möchte ich das ganze im absolouten anfänger beispiel testen. Ohne Bits invertiert zu lesen. wenn ich es im AVR Simulator debugge und so schreibe.
1 | uint8_t x = 1; // oder x = 2 dann springt er in die zweite zeile |
2 | |
3 | switch(x) |
4 | |
5 | case 1: PORTD |= (1<<PD0); break; |
6 | case 2: PORTD |= (1<<PD0); break; |
klappt es, und ich kann es absolout nachvollziehen. Will ich es aber mit einem Tatster machen, komme ich einfach nicht klar. Wenn ich nachfolgendes flashe dann fängt PD0 einfach dauerhaft an zu leuchten. Und direkt am controller kann ich es nicht debuggen ( Tasterpin im I/O view ansehen), weil mein MK2 das nicht unterstützt. Wie kann ich das jetzt ohne invertieren umsetzen grüsse huber
1 | /*
|
2 | * GccApplication2.c
|
3 | *
|
4 | * Created: 09.10.2016 14:48:27
|
5 | * Author: HUBER M
|
6 | */
|
7 | |
8 | |
9 | #include <avr/io.h> |
10 | |
11 | #define tasterpins (1<<PD5)
|
12 | |
13 | int main(void) |
14 | {
|
15 | DDRC &= (1<<PC5); //Eingang |
16 | PORTC = (1<<PC5); //Pullup Eingang |
17 | DDRD = (1<<PD0); //Ausgang LED |
18 | |
19 | |
20 | while(1) |
21 | {
|
22 | uint8_t n = tasterpins; |
23 | |
24 | switch (n) |
25 | {
|
26 | case (1<<PC5) : |
27 | |
28 | PORTD |= (1<<PD0); // soll led an PD0 einschalten |
29 | |
30 | break; |
31 | }
|
32 | |
33 | }
|
34 | }
|
Huber M. schrieb: > Wie kann ich das > jetzt ohne invertieren umsetzen https://www.mikrocontroller.net/articles/Bitmanipulation Was soll das Huber M. schrieb: > DDRC &= (1<<PC5); //Eingang und das bewirken? Huber M. schrieb: > PORTC = (1<<PC5); //Pullup Eingang > DDRD = (1<<PD0); //Ausgang LED Wozu gibt es & und | ? Was macht man, um EIN Bit auf 0 bzw. auf 1 zu setzen? Mal abgesehen davon, das Du Dir auch mal den Artikel über Tasten-Entprellung durchlesen solltest (und versuchen, es zu verstehen ...). Übrigens ist das Huber M. schrieb: > uint8_t x = 1; // oder x = 2 dann springt er in die zweite zeile > > switch(x) > > case 1: PORTD |= (1<<PD0); break; > case 2: PORTD |= (1<<PD0); break; vollkommen sinnfrei, wenn Du bei jedem Zustand das Gleiche ausführst. Da dürfte auch ein Test schwer fallen :-)
Dieter F. schrieb: > vollkommen sinnfrei, wenn Du bei jedem Zustand das Gleiche ausführst. Da > dürfte auch ein Test schwer fallen :-) das ist mir schon klar, ich wil ja nur mit einem tastendruck mal in die Schleife kommen, dann kann ich mir mal was überlegen was ein bischen Sinn macht.
Huber M. schrieb: > das ist mir schon klar Huber M. schrieb: > wenn ich es im AVR Simulator debugge und so > schreibe. > > uint8_t x = 1; // oder x = 2 dann springt er in die zweite zeile > > switch(x) > > case 1: PORTD |= (1<<PD0); break; > case 2: PORTD |= (1<<PD0); break; > > klappt es, und ich kann es absolout nachvollziehen. Was kannst Du DA nachvollziehen? Das PIND0 immer 1 ist? Egal, welchen Wert X hat? Quatsch ... :-) Versuche "Bitmanipulation" zu verstehen ...
Huber M. schrieb: > while(1) > { > uint8_t n = tasterpins; > > switch (n) > { > case (1<<PC5) : > > PORTD |= (1<<PD0); // soll led an PD0 > einschalten > > break; > } > > } > } Dein switch-ase bearbeitet den Fall, das PC5 auf high ist. Und das ist er dank Pullup immer, wenn der Taster nicht gedrückt ist. Entweder schreibst du die Case Bedingung um oder das Switch Argument
1 | uint8_t n = ~(PINC); // oder eben das richtige Pinregister deiner Taster invertiert einlesen |
2 | switch (n) { |
3 | |
4 | case (1 << PC5) : PORTD |= (1 << PD0); break; // LED ein bei Taste PC5 |
5 | case (1 << PC4) : PORTD &= ~(1 << PD0); break; // LED aus bei Taste PC4 |
6 | }
|
:
Bearbeitet durch User
Matthias S. schrieb: > Dein switch-ase bearbeitet den Fall, das PC5 auf high ist. Und das ist > er dank Pullup immer, wenn der Taster nicht gedrückt ist. > Entweder schreibst du die Case Bedingung um oder das Switch Argument Ok,das leuchtet ein, das heisst, wenn ich Taster an PC5 drücke sollte PD0 angehen oder ?
1 | /*
|
2 | * GccApplication2.c
|
3 | *
|
4 | * Created: 09.10.2016 14:48:27
|
5 | * Author: HUBER M
|
6 | */
|
7 | |
8 | |
9 | #include <avr/io.h> |
10 | |
11 | #define tasterpins (1<<PC5)
|
12 | |
13 | int main(void) |
14 | {
|
15 | PORTC |= (1<<PC5); //Pullup Eingang |
16 | DDRD |= (1<<PD0); //Ausgang LED |
17 | |
18 | void tastertest() |
19 | {
|
20 | if (!(PINC &(1<<PC5))) |
21 | {
|
22 | PORTD |= (1<<PD0); |
23 | }
|
24 | else
|
25 | {
|
26 | PORTD &= ~(1<<PD0); |
27 | }
|
28 | }
|
29 | while(1) |
30 | {
|
31 | |
32 | |
33 | uint8_t n = ~(PINC); // oder eben das richtige Pinregister deiner Taster invertiert einlesen |
34 | switch (n) |
35 | {
|
36 | |
37 | case (1 << PC5) : PORTD |= (1 << PD0); break; // LED ein bei Taste PC5 |
38 | case (1 << PC4) : PORTD &= ~(1 << PD0); break; // LED aus bei Taste PC4 |
39 | }
|
40 | |
41 | |
42 | }
|
43 | }
|
weshalb leuchtet hier PD0 nicht? wenn ich meine tastertest Funktion in die while schleife schreibe. Und die Taste drücke dann leuchtet PD0. Also an der Verkabelung kann es schon mal nicht liegen
1 | while(1) |
2 | {
|
3 | |
4 | tastertest(); |
5 | // uint8_t n = ~(PINC); // oder eben das richtige Pinregister deiner Taster invertiert einlesen
|
6 | //switch (n)
|
7 | // {
|
8 | |
9 | // case (1 << PC5) : PORTD |= (1 << PD0); break; // LED ein bei Taste PC5
|
10 | // case (1 << PC4) : PORTD &= ~(1 << PD0); break; // LED aus bei Taste PC4
|
11 | // }
|
12 | |
13 | |
14 | }
|
:
Bearbeitet durch User
Ich kann leider nicht alles zitieren - aber: Scharf - "Der goldene Troll 2016" ist Dir sicher :-)
Uups, dir muss man ja alles vorkauen, aber gut. Du solltest die Buttons natürlich ausmaskieren, und nicht den gesamten Ausdruck verwenden, der aus dem Pinregister kommt. Am übersichtlichsten wird das mit defines:
1 | // Ausgangsport
|
2 | #define LED1 PD0
|
3 | #define LEDPORT PORTD
|
4 | #define LEDDIR DDRD
|
5 | // Eingangsport
|
6 | #define BUTTONPINS PINC
|
7 | #define BUTTONDIR
|
8 | #define BUTTONPORT PORTC
|
9 | |
10 | #define BUTTON1 PC5
|
11 | #define BUTTON2 PC4
|
12 | |
13 | #define BUTTONMASK (1 << BUTTON1) | (1 << BUTTON2)
|
14 | |
15 | void init_ports(void) { |
16 | BUTTONDIR = ~(BUTTONMASK); // nicht wirklich nötig nach Reset |
17 | BUTTONPORT = BUTTONMASK; // init pullups |
18 | LEDDIR = (1 << LED1); // LED Ausgang |
19 | }
|
20 | |
21 | // aus dieser Routine wird ein gegen GND gedrückter Taster als high retourniert
|
22 | // aber pins die nicht in der BUTTONMASK sind, ignoriert
|
23 | uint8_t keyin(void) { |
24 | return (~(BUTTONPINS) & BUTTONMASK); |
25 | }
|
26 | // das hauptprogramm
|
27 | int main (void { |
28 | init_ports(); |
29 | // Hauptschleife
|
30 | while (1) { |
31 | switch (keyin()) { |
32 | case (1 << BUTTON1) : LEDPORT |= (1 << LED1); break; // Ausgang high |
33 | case (1 << BUTTON2) : LEDPORT &= ~(1 << LED1); break; // Ausgang low |
34 | }
|
35 | } // ende while |
36 | } // ende main |
Natürlich führen viele Wege nach Rom. Die defines erleichtern aber Erweiterung und etwaige Umbelegungen.
Morgen, ich weiß schon, ich bin schlimm, war wohl schon wieder zu lange davor gesessen. Hatte eine totale Hirnblockade, aber trotzdem Danke für deine Mühe.
so, jetzt habe ich nochmal ein Problem. Und zwar würde ich gerne einen Fall bearbeiten , wenn ein taster nicht gedrückt ist, mach irgend was. Jetzt, wenn ich bei PA0 eine 0 reinschreibe funktioniert das auch wunder bar, bei PA0. Bei PA1 das selbe und er meckert beim compilieren :::duplicate case value::: ich habe natürlich auch schon probiert ~(1<<PA0)invertiert das in der klammer doch ? &= ~(1<<PA0) löscht das bit. (PINA&(1<<PA0)) wenn bit high (!(PINA&(1<<PA0))) wenn bit low oder muss ich hier extra nochmal definieren?
1 | switch (n) { |
2 | case (1 << PA0) : PORTA |= (1<<PA3); break; // PA0 gedrückt |
3 | case (0 << PA0) : PORTA &= ~(1<<PA3); break; // PA0 nicht gedrückt |
4 | |
5 | case (1 << PA2) : PORTB |= (1<<PB1); break; // |
6 | case (0 << PA2) : PORTB &= ~(1<<PB1); break; // |
:
Bearbeitet durch User
Huber M. schrieb: > Bei PA1 das selbe und er meckert beim compilieren > :::duplicate case value::: Und da hat er recht. Du hast den Sinn von switch/case immer noch nicht verstanden. Wie schon gesagt: Beitrag "Re: bitte um hilfe bei switch case aufbau"
:
Bearbeitet durch User
ja, aber ich hatte es ja schon mal hinbekommen vor ein paar wochen, habs mir aber wieder gelöscht :-(, und vergessen wie ich es gemacht habe. Und ich stelle mir das so vor, wenn ich mir ein paar Taster anschließe, die dann in der Praxis drücke und danach drauf komme, den fall hatte ich hier nicht mit berechnent, dann schreib ich mir einfach einen neuen fall dazu, so in etwa.Und ich bin wieder glücklich.
Peter D. schrieb: > Du hast den Sinn von switch/case immer noch nicht verstanden. das "Nicht verstehen" fängt doch schon ganz unten an, bei Bitmanipulation und Pinabfrage, und hat mit switch/case (noch) nix zu tun @TE: leg den µC beiseite und lern erstmal die C Grundlagen 'normal' am PC, ohne Hardwarebezug, bevor du dich dann an µCs wagst...
habe seit vorletzter Woche das buch C programmiern von anfang an. Darin übe ich mich mit Codeblocks. Und Avr microcontroller in c Programmieren schon etwas länger. Das einzige das ich momentan damit nicht zu hundert prozent durcharbeiten kann, ist zb. taster beim debuggen im I/O view beobachten. da mir zu anfang der mk2 isp programmer empfohlen worden ist. und der keine debugg Funktion hat. Und deshalb tu ich mich da so schwer das zu verstehen. Brauche erstmal dennächst den avr dragon o.ä. dann muss ich auch nicht mehr soviel fragen.
Der Debugger kann Dir auch nichts anderes dazu sagen: 1 Taster = 1 IO-Pin = 1 Bit. Da noch Nachbarpins hinein zu verwursten, muß in die Hose gehen und geht auch in die Hose, wie Du ja gemerkt hast. Schau Dir einfach mal an, wie andere ihre Tasten auswerten.
Ein Dragon ändert weder was dan den Compilerfehlermeldungen, die dein Code versursacht, noch an deinem fehlenden grundlegenden Verständnis der Sprache C. Da wirst du erst mal die Grundlagen lernen müssen. Danach ist der natürlich eine gute Hilfe. Oliver
Oliver S. schrieb: > Ein Dragon ändert weder was dan den Compilerfehlermeldungen, die dein > Code versursacht das ist mir schon klar, dann wäre ich aber gleich viel eher drauf gekommen. Peter D. schrieb: > Schau Dir einfach mal an, wie andere ihre Tasten auswerten. warscheinlich mit if..else if.... ich habe auch kein grösseres Problem mir ne state maschine zu bauen, wie beispielsweise bei ner Ampel. Ich dachte ich habe mal gelesen das die case verzweigung eine elegantere Lösung für die if abfrage ist. Da habe ich wohl irgendwas falsch verstanden ps.: ich glaube bei ner rollo taster schaltung wurde die case mal zu mir gesagt. weil man da jeden Fall abdecken kann.
:
Bearbeitet durch User
Huber M. schrieb: > warscheinlich mit if..else if.... Eher ohne "else". Es sei denn, Du willst explizit verbieten, daß mehrere Tasten betätigt werden dürfen. Auch fragt man Tasten nie im Code direkt ab, sondern nur die Ereignisse, die eine Entprellroutine liefert.
Ein switch wie folgendes:
1 | switch(x){ |
2 | case 1: |
3 | case 2: |
4 | do_something1(); |
5 | break; |
6 | case 3: |
7 | case 4: |
8 | do_something2(); |
9 | break; |
10 | default:
|
11 | do_something(); |
12 | }
|
Kann man mit if's so schreiben:
1 | if( x == 1 || x == 2 ){ |
2 | do_something1(); |
3 | }else if( x == 3 || x == 4 ){ |
4 | do_something2(); |
5 | }else{ |
6 | do_something(); |
7 | }
|
Switch überprüft immer, ob ein Wert gleich einer Konstante ist. Du hast aber folgende situation:
1 | if( x & (1<<0) ){ // ist bit 1 gesetzt? |
2 | }
|
3 | if( x & ( (1<<1) | (1<<2) ) ){ // ist bit 2 oder bit 3 gesetzt? |
4 | }
|
Das kann man nicht mit switch case abbilden, denn es ist kein Vergleich ob ein Wert gleich einem anderen ist, sonderneine Verundung, bei der die Werte in der Bitmaske übrig bleiben, und auf nicht gleich 0 getestet werden. Das ist kein Vergleich zwischen x und der Bitmaske/konstante, ergo nicht mit switch case abbildbar. (ausser man macht 128 cases pro prüfung bei 8 bit)
:
Bearbeitet durch User
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.