AVR, Externer Interrupt 11 beim Atmega168 -> Howto-Problem

#885300
Lesenswert?

Bin jetzt nach 2 Tagen erfolgloser Suche soweit, dass ich dringend auf 
Eure geneigte Expertise angewiesen bin.

Ich betreibe einen Atmega168 bei ext. 20MHz und benötige zur Steuerung 
vier externe Interrupts, die aufgrund der Layoutvorgaben nur an Pins 
PCINT8/ PCINT9/ PCINT10/ PCINT11 angelegt werden können.

Die Signale dort kommen auf TTL-Pegel mit einem Abstand von ca. 1 bis 
100ms.

Ich verwende als Entwicklungsumgebung BASCOM-AVR in der Version 
1.11.8.4. und kann damit nur Routinen bis ENABLE INT7 definieren 
(Handbücher und Datenblätter habe ich schon rauf, runter und durch).

So wie ich es bisher verstanden habe, muss man für die "höheren" 
Interrupts so etwas wie Vektoren und/oder Masken ensetzen - und hier 
liegt mein Problem
   -> Wie definiert man in BASCOM AVR BASIC die Routinen für Interrupts 
oberhalb von PCINT7?

Für einen kleinen Hirnschubser in die richtige Richtung wäre ich schon 
dankbar.

Rolf
#885309
Lesenswert?

Erstmal sind die Pin Change Interrupts etwas anderes als die "normalen" 
externen Interrupts, da sie erstens grundsätzlich auf jeden Pegelwechsel 
reagieren (also nicht konfigurierbar sind) und da jeder Pin Change 
Interrupt von einer bestimmten Anzahl von Pins ausgelöst werden kann 
(externe Interrupts nur durch jeweils einen einzigen Pin). Um zu 
definieren, auf welche Pins der Interrupt reagieren soll, muss man die 
Pins maskieren.

INT0 usw. bezieht sich auf die externen Interrupts, und davon hat der 
ATMega168 nur zwei Stück, nämlich INT0 und INT1. INT2...INT7 gibt es da 
gar nicht.

Die Pins PCINT7...0 sind dem Interrupt PCI0 zugeordnet. Steht aber alles 
im Datenblatt...
#885330
Lesenswert?

Rolf S. wrote:
> Ich betreibe einen Atmega168 bei ext. 20MHz und benötige zur Steuerung
> vier externe Interrupts, die aufgrund der Layoutvorgaben nur an Pins
> PCINT8/ PCINT9/ PCINT10/ PCINT11 angelegt werden können.

Dann mußt Du einen Handler für PCINT1 definieren und natürlich die 
entsprechenden Enablebits in PCMSK1 setzen.

Und in dem Handler mußt Du die 4 Inputs testen und mit dem vorherigen 
Zustand vergleichen, um zu sehen, auf welchem die Flanke war und in 
welche Richtung.

Du hast also nur einen Handler für alle 4 Eingänge und mußt darin 
entscheiden, was bei welchem zu tun ist.

Schau einfach mal ins Datenblatt, da steht alles drin.


Peter
#887435
Lesenswert?

> Besten Dank für Eure schnellen Hints -> ich ahne schon etwas Licht am
> Ende des Tunnels....

Nachfolgend mein Ansatz zur Lösung -> funktioniert leider nur zu 99%. Es 
ist mir letzendlich nicht gelungen zu ermitteln, welcher der Pins in 
einem Port den PCINT ausgelöst hat...
1
' -----------------------------------------------------------------------
2
' PIN CHANGE INTERRUPTS / ATMEGA168 / BASCOM
3
' siehe auch ATMEL-Datenblatt Seiten 70 und 345
4
' -----------------------------------------------------------------------
5

6
$regfile = "m168def.dat"
7
$crystal = 20000000
8
$hwstack = 80
9
$swstack = 80
10
$framesize = 80
11
' -----------------------
12
Dim Countx As Integer
13
Dim Iportval As Byte
14
Dim Iportvalold As Byte
15
Dim Iportdif As Byte
16
' -----------------------
17
Declare Sub Blinksig
18
' -----------------------
19
Config Lcdpin = Pin , Db4 = Portb.0 , Db5 = Portb.1 , Db6 = Portb.2 , Db7 = Portb.3 , E = Portb.4 , Rs = Portb.5
20
Config Lcd = 16 * 1a                                        ' LCD-Modul 1x16
21

22

