Forum: Mikrocontroller und Digitale Elektronik kleines C-Problem


von Jürgen (Gast)


Lesenswert?

Hallo,

vielleicht kann jemand mal einen kurzen, aber fachmännischen Blick auf
den unten stehenden Code werfen, den ich bewusst extem einfach gehalten
habe. Und trotzdem funktioniert es nicht nach meinen Vorstellungen. In
"main()" wird eigentlich nur der externe Interrupt INT0 initialisiert
und dann gewartet. Der Sprung in die Routine klappt auch, allerdings
lande ich beim Rücksprung wieder bei "int i=0" in "main()".
Eigentlich müsse ich aber doch immer in der Endlosschleife "while
(1)" landen. Das Ganze läuft auf dem ICCAVR von Imagecraft.
Weiß jemand, warum dem nicht so ist?

vielen Dank

Jürgen

________________________________________________

#include <iom8535v.h>
#pragma interrupt_handler  INT0_handler:    INT0

void INT0_handler (void);
void init (void);

void main (void)
{
    int i=0;

   MCUCR = 0x03;
   SREG |= 0x80;
   GICR = 0x40;

   while (1);
}

void INT0_handler(void)
{
 i++;
}

von leo9 (Gast)


Lesenswert?

ich kann zwar kein c, aber in den anderen Sprachen (asm und Bascom)
brauchen die interruptroutinen einen expliziten reti.
Könnte vielleicht eine Lösungsidee sein??

grüsse leo9

von Jürgen (Gast)


Lesenswert?

Hallo Leo,

vielen Dank für dein Antwort. Ein "reti"-Befehl dürfte nicht nötig
sein.

Jürgen

von Tux (Gast)


Lesenswert?

Hallo Jürgen,

kann es sein, dass du "int i" global, d.h. außerhalb von main
deklarieren musst?

Tux

von Matthias (Gast)


Lesenswert?

Hi

<glaskugelmode>
Meaga128? Simulation oder Hardware? Wenn Hardware und Mega128 ist die
M103C-Fuse gesetzt.
</glaskugelmode>

Matthias

von Jürgen (Gast)


Lesenswert?

Hallo,

@Tux: Auch eine globale Variable löst das Problem nicht

@Matthias: Hardwaremäßig habe ich es ehrlich gesagt noch nicht
ausporbiert. Es handelt sich um einen Atmega8535.

von Ralf (Gast)


Lesenswert?

Hi,

hast Du schonmal ins listing des Compilers geschaut? Da erkennt man oft
mehr. Vielleicht muss man die Interrupt-Routine anders deklarieren. Ich
denke allerdings auch, dass i global sein muss.

Viele Grüße,

Ralf

von crazy horse (Gast)


Lesenswert?

muss ja global sein, sonst hätte der Compiler das ja nicht übersetzt,
was soll er denn mmit i++ machen, wenn er i nicht kennt?
Was mich wundert: wieso steht da zweimal: "void INT0_handler(void)",
müsste doch auch einen Compilierungsfehler erzeugen?

von Jürgen (Gast)


Lesenswert?

Hallo,

"void INT0_handler(void)" kommt zweimal vor, da es sich beim ersten
mal um die Deklaration, beim zweiten mal um die Definition handelt. Ich
hoffe ich bring nicht alles durcheinander :) Jedenfalls denke ich, das
hat seine Richtigkeit. Es wird ja alles fehlerfrei compiliert und ich
kann ja bis auf den Rücksprung aus der Routine alles einwandfrei
simulieren.

Jürgen

von AndreasH (Gast)


Lesenswert?

Ich kenne den ICCAVR nicht.
Aber mach doch testweise einfach mal das int i = 0; in der main weg.

Ich vermute mal, daß dir der Debugger dieses i anzeigt. Das ist aber
nur lokal in main. Bei dem anderen muß es sich um eine andere Variable
handeln. Wo die allerdings deklariert wird weiss ich nicht.

von Manuel (Gast)


Lesenswert?

Ich habe mit _SEI immer alle Interrupts freigegeben

