Forum: Mikrocontroller und Digitale Elektronik Attiny84 - Interrupt an PIN8 PCINT10 triggert nur jedes 2. mal


von Matthias (Gast)


Lesenswert?

Hallo,

ich finde den Fehler nicht. PIN8 ist mit Pulldown an GND und eine 
parallel an den auslösenden Taster (VCC) angeschlossene LED leuchtet bei 
jeder Betätigung -> Fehler kann nur im Code versteckt sein.

1
#include <avr/sleep.h>
2
#include <avr/interrupt.h>
3
4
const int PIN2Free = 2;
5
6
const int aRDelay = A0;
7
8
const int dRFritzLEDWLAN = 1;
9
const int dROKFritzLEDINet = 6;
10
const int dROKP7 = 7;
11
const int dRBell = 8;
12
13
const int dWWLANOn =  3;
14
const int dWNETIO =  4;
15
const int dWWLANOff =  5;
16
const int dWLiftHandset =  9;
17
const int dWRedial = 10;
18
19
volatile int ISRTrigger=0;
20
21
volatile uint8_t portbhistory;
22
volatile uint8_t portahistory;
23
24
  
25
void setup() {
26
27
  pinMode(0, INPUT);
28
  pinMode(dRFritzLEDWLAN, INPUT);
29
  pinMode(dROKFritzLEDINet, INPUT);
30
  pinMode(dROKP7, INPUT);
31
  pinMode(dRBell, INPUT);
32
33
  pinMode(PIN2Free, OUTPUT);
34
  digitalWrite(PIN2Free, LOW);
35
36
  pinMode(dWWLANOn, OUTPUT);
37
  digitalWrite(dWWLANOn, LOW);
38
39
  pinMode(dWNETIO, OUTPUT);
40
  digitalWrite(dWNETIO, LOW);
41
  
42
  pinMode(dWWLANOff, OUTPUT);
43
  digitalWrite(dWWLANOff, LOW);
44
45
  pinMode(dWRedial, OUTPUT);
46
  digitalWrite(dWRedial, LOW);
47
48
  pinMode(dWLiftHandset, OUTPUT); 
49
  digitalWrite(dWLiftHandset, LOW);
50
  
51
  SetWMA1000();
52
  
53
  portahistory = PINA;
54
  portbhistory = PINB;
55
  
56
}
57
58
59
void sleep() {
60
61
  GIMSK |= _BV(PCIE0);
62
  GIMSK |= _BV(PCIE1);
63
64
  PCMSK0 |= _BV(PCINT1);
65
  PCMSK0 |= _BV(PCINT6);
66
  PCMSK1 |= _BV(PCINT10);
67
  ADCSRA &= ~_BV(ADEN);
68
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
69
70
  sleep_enable();
71
  sei();
72
  sleep_cpu();
73
74
  cli();  
75
76
  PCMSK1 &= ~_BV(PCINT10);
77
  PCMSK0 &= ~_BV(PCINT6);
78
  PCMSK0 &= ~_BV(PCINT1);
79
  sleep_disable();
80
  ADCSRA |= _BV(ADEN);
81
82
}
83
84
85
ISR(PCINT0_vect) {
86
  
87
  uint8_t changedbits;
88
89
  changedbits = PINA ^ portahistory;
90
  portahistory = PINA;
91
92
  if(changedbits & (1 << PCINT1)){
93
    ISRTrigger=dRFritzLEDWLAN;
94
  }
95
96
  if(changedbits & (1 << PCINT6)){
97
    if (digitalRead(dROKFritzLEDINet)==HIGH){
98
      ISRTrigger=dROKFritzLEDINet;
99
    }
100
  }
101
  
102
}
103
104
105
ISR(PCINT1_vect) {
106
107
  uint8_t changedbits;
108
  
109
  changedbits = PINB ^ portbhistory;
110
  portbhistory = PINB;
111
112
  if(changedbits & (1 << PCINT10)){
113
    if (digitalRead(dRBell)==HIGH){
114
      ISRTrigger=dRBell;
115
    }
116
  }
117
  
118
}
119
120
121
void SetWMA1000(){
122
  if (digitalRead(dRFritzLEDWLAN)==HIGH) {
123
    digitalWrite(dWWLANOff, HIGH);
124
    delay(500);
125
    digitalWrite(dWWLANOff, LOW);
126
  }
127
  else {
128
    digitalWrite(dWWLANOn, HIGH);  
129
    delay(500);
130
    digitalWrite(dWWLANOn, LOW);
131
  }
132
}
133
134
135
void loop() {
136
137
  sleep();
138
  
139
  if (ISRTrigger==dRFritzLEDWLAN){
140
    unsigned long ticker=0;
141
    int state=digitalRead(dRFritzLEDWLAN);
142
    while (ticker < 50000){
143
      if (digitalRead(dRFritzLEDWLAN)!=state){
144
        state=1-state;
145
        ticker=0;
146
      }
147
      else{
148
        ticker++;
149
      }
150
    }
151
    SetWMA1000();
152
  }
153
  else if (ISRTrigger==dROKFritzLEDINet){  
154
    digitalWrite(dWNETIO, HIGH);
155
    delay(500);
156
    digitalWrite(dWNETIO, LOW);
157
  }        
158
  else if (ISRTrigger==dRBell){  
159
    digitalWrite(dWLiftHandset, HIGH);
160
    delay(250);
161
    digitalWrite(dWRedial, HIGH);
162
    delay(250); 
163
    digitalWrite(dWRedial, LOW);
164
    delay(8000+analogRead(0)/1.023*5);
165
    digitalWrite(dWLiftHandset, LOW);
166
  }
167
  
168
  ISRTrigger=0;
169
  
170
}


