Forum: Mikrocontroller und Digitale Elektronik ATTiny84 - 4 Pin Change Interrupts


von Matthias (Gast)


Lesenswert?

Hallo,

versuche seit Tagen mit dem ATTiny84 und der Arduino IDE/Arduino ISP 3 
Pin Change Interupts auf PCIE0 und 1 Pin Change Interupt auf PCIE1 inkl. 
4 LED Kontrollen hinzubekommen. Zusätzlich müsste ich bei den 3en noch 
ermitteln können, welcher Pin getriggert hat, um die richtige LED 
ansteuern zu können.
Bin Anfänger und erbitte Hilfe. Codebeispiel (Arduino) ist herzlich 
willkommen.

Danke

Matthias

von Michael U. (amiga)


Lesenswert?

Hallo,

Deinen Satz, was Du wo und wie machen willst, habe ich nichteinmal 
verstanden...

Zeige Dein Programm, was Du gemacht hast, erkläre, was es machen soll 
und  sage, was stattdessen passiert.

Dann kann man sich damit auch auseinandersetzen und vielleicht helfen.
Hast Du eine der existierenden Libs benutzt oder den PCI selbst 
geschrieben?

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Matthias schrieb:
> Zusätzlich müsste ich bei den 3en noch
> ermitteln können, welcher Pin getriggert hat, um die richtige LED
> ansteuern zu können.

Das geht nur, wenn du weisst, was für ein Pegel den IRQ ausgelöst haben 
müsste, denn der PinChange Interrupt tut genau das - bei Pegelwechsel 
reagieren.
Wenn du z.B. weisst, das ein Lowpegel den IRQ ausgelöst haben muss, 
fragst du das PIN Register des Portes direkt am Anfang der ISR ab und 
entscheidest, welcher der drei Pins ausgelöst hast.

von Matthias (Gast)


Lesenswert?

Danke für die Antwort

Habe 3 Bewegungsmelder und einen Taster und möchte, dass der uC per 
Interrupt aufwacht, sobald einer davon auslöst. Erforderlich ist, dass 
der auslösende Bewegungsmelder im Programm ermittelt werden kann. Als 
Kontrolle soll jeweils noch die entsprechende LED angesteuert werden.

1
#include <avr/sleep.h>
2
#include <avr/interrupt.h>
3
4
const int dRButton = ??;         //pin?? Taster
5
const int dRPC1 = ??;            //pin?? Eingang1
6
const int dRPC2 = ??;            //pin?? Eingang2
7
const int dRPC3 = ??;            //pin?? Eingang3
8
9
const int dwButton = ??;         //pin?? LED
10
const int dWPC1 = ??;            //pin?? LED
11
const int dWPC2 = ??;            //pin?? LED
12
const int dWPC3 = ??;            //pin?? LED
13
14
15
void setup() {
16
17
  pinMode(dRButton, INPUT);
18
  digitalWrite(dRButton, HIGH);
19
20
  pinMode(dRPC1, INPUT);
21
  digitalWrite(dRPC1, HIGH);
22
23
  pinMode(dRPC2, INPUT);
24
  digitalWrite(dRPC2, HIGH);
25
26
  pinMode(dRPC3, INPUT);
27
  digitalWrite(dRPC3, HIGH);
28
29
30
  pinMode(dWButton, OUTPUT);
31
  digitalWrite(dWButton, LOW);
32
33
  pinMode(dWPC1, OUTPUT);
34
  digitalWrite(dWPC1, LOW);
35
36
  pinMode(dWPC2, OUTPUT);
37
  digitalWrite(dWPC2, LOW);
38
39
  pinMode(dWPC3, OUTPUT);
40
  digitalWrite(dWPC3, LOW);
41
 
42
}
43
44
45
void sleep() {
46
47
  GIMSK |= _BV(PCIE0); 
48
  GIMSK |= _BV(PCIE1);
49
  PCMSK0 |= _BV(PCINT0);                  // Use PA0 as interrupt pin
50
  PCMSK0 |= _BV(PCINT1);                  // Use PA1 as interrupt pin
51
  PCMSK0 |= _BV(PCINT2);                  // Use PA2 as interrupt pin
52
  PCMSK1 |= _BV(PCINT8);                  // Use PB0 as interrupt pin
53
  ADCSRA &= ~_BV(ADEN);                   // ADC off
54
55
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // replaces above statement
56
  sleep_enable();                         // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
57
  sei();                                  // Enable interrupts
58
  sleep_cpu();                            // sleep
59
60
  sleep_disable();                        // Clear SE bit
61
62
  cli();                                  // Disable interrupts
63
64
  PCMSK1 &= ~_BV(PCINT8);                 // Turn off PB0 as interrupt pin
65
  PCMSK0 &= ~_BV(PCINT2);                 // Turn off PA2 as interrupt pin
66
  PCMSK0 &= ~_BV(PCINT1);                 // Turn off PA1 as interrupt pin
67
  PCMSK0 &= ~_BV(PCINT0);                 // Turn off PA1 as interrupt pin
68
  ADCSRA |= _BV(ADEN);                    // ADC on
69
70
}
71
72
73
ISR(PCINT0_vect) {
74
75
//  Check which Pin triggered
76
77
//  ToDO if dRPC1 triggered
78
//  ToDO if dRPC2 triggered
79
//  ToDO if dRPC3 triggered
80
81
}
82
83
84
ISR(PCINT1_vect) {
85
86
//  ToDO if dRButton triggered
87
88
}
89
90
91
void loop() {
92
93
  sleep();
94
95
// ToDo
96
97
}

