Taster auf "1" abfragen in AVR-C

OP #5024158
Lesenswert?

Hallo Forumsmenschen,

ich brauche mal wieder Hilfe und zwar habe ich ein einfaches Programm 
gemacht, bei dem ich per Tasterdruck die Leds nacheinander einschalte..

Leider funktioniert es nicht so wie erhofft.

Aus einem Buch habe ich die Tasterabfrage übernommen die so aussieht.

if (!(PINB & (0x01)))

ich habe es bei mir mit while gemacht.

Leider gehen die Leds aber sofort an(ohne dass ich den Taster drücke), 
erst wenn ich das "!" rausnehme geht es wie gewünscht.

Aber das "!" muss doch drin sein, wegen dem Pullup.

Was mache ich falsch?
1
#define F_CPU 3686400
2
#include <avr/io.h>
3
#include <util/delay.h>
4

5

6

7

8

9
int main()
10
{
11

12
DDRB=0x00;      //PortB Eingänge
13
DDRC=0xFF;      //PortC Ausgänge
14
PORTB=0xFF;     //Pullup 
15

16

17
do  
18
{
19
PORTC = 0;
20
}
21

22
while(!(PINB & (0x01)));    //wenn TasterEin gedrückt
23
{
24
PORTC = 0x01;
25
_delay_ms(500);      
26
PORTC = 0x02;
27
_delay_ms(500);  
28
PORTC = 0x04;
29
_delay_ms(500);  
30
}
31
return 0;
32
}
#5024237
Lesenswert?

Vermutlich hast du vorher nur mit Arduino gearbeitet. Dort gibt es eine 
"setup"-Funktion welche nur einmal beim starten aufgerufen wird und eine 
"loop"-Funktion welche danach immer wieder aufgerufen wird.

Nun arbeitest du aber mit der Main-Funktion als wäre sie die loop 
funktion. Die while-Schleife wird jedoch nur dann durchlaufen wenn der 
Taster beim Reset des Controllers gedrückt war. Und da das vermutlich 
nie bei dir der Fall ist wird die main-Funktion direkt mit "return 0" 
"verlassen" und der Controller macht quasi ein Reset und fängt in der 
Main wieder von vorne an, inkl. der Initialisierung.
Was du aber willst ist eher sowas:
1
main(){
2
  DDRB=0x00;      //PortB Eingänge
3
  DDRC=0xFF;      //PortC Ausgänge
4
  PORTB=0xFF;     //Pullup 
5

6
  PORTC = 0;
7

8
  while(1){
9

10
    if (!(PINB & (0x01))){
11
     //mach was
12
    }
13

14
  }
15

16

17
}
Gast #5024241
Lesenswert?

Moin,

O. A. schrieb:
> while(!(PINB & (0x01)));


Gehe die Schleifenbedingung noch einmal genau durch und veranschauliche 
dir dabei, welcher Zustand bei gedrücktem und nicht-gedrücktem Taster 
anliegt.


Das Beispiel in deinem Buch fragt den Taster ab, ob er gedrückt ist
 -> wenn(Taster gedrückt): mache sonstwas

Du möchtest in deiner while-Schleife aber warten, solange der Taster 
nicht gedrückt ist
 -> solange(Taster nicht gedrückt): mache nichts.

Dadurch wird dann auch deine Bedingung negiert.


Noch ein paar Anmerkungen:
- Du solltest dir von vornherein einen "sauberen" Programmierstil 
angewöhnen, was schon beim Einrücken der Zeilen beginnt
- Deine kopfgesteuerte "do-Schleife" ist überflüssig
- Die geschweiften Klammern nach der while-Schleife sind überflüssig
- Du solltest dich demnächst mit dem Thema "Taster-Entprellung" 
auseinandersetzen
- Da du scheinbar auf einem (AVR-) µC programmierst, beachte, dass ein 
Mikrocontroller niemals "ins leere" laufen sollte. Nachdem deine 
while-Schleife verlassen und PORTC mit den _delay's gesetzt wurde, 
sollte das Programm von vorne beginnen (Endlosschleife)

1
#define F_CPU 3686400
2
#include <avr/io.h>
3
#include <util/delay.h>
4

5

6
int main(){
7

8
   DDRB = 0x00;      //PortB Eingänge
9
   DDRC = 0xFF;      //PortC Ausgänge
10
   PORTB = 0xFF;     //Pullup 
11
   PORTC = 0;
12

13
   while(1){                   // oder: for(;;){
14

15
      while(PINB & (0x01));    //*solange* TasterEin *NICHT* gedrückt
16

17
      PORTC = 0x01;
18
      _delay_ms(500);      
19
      PORTC = 0x02;
20
      _delay_ms(500);  
21
      PORTC = 0x04;
22
      _delay_ms(500);  
23
   }
24
   return 0;
25
}
Gast #5024263
Lesenswert?

> Deine kopfgesteuerte "do-Schleife" ist überflüssig
> Die geschweiften Klammern nach der while-Schleife

