PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Interrupts & Asuro



MadMan2k
22.08.2005, 22:30
habe ich das Tutorial von microcontroller.net soweit richtig verstanden, dass es nur eine beschränkte Zahl an interrupts gibt und diese auch automatisch ausgelöst werden - ich mich also auf die Implementierung dieser konzentrieren kann?

Ich möchte gerne die Änderung der Licht/ Tastsensoren über Interrupts überwachen - leider sagen mir die kryptischen Registerkonstanten nichts.

Könnte mir vielleicht jemand ein Beispielscript zur verfügung stellen bzw. sagen welche Signals ich wofür abfangen soll?

Genaugesagt geht es hier um die beiden Odometriesensoren, die Lichtsensoren unten und die Tastensensoren des Asuro.

RCO
23.08.2005, 18:43
Es gibt nur für bestimmte Ereignisse Interrupts, du kannst nicht bei einer Änderung eines Wertes eine Interruptsroutine auslösen. Da sowohl die Taster als auch die Lichtsensoren über den Analog-Digital-Wandler laufen, steht dir nur ein Interrupt zur verfügung, wenn er eingschaltet ist springt er in eine Routine wenn eine ADC-Messung komplett ist. Ein weiterer ist der Analog-Comparator. Andere AD-Wandler-interrupts gibt es beim Mega8 mMn nicht.

MadMan2k
23.08.2005, 21:58
in der Routine könnte ich den Wert ja dann abfragen und für die main Schleife einen Statuswert setzen....

der mega8 war praktischerweise bei microcontroller.net das Beispiel:


#define SIG_INTERRUPT0 _VECTOR(1)
#define SIG_INTERRUPT1 _VECTOR(2)
#define SIG_OUTPUT_COMPARE2 _VECTOR(3)
#define SIG_OVERFLOW2 _VECTOR(4)
#define SIG_INPUT_CAPTURE1 _VECTOR(5)
#define SIG_OUTPUT_COMPARE1A _VECTOR(6)
#define SIG_OUTPUT_COMPARE1B _VECTOR(7)
#define SIG_OVERFLOW1 _VECTOR(8)
#define SIG_OVERFLOW0 _VECTOR(9)
#define SIG_SPI _VECTOR(10)
#define SIG_UART_RECV _VECTOR(11)
#define SIG_UART_DATA _VECTOR(12)
#define SIG_UART_TRANS _VECTOR(13)
#define SIG_ADC _VECTOR(14)
#define SIG_EEPROM_READY _VECTOR(15)
#define SIG_COMPARATOR _VECTOR(16)
#define SIG_2WIRE_SERIAL _VECTOR(17)
#define SIG_SPM_READY _VECTOR(18)


demnach wäre SIG_ADC mein Signal?

Und was hat es mit dem Analog-Comparator auf sich? (SIG_COMPARATOR wahrscheinlich)

Achja, danke schonmal!

RCO
23.08.2005, 22:15
Yepp! So ganz einfach sit das ganze jetzt allerdings nicht:

1. Du musst irgendwo die Kanäle des ADCs umschalten, du hast zwar mehrere Kanäle, wo dann die Taster, oder die Lichtsensoren dranhängen, aber nur einen AD-Wandler. Du kannst also immer nur eine Sach zur gleichen Zeit messen.

2. Die Messung muss irgendwie gestertet werden, entweder du lässt sie "free", dann misst er ununterbrochen, oder du sagst im, wann er starten soll mit einer! Messung.

Die Interruptvektoren sind übrigens bei allen AVRs gleich. Außer natürlich denen, die kein UART oder ADC oder so haben.

mikrocontroller.net ist auf jeden Fall ne gute Adresse!

MadMan2k
23.08.2005, 23:22
das macht die Sache natürlich etwas komplizierter...

Im Prinzip wollte ich folgendes aus Java nachbauen:

X SensorListner(Thread)
1 MotorController(Thread)

der MotorController startet mit niedriger Priorität und wird von den SensorListnern unterbrochen, wenn sie die Überschreitung eines Schwellwertes festgestellt haben.
Sie setzen ebenfalls die Status-variable.

Unter C würde das dann wohl so aussehen:

main:
- irgendwas abfragen, was den ADC Wandler braucht
- Endlosschleife: Status abfragen => behandeln

SIGNAL(SIG_ADC):
- wert prüfen & ggf. status setzen
- nächsten Sensor abfragen (z.B. LineData() aufrufen)

beim letzten unkt bin ich mir aber noch unsicher, ob das nicht in einer endlosen Rekursion endet und den Haupt-thread blockiert...

RCO
24.08.2005, 00:04
Ich würde es etwas anders machen:

Main:
*Endlosschleife start
- Wähle ADC-Channel
- Starte Messung
- Tue was nicht zeitkritisches (irgendwas)
*Endlosschleife stop

ADC-Interruptroutine
- Checken, was der ADC-Wert bedeutet (Licht oder Taster oder Odometrie)
- Deutung, Anpassung...

Taster-Interrupt
- Wähle ADC-Channel Taster
- Stoppe Motoren (evtl.)

Also bei den Tastern hat man den Vorteil, dass man nicht permanent die Werte überwachen muss, sondern ein zusätzlicher Interrupt an INT1 ausgelöst (SIG_INTERRUPT1; VECTOR(2)) wird. Das ist wichtig, um den Motor möglichst schnell stoppen zu können. Es muss dann halt über ne ADC-Messung der Taster festgestellt werden welcher der 6 Taster (oder welche) gedrückt sind und entsprechend reagiert werden.

Der ADC arbeitet übrigens nach Auswahl des Kanals und dem Start vollkommen im Hintergrund und wird nur durchd en Interrupt unterbrochen.

Noch Fragen O:) ?

MadMan2k
24.08.2005, 10:29
dazu muss ich wahrscheinlich die Messfunktionen etwas umschreiben, sprich $data = ADCL + (ADCH << 8) in die SIG_ADC routine verlagern.
Um zu gucken was ich gerade gemessen habe, kann ich ADMUX lesen?

Die Anpassung würe ich jedoch in der main lassen, da man ggf. auf eine Zweite Änderung warten muss, bis man den in den Ursprungszustand zurückgeht denn so wie ich es verstanden habe blockieren SIGNAL Routinen das Hauptprogramm.

Dann noch was zu den Tastern:
was spuckt der AD-Wandler eigentlich aus, dass man "es" mit dieser komplizierten Formel erst umwandeln muss?

angenommen ich nehme aus den Lese Methoden von asuro.c das eigentlich lesen des AD Wandlers aus, würde mein Code etwa so aussehen:

[php:1:cbaae07140]#include "asuro.h"
#define INITIAL 0
#define BLOCKED 1

unsigned char status = INITIAL;

int main(void)
{
Init();
StartSwitch();

while(TRUE) {
switch (status) {
case BLOCKED:
// zurücksetzen, z.B. LineData lesen
break;
//...
default:
LineData(IR_LEFT); // auch leicht abgewandelt
// der Rest
break;
}
}

return 0;
}

SIGNAL(SIG_ADC) {
unsigned int data = ADCL + (ADCH << 8);

switch (ADMUX) {
case (1 << REFS0) | SWITCH:
status = BLOCKED;
break;

case (1 << REFS0) | IR_LEFT:
if(status == BLOCKED) {
status = was_anderes
}
//data speichern, vergleichen, status setzen
break;
}

}

SIGNAL(SIG_INTERRUPT1) {
MotorSpeed(0,0);
PollSwitch();
}[/php:1:cbaae07140]

kommt das hin?

RCO
24.08.2005, 12:26
Also...


was spuckt der AD-Wandler eigentlich aus, dass man "es" mit dieser komplizierten Formel erst umwandeln muss?

Wenn ich mich nicht verrechnet habe, müsste es ungefähr so sein. Links der ADC-Wert, rechts der Wert von Pollswitch() nach der Rechnung.

678-682 --> 32
812-821 --> 16
903-915 --> 8
956-970 --> 4
985-1000 --> 2
1001-1015 --> 1

Durch den geschickten Einsatz von fließkomma und nicht fließkomma Zahlen kann man so runden.


return ((unsigned char) ((( 1024.0/(float)i - 1.0)) * 63.0 + 0.5));

Zum Code, ich muss zugeben, dass ich da nciht ganz durchgestiegen bin, aber müsste so eingeltich funktionieren. Wenn ich das richtig sehe, überprüfst du, was in ADMUX gesetzt ist und führst dann entsprechend aus (sinnvoll!). In der Hauptroutine prüfst du dann, ob noch irgendwas gemacht werden soll, oder "bocrmaler Code" laufen kann.

Was meint status=blocked?