Vielleicht ist jemand so freundlich mir Anfänger bei der Fehlersuche zu 
helfen.

Danke

Matthias

von Georg G. (df2au)


Lesenswert?

Als erstes solltest du dein Programm zusammenstreichen, bis nur noch 
deine ISR und die Auswertung da sind. Und dann sehen wir weiter.

von Stefan F. (Gast)


Lesenswert?

Falls es hier um schnell aufeinander folgende Signale geht, könnte es 
sein, dass deine digitalRead() Aufrufe in den Interruptroutinen zu viel 
Zeit verplempern. Um das zu lösen, kannst du direkt aus dem PINx 
Register lesen.

Dann ist mir aufgefallen, dass du beiden ISR jeweils zweimal das PINx 
Register liest - in der Hoffnung, dass da auch zweimal der selbe Wert 
bei heraus kommt. Das ist aber nicht unbedingt der Fall, das Signal 
könnte sich zwischenzeitlich geändert haben. Lies nur einmal in eine 
zusätzliche Zwischen-Variable.

In der Loop willst du im Prinzip ständig schlafen - außer es kommt ein 
Signal rein. Richtig? Due musst hier beachten, dass das Aufwachen eine 
beträchtliche Zeit kostet. Ich hatte mich auch schonmal gewundert, warum 
mein µC zwar aufwachte, danach aber der Meinung war, dass das kein 
Signal sei. Er war einfach zu träge, bis er aufgewacht war, war das 
Signal schon wieder weg.

von Matthias (Gast)


Lesenswert?

Danke Stefanus für die Antwort.

Die Signale sind Türklingel über Relais geschalten, Fritzbox WLAN LED 
und Fritzbox Internet LED - alles Signale im Sekundenbereich und länger 
als die Aufwachzeit.

Habe die Schaltung jetzt so umgebaut, dass die Eingänge auf INT1, INT5 
und INT6 liegen und nur ein ISR benötigt wird.

Hier zickt jetzt auch der andere Eingang, den ich im ISR mit digitalRead 
auf HIGH abfrage - um direkt aus dem PINx Register zu lesen, werde ich 
hoffentlich ein Beispiel finden.

von Stefan F. (Gast)


Lesenswert?

Bei Relais fällt mir direkt das Kontaktprellen ein. Hast du das bedacht?

von Matthias (Gast)


Lesenswert?

Nein, hab nicht gewusst dass es beim Relais so was gibt - wie erwähnt 
Anfänger

Seit ich den ISR Code wie folgt
1
ISR(PCINT0_vect) {
2
  
3
  byte PinVal=PINA;
4
5
  IRQFritzLEDWLAN = PinVal & (1<<PCINT1);
6
  IRQFritzLEDWLAN = IRQFritzLEDWLAN >> PCINT1;
7
8
  IRQBell = PinVal & (1<<PCINT5);
9
  IRQBell = IRQBell >> PCINT5;
10
11
  IRQOKFritzLEDINet = PinVal & (1<<PCINT6);
12
  IRQOKFritzLEDINet = IRQOKFritzLEDINet >> PCINT6;
13
  
14
}

geändert habe, funktioniert es einwandfrei

Habe im Loop in der Zustandsabfrage trotzdem noch eine 50ms 
Prellsicherheit eingepflegt

Danke

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.