Ich wette, der TO wollte da zwei Schleifen programmieren. Ihm ist wohl 
gar nicht bewusst, dass der Block hinter while gar nicht Bestandteil der 
Schleife ist.
Gast #5024302
Lesenswert?

Stefan U. schrieb:
> Ich wette, der TO wollte da zwei Schleifen programmieren. Ihm ist wohl
> gar nicht bewusst, dass der Block hinter while gar nicht Bestandteil der
> Schleife ist.

Ich dachte ...der Port soll ausgeschaltet werden ...
Durch do
Und solange die Bedingung im while erfüllt ist
Wird das lauflicht ausgeführt
Das hat auch geklappt..aber nur einmal ..
Also sobald der Taster gedrückt war ging alle Lampen einmal an und dann 
leuchtete nur noch die lerzte...
#5024318
Lesenswert?

O.a schrieb:
> Das hat auch geklappt..aber nur einmal ..
> Also sobald der Taster gedrückt war ging alle Lampen einmal an und dann
> leuchtete nur noch die lerzte...

das ist ja kein Wunder

O. A. schrieb:
> while(!(PINB & (0x01)));    //wenn TasterEin gedrückt
> {
> PORTC = 0x01;
hier dritte LED aus und
erste  LED an

> _delay_ms(500);
> PORTC = 0x02;
hier erste LED aus und
zweite LED an

> _delay_ms(500);
> PORTC = 0x04;
> _delay_ms(500);
hier erste & zweite LED aus und
dritte LED an

und so bleibt es doch, was sollte sich ändern?
Gast #5024340
Lesenswert?

Du hast nicht verstanden, wie man Schleifen mit do und while 
programmiert.

Die einzige Schleife in deinem Programm ist dies:
1
do  
2
{
3
    PORTC = 0;
4
}
5
while(!(PINB & (0x01)));

Hier wird der ganze Port C auf Low geschaltet. Und wenn danach PB1=Low 
ist, dann wird das solange wiederholt, bis PB1 nicht mehr Low ist.

Danach (also wenn PB1 nicht mehr Low ist) wir der nächste Block 
ausgeführt:
1
{
2
    PORTC = 0x01;
3
    _delay_ms(500);      
4
    PORTC = 0x02;
5
    _delay_ms(500);  
6
    PORTC = 0x04;
7
    _delay_ms(500);  
8
}
9
return 0;

Das ist der Teil, wo die Klammern nichts Sinnvolles bewirken. Also 
nachdem der Taster losgelassen wird, gehen deine drei LED's nacheinander 
an. Zum Schluss bleibt PC2 an und das Programm ende mit return 0.

Prinzipiell dürfen Mikrocontroller Programme niemals enden, denn dies 
würde Frage aufwerfen, was er denn danach machen soll. Beim AVR fügt der 
Compiler automatisch eine leere Endlosschleife am Ende des Programmes 
sein, damit es bei solchen Fehlern wenigstens nicht abstürzt.

In deinem Fall scheint es sinnvoll, dass das Programm sich nach dem LED 
geblinke wiederholt, so dass es auf den nächsten Tastendruck wartet. 
Also brauchst du zwei verschachtelte Schleifen. VIA hat es schon korrekt 
geschrieben:
1
int main()
2
{
3
   initialisierung;
4

5
   while (1)  // Wiederhole endlos oft
6
   {
7

8
      while (taste nicht gedrückt)
9
      {
10
         ; // tu nichts, leere Warteschleife
11
      }
12

13
      lasse die LED's blinken
14

15
   }
16
}

Gewöhne Dir ganz schnell an, den Code richtig einzurücken und Leerzeilen 
sinngemäß zu setzen. Dann ist der fehler nämlich offensichtich.

Hier nochmal dein ganzes fehlerhaftes Programm, jedoch mit korrekter 
Formatierung:
1
#define F_CPU 3686400
2
#include <avr/io.h>
3
#include <util/delay.h>
4

5
int main()
6
{
7

8
    DDRB=0x00;      //PortB Eingänge
9
    DDRC=0xFF;      //PortC Ausgänge
10
    PORTB=0xFF;     //Pullup 
11

12
    do  
13
    {
14
        PORTC = 0;
15
    }
16
    while(!(PINB & (0x01)));    // Wiederhole, solange TasterEin gedrückt
17

18
    // Wenn Taster nicht mehr gedrückt:
19
    {
20
        PORTC = 0x01;
21
        _delay_ms(500);      
22
        PORTC = 0x02;
23
        _delay_ms(500);  
24
        PORTC = 0x04;
25
        _delay_ms(500);  
26
    }
27

28
    return 0;
29
}

Ist der Fehler jetzt klar?
OP #5026274
Lesenswert?

VIA schrieb:

>
>
1
> #define F_CPU 3686400
2
> #include <avr/io.h>
3
> #include <util/delay.h>
4
> 
5
> 
6
> int main(){
7
> 
8
>    DDRB = 0x00;      //PortB Eingänge
9
>    DDRC = 0xFF;      //PortC Ausgänge
10
>    PORTB = 0xFF;     //Pullup
11
>    PORTC = 0;
12
> 
13
>    while(1){                   // oder: for(;;){
14
> 
15
>       while(PINB & (0x01));    //*solange* TasterEin *NICHT* gedrückt
16
> 
17
>       PORTC = 0x01;
18
>       _delay_ms(500);
19
>       PORTC = 0x02;
20
>       _delay_ms(500);
21
>       PORTC = 0x04;
22
>       _delay_ms(500);
23
>    }
24
>    return 0;
25
> }
26
>

Hey Via,

wenn ich den Taster loslasse, dann leuchtet die letzte Led 
(0x04)..warum?
Es müsste doch alles ausgehen wegen PORTC = 0;
Gast #5026309
Lesenswert?

> wenn ich den Taster loslasse, dann leuchtet die letzte Led
> (0x04)..warum?

Weil der vorletzte Befehl in deiner While Schleife sie eingeschaltet hat 
und da ist niemad, der sie danach wieder aus schaltet.

Du schaltest die LED's nur ein einziges mal während der 
Initialisierungs-Sequenz aus.

Wann genau möchtest du denn, dass die LED's alle aus gehen?
#5026334
Lesenswert?

O. A. schrieb:
> Es müsste doch alles ausgehen wegen PORTC = 0;

da kommt er doch nach dem Init NIE WIEDER hin, wegen

Endlosschleife nach dem power on:
O. A. schrieb:
>>    while(1){                   // oder: for(;;){
>>
>>       while(PINB & (0x01));    //*solange* TasterEin NICHT gedrückt
>>
>>       PORTC = 0x01;
>>       _delay_ms(500);
>>       PORTC = 0x02;
>>       _delay_ms(500);
>>       PORTC = 0x04;
>>       _delay_ms(500);
>>    }


es gilt weiterhin
Beitrag "Re: Taster auf "1" abfragen in AVR-C"
Gast #5026418
Lesenswert?

O. A. schrieb:
> ..warum?

Joachim B. hat es schon erklärt:

Die Zeile
1
    PORTC = 0;

wird in diesem Fall genau ein einziges Mal ausgeführt.
Und zwar nach dem POR (Power-On-Reset) und danach nie wieder,
bis der µC neu gestartet wird (Reset).

Nachdem er dies ein Mal gemacht hat, wird er in der ersten 
"while-Schleife" gefangen,
da die Schleifenbedingung niemals FALSE sein wird (Endlosschleife):
1
    while(1){                   // oder: for(;;){


Wenn die LED nach dem Loslassen des Tasters ausgehen soll,
musst du ihm das auch so beibringen:
1
#define F_CPU 3686400
2
#include <avr/io.h>
3
#include <util/delay.h>
4

5

6
int main(){
7

8
   DDRB = 0x00;      //PortB Eingänge
9
   DDRC = 0xFF;      //PortC Ausgänge
10
   PORTB = 0xFF;     //Pullup 
11
   PORTC = 0;
12

13
   while(1){                      // oder: for(;;){
14

15
      while(PINB & (0x01));       //*solange* TasterEin *NICHT* gedrückt
16

17
      PORTC = 0x01;
18
      _delay_ms(500);      
19
      PORTC = 0x02;
20
      _delay_ms(500);  
21
      PORTC = 0x04;
22
//      _delay_ms(500);           // ueberflüssig
23

24
      while(!(PINB & (0x01)));    //*solange* TasterEin *gedrückt*
25
      PORTC = 0x00;               // alle Lampen aus
26
  
27
   }
28
   return 0;
29
}
Gast #5026427
Lesenswert?

Sorry, nochmal Korrektur:

am besten du schreibst das letzte _delay nach dem Warten auf den Taster.
Damit blendest du das Prellen des Tasters zumindest provisorisch erst 
einmal aus.

Also:

1
#define F_CPU 3686400
2
#include <avr/io.h>
3
#include <util/delay.h>
4

5

6
int main(){
7

8
   DDRB = 0x00;      //PortB Eingänge
9
   DDRC = 0xFF;      //PortC Ausgänge
10
   PORTB = 0xFF;     //Pullup 
11
   PORTC = 0;
12

13
   while(1){                      // oder: for(;;){
14

15
      while(PINB & (0x01));       //*solange* TasterEin *NICHT* gedrückt
16

17
      PORTC = 0x01;
18
      _delay_ms(500);      
19
      PORTC = 0x02;
20
      _delay_ms(500);  
21
      PORTC = 0x04;
22

23
      while(!(PINB & (0x01)));    //*solange* TasterEin *gedrückt*
24
      _delay_ms(500);
25
      PORTC = 0x00;               // alle Lampen aus
26
  
27
   }
28
   return 0;
29
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren