PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Programmieren mit Interrupts



farratt
17.09.2007, 15:18
Hallo Leute!

Ich möchte mich nun mal an das Programmieren mit Interrupts heranwagen und hab dazu mittlerweile einiges gelesen. Nun zum konkreten Beispiel. Ich hab mir eine Funktion void fahren(int strecke) programmiert, die Asuro geradeaus fahren lässt. Sie funktioniert auch sehr gut, also das eigentliche Problem liegt nicht im Fahren an sich. Das Problem ist, dass ich keine Kontrolle über Asuro habe, so lange er fährt, da er ja solange in der Funktion fahren steckt. Das heißt ich kann Asuro nicht auf einen Schalter reagieren lassen, während er fährt. Die Lösung: Interrupts!
Aber irgendwie krieg ichs nicht hin. Ich zeig euch mal wie ichs probiert hab:


#include asuro.h
#include fahren.h

SIGNAL(SIG_INTERRUPT1)
{
StatusLED(RED);
while(1);
}

int main(void)
{
Init();

StartSwitch();
fahren(2000); //lässt Asuro 2000mm geradeaus fahren
StopSwitch();

while(1);
return 0;
}

Dieses Programm soll Asuro 2000mm geradeaus fahren lassen und soll ihn anhalten lassen, wenn ein Schalter betätigt wird.

Aber leider funktioniert es nicht. Asuro fährt seine 2000mm, egal ob ein Taster gedrückt wird oder nicht. Wo ist der Fehler?

Gruß farratt

PS: Ich nutze die originale "asuro.h", bin mehr so der Selbermach-typ...

damaltor
17.09.2007, 16:39
du musst in der interruptroutine die motoren auch abstellen... =)

farratt
17.09.2007, 16:42
Stimmt zwar, aber die StatusLED wird nicht rot, also muss irgendwo noch ein fehler sein.

farratt
17.09.2007, 16:54
Wir können mal einen einfacheren Code betrachten:


#include "asuro.h"

int main(void)
{
Init();

StartSwitch();

while(1);
return 0;
}

SIGNAL(SIG_INTERRUPT1)
{
StatusLED(RED);
StopSwitch();
while(1); //Diese Endlosschleife kann man weglassen, oder?
}

Nachdem die Init() ausgeführt wurde, ist die StatusLED krühn.
Der Code sollte die StatusLED auf rot schalten, falls ein Schalter gedrückt wird, tut er aber nich. Sie bleibt grün.

Wo is der Fehler?

Einen Hardware-Fehler kann ich ausschließen, weil die Taster im Polling-Betrieb einwandfrei funktionieren.

damaltor
17.09.2007, 17:26
diese endlosschleife bewirkt, dass die interruptroutine niemals verlassen wird. tödlich!!

ansonsten verwende mal nicht startswitch sondern nutze die register um niterupts zu aktivieren. entferne startswitch und stopswitch, und schreibe stattdessen sei(); hinter init();.

welche version des gcc compilers benutzt du?

KayH
17.09.2007, 17:28
Hi,

da ich leider die ASURO lib nicht kenne, kann ich nur allg. Betrachtungen anstellen. Aber vielleicht hilft das ja schon... ;-)

Die Interrupts muessen auch aktiviert sein, sind sie das auch standardmaessig? Du hast zumindest keinen expliziten Code dafuer ...

Eine Endlosschleife in einer ISR halte ich fuer keine gute Idee. Eine ISR sollte kurz sein, was man von einer Endlosschleife nicht gerade behaupten kann.

Innerhalb einer einfachen ISR wird meisst zunaechst der IRQ disabled um nested IRQs zu vermeiden. Am Ende der ISR wird er dann wieder altiviert.

HTH
Kay

damaltor
17.09.2007, 17:32
irqs sind automatisch deaktiviert beim start der routine. es fehlt jedoch ein return am ende!!!

damaltor
17.09.2007, 17:36
probier mal folgenden code:
[code]#include "asuro.h"

int main(void)
{
Init();
StatusLED(GREEN);

while(1);
return 0;
}

SIGNAL(SIG_INTERRUPT1)
{
StatusLED(RED);
return;
}

KayH
17.09.2007, 17:38
Ich bin mir nicht sicher, sind ISR nicht void Funktionen ...?
Dann braucht man nicht unbedingt ein return, mit verlassen des Blocks kehrt er automatisch zurueck. "return value" braucht man nur zwingend bei nicht void-Funktionen, oder?

Aber es ist zumindest besser zu lesen und macht die Absicht des Entwicklers deutlicher (nicht nur "aus Versehen" zurueck) ...

damaltor
17.09.2007, 17:42
ohne return werden jedoch die interrupts nicht wieder aktiviert...

izaseba
17.09.2007, 17:50
ohne return werden jedoch die interrupts nicht wieder aktiviert...

Wo hast Du diesen Quatsch her ?
Und SIGNAL würde ich mal überdenken, ob es so gut ist.

Gruß Sebastian

farratt
17.09.2007, 17:55
Danke für Eure Hilfe. Aber ich glaub das isses alles nich. Die Interruptroutine wird ja erst gar nicht betreten. Denn dann würde die StatusLED ja rot werden. Außerdem kann man in der asuro.c sehen, dass das Makro sei() der letzte Befehl der Funktion Init() ist. Daran kanns also auch nicht liegen.

damaltor
17.09.2007, 18:07
nu mal langsam... davon bin ich eigentlich recht überzeugt. so wie is im assembler die möglichkeiten RET und RETI gibt, um entscheidenzu können, ob die interrupts wieder aktiviert werden sollen, müsste das eigentlich die möglichkeit in c sein, oder? war mir da ganz sicher, und bin bis jetzt auch immer gut damit gefahren.

und signal ist zwar alt, aber warum sollte es nicht funktionieren? trotzdem ist hier ein paar grundlegende infos, dann sollte es wohl gehen....

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmieren_mit_Interrupts

farratt
17.09.2007, 18:17
Das hab ich alles schon gelesen. Aber wie gesagt, die Routine wird nicht betreten.

Ich persönlich glaube auch, dass man kein return braucht. Sieht man z.B. in der asuro.c:

SIGNAL (SIG_OUTPUT_COMPARE2)
{
count72kHz ++;
}

damaltor
17.09.2007, 18:23
das ist natürlich ein argument...

noch was: ist nicht in der lib schon ein interrupt für die taster drin? hast du diesen auskommentiert? oder sind die taster eigentlich am int0 pin dran...?

izaseba
17.09.2007, 18:23
davon bin ich eigentlich recht überzeugt.
aha, die Aussage beruht also auf Deine Überzeugung ?
Ja super, dann macht mal weiter ;-)
Mehr wollte ich eigentlich nicht wissen
Den Sinn in ret und reti brauchst Du mir auch nicht näherzubringen, oder bist Du auch davon überzeugt, das Du da recht hast ?

Gruß Sebastian

farratt
17.09.2007, 18:37
Ne, die Taster werden mit StartSwitch() an den Int1 gelegt, glaube ich zumindest. Also es steht so im AsuroWiki und wenn ich mir StartSwitch() in der asuro.c angucke, sieht man das da die Schalter auf Int1 gelegt werden.
Der Int0 ist meines Wissens nach auf die CON-Erweiterungsschnittstelle vorne am Asuro gelegt. Außerdem gibt es weiter unten im Forum einen Thread in dem auch mit SwitchStart() und den Schaltern gearbeitet wird.

damaltor
17.09.2007, 19:17
izaseba: beherrsch dich. sprüche helfen hier nicht weiter.

ok, soweit so gut. hast du denn die interruptroutine aus der asuro.c auskommentiert?

farratt
17.09.2007, 19:31
wo muss ich da was auskommentieren? Also mit anderen Worten: Nein, hab ich nicht!

damaltor
17.09.2007, 19:33
ok... öffne doch mal die asuro.c; da müsste glaub ich was sein was mit interrupt1 zu tun hat. wenn du einen solchen abschnitt findest, dann poste ihn doch mal bitte.

farratt
17.09.2007, 19:35
Ich finde einen solchen Abschnitt nicht.

damaltor
17.09.2007, 19:37
ok. welche lib benutzt du? die originale von der c? oder eine heruntergeladene?

farratt
17.09.2007, 19:38
ich benutzte die originale

damaltor
17.09.2007, 19:47
achso, ok. mir ist aufgefallen, dass im programmcode der erweiterten lib zwischen hinter dem wort SIGNAL immer ein leerzeichen ist. ich denke nicht, dass es daran liegt, aber ich habe bei meinen programmen immer das leerzeichen gesetzt und sie gingen alle. könntest du das probieren?

farratt
17.09.2007, 19:51
Nö, es geht nicht. Das hier is mein aktueller Code:

#include "asuro.h"

SIGNAL (SIG_INTERRUPT1)
{
StatusLED(RED);
StopSwitch();
}

int main(void)
{
Init();

StartSwitch();

while(1);
return 0;
}

damaltor
17.09.2007, 19:53
ok.

nimm mal unter die include zeile noch folgendes:
#include <avr/io.h>
#include <avr/interrupt.h>

farratt
17.09.2007, 19:56
diese beiden Zeilen sind in der "asuro.h" bereits drin.
Vielleicht kannst du den Code einfach mal testen? Vielleicht liegts ja doch an meiner Hardware.

izaseba
17.09.2007, 20:01
izaseba: beherrsch dich. sprüche helfen hier nicht weiter.
Was ist los ?
Ich glaube, Du kannst keine Kritik einstecken mein lieber, arbeite mal was daran, bevor Du mir sagst, was ich machen soll :-s

Aber zum Thema:
Mische nicht die Asurolib mit eigenen Sachen, und vor allem nicht mit Interrupts, die in der Lib schon deklariert sind.
Es wundert mich, daß der Kompiler nicht wegen doppelter Deklaration meckert.
Du hast geschrieben, Du machst gerne aller "zu Fuß", also mach das.

Jeder Tastendruck erzeugt eine fallender Flanke an INT1, den Interrupt mußt Du freigeben, Dattenblatt von M8 zur Hand und so geht es :


#include<avr/io.h>
#include<avr/interrupt.h>

ISR(INT1_vect){
PORTB &=~(1<<PB0);
PORTD = (1<<PD2);
}

int main(void) {
DDRB = (1<<PB0);
DDRD = (1<<PD2);
MCUCR = (1<<ISC11);
GICR = (1<<INT1);
sei();
PORTB = (1<<PB0);
while(1);
return 0;
}
sehe auch Dattenblatt m8 Seite 66

Gruß Sebastian

damaltor
17.09.2007, 20:01
ich bin leider nicht in der nähe von meinem elektronik-kram =) sonst gern. lies doch mal den abschnitt des tutorials was ich dir vorhin geschickt habe, und versuche die interruptvektoren auf die "neue" art zu definieren. evtl gehts dann.

wenn deine taster an sich gehen, sollte eigentlich kein fehler auftreten.

farratt
17.09.2007, 20:05
@izaseba: Diese Funktion ISR is in der Lib, die ich verwende nicht enhalten. Außerdem werden in der StartSwitch() die ganzen Sachen deklariert, d.h. ich mische gar nix.

@damaltor: Gelesen hab ichs ja schon.

damaltor
17.09.2007, 20:06
und... probiert? :)
teste das doch mal... wo hast du eigenlich die funktion startswitch her?

farratt
17.09.2007, 20:14
@damaltor: Die Funktion StartSwitch() ist in der originalen asuro.c drin.

@izaseba: Hab deinen Code mal auf meine Syntax umgeschrieben:

#include<avr/io.h>
#include<avr/interrupt.h>
#include<avr/signal.h>

SIGNAL(SIG_INTERRUPT1){
PORTB &=~(1<<PB0);
PORTD = (1<<PD2);
}

int main(void) {
DDRB = (1<<PB0);
DDRD = (1<<PD2);
MCUCR = (1<<ISC11);
GICR = (1<<INT1);
sei();
PORTB = (1<<PB0);
while(1);
return 0;
}

Und er funktioniert nicht!

damaltor
17.09.2007, 20:21
oha... das hatte ich gar nicht mehr in erinnerung... fuktioniert folgender code?



#include "asuro.h"

int main(void){
Init();
StartSwitch();
switched=0;
StatusLED(GREEN);
while(1){
if(switched==1) StatusLED(RED);
}
}

farratt
17.09.2007, 20:23
Der Compiler behauptet, dass die Variable switched nicht deklariert wurde.
Außerdem wird in der StartSwitch() auch auf keine Variable geschrieben, sie ist nur dazu da, um den Int1 auf die Schalter zu legen und den IR-Betrieb zu initialisieren.

damaltor
17.09.2007, 20:25
hm. schlecht.

poste doch mal bitte deine startswitch funktion.

farratt
17.09.2007, 20:28
Hab den oberen Beitrag nochmal editiert...

Hier is die StartSwitch():

void StartSwitch(void)
{
SWITCH_OFF;
DDRD &= ~SWITCHES; // Switches as Input => ext. Int 1
MCUCR &= ~((1 << ISC11) | (1 << ISC10));// Low level generates interrupt
GICR |= (1 << INT1); // Enable external Interrupt 1
}

damaltor
17.09.2007, 20:31
soweit, so gut. ich sehe keine fehler mehr im moment, habe grad mal im irc nach hilfe gefragt. mal sehen was noch kommt...

farratt
17.09.2007, 20:32
Vielleicht findet sich ja jemand, der den code testen würde...

Sternthaler
17.09.2007, 23:23
Gruß an alle.

Interressant!
izaseba gibt für MCUCR an: MCUCR = (1<<ISC11);
Im original Source steht:
MCUCR &= ~((1 << ISC11) | (1 << ISC10));// Low level generates interrupt
(Im Übrigen muss ich damaltor zustimmen, dass Einwände höflicher gestaltet werden können.)

Beim Programmcode kann ich izaseba allerdings nur zustimmen, dass sein Code auf alle Fälle 'richtiger' sein muss. Der INT1-Pin ist, ohne gedrückten Taster, über R24/1K und R23/1M auf U+ gelegt.
Bei gedrücktem Taster, selbst K6 mit nur R30/68K, geht die Spannung auf alle Fälle in Richtung 0 Volt. Somit also tatsächlich eine fallende Flanke. Und damit sollte ISC11=1 und ISC10=0 laut ATmega8-Doku Seite 64, und izaseba, gesetzt werden.

------------------------
Test 1:
Letztes Programm von farratt ohne Motorbewegung, nur mit original Funktionen.
- Asuro einschalten
- LED geht auf gelb (Wartezeit zum download neuer Programme)
- LED geht auf grün (Feststecken in der main() while(1)-Schleife nach dem Init() und StartSwitch()
- beliebige Taste drücken: LED geht auf ROT
Somit ist es erst einmal egal ob fallende oder steigende Flanke (wie im original Source) programmiert ist. Warum ist hier egal.
Somit ist auch festgestellt, dass das Programm grundsätzlich funktioniert.

------------------------
Test 2:
Da ich die Funktion fahren() von farratt nicht habe, fahre ich nach Init() und StartSwitch() einfach mit MotorDir(FWD,FWD); und MotorSpeed(180,180) einfach so los.
In der Interruptfunktion dann natürlich noch ein MotorSpeed(0,0).
- Asuro einschalten
- LED geht auf gelb (Wartezeit zum download neuer Programme)
- LED geht auf grün (Feststecken in der main() while(1)-Schleife nach dem Init() und StartSwitch() und Motoren drehen
- beliebige Taste drücken: LED geht auf ROT und Motoren stoppen

Fazit:
Mein Asuro schafft das gewünschte Problem zu bearbeiten.

Was kann kaputt sein?
Ich tippe auf eine unterbrochene Verbindung beim Widerstand R23/1M, da die Ermittlung der Tasten ja geht, aber der Widerstand R23 ja nur parallel zum R24/1K bei der Tastenmessung zu Buche schlägt, und sich dort somit fast nicht auswirkt.
Ist die Verbindung aber unterbrochen, könnte es sein, dass dies vom AVR schon als LOW-Pegel 'gesehen' wird, und somit ein Tastendruck nicht noch mehr LOW erzeugen kann, und somit keine fallende Flanke am AVR ankommt.
Messen kann man dies so:
- AVR aus dem Sokel nehmen.
- Asuro einschalten
- Spannung zwischen Pin 1 (V+) und Pin 27 (PC4/ADC4) messen. Sollten mehr als 3 Volt sein.

P.S.: Noch ein Wort zu SIGNAL() bzw. dem wohl gemeinten INTERRUPT().
SIGNAL() hat ja die nette Eigenschaft, dass der gerade laufende Interrupthandler NICHT durch weitere Interrupts unterbrochen wird. Somit ist das Handling über dieses Macro auf alle Fälle überschaubarer.
Wer sich auf INTERRUPT() einläßt, muss schliesslich noch mit gestaffelten Aufrufen rechnen, die auch noch, durch die in der Hardware festgelegte Priorität der Interrupts, nicht immer gestaffelt auftreten müssen. Dies dürfte hier aber nicht für jederman handelbar sein, und würde in diesem Fall auch keine Vorteile, geschweige den funktionierendes Verhalten, bringen.

farratt
18.09.2007, 12:05
[flüster]Das Programm läuft bei dir und bie mir nicht?[/flüster]

wuhaaaaaa...waruuuum?

also zwischen Pin1 und Pin27 messe ich knapp 4,9V

farratt
18.09.2007, 12:17
Ich hab mal noch die Spannung zwischen Int1 (Pin5) und GND(Pin8) gemessen. Sie beträgt ebenfalls knapp Vcc, egal ob ich einen Taster drücke oder nicht. eigentlich sollte da aber die Spannung fallen, stimmts?

damaltor
18.09.2007, 14:01
drück mal mehrere taster gleichzeitig (tesafilm...) und miss dann nochmal. spätestens jetzt sollte die spannung doch deutlich abfallen.

farratt
18.09.2007, 14:55
nein die spannung bleibt bei Vcc. was soll ich tun?

farratt
18.09.2007, 14:56
nein die spannung bleibt bei Vcc. was soll ich tun?

damaltor
18.09.2007, 16:03
flashe nochmal den selbsttest. passen die aktionen beim switch test zu den in der anleitung beschriebenen? also dass die richtigen leds leuchten usw?

farratt
18.09.2007, 16:10
Im Selbsttest funktioniert alles exakt so, wie in der Anleitung beschrieben.
(Habs grade getestet)

izaseba
18.09.2007, 16:25
Hallo,
prüfe nochmal Verbindungen zwischen Int1 und den Tastern, irgendwo hast Du wohl eine Unterbrechung, Die Spannung muß auf jeden Fall Fallen, wenn Du eine der Tasten drückst.
Noch ein Wort zu Flanken und Level interrupts.
Ich habe bewusst Flankeninterrupt gewält, aus den einfachem Grund, daß ein Lowlevelinterrupt solange ausgeführt wird, bis man die Taste wieder losläßt(Es sei denn, man schaltet den in der ISR ab).
Es kann dann zu unerwünschten Nebeneffekten kommen, daß der Interrupt 100,1000,10000 ausgelöst wird, obwohl man das garnicht will.
Bei Flankensteuerung kommt der Interrupt genau einmal(es sei die Taste prellt),

Gruß Sebastian

farratt
18.09.2007, 16:39
Leute, ich hab den Fehler gefunden. Ich R24 und R11 falsch eingelötet...#-o
Danke für Eure großartige Hilfe!

izaseba
18.09.2007, 16:40
Ich habe es doch noch gefunden ;-)
hier (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=10101&highlight=asuro+assembler) habe ich ein Programm geschrieben, das die ADC Werte von den Tastern über UART an den Computer schickt.
Ich habe da auch nur den INT1 benutzt, schau mal, ob es bei Dir funktioniert, wenn nicht, liegt es 100% an der Hardware
Es ist zwar in Assembler geschrieben, ich habe aber auch eine hex geschickt.

Gruß Sebastian

P.S. da war ich doch etwas zu langsam...

damaltor
18.09.2007, 21:03
sehr gut... so kleine fehler dauern lange =)

Sternthaler
18.09.2007, 21:30
@farratt
UFF, das war aber eine schwere Geburt. Hauptsache es geht nun.
Ja, dass konnte nicht gut gehen, wenn der 1k-Widerstand gegen popelige 100 Ohm ausgetauscht wurde. Herr Ohm würde da auch keine fallende Flanke oder einen LOW-Pegel ausrechnen.

farratt
19.09.2007, 11:03
Na vertauscht ist nicht unbedingt das richtige Wort. Wenn du deinen Asuro mal so vor dich hinstellst, dass die Achse links ist und der Atmega rechts ist, dann siehst du, dass die Widerstände R11 und R24 "zeilenweise" eingelötet sind und ich hab sie dummerweise "spaltenweise" eingelötet.

damaltor
19.09.2007, 11:15
oha.. das kenn ich... =)

Sternthaler
19.09.2007, 19:53
@farratt
macht nix, wie du siehst, schaffen wir alle zusammen eine Fernwartung, ohne dass du deinen Asuro erst beim Mediamarkt für 13,5 Wochen einschicken musst ;-)

@damaltor
Du auch? Ich auch! (Zum Glück nicht beim Asuro)

damaltor
19.09.2007, 20:01
tja... also wiederstände "kreuzweise" einzulöten ist wirklich ein schneller fehler, en man nur sehr schwer findet. besonders auf lochraster, wenn viel beieinander ist, auf der unterseite pins zu vertauschen passiert öfter mal... =)