Bin noch am Probieren, ob ich bei den Konstanten-Deklarationen die Phys. 
Pin Nr. oder die Tinycore Ref Nr. angeben muss, deshalb die ??

Wie erwähnt bin ich Anfänger und habe mir o.g. Code fragmentweise aus 
dem Internet zusammengereimt

von Matthias (Gast)


Lesenswert?

Matthias S. schrieb:
> fragst du das PIN Register des Portes direkt am Anfang der ISR ab und

Wenn ich wüsste wie, hätte ich es vielleicht schon gemacht ;-)

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Matthias schrieb:
> und habe mir o.g. Code fragmentweise aus
> dem Internet zusammengereimt

Da steht ja auch gar nichts drin, ausser ein bisschen Arduino Zeugs. Bei 
deinem jetzigen Stand empfehle ich dir, lieber einfach in der 
Hauptschleife die Eingänge der Bewegungsmelder abzufragen und damit 
weiter zu arbeiten.

Die Sache mit den Interrupts verschieben wir mal.

von Michael U. (amiga)


Angehängte Dateien:

Lesenswert?

Hallo,

bei der Arduino-Geschichte gibt es gerade am Anfang mehrere Wege:
man legt sich vorerst auf die Möglichkeiten der Ardunino-Libs fest und 
schaut, was man da findet und wie man damit klarkommt.

Alternativ kann man auch in der Arduino-IDE einfach alles in C von Hand 
machen und orientiert sich an den Beispielen  die es dort gibt.

Beides mischen ohne große Programmiererfahrung auf dem AVR ist zumindest 
problematisch.

Die Arduino-Erweiterungen erwarten die Pinnummern der Arduino-Boards, 
die GCC-Makros (_BV z.B.) erwarten die Bezeichnungen der AVR-CPU.

Ich habe hier gerade ein Beipiel gefunden, das scheint auch Deine Basis 
zu sein und sollte zum ersten Test unverändert ganz brauchbar zu sein.
Daran dann eben schrittweise anbauen.

https://bigdanzblog.wordpress.com/2014/08/10/attiny85-wake-from-sleep-on-pin-state-change-code-example/

Im Anhang ein Bild mit den Pin-Zuordnungen der Tinys, ich finde das 
leider im Netz nicht mehr wieder...

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Matthias (Gast)


Lesenswert?

Hallo Michael,

Michael U. schrieb:
> Die Arduino-Erweiterungen erwarten die Pinnummern der Arduino-Boards,

Diese Info und der Anhang helfen mir sicher weiter, werde heute Abend 
mal testen

Danke

von Matthias (Gast)


Lesenswert?

Habs hinbekommen inkl. Abfrage Pin Register
Evtl. kann der Code jemand anders weiterhelfen

