mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVRTiny13: Code verhält sich sonderbar


Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!


Hier der Coder der Probleme macht (Debugger von AVR Studio 4.18SP2):
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#ifndef F_CPU
#define F_CPU 4000000UL
#endif

volatile short status = 0;

ISR(TIMER0_OVF_vect)
{
  status = 0;
  //PORTB |= (1 << PB2);
}

int main (void)
{
  DDRB = (1 << PB0) | (1 << PB1) | (1 << PB2);
  //PORTB |= (1 << PB2);  // Q1
  sei();

  // Q2: better usse interrupt?
  while(1)
  {
    while((PINB && (1 << PB3)) || (PINB && (1 << PB4)))
    {
      if(PINB && (1 << PB3))
      {
        if(status == 0)
        {
          status = 1;
          //PORTB |= (0 << PB2);
          PORTB = PINB ^ (1 << PB0);
          _delay_ms(2);
          PORTB = PINB ^ (1 << PB0);
        }
        else
        {
          status = 0;
          //PORTB |= (1 << PB2);
          PORTB = PINB ^ (1 << PB1);
          _delay_ms(2);
          PORTB = PINB ^ (1 << PB1);
        }
      }
      else    // Q3: never reached
      {
        status = 0;
        //PORTB |= (1 << PB2);
      }
    }
  }

  cil();
  return 0;
}

Frage 1: Mehrere Stellen (z.B. Stelle mit Q1) im Code mit "PORTB |= ..." 
sind auskommentiert. Das Programm macht mit diesen Kommentaren fast 
(vgl. Frage 3) was es soll. Sobald ich diese Kommentare entferne um mir 
den Wert von status auf PB2 anzeigen zu lassen wird das so itnerpretiert 
als ob PB3 die ganze Zeit high wäre.
a) Wieso kommt es zu diesem sonderbaren Verhalten?
b) Kann ich die Variable status nicht irgendwie ganz in PB2 auslagern 
und wie kann ich dann PB2 abfragen?

Frage 2: Die Abfrage von PB3 und PB4 befinden sich in der main-Loop 
innerhalb einer while-Schleife (vgl. Stelle mit Q2). Wäre es besser die 
Abfrage dieser Taster mit Interrupts zu lösen?

Frage 3: An der Stelle Q3 sollte durch Drücken des Tasters an PB4 die 
Variable status zurückgesetzt werden, nur wird diese Stelle nie 
erreicht. Wenn PB4 high ist, verhält sich das Programm genauso wie wenn 
PB3 high ist. Warum ist das so und was mache ich da falsch?

Das ist mein erstes AVR-GCC-Projekt und vielleicht kann mir der eine 
oder andere hier helfen um klarer zu sehen.


Peter

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> PORTB |= (0 << PB2);

was erwartest du von der Anweisung? ein wert mit 0 verodern ändert wenig 
an einem wert?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:

> Frage 1: Mehrere Stellen (z.B. Stelle mit Q1) im Code mit "PORTB |= ..."
> sind auskommentiert. Das Programm macht mit diesen Kommentaren fast
> (vgl. Frage 3) was es soll. Sobald ich diese Kommentare entferne um mir
> den Wert von status auf PB2 anzeigen zu lassen wird das so itnerpretiert
> als ob PB3 die ganze Zeit high wäre.

Und?
Sollte der das nicht sein?

PB3 ist bei dir Eingang. Kein Mensch kann vorhersagen, welchen Wert der 
µC einlesen wird, wenn wir nicht wissen ob da was drann hängt und wenn 
ja was und wie.

dir ist schon klar, dass du hier

         PORTB = PINB ^ (1 << PB0);

den kompletten PORT änderst, inklusive
   eventueller Pullupwiderstände für die Eingangspins

Ausserdem: da PB0 ein Ausgang ist, macht es IMHO nicht wirklich Sinn, 
vom Pin Register das Bit PB0 zu toggeln um damit dann das Port Register 
umzustellen


Einen Ausgangspin auf 1 setzen

    PORTx |= ( 1 << Pin );

Einen Ausgansgpin auf 0 setzen

    PORTx &= ~( 1 << Pin );

