Forum: Mikrocontroller und Digitale Elektronik Variable für PIN-Input und Interrupt richtig definieren


von Basti (Gast)


Lesenswert?

Variable für PIN-Input und Interrupt richtig definieren

Ich programmiere einen Atmel-Controller in C mit AVRStudio 5.0 und 
möchte gerne vier Werte über Interrupteingänge einlesen, die mit 
Schaltern/Tastern bedient werden. Jeweils zwei Öffner und zwei 
Schließer.
Wenn sich an einem Pin ein Wert ändert (Pin-Change Interrupt) möchte ich 
aber alle vier Werte einlesen um daraus Aktionen abzuleiten.

Meine Vorgehensweise ist zur zeit folgende:
1
#define _S_aus        0x01  //PD0 / SCL/INT0    // Schalter "aus"
2
#define _T_ein        0x02  //PD1 / SDA/INT1    // Taster "ein"
3
#define _NA2          0x04  //PD2 / RXD1/INT2   // NOT-Aus 2
4
#define _NA1          0x08  //PD3 / TXD1/INT3   // NOT-Aus 1
5
6
7
/*globale Variablen */
8
9
volatile uint8_t _ein_aus = (_NA1|_NA2|_T_ein|_S_aus);
10
11
/* Interrupts */
12
13
ISR(INT0_vect)    // Interrupt Vector INT0 
14
{
15
  // keine Aktion erforderlich???
16
}
17
18
int main (void)
19
{
20
if ((_ein_aus <= 0xB) & (_ein_aus >= 4)
21
  {
22
    //Fehlerfall
23
    // Code hier
24
  }
25
  else
26
  {
27
    switch (_ein_aus)
28
    {
29
    case 0:
30
    case 1:
31
    case 2:
32
    case 3:
33
      //NOT-AUS FAll
34
    //Code hier
35
    break;
36
    case 0xD:
37
      // etwas ausschalten
38
    break;
39
    case 0xE:
40
      // etwas einschalten
41
    break;
42
    default:
43
      // nicht definiert, keine Aktion
44
    break;
45
      //       
46
    }
47
  }  
48
}

- In der Interrupt - Routine muss ich nichts hineinschreiben, da ich in 
der main nur meine Variablen auswerten möchte und meine Variable 
(_ein_aus) als volatile deklariert ist - richtig?
- Muss ich alle ISRs (INT1...INT3) definieren, wie INT0 oben?
- Ist die globale Variable für diesen Fall richtig definiert? als 
Volatile?
- Ist die globale Variable richtig verknüpft? (_NA1|_NA2|_T_ein|_S_aus) 
?

Natürlich werde ich noch die Interrupt-Register setzen, das fehlt hier 
im Code.

von Justus S. (jussa)


Lesenswert?

_ein_aus muss sich schon auch irgendwo ändern können...

von Basti (Gast)


Lesenswert?

passiert das nicht durch den Interrupt?

von Ralf (Gast)


Lesenswert?

interrupt = Unterbrechung
Der Programmablauf wird unterbrochen damit man was machen kann.

von Justus S. (jussa)


Lesenswert?

Basti schrieb:
> passiert das nicht durch den Interrupt?

wenn du in den Interrupt nichts reinschreibst dann natürlich nicht...im 
Moment ist deine Variable einfach immer nur 0b00001111...

von Basti (Gast)


Lesenswert?

Das ist mir klar.
Der Interrupt wird ausgelöst, wenn sich ein Signal am entsprechendem 
Eingang ändert (PIN-Change an INT0...INT3)
Die Variable _ein_aus wird automatisch angepasst (geändert) weil Sie ja 
als volatile deklariert wurde.

Soweit so theoretisch...

von Justus S. (jussa)


Lesenswert?

arbeite dich erstmal durch das Tutorial hier durch und komm dann 
zurück...

von tuxadi (Gast)


Lesenswert?

Basti schrieb:
> Die Variable _ein_aus wird automatisch angepasst (geändert) weil Sie ja
> als volatile deklariert wurde.

Von wem?

Denke mal darüber nach, wer oder was oder wie der Inhalt einer Variablen 
geändert wird.

Have fun
Adi

von Justus S. (jussa)


Lesenswert?

du fragst nirgendwo den Pinstatus auch nur einmal ab und sowas wie ein 
"dynamisches Linken" einer Variablen an Pins gibt es nicht...

von Ralf (Gast)


Lesenswert?

Basti schrieb:
> Die Variable _ein_aus wird automatisch angepasst (geändert) weil Sie ja
> als volatile deklariert wurde.
... und nachts ist es kälter als draußen.
(Will sagen: das eine hat mit dem anderen nichts zu tun!)

von Basti (Gast)


Lesenswert?

Man, ich depp!

Vermutlich muss in die Interrrupt Routine folgendes ergänzt werden:
1
Zustand = 0x0F & (PIND)

Und "Zustand" dann als globale volatile Variable definieren.
die defines brauche ich dann ja prinzipiell nicht mehr.

Also hier mal abgeändert:
1
#define _S_aus        0x01  //PD0 / SCL/INT0    // Schalter "aus"
2
#define _T_ein        0x02  //PD1 / SDA/INT1    // Taster "ein"
3
#define _NA2          0x04  //PD2 / RXD1/INT2   // NOT-Aus 2
4
#define _NA1          0x08  //PD3 / TXD1/INT3   // NOT-Aus 1
5
6
7
/*globale Variablen */
8
9
volatile uint8_t Zustand;
10
11
/* Interrupts */
12
13
ISR(INT0_vect)    // Interrupt Vector INT0 
14
{
15
  Zustand = 0x0F & (PIND);
16
}
17
18
int main (void)
19
{
20
if ((Zustand <= 0xB) & (Zustand >= 4)
21
  {
22
    //Fehlerfall
23
    // Code hier
24
  }
25
  else
26
  {
27
    switch (Zustand)
28
    {
29
    case 0:
30
    case 1:
31
    case 2:
32
    case 3:
33
      //NOT-AUS FAll
34
    //Code hier
35
    break;
36
    case 0xD:
37
      // etwas ausschalten
38
    break;
39
    case 0xE:
40
      // etwas einschalten
41
    break;
42
    default:
43
      // nicht definiert, keine Aktion
44
    break;
45
      //       
46
    }
47
  }  
48
}

von J.-u. G. (juwe)


Lesenswert?

Basti schrieb:
> ISR(INT0_vect)    // Interrupt Vector INT0

INT_vect0 ist der Interruptvektor für den externen Interrupt INT0.

Du benötigst aber den Vektor für den Pinchange-Interrupt von PIND.
Vermutlich:
1
ISR(PCINT3_vect)

Schau am besten nochmal ins Datenblatt Deines Controllers.

von J.-u. G. (juwe)


Lesenswert?

Weiterhin könnte es sinnvoll sein, dass Du Dich mit dem Thema 
Entprellung

http://www.mikrocontroller.net/articles/Entprellung

befasst.

von Basti (Gast)


Lesenswert?

J.-u. G. schrieb:
> INT_vect0 ist der Interruptvektor für den externen Interrupt INT0.
>
> Du benötigst aber den Vektor für den Pinchange-Interrupt von PIND.
> Vermutlich:ISR(PCINT3_vect)


INT_vect0 ist in der Tat der Interruptvector für den Externen Interupt 
INT0 der sich an PIN D0 befindet. In den Registern kann ich einstellen 
wann er ausgelöst wird.
Low Level  Pin change  falling edge  und rising edge.

von J.-u. G. (juwe)


Lesenswert?

Basti schrieb:
> INT_vect0 ist in der Tat der Interruptvector für den Externen Interupt
> INT0 der sich an PIN D0 befindet. In den Registern kann ich einstellen
> wann er ausgelöst wird.
> Low Level  Pin change  falling edge  und rising edge.

Dann wird aber beim Betätigen der Taster PD1, PD2 und PD3 kein Interrupt 
ausgelöst.

von Basti (Gast)


Lesenswert?

J.-u. G. schrieb:
> Basti schrieb:
>> INT_vect0 ist in der Tat der Interruptvector für den Externen Interupt
>> INT0 der sich an PIN D0 befindet. In den Registern kann ich einstellen
>> wann er ausgelöst wird.
>> Low Level  Pin change  falling edge  und rising edge.
>
> Dann wird aber beim Betätigen der Taster PD1, PD2 und PD3 kein Interrupt
> ausgelöst.

Ja klar, wird analog zu INT0 auch bei INT1, INT2 und INT3 gemacht, 
selber Inhalt wie bei INT0

von J.-u. G. (juwe)


Lesenswert?

Basti schrieb:
> Ja klar, wird analog zu INT0 auch bei INT1, INT2 und INT3 gemacht,
> selber Inhalt wie bei INT0

OK. Dann haben wir aneinander vorbeigeredet. Welchen Controller hast Du 
denn?

von Basti (Gast)


Lesenswert?

Ich benutze den AT90CAN64.

Die Register müsste ich dann so setzen:
1
EIMSK = 0x0F // aktiviert INT0...INT3
2
EICRA = 0xAF // NA1 / NA2   = Falling edge (1010 = A)
3
             // S_aus/T_ein = Rising edge  (1111 = F)

von Basti (Gast)


Lesenswert?

Was ist an dieser Konbination falsch?
1
[...]
2
#define A-Zustand 2;
3
#define B-Zustand 3;
4
[...]
5
uint16_t Shut_Down (uint8_t Auszustand)
6
{
7
  switch (Auszustand)
8
  {
9
    case 1: // normal
10
      return(60);
11
    case 2: // A-Zustand
12
      return(10);
13
    case 3: // B-Zustand
14
      return(1200);
15
    default: //alles Andere gibt es nicht
16
      return(0);
17
      break;
18
  } 
19
}
20
[...]
21
uint16_t = time_off = 0xFFFF;
22
[...]
23
time_off = Shut_Down(A-Zustand);
24
[...]

von Basti (Gast)


Lesenswert?

es kommt folgende Fehlermeldung:
1
expected ')' before ';' token

von ikorb (Gast)


Lesenswert?

Basti schrieb:
> es kommt folgende Fehlermeldung:

Und die Zeilennummer sollen wir erraten?

von J.-u. G. (juwe)


Lesenswert?

Basti schrieb:
> uint16_t = time_off = 0xFFFF;

Mach mal des erste Gleichheitszeichen weg.

von Basti (Gast)


Lesenswert?

Hallo, ich wollte eine kurze Rückmeldung geben, ich habs gefunden.

J.-u. G. schrieb:
>> uint16_t = time_off = 0xFFFF;
>
> Mach mal des erste Gleichheitszeichen weg.

Im Code ist es weg, war nur ein Schreibfehler hier im Forum.

Der fehler liegt am Semikolon hinter dem define! Das gehört dort 
natürlich nicht hin:
Falsch:
1
#define A-Zustand 2;

Richtig:
1
#define A-Zustand 2

Ich hatte nur im Code geschaut und nicht in den defines, daher ist es 
mir auch erst später aufgefallen.

von Karl H. (kbuchegg)


Lesenswert?

Und jetzt überlegst du noch wie dein Compiler wohl

int A;
int Zustand;
int c;

   c = A-Zustand;


von deinem

A-Zustand

auseinanderhalten soll.


Kauf dir doch ein C-Buch und arbeite das erst mal durch. So wie du dir 
das vorstellst, durch Raten, wirst du das nie lernen.

Und das man Taster nicht per Interrut auswertet hat auch einen guten 
Grund. Zum einen kann kein Mensch einen Taster schnell genug drücken und 
loslassen, ohne dass es durch Polling in der Hauptschleife nicht 
registriert werden würde, zum anderen prellen Taster.

von Basti (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Und das man Taster nicht per Interrut auswertet hat auch einen guten
> Grund. Zum einen kann kein Mensch einen Taster schnell genug drücken und
> loslassen, ohne dass es durch Polling in der Hauptschleife nicht
> registriert werden würde, zum anderen prellen Taster.

Also reicht es aus, wenn ich die Entprell-Routine von P.Danegger einbaue 
und in der Hauptschleife einmal den Status abfrage?
Dann entfällt die Sache mit Interrupt auf Flankenwechsel?

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.