1
#include <avr/sleep.h>
2
#include <avr/interrupt.h>
3
4
const int dRPC1 = 1;
5
const int dRPC2 = 2;
6
const int dRPC3 = 3;
7
const int dRBell = 9;
8
9
const int dWAlarm = 0;
10
const int dWPC1 = 4;
11
const int dWPC2 = 5;
12
const int dWPC3 = 6;
13
const int dWBell = 10;
14
15
volatile int IRQNr = 0;
16
volatile int IRQRegister = 2;
17
18
19
void setup() {
20
21
  pinMode(dWAlarm, OUTPUT);
22
  digitalWrite(dWAlarm, LOW);
23
24
  pinMode(dWPC1, OUTPUT);
25
  digitalWrite(dWPC1, LOW);
26
27
  pinMode(dWPC2, OUTPUT);
28
  digitalWrite(dWPC2, LOW);
29
30
  pinMode(dWPC3, OUTPUT);
31
  digitalWrite(dWPC3, LOW);
32
33
  pinMode(dWBell, OUTPUT);
34
  digitalWrite(dWBell, LOW);
35
36
37
  pinMode(dRPC1, INPUT);
38
  digitalWrite(dRPC1, HIGH);
39
40
  pinMode(dRPC2, INPUT);
41
  digitalWrite(dRPC2, HIGH);
42
43
  pinMode(dRPC3, INPUT);
44
  digitalWrite(dRPC3, HIGH);
45
46
  pinMode(dRBell, INPUT);
47
  digitalWrite(dRBell, HIGH);
48
49
}
50
51
52
void sleep() {
53
54
  GIMSK |= _BV(PCIE0);
55
  GIMSK |= _BV(PCIE1);
56
  PCMSK0 |= _BV(PCINT1);                  // Use PA1 as interrupt pin
57
  PCMSK0 |= _BV(PCINT2);                  // Use PA1 as interrupt pin
58
  PCMSK0 |= _BV(PCINT3);                  // Use PA1 as interrupt pin
59
  PCMSK1 |= _BV(PCINT9);                  // Use PA0 as interrupt pin
60
  ADCSRA &= ~_BV(ADEN);                   // ADC off
61
62
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // replaces above statement
63
  sleep_enable();                         // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
64
  sei();                                  // Enable interrupts
65
  sleep_cpu();                            // sleep
66
67
  sleep_disable();                        // Clear SE bit
68
69
//  cli();                                  // Disable interrupts
70
71
  PCMSK1 &= ~_BV(PCINT9);                 // Turn off PA1 as interrupt pin
72
  PCMSK0 &= ~_BV(PCINT3);                 // Turn off PA1 as interrupt pin
73
  PCMSK0 &= ~_BV(PCINT2);                 // Turn off PA1 as interrupt pin
74
  PCMSK0 &= ~_BV(PCINT1);                 // Turn off PA0 as interrupt pin
75
  ADCSRA |= _BV(ADEN);                    // ADC on
76
77
}
78
79
80
ISR(PCINT0_vect) {
81
82
  cli();                                       // Disable interrupts
83
84
  byte PVal;                                   // Port value (8 Bits)
85
  byte IRQ1ActVal;                             // Actual IRQ1 value
86
  byte IRQ2ActVal;                             // Actual IRQ2 value
87
  byte IRQ3ActVal;                             // Actual IRQ2 value
88
89
  IRQRegister = 0;
90
91
  PVal = PINA;                                 // Read port A (8 bit)
92
  IRQ1ActVal = PVal & (1<<PCINT1);             // Mask out all except IRQ1
93
  IRQ1ActVal = IRQ1ActVal >> PCINT1;           // shift to right for bit0 position
94
  IRQ2ActVal = PVal & (1<<PCINT2);             // Mask out all except IRQ2
95
  IRQ2ActVal = IRQ2ActVal >> PCINT2;           // shift to right for bit0 position
96
  IRQ3ActVal = PVal & (1<<PCINT3);             // Mask out all except IRQ2
97
  IRQ3ActVal = IRQ3ActVal >> PCINT3;           // shift to right for bit0 position
98
99
  if(IRQ1ActVal==0)
100
  {
101
    IRQNr = 1;
102
  }
103
  
104
  if(IRQ2ActVal==0)
105
  {
106
    IRQNr = 2;
107
  }
108
109
  if(IRQ3ActVal==0)
110
  {
111
    IRQNr = 3;
112
  }
113
114
}
115
116
117
ISR(PCINT1_vect) {
118
  cli();                                  // Disable interrupts
119
  IRQRegister = 1;
120
}
121
122
123
void loop() {
124
125
  sleep();
126
127
  if (IRQRegister == 0)
128
  {
129
    digitalWrite(IRQNr + 3, HIGH);
130
    digitalWrite(dWAlarm, HIGH);
131
    delay(2000);
132
    digitalWrite(dWAlarm, LOW);
133
    digitalWrite(IRQNr + 3, LOW);
134
  }
135
  else if (IRQRegister == 1)
136
  {
137
    digitalWrite(dWBell, HIGH);
138
    delay(2000);
139
    digitalWrite(dWBell, LOW);
140
  }
141
142
  IRQRegister = 2;
143
  IRQNr = 0;
144
145
}
Danke an alle Helfer

von Michael U. (amiga)


Lesenswert?

Hallo,

die Interrupts brauchst Du in der ISR nicht zu sperren, das erledigt die 
Hardware des AVR alleine.
Um den restlichen Ablauf (nötige Register retten usw.) kümmert sich der 
Compiler.
Die nötige Nutzung von volatile hast Du ja offenbar schon selbst 
entdeckt.

Viel Spaß weiterhin.

Gruß aus Berlin
Michael

: Bearbeitet durch User
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.