PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Interrupt-Verwirrnisse / Quadraturdecoder



ThSteier
17.07.2005, 21:44
Hallo allerseits,

ich grübele hier gerade an einer Auswerteroutine für einen Inkrementaldrehgeber und habe dabei noch ein Verständnisproblem. Das Programm


$regfile = "attiny2313.dat"

$hwstack = 32
$swstack = 32
$framesize = 32

Dim Q_in As Byte ' aktuelle Werte am Eingang
Dim Q_alt As Byte 'Eingangswert vom letzten Zyklus
Dim Test As Byte
Dim Ud As Byte 'Drehrichtung, nur für Test

Config Portd = &B11111100 'Eingänge festlegen

Do
Q_in = Portd And &B00000011 'Ports D0 und D1 einlesen
Test = Q_alt Xor Q_in 'Wert geändert?
If Test = 0 Then
Goto Ende 'nein: Auswertung überspringen
End If
Rotate Q_alt , Right , 1 'vorherigen Wert rechtsverschieben
Ud = Q_alt Xor Q_in 'Drehrichtung bestimmen
Ud = Ud And 1
If Ud = 0 Then
Print "L"
Else
Print "R"
End If
Ende:
Q_alt = Q_in
Loop

End
funktioniert soweit, frißt allerdings durch das Polling gewaltig Rechenleistung.

Nun könnte man die Auswertung doch theoretisch auch in eine Interruptroutine packen, die jedesmal ausgelöst wird, wenn sich der Zustand der Eingänge ändert. Allerdings habe ich keine Idee, wie man ein und den selben IRQ auf beide Eingangspins legen kann. INT0 und INT1 zu verwenden, klappt hier (zumindest im BASCOM-Simulator) irgendwie nicht. Mal das Programm dazu:


$regfile = "attiny2313.dat"

$hwstack = 32
$swstack = 32
$framesize = 32

Dim Q_in As Byte ' aktuelle Werte am Eingang
Dim Q_alt As Byte 'Eingangswert vom letzten Zyklus
Dim Ud As Byte 'Drehrichtung, nur für Test

Config Portd = &B11110011 'Eingänge festlegen

Enable Interrupts
Enable Int0
Enable Int1
On Int0 Auswertung
On Int1 Auswertung

Do
Loop

Auswertung:
Q_in = Portd And &B00001100 'Ports D2 (INT0) und D3 (INT1) einlesen
Rotate Q_in , Right , 2 'Bits rechtsbündig verschieben
Rotate Q_alt , Right , 1 'vorherigen Wert rechtsverschieben
Ud = Q_alt Xor Q_in 'Drehrichtung bestimmen
Ud = Ud And 1
If Ud = 0 Then
Print "L"
Else
Print "R"
End If
Q_alt = Q_in
Return

End

Obwohl die gleiche Routine wie bei der Polling-Variante zum Einsatz kommt (die Überprüfung auf Zustandsänderung wird hier ja nicht gebraucht), stehen mir bei der Simulation alle Haare zu Berge: die Interruptroutine scheint nicht nur auf Flankenwechsel an D2 und D3, sondern auch (aber nur sporadisch) an anderen Pins zu reagieren - und liefert keine reproduzierbaren Ergebnisse.

Ich habe mir hier schon den Kopf blutig gekratzt, aber mir fällt einfach nicht ein, wo der Fehler sitzen könnte. Oder liegt es eher am Simulator? In Hardware kann ich es leider noch nicht testen, die Platine ist noch nicht fertig...

rätselnderweis,
Thomas

ThSteier
17.07.2005, 23:04
Hm, man sollte die Datenblätter wirklich sorgfältiger lesen...

Wenn ich nicht völlig danebenliege, hängen meine Probleme mit den Interruptmasken zusammen. INT0 scheint hier bei jedem Flankenwechsel auszulösen und INT1 nur beim Hi/Lo-Wechsel. Was uns zu der Frage bringt, wie man diese Register (konkret MCUCR) in BASCOM direkt beschreiben kann.

Oder gibt es eine Möglichkeit, den PCINT-Interrupt zu nutzen? Die Hilfe schweigt sich dazu leider aus.

Ich wäre für jeden Hinweis dankbar.

Viele Grüße,
Thomas

EDIT: Ich bin wirklich blind - oder man sollte um diese Zeit einfach nicht mehr vorm PC sitzen...
Allerdings hilft mir das Setzen von MCUCR (auf &Bxxxx0101 entsprechend "interrupt at logical change") irgendwie auch nicht weiter: das sperrt INT0 und INT1 gleich völlig. Ich glaube, ich schlafe erstmal drüber...

PicNick
18.07.2005, 07:20
Zwischenfrage, bevor wir uns vertiefen: Welche BasCom Version verwendest du ?
1.11.7.4 oder
1.11.7.7 ( 8 )

ThSteier
18.07.2005, 17:27
Hier werkelt seit dem Wochenende die 1.11.7.9 in der Demo-Version. Vorher wars die 1.11.7.7 - ich habe das Update eigentlich nur wegen der ATTiny-Libs drübergejagt...

Der entsprechende Programmabschnitt sieht inzwischen so aus:

Config Portd = &B11110011 'Eingänge festlegen

Enable Interrupts

Enable Int0
Enable Int1

Mcucr.0 = 1 'INT0 auf "on logical change" setzen
Mcucr.1 = 0

Mcucr.2 = 1 'INT1 auf "on logical change" setzen
Mcucr.3 = 0

On Int0 Auswertung
On Int1 Auswertung
Die Bits stehen anschließend auch korrekt im MCRCU-Register - werden aber ignoriert. :(

Viele Grüße,
Thomas

PicNick
18.07.2005, 19:35
Der blöden Fragen kein Ende: Bist du sicher, daß das ein
Attiny2313 ist und nicht ein 90S2313 ? Weil letzterer kann das nicht mit beiden flanken

ThSteier
18.07.2005, 19:56
Ich bin mir eigentlich sicher (siehe $regfile = "attiny2313.dat"), aber der Compiler vielleicht nicht. Die dat-Files sagen mir leider ungefähr das gleiche wie ein chinesisches Telefonbuch, so daß ich da gar nicht erst nachzuschauen brauche :(

Ich werde das Programm morgen mal auf der RNCONTROL testen - mal schauen, was die dazu sagt. Und wenn's dort klappt, muß ich mal schauen, ob ich den ATTiny provisorisch verdrahten kann. Irgendwann muß ich mir doch mal 'ne einfache Experimentierplatine für den ATTiny basteln...

Viele Grüße,
Thomas

PicNick
18.07.2005, 20:04
Du mußt im Datenblatt schauen, ob der Chip überhaupt BEIDE Flanken kann.
Der Atmega32 z.B. kann es NICHT (und 90S2313 auch nicht)
Simulator weiß ich nicht, verwend' ich nie.
Probier mal, ob du nicht mit EINER Flanke fürs Erste auch zurechtkommst.
Kann dir jetzt nix besseres anbieten, die Statements im Programm stimmen, da is nix. Du hast es ja auch kontrolliert.

ThSteier
18.07.2005, 20:21
Seltsam. Laut den Datenblätt sollten es sowohl der Tiny2313 und der Mega32 können (zumindest würde ich die zweite Zeile in "Table 32" so interpretieren), die entsprechenden Seiten sind jedenfalls identisch und Errata habe ich dazu bisher nicht gefunden. Ich hab mal 'nen Schreenshot angehängt.

Zu der Auswertung nur einer Flanke habe ich bisher keine Idee. Hab auch schon überlegt, aber im schlimmsten Fall können dabei zwei Übergänge "durchrutschen", bis wieder ein "gültiger" Flankenwechsel kommt und den Interrupt auslöst. :(

Viele Grüße,
Thomas

hansmicha
30.07.2005, 04:23
warum nicht
config int0 = rising / falling

Roberto
07.08.2005, 21:36
Hallo

Hier gibt es ein Beispiel in Basic für eine Vierfachauswertung für einen Encoder
(läuft bei mir am Mega8 ohne Probleme)
http://www.mikrocontroller.net/forum/read-1-37689.html#new

Aber auf der Home von MCS gibt es auch ein Beispiel für normale Auswertung:
http://www.mcselec.com/an_115.htm
Funktioniert auch gut :-)

ThSteier
08.08.2005, 15:03
War 'ne Weile nicht zuhause, daher die späte Antwort...

@hansmicha:
Sobald man nur eine Flanke auswertet, klappt die Sache leider nicht mehr. Da so nur jeder zweite Wechsel erkannt würde, wäre eine Richtungsbestimmung unmöglich.

@Roberto:
Danke für die Links, muß ich mir mal in Ruhe ansehen und probieren. Momentan ist hier eh' Chaos pur... :(

Viele Grüße,
Thomas

Roberto
08.08.2005, 15:20
Hallo

Inzwischen gibt es in Bascom auch den Befehl ENCODER der das alles selber macht :-) (Siehe Hilfe im Bascom)
Dürfte aber nur für langsame Drehgeber für Hand sein..