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


von Peter (Gast)


Lesenswert?

Hallo!


Hier der Coder der Probleme macht (Debugger von AVR Studio 4.18SP2):
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
5
#ifndef F_CPU
6
#define F_CPU 4000000UL
7
#endif
8
9
volatile short status = 0;
10
11
ISR(TIMER0_OVF_vect)
12
{
13
  status = 0;
14
  //PORTB |= (1 << PB2);
15
}
16
17
int main (void)
18
{
19
  DDRB = (1 << PB0) | (1 << PB1) | (1 << PB2);
20
  //PORTB |= (1 << PB2);  // Q1
21
  sei();
22
23
  // Q2: better usse interrupt?
24
  while(1)
25
  {
26
    while((PINB && (1 << PB3)) || (PINB && (1 << PB4)))
27
    {
28
      if(PINB && (1 << PB3))
29
      {
30
        if(status == 0)
31
        {
32
          status = 1;
33
          //PORTB |= (0 << PB2);
34
          PORTB = PINB ^ (1 << PB0);
35
          _delay_ms(2);
36
          PORTB = PINB ^ (1 << PB0);
37
        }
38
        else
39
        {
40
          status = 0;
41
          //PORTB |= (1 << PB2);
42
          PORTB = PINB ^ (1 << PB1);
43
          _delay_ms(2);
44
          PORTB = PINB ^ (1 << PB1);
45
        }
46
      }
47
      else    // Q3: never reached
48
      {
49
        status = 0;
50
        //PORTB |= (1 << PB2);
51
      }
52
    }
53
  }
54
55
  cil();
56
  return 0;
57
}

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

von Peter (Gast)


Lesenswert?

> PORTB |= (0 << PB2);

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

von Karl H. (kbuchegg)


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

von Mike R. (thesealion)


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

von Peter (Gast)


Lesenswert?

Danke!!! Jetzt macht das Programm was es soll!
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
5
#ifndef F_CPU
6
#define F_CPU 4000000UL
7
#endif
8
9
volatile short status = 0;
10
11
ISR(TIMER0_OVF_vect)
12
{
13
  status = 0;
14
  PORTB |= (1 << PB2);
15
}
16
17
int main (void)
18
{
19
  DDRB = (1 << PB0) | (1 << PB1) | (1 << PB2);
20
  PORTB |= (1 << PB2);
21
  sei();
22
23
  while(1)
24
  {
25
    while((PINB & (1 << PB3)) || (PINB & (1 << PB4)))
26
    {
27
      if(PINB & (1 << PB3))
28
      {
29
        if(status == 0)
30
        {
31
          status = 1;
32
          PORTB &= ~(1 << PB2);
33
          PORTB |= (1 << PB0);
34
          _delay_ms(2);
35
          PORTB &= ~(1 << PB0);
36
        }
37
        else
38
        {
39
          status = 0;
40
          PORTB |= (1 << PB2);
41
          PORTB |= (1 << PB1);
42
          _delay_ms(2);
43
          PORTB &= ~(1 << PB1);
44
        }
45
      }
46
      else
47
      {
48
        status = 0;
49
        PORTB |= (1 << PB2);
50
      }
51
    }
52
  }
53
54
  cil();
55
  return 0;
56
}

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

von Karl H. (kbuchegg)


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.

von Silvan K. (silvan) Benutzerseite


Lesenswert?

1
cil();

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

von Karl H. (kbuchegg)


Lesenswert?

Silvan König schrieb:
>
1
> cil();
2
>
>
> 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.

von Silvan K. (silvan) Benutzerseite


Lesenswert?

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

Bitte Lesebrille aufsetzen. ;-)

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

von Peter D. (peda)


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

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.