23
' ------------------------
24
' Port-Settings (Beispiel)
25
' ------------------------
26
Sensor_1 Alias Portc.3                                      ' PCINT 11
27
Sensor_2 Alias Portc.2                                      ' PCINT 10
28
Sensor_3 Alias Portc.1                                      ' PCINT  9
29
Sensor_4 Alias Portc.0                                      ' PCINT  8
30
Config Sensor_1 = Input
31
Config Sensor_2 = Input
32
Config Sensor_3 = Input
33
Config Sensor_4 = Input
34
Sensor_1 = 1                                                ' Pullups
35
Sensor_2 = 1
36
Sensor_3 = 1
37
Sensor_4 = 1
38
' ------------------------
39
Actor_1 Alias Portc.5
40
Config Actor_1 = Output
41
' ------------------------
42

43

44

45
' ---------------------------
46
' Interrupt settings mit
47
' Besonderheiten in Bascom
48
' ---------------------------
49
' PCINT1 ist NICHT der IC-Pin "PcInt1",
50
' sondern der "reaction Block" für logiclevel-changes
51
' an PortC (aktive Pins siehe PCMSK1)
52

53
On Pcint1 Isr_1
54
Enable Pcint1
55

56
' PCINT8..11 als ext. Interrupt-Pins maskieren.
57
' Wenn an einem dieser Pins ein Logiklevel WECHSELT,
58
' dann wird der Interrupt "Pcint1" ausgelöst
59

60
Pcmsk1 = &B00001111
61

62

63

64
' PCIE1-Block enable
65
' Die Pins PCINT8..14 werden hier als Block freigeschaltet
66

67
Pcicr = &B00000010
68

69

70

71

72
' -----------------------
73
' Initialisieren
74
' -----------------------
75
Countx = 0
76
Iportval = 0
77
Iportvalold = 0
78
' -----------------------
79

80
' +++++++++++++++++++++++++++++
81
' Main loop
82
' +++++++++++++++++++++++++++++
83
Cls
84
Lcd "<Bereit>"
85
Enable Interrupts
86
Do
87
   ' godot...
88
Loop
89
End
90
' +++++++++++++++++++++++++++++
91

92

93
' -----------------------
94
' Subroutine
95
' -----------------------
96
Sub Blinksig
97
   Actor_1 = 0
98
   Waitms 5
99
   Actor_1 = 1
100
End Sub
101
' -----------------------
102

103

104
' ---------------------------*******************************************
105
' Interrupt service routine
106
' ---------------------------*******************************************
107
Isr_1:
108

109
   Disable Interrupts
110

111
   ' Wert vom Port holen und Mögl. betroffene Bits ausfiltern
112
   Iportval = Portc And &B00001111
113

114
   ' Änderungen zum vorherigen Wert ermitteln
115
   Iportdif = Iportvalold Xor Iportval
116

117
   ' Info
118
   Call Blinksig
119
   Countx = Countx + 1
120
   If Countx > 299 Then
121
      Countx = 0
122
   End If
123
   Cls
124
   Lcd ">" ; Bin(iportdif) ; " >" ; Countx
125

126
   ' Aktuellen Portwert für nächsten Interrupt merken
127
   Iportvalold = Iportval
128

129
   Enable Interrupts
130

131
   Return
132

133
' -----------------------
#887446
Lesenswert?

Rolf S. wrote:
> Nachfolgend mein Ansatz zur Lösung -> funktioniert leider nur zu 99%.

Darunter kann sich niemand etwas vorstellen.

Was wird erwartet, was ist die Abweichung dazu?


Der Code sieht prinzipiell o.k. aus, außer den riesigen Wartezeiten im 
Interrupt drin (lahme LCD-Ausgabe + 5ms Warten).
Interrupts sollten kurz sein, langsame Sachen sollte man nur im Main 
machen.

Wenn Du für über 5ms sämtliche CPU-Aktivität im Interrupt blockierst, 
kanns Du natürlich nie Pulse mit 1ms Abstand erkennen.


Peter
#5417134
Lesenswert?

Vielleicht nicht elegant aber es funktioniert.
Bei mir sieht das so aus:
1
char test (void){
2
int_mask = PCMSK0;
3
temp = PINB;
4
temp &= int_mask;
5
return temp;
6
}

und im Interrupt:
1
ISR(PCINT0-vect){
2
char x=0,y=0;
3
temp_old = temp;
4
test();
5
x = temp;
6
x &= 4;
7
y = temp_old;
8
y &= 4;
9

10
if (x==y)
11
{
12
    // Code falls es PB3 war...
13
}
14
}


Und nach dem veröffentliche erst gesehen, wie alt der Post ist....

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren