Forum: Compiler & IDEs Input Capture Interrupt Problem


von Witali G. (witali)


Lesenswert?

Hallo!

Ich wäre euch sehr dankbar für jeden Hinweis. Ich bin gerade dabei, mir 
die Interrupt-Programmierung mit Hilfe von dem GCC-Tutorial 
beizubringen. Habe den entsprechenden Teil gelesen und ein Programm für 
ATMega168 geschrieben (einfach nur zum lernen). Jetzt versuche ich das 
Programm mit dem Simulator zu simulieren und habe folgendes Problem: Bei 
der Simulation der Flanke am ICP springt der Simulator nicht zum 
ISR-Code sonder zum Anfang von main und beginnt von vorne. Ich verstehe 
nicht was ich falsch gemacht habe.

von Witali G. (witali)


Lesenswert?

Sorry, den Code vergessen!


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

int main(void)
{
  sei();
  TIMSK1 = 0x08;
  TCCR1B = 0x82;
  while (1)  { }
  return 0;
}



ISR(TIMER1_CAPT_vect)
{
  DDRD = 0xff;
  PORTD = 0xff;
}

von Johannes M. (johnny-m)


Lesenswert?

Du hast den falschen Interrupt freigegeben! Bitte gewöhn Dir gleich eine 
lesbarere Schreibweise für die I/O-Register an, siehe 
Bitmanipulation. Wenn Du geschrieben hättest
1
TIMSK1 = 1 << ICIE1;
dann wäre alles i.O. und ich hätte nicht erst im Datenblatt nachsehen 
müssen, was Du da eigentlich gemacht hast. Das Bit, das Du gesetzt hast, 
ist ein reserviertes (nicht belegtes) Bit. Das hätte Dir aber auch im 
I/O-View im Simulator auffallen können...

von Witali G. (witali)


Lesenswert?

Vielen Dank für die schnelle Antwort. Ich habe mich nach der 
Bitreihenfolge im Tutorial gerichtet und habe nicht beachtet, dass der 
ICIE-Bit bei 168 woanders sein kann. Ich werde es gleich mal 
ausprobieren. Besten Dank.

von Johannes M. (johnny-m)


Lesenswert?

Witali Gustschin wrote:
> Vielen Dank für die schnelle Antwort. Ich habe mich nach der
> Bitreihenfolge im Tutorial gerichtet und habe nicht beachtet, dass der
> ICIE-Bit bei 168 woanders sein kann.
Eben deshalb immer die Schreibweise mit Bitnamen verwenden. Da ist es 
für den Programmierer völlig egal, an welcher Stelle das Bit wirklich 
steht und solche Sachen passieren einfach nicht. Man muss dann natürlich 
noch wissen, in welchem Register das Bit steht, aber das ist ja 
zumindest in Deinem Fall korrekt...

von Johannes M. (johnny-m)


Lesenswert?

Ist mir grad noch aufgefallen:
Die globale Interrupt-Freigabe mit sei() sollte man erst dann machen, 
wenn man alle I/O-Register initialisiert hat! Wenn man das schon vor der 
Initialisierung macht, kann es zu unschönen Nebeneffekten kommen.

von Witali G. (witali)


Lesenswert?

Danke für den Hinweis! Ich habe den Code entsprechend geändert. Es sieht 
jetzt so aus:

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

int main(void)
{
  TIMSK1 = 1 << ICIE1;
  TCCR1B = ((1 << ICNC1) | (1 << CS10));
  sei();
  while (1)  { }
  return 0;
}



ISR(SIG_INPUT_CAPTURE1)
{
  DDRD = 0xff;
  PORTD = 0xff;
}

Wenn ich jetzt im Simulator eine Flanke am ICP (Port B, Bit 0 laut 
Datenblatt) simuliere wird die Endlosschleife zwar verlassen aber der 
Pfeil springt nicht wie erwartet zum ISR-Code sonder zum Anfang von main 
und beginnt von vorne.

von Witali G. (witali)


Lesenswert?

Vielleicht muss ich irgendwelche Dateien einbinden oder so. Ich habe da 
zwar gar keine Ahnung aber wo wird die Funktion ISR definiert? Ich habe 
in den Projektdateien im Ordner External Dependancies geschaut und nicht 
mit ISR gefunden.

von Heiko_S (Gast)


Lesenswert?

Wenn ich mich recht erinnere, heisst der Interrupt "TIMER1_CAPT_vect". 
Ist in der avr/interrupt.h definiert.

von Jojo S. (Gast)


Lesenswert?

wenn du das mit dem AVRStudio gemacht hast: da gibt es zwei Stellen wo 
der Zeilprozessor eingestellt wird: in den 'Projekt / Configuration 
Options' und unter 'Debug / Select Platform and Device'. In den 
Projektoptionen ist es wichtig damit richtig compiliert wird, es wird 
ein define gemacht und das wird z.B. im io.h abgefragt. Die andere 
Einstellung ist für den Simulator damit die richtige Hardware 
eingestellt wird.

von Jojo S. (Gast)


Lesenswert?

die Int-Vektoren sind Deviceabhängig und beide Namen liefern das gleiche 
Ergebniss. Im gcc und den Libs wird gerne mal was umbenannt bei neueren 
Versionen.

von Witali G. (witali)


Lesenswert?

Ich habe jetzt nochmal nachgeschaut, Debug platform und Device sind 
schon richtig eingestellt, die habe ich noch beim Erstellen des Projekts 
eingestellt.

von Karl H. (kbuchegg)


Lesenswert?

Schuss ins Blaue:

Dreh mal hier

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

die Reihenfolge um.

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

Die io.h stellt ein paar Makros bereit, die ja nach eingestelltem
Prozessortyp variiert werden. Wenn interrupt.h davon abhängt
dann hat er mit der falschen Reihenfolge die falsche Einstellung.

von Jörg X. (Gast)


Lesenswert?

Die ISR heißt "ISR(TIMER1_CAPT_vect)" (kann man aus dem Namen im 
Datenblatt 'basteln', steht außerdem in <avr/iomx8.h>, DIE datei wird 
aber automatisch eingebunden, die sollst DU NICHT einbinden).

Mach mal aus der Endlos-Schleife ein
1
//...
2
  while(1) {
3
    asm volatile ("nop");
4
  }
5
/*ODER*/
6
#define DEBUG_NOP() asm volatile ("nop") 
7
8
  while(1) {
9
    DEBUG_NOP();
10
  }
dann hast du ein bischen Zeit den pin zu togglen.

hth. Jörg

von Jojo S. (Gast)


Lesenswert?

habe die 2. Version ins AVRStudio reinkopiert und es funktioniert ohne 
Probleme. Der Interrupt wird nur bei der fallenden Flanke am PB.0 
ausgelöst, für die steigende Flanke muss noch das Bit ICES1 im TCCR1B 
gesetzt werden.

von Witali G. (witali)


Lesenswert?

an Jahannes Stratmann

Und die ISR-Routine wird auch abgearbeitet? Bei mir wird der Interrupt 
auch ausgelöst, also die while-Schleife wird bei fallender Flanke 
verlassen. Nach Verlassen der Schleife sollte der Pfeil doch in die 
ISR-Routine springen, oder? Stattdessen springt er bei mir an den Anfang 
von main.

von Jörg X. (Gast)


Lesenswert?

1
#include <avr/interrupt.h>
2
#include <avr/io.h>
3
4
int main(void)
5
{
6
  TIMSK1 = 1 << ICIE1;
7
  TCCR1B = ((1 << ICNC1) | (1 << CS10));
8
  sei();
9
  while (1) {
10
  //sogar das geht ;)
11
    asm volatile(";");
12
  }
13
  return 0;
14
}
15
16
ISR(TIMER1_CAPT_vect)
17
{
18
  DDRD = 0xff;
19
  PORTD = 0xff;
20
}

So geht's bei mir (wenn man PINB0 togglet)

hth. Jörg
evtl. hilft ja ein "make clean" bzw. "clean current configuration"

von Witali G. (witali)


Lesenswert?

An Jörg X.

Und die ISR-Routine wird auch angesprungen und abgearbeitet?

Wie mache ich "make clean" bzw. "clean current configuration"?

Danke für die Antwort

von Jörg X. (Gast)


Lesenswert?

Die ISR wird angesprungen und auch korrekt wieder verlassen.

>Wie mache ich "make clean" bzw. "clean current configuration"?

Wenn du das AVR-Studio zum Programmieren/compilieren nutzt, führen viele 
Wege nach Rom ;) :
 - F12
 - "Build"->"Clean"
 - das blaue Kreuz, in der GCC-Tool bar

hth, Jörg

von Witali G. (witali)


Lesenswert?

Sagt mal, woher weiß der Compiler was ISR(..) bedeutet? Das sollte doch 
eigentlich in irgend einer in das Projekt eingebundener Datei definiert 
sein, oder??? Ich habe alle eingebundenen Dateien durchsucht und keine 
Definition für ISR gefunden. Oder verstehe ich etwas falsch?

Ich habe im Code ISR einfach durch Klaus ersetzt und der Compiler frist 
es und bringt keine Fehlermeldungen. Ist das normal?

von Witali G. (witali)


Angehängte Dateien:

Lesenswert?

Meine Projekt-Dateien schauen so aus.

von OliverSo (Gast)


Lesenswert?

Leider weiß der Compiler nichts von Interrupt-Funktionen. Wenn du da 
Klaus hinschreibst, findet er halt eine Funktion mit Namen Klaus, was 
ihn höchsten zu der Warnung veranlasst, daß die nicht vorher deklariert 
wurde. Nur wird eine Funktion Klaus niemals vom Interrupt angesprungen.

Die "Magie" einer Interruptfunktion steckt im Makro ISR, das in 
<avr/interrupt.h> definiert ist, und in den Makros für die 
Interruptnamen. Die sind prozessorabhängig, und daher muß vor 
<avr/interrupt.h> <avr/io.h> eingebunden sein, damit das funktioniert. 
Es ist eigentlich nie verkehrt, <avr/io.h> immer als oberstes #include 
hinzuschreiben.

Verschreibt man sich bei ISR oder dem Interruptnamen, wird das 
entsprechende Makro nicht ausgeführt. Für den Compiler steht dann da 
eine normale Funktion.

Oliver

von Witali G. (witali)


Lesenswert?

ich dachte, bei einem unbekannten Ausdruck wird der Compiler eine 
Fehlermeldung bringen, wie ich es aus Visual C++ kenne. Er bringt nicht 
einmal die Warnung dass Klaus nicht deklariert wurde.

Zwei Warnungen meldet er:

../ds.c:21: warning: return type defaults to `int'
../ds.c: In function `Klaus':

../ds.c:24: warning: control reaches end of non-void function

von Karl H. (kbuchegg)


Lesenswert?

Witali Gustschin wrote:
> ich dachte, bei einem unbekannten Ausdruck

wo ist denn da eine unbekannter Ausdruck?

Da ist nichts unbekannt!
Du definierst eine Funktion!

> Zwei Warnungen meldet er:
>
> ../ds.c:21: warning: return type defaults to `int'
> ../ds.c: In function `Klaus':

Alleine diese Warnung muss dich schon stutzig machen.
Eine ISR hat keinen Returntyp (void Funktion).
Wenn der Compiler da also laut Standardregeln eine int
Funktion daraus macht, dann hat er das ISR Makro nicht
richtig gesehen.

Dinge auf die man aufpassen muss
* #include <avr/io.h>
  #include <avr/interrupt.h>

  Am besten in der Reihenfolge, dann kann schon mal mit der
  Prozessorerkennung nicht viel schief gehen

* Der Name des Vectors in der ISR muss stimmen.
  Nicht darauf verlassen, dass der Compiler schon meckern
  wird. Lieber 3 mal (mit der prozessorspezifischen ioxxx.h)
  abklären, ob der Name stimmt. Im AVR Studio wird der der
  Name der Prozessorspezifischen ioxxx.h nach dem ersten
  Compilieren unter 'External Dependencies' angezeigt und
  lässt sich von dort aus auch öffnen.

* Sowohl beim Compiler als auch beim Simulator muss der
  übereinstimmende, korrekte Prozessor eingetragen sein.

* Bei der Interruptfreigabe darauf achten, dass auch der
  richtige Interrupt durch schreiben des richtigen Wertes
  in das richtige Register freigegeben wird

* Nur die Interrupts freigeben, für die auch tatsächlich eine
  ISR existiert

* sei() muss aufgerufen werden

Wenn diese Dinge stimmen, dann kann eigentlich nichts mehr
schief gehen. Es sei denn bei der Installation des Compilers
bzw. AVR-Studio ist irgendetwas schief gelaufen.

von Witali G. (witali)


Lesenswert?

>
> Alleine diese Warnung muss dich schon stutzig machen.
> Eine ISR hat keinen Returntyp (void Funktion).
> Wenn der Compiler da also laut Standardregeln eine int
> Funktion daraus macht, dann hat er das ISR Makro nicht
> richtig gesehen.


Wo sieht der Compiler das ISR Makro und was mache ich damit er das 
richtig sieht?

>
> Wenn diese Dinge stimmen, dann kann eigentlich nichts mehr
> schief gehen. Es sei denn bei der Installation des Compilers
> bzw. AVR-Studio ist irgendetwas schief gelaufen.

Es sollte doch eigentlich alles stimmen. Es haben einige hier meinen 
Code auf ihren Rechnern im AVR-Studio simuliert und es ging problemlos.

Wie kann die Installation z. B. schief gelaufen sein? Was sollte man bei 
der Installation beachten, dass alles in Ordnung ist?

Danke

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Witali Gustschin schrieb:

> Es sollte doch eigentlich alles stimmen. Es haben einige hier meinen
> Code auf ihren Rechnern im AVR-Studio simuliert und es ging problemlos.

Ich sehe keinen richtigen Code von dir. Deine Angaben zu Code sind 
alle von anderen geäandert und kommentiert worden. Hast du mal den Code 
von anderen simuliert?

von Jojo S. (Gast)


Angehängte Dateien:

Lesenswert?

doch, Witali hat im 7. Posting seinen Code geschrieben, und der läuft 
auch hier. AVRStudio 4.13 und gcc von 2007/12.
Die ISR-Vektornamen sind auch beide ok, werden aus iom8x.h geholt:
/* Timer/Counter1 Capture Event */
#define TIMER1_CAPT_vect    _VECTOR(10)
#define SIG_INPUT_CAPTURE1    _VECTOR(10)

Ich habe beim Simulator das 'View / Disassembler' eingeschaltet, da 
sieht man besser was passiert. Nach dem rücksetzen von PB.0 braucht man 
noch 4 Einzelschritte bis die ISR angesprungen wird.

von Witali G. (witali)


Lesenswert?

An  Johannes Stratmann

Ich habe WinAVR installiert und AVR-Studio benutzt den Compiler daraus. 
Vielleicht ist das die Ursache warum es bei mir nicht geht, obwohl es 
bei dir geht.

von Witali G. (witali)


Lesenswert?

Hurra!!!

Ich habe jetzt auf meinem privaten Rechner ausprobiert und das 
funktioniert. Die Versuche davor habe ich auf dem Rechner in der Arbeit 
durchgeführt. Jetzt  ist zumindest klar, dass auf dem Notebook dort mit 
der Installation was nicht in Ordnung ist. Ich werde morgen WinAVR und 
AVR-Studio neu installieren. Ich danke euch allen für eure 
Unterstützung. Einfach Spitze, dass es hier diese Seite und euch alle 
gibt, die sich für einen Anfänger wie ich Zeit nehmen.

VIELEN HERZLICHEN DANK!!!!!!!!

von OliverSo (Gast)


Lesenswert?

Die sicherste Methode zur Überprüfung, ob bei er Deklaration der ISR 
alles in Ordnung ist, ist ein Blick in das .lss-File. Da sieht man die 
Vektortabelle, die defaultmässig mit <__bad_interrupt> gefüllt wird.

00000000 <__vectors>:
   0:  0c 94 2a 00   jmp  0x54  ; 0x54 <__ctors_end>
   4:  0c 94 47 00   jmp  0x8e  ; 0x8e <__bad_interrupt>
   8:  0c 94 47 00   jmp  0x8e  ; 0x8e <__bad_interrupt>
...
50:  0c 94 47 00   jmp  0x8e  ; 0x8e <__bad_interrupt>

Hat alles mit der oder den ISR's geklappt, finden sich da die 
entsprechenden <_vector_xx>-Einträge.

Oliver

von Witali G. (witali)


Lesenswert?

aha...  und wo finde ich dieses .lss-File

von Johannes M. (johnny-m)


Lesenswert?

Witali Gustschin wrote:
> aha...  und wo finde ich dieses .lss-File
Wenn du mit AVRStudio arbeitest, dann musst Du erstmal dem Programm 
erklären, dass Du überhaupt ein .lss-File haben möchtest. Standardmäßig 
wird das nämlich nicht erzeugt. Also unter "Project | Configuration 
Options" in dem Tab "General" unten bei "Generate List File" ein Häkchen 
machen. Das List-File wird dann im selben Verzeichnis wie das Projekt 
(Sourcecode) abgelegt. Im Project-Tree im AVRStudio kannst Du es dann 
unter "Other Files" finden.

von Witali G. (witali)


Lesenswert?

Danke für den Hinweis!!!

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.