mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Taster auf "1" abfragen in AVR-C


Autor: O. A. (sokrates1989)
Datum:

Bewertung
0 lesenswert
nicht 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?
#define F_CPU 3686400
#include <avr/io.h>
#include <util/delay.h>





int main()
{

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


do  
{
PORTC = 0;
}

while(!(PINB & (0x01)));    //wenn TasterEin gedrückt
{
PORTC = 0x01;
_delay_ms(500);      
PORTC = 0x02;
_delay_ms(500);  
PORTC = 0x04;
_delay_ms(500);  
}
return 0;
}


Autor: Timmo H. (masterfx)
Datum:

Bewertung
1 lesenswert
nicht 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:
main(){
  DDRB=0x00;      //PortB Eingänge
  DDRC=0xFF;      //PortC Ausgänge
  PORTB=0xFF;     //Pullup 

  PORTC = 0;

  while(1){

    if (!(PINB & (0x01))){
     //mach was
    }

  }


}

Autor: VIA (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

#define F_CPU 3686400
#include <avr/io.h>
#include <util/delay.h>


int main(){

   DDRB = 0x00;      //PortB Eingänge
   DDRC = 0xFF;      //PortC Ausgänge
   PORTB = 0xFF;     //Pullup 
   PORTC = 0;

   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);  
   }
   return 0;
}

Autor: O. A. (sokrates1989)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
DAnke ...!

: Bearbeitet durch User
Autor: Stefanus F. (stefanus)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Patrick J. (ho-bit-hun-ter)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Anders ausgedrückt:

Die geschweifte Klammer muß IN DER SELBEN ZEILE wie die Abfrage stehen, 
damit der Rest auch zur Abfrage gehört.

MfG

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Patrick J. schrieb:
> Die geschweifte Klammer muß IN DER SELBEN ZEILE wie die Abfrage stehen,
> damit der Rest auch zur Abfrage gehört.

Sieht vielleicht gut aus, ist aber Quatsch.

Autor: O.a (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Joachim B. (jar)
Datum:

Bewertung
0 lesenswert
nicht 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?

: Bearbeitet durch User
Autor: Stefanus F. (stefanus)
Datum:

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

Die einzige Schleife in deinem Programm ist dies:
do  
{
    PORTC = 0;
}
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:
{
    PORTC = 0x01;
    _delay_ms(500);      
    PORTC = 0x02;
    _delay_ms(500);  
    PORTC = 0x04;
    _delay_ms(500);  
}
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:
int main()
{
   initialisierung;

   while (1)  // Wiederhole endlos oft
   {

      while (taste nicht gedrückt)
      {
         ; // tu nichts, leere Warteschleife
      }

      lasse die LED's blinken

   }
}

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:
#define F_CPU 3686400
#include <avr/io.h>
#include <util/delay.h>

int main()
{

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

    do  
    {
        PORTC = 0;
    }
    while(!(PINB & (0x01)));    // Wiederhole, solange TasterEin gedrückt

    // Wenn Taster nicht mehr gedrückt:
    {
        PORTC = 0x01;
        _delay_ms(500);      
        PORTC = 0x02;
        _delay_ms(500);  
        PORTC = 0x04;
        _delay_ms(500);  
    }

    return 0;
}

Ist der Fehler jetzt klar?

: Bearbeitet durch User
Autor: O. A. (sokrates1989)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
VIA schrieb:

>
>
> #define F_CPU 3686400
> #include <avr/io.h>
> #include <util/delay.h>
> 
> 
> int main(){
> 
>    DDRB = 0x00;      //PortB Eingänge
>    DDRC = 0xFF;      //PortC Ausgänge
>    PORTB = 0xFF;     //Pullup
>    PORTC = 0;
> 
>    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);
>    }
>    return 0;
> }
> 

Hey Via,

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

Autor: Jonas B. (jibi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Hey Via,

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

Schaltet der Taster vielleicht gegen Masse?

Gruß

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Joachim B. (jar)
Datum:

Bewertung
0 lesenswert
nicht 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"

: Bearbeitet durch User
Autor: VIA (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
O. A. schrieb:
> ..warum?

Joachim B. hat es schon erklärt:

Die Zeile
    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):
    while(1){                   // oder: for(;;){


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


int main(){

   DDRB = 0x00;      //PortB Eingänge
   DDRC = 0xFF;      //PortC Ausgänge
   PORTB = 0xFF;     //Pullup 
   PORTC = 0;

   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);           // ueberflüssig

      while(!(PINB & (0x01)));    //*solange* TasterEin *gedrückt*
      PORTC = 0x00;               // alle Lampen aus
  
   }
   return 0;
}

Autor: VIA (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
VIA schrieb:
> //      _delay_ms(500);           // ueberflüssig


Das _delay ist nicht überflüssig, wenn du sicher stellen willst,
dass die letzte LED mindestens 500ms lang leuchtet.

Autor: VIA (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:

#define F_CPU 3686400
#include <avr/io.h>
#include <util/delay.h>


int main(){

   DDRB = 0x00;      //PortB Eingänge
   DDRC = 0xFF;      //PortC Ausgänge
   PORTB = 0xFF;     //Pullup 
   PORTC = 0;

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

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

      PORTC = 0x01;
      _delay_ms(500);      
      PORTC = 0x02;
      _delay_ms(500);  
      PORTC = 0x04;

      while(!(PINB & (0x01)));    //*solange* TasterEin *gedrückt*
      _delay_ms(500);
      PORTC = 0x00;               // alle Lampen aus
  
   }
   return 0;
}

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.