Forum: Mikrocontroller und Digitale Elektronik mit Tastern auswählen (ATMEGA8)


von Huber (Gast)


Lesenswert?

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.

von Rahul (Gast)


Lesenswert?

Vielleicht noch das Problem der prellenden Tasten?
Und "goto" ist ganz böse...

von johnny.m (Gast)


Lesenswert?

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...

von Huber (Gast)


Lesenswert?

was soll ich denn anstelle von goto benutzen?

von johnny.m (Gast)


Lesenswert?

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!

von Huber (Gast)


Lesenswert?

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

von johnny.m (Gast)


Lesenswert?

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.

von johnny.m (Gast)


Lesenswert?

...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

von Huber (Gast)


Lesenswert?

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.

von Thomas O. (Gast)


Lesenswert?

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

von Manos (Gast)


Lesenswert?

Also statt 0x02 (oder 0b00000010) ein 0xFD (oder 0b11111101)...

von johnny.m (Gast)


Lesenswert?

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.

von Huber (Gast)


Lesenswert?

das mit PORT B ist oben ein Tippfehler. Soll PORT C heißen.

von peter dannegger (Gast)


Lesenswert?

"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

von johnny.m (Gast)


Lesenswert?

@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

von Karl H. (kbuchegg)


Lesenswert?

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.

von peter dannegger (Gast)


Lesenswert?

@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

von Huber (Gast)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

@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.

von peter dannegger (Gast)


Lesenswert?

"was meinst du genau mit undieren?"

Das, was mein erster Beitrag macht.


Peter

von Karl H. (kbuchegg)


Lesenswert?

@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

von Jörn-H. G. (joern_g)


Lesenswert?

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

von Marco S. (masterof)


Lesenswert?

abo

von Rahul (Gast)


Lesenswert?

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?

von Hannes L. (hannes)


Lesenswert?

Vergesst die Entprellung nicht...

...

von Huber (Gast)


Lesenswert?

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.

von Huber (Gast)


Lesenswert?

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"

von Hannes L. (hannes)


Lesenswert?

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...

...

von Rahul (Gast)


Lesenswert?

@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...])

von Hannes L. (hannes)


Lesenswert?

Schtümpth... - Das Runde muss in das Eckige... - Oder so...

...

von Thomas O. (Gast)


Lesenswert?

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.

von Hannes L. (hannes)


Lesenswert?

> 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
Noch kein Account? Hier anmelden.