Einen Ausgangspin zu toggeln

    PORTx ^= ( 1 << Pin );


Einen Eingangspin abfragen:

    if( PINx & ( 1 << Pin ) )

Autor: Mike R. (thesealion)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:
>     while((PINB && (1 << PB3)) || (PINB && (1 << PB4)))
>     {
>       if(PINB && (1 << PB3))

Ich denk diese beiden Abfragen machen auch nicht das, was du willst.
Die If Bedingung ist immer dann war, wenn ein Bit (egal welches) in PINB 
1 ist.

Wenn du einen einzelnen Pin (ein Bit) in einem Byte testen willst, 
brauchst du die Bitweise Verknüpfung & und nicht die logische &&

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke!!! Jetzt macht das Programm was es soll!
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#ifndef F_CPU
#define F_CPU 4000000UL
#endif

volatile short status = 0;

ISR(TIMER0_OVF_vect)
{
  status = 0;
  PORTB |= (1 << PB2);
}

int main (void)
{
  DDRB = (1 << PB0) | (1 << PB1) | (1 << PB2);
  PORTB |= (1 << PB2);
  sei();

  while(1)
  {
    while((PINB & (1 << PB3)) || (PINB & (1 << PB4)))
    {
      if(PINB & (1 << PB3))
      {
        if(status == 0)
        {
          status = 1;
          PORTB &= ~(1 << PB2);
          PORTB |= (1 << PB0);
          _delay_ms(2);
          PORTB &= ~(1 << PB0);
        }
        else
        {
          status = 0;
          PORTB |= (1 << PB2);
          PORTB |= (1 << PB1);
          _delay_ms(2);
          PORTB &= ~(1 << PB1);
        }
      }
      else
      {
        status = 0;
        PORTB |= (1 << PB2);
      }
    }
  }

  cil();
  return 0;
}

Frage 1b und Frage 2 aus dem Eingangspost sind immer noch aktuell. 
Momentan läuft das Programm nur im Debugger. hardware hängt da noch 
keine dran.


Peter

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:
> Danke!!! Jetzt macht das Programm was es soll!

Interessant.
Und dabei haben wir hier nur in aller Kürze wiedergegeben, was man auch 
in langer Breite im AVR-GCC-Tutorial wiederfindet.

> Frage 1b und Frage 2 aus dem Eingangspost sind immer noch aktuell.

> 1b) Kann ich die Variable status nicht irgendwie ganz in PB2
>     auslagern und wie kann ich dann PB2 abfragen?

Sicher kann man

    if( PORTB & ( 1 << PB2 ) )    // PB2 war gesetzt


> Frage 2: Die Abfrage von PB3 und PB4 befinden sich in der
> main-Loop innerhalb einer while-Schleife (vgl. Stelle mit Q2).
> Wäre es besser die Abfrage dieser Taster mit Interrupts zu lösen?

Nein.
Taster an einem Interrupt sind mit einer Ausnahme meistens eine 
schlechte Idee.
Die Ausnahme: Wenn der Taster den µC aus dem Tiefschlaf aufwecken muss. 
Das geht nur mit Interrupts.

Autor: Silvan König (silvan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
cil();

Die Funktion hab ich noch nie gesehen. Wo ist die denn definiert? ;-)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Silvan König schrieb:
>
> cil();
> 
>
> Die Funktion hab ich noch nie gesehen. Wo ist die denn definiert? ;-)

Höchst wahrscheinlich dort, wo auch sei() definiert ist. Isz 
schliesslich das Gegenteil davon.

Autor: Silvan König (silvan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Höchst wahrscheinlich dort, wo auch sei() definiert ist. Isz
> schliesslich das Gegenteil davon.

Bitte Lesebrille aufsetzen. ;-)

cil();  //unbekannt
cli();  //Interrupts ausschalten

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:
> volatile short status = 0;

16Bit-Variablen in Interrupts müssen im Main atomar zugegriffen werden, 
da die CPU dafür 2 Befehle braucht.

Dein Glück ist, daß hier eine 8Bit-Variable reichen würde.


Peter

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.