von Mehmet Kendi (Gast)


Lesenswert?

Variable i ist in main deklariert, weshalb es in der Interrupt-Funktion
gar nicht sichtbar ist. Eigentlich haette der Compiler hier ein Error
ausgeben muessen.
Wenn Du i ausserhalb von main deklarierst, sollte es klappen.

MfG

von Marcel (Gast)


Lesenswert?

Hallo Juergen,

ich kenne mich zwar nicht mit dem ICCAVR aus, aber beim avrgcc werden
Konstrukte wie while (1) z.T. wegoptimiert, wenn man die Optimierung
nicht explizit ausschaltet.

Ich verwende im Hauptprogramm meistens solche Schleifen

for(;;){
tastenabfrage();
warten(x);
}

Hoffe, dir weitergeholfen zu haben.

MfG

Marcel

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

while(1) sollte auf keinen Fall wegoptimiert werden, warum auch?

von MooseC (Gast)


Lesenswert?

Hi Jürgen,

Du deklariert falsch.
Du schreibst:

#pragma interrupt_handler  INT0_handler:    INT0

richtig ist aber
#pragma interrupt_handler  INT0_handler:iv_INT0

wenn Du nur INT0 schreibst wird der Interruptvektor Nr.6
benutzt, also iv_TIMER1_CAPT. Du willst aber ja iv_INT0
und der hat laut der #include <iom8535v.h> die Nr. 2!

siehe unten:


#define iv_RESET        1
#define iv_INT0         2    <----------- richtig
#define iv_INT1         3
#define iv_TIMER2_COMP  4
#define iv_TIMER2_OVF   5
#define iv_TIMER1_CAPT  6    <----------- falsch
#define iv_TIMER1_COMPA 7
#define iv_TIMER1_COMPB 8
#define iv_TIMER1_OVF   9
#define iv_TIMER0_OVF   10
#define iv_SPI_STC      11
#define iv_UART_RX      12
#define iv_UART_RXC     12
#define iv_UART_DRE     13
#define iv_UART_UDRE    13
#define iv_UART_TX      14
#define iv_UART_TXC     14
#define iv_ADC          15
#define iv_EE_RDY       16
#define iv_EE_READY     16
#define iv_ANA_COMP     17
#define iv_ANALOG_COMP  17


#define    INT0     6   <--------- hier kommt die "falsche" 6 her


MooseC

von Jürgen (Gast)


Lesenswert?

Hallo MooseC,

bei mir stehen folgende Interrupt_Vektoren in der include-Datei
"iom8535v.h":
__________________________________________________
/* General Interrupts */
#define GIFR  (*(volatile unsigned char *)0x5A)
#define  INTF1    7
#define  INTF0    6
#define  INTF2    5
#define GIMSK  (*(volatile unsigned char *)0x5B)
#define GICR  (*(volatile unsigned char *)0x5B)
#define  INT1     7
#define  INT0     6
#define  INT2     5
#define  IVSEL    1
#define  IVCE     0
____________________________________________________

Ich verstehe nicht, woher du da iv_INT0 nimmst.
Aber wie ich sehe liegt das Problem wohl eher beim Simulieren mit
AVR-Studio. Selbst bei unten stehendem "Progrämmchen" stimmt der
gelbe Pfeil mit den Tatsachen überhaupt nicht überein.
#include <iom8535v.h>
___________________________
void main ()
{
   MCUCR = 0x03;
   SREG |= 0x80;
   GICR = 0x40;

   while (1);
}
____________________________
Wenn ich mir das Ganze aber in der "Disassembler"-Ansicht ansehe,
dann sehe ich, dass das Programm richtig abläuft, während sich der
gelbe Pfeil in der Normalansicht ausserhalb des Codes befindet.
Naja, da kann ich wohl nicht viel machen. Vielleicht mal sehen, ob es
bei Atmel irgendwelche Updates vor das Studio gibt.

Jürgen

von Olaf (Gast)


Lesenswert?

Hallo Jürgen,

du kannst in einer Interrupt-Routine nur auf globale Variablen
zugreifen und diese müssen dann auf jeden Fall als "volatile"
deklariert sein. Damit wird angegeben, dass die Variable auch außerhalb
des normalen Programmablaufs geändert werden kann (-> in einer
Interrupt-Routine).

volatile int i;

Gruß,
Olaf

von Jürgen (Gast)


Lesenswert?

Hallo Olaf,

mir gehts nicht so sehr um den Zugriff auf Variablen. Das Beispiel habe
ich rein zufällig so gewählt. Von mir aus macht die Routine auch
nichts. Das komische ist halt der Rücksprung, da der nicht richtig
erfolgt.
Tja, so wurde aus meinem kleinen C-Problem doch ein großes :)

Jürgen

von Olaf (Gast)


Lesenswert?

... ein wirkliches Problem gibt es hier anscheinend gar nicht. Wenn man
"Schrott" (Entschuldigung für diesen Ausdruck) programmiert, dann
darf man sich auch nicht über das Verhalten des Debuggers wundern
(unabhängig davon, ob und warum und wie der Code übersetzt wurde). Du
schraubst ja auch nicht einfach ein viereckiges Rad an dein Auto und
wunderst dich danach über die komischen Fahreigenschaften, gell?

Vielleicht verhält der Debugger sich so wie du es erwartest, wenn du es
mit einem vernünftigen Programm probierst ;o)

Gruß,
Olaf

von Jürgen (Gast)


Lesenswert?

Hallo,

@Olaf: Vielen Dank für diese unglaublich geistreichen Ausführungen.

von MooseC (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Jürgen,

>>bei mir stehen folgende Interrupt_Vektoren in der include-Datei
"iom8535v.h":
>>____________________________________________________
/* General Interrupts */
#define GIFR  (*(volatile unsigned char *)0x5A)
#define  INTF1    7
#define  INTF0    6
#define  INTF2    5
#define GIMSK  (*(volatile unsigned char *)0x5B)
#define GICR  (*(volatile unsigned char *)0x5B)
#define  INT1     7
#define  INT0     6
#define  INT2     5
#define  IVSEL    1
#define  IVCE     0
____________________________________________________

>>Ich verstehe nicht, woher du da iv_INT0 nimmst.

Hmm, das sind nicht die Interruptvektoren, sondern Bitdeklarationen
einiger im Mega8535 vorhandenen Interruptbits für Flags und Enable.

Die Interruptvektoren heißen in der iom8535v.h vom ICCAVR auch so -
siehe Anhang ganz unten.

Dein Vektor ist auf jeden Fall mit INT0 verkehrt, da es mit 6 nicht den
Vektor beschreibt, sondern das Enblebit im GICR.


MooseC

von Jürgen (Gast)


Lesenswert?

Hallo MooseC,

wenn ich heute heimkomme, schau ich mir das nochmal genauer an.
Vorerst einmal vielen Dank für deine Hilfe. Irgendwie wirds dann schon
noch klappen.

Jürgen

von André (Gast)


Lesenswert?

Ich kenn mich mit uController nicht gut aus.

Aber sollte nicht in der interrupt routine am ende ein "return "
stehen?

Ich vermute mal, da du die interupt routine vor main inizierst, dass
der Code im speicher des controllers vor der main steht und du dann
logischerweise immer am anfang der main landest nachdem der interrupt
ausgefürt wurde.

von Jürgen (Gast)


Lesenswert?

Hallo,

an alle vielen Dank für die Unterstützung. Hat mir geholfen, Neues zu
lernen und mein Problem zu lösen.

@MooseC: Natürlich hast du recht, die Sache mit den Interruptvektoren
habe ich total verpeilt :)

Die Simulation mit AVR Studio hat nur nicht geklappt, weil man die
Datei \icc\libsrc.avr\iostudio.s aus dem icc-Ordner in den den
aktuellen Projektordner kopieren muss. Diese Information habe ich erst
heute in der Hilfe gefunden.

Trotzdem noch mal vielen Dank an alle.

Jürgen

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.