www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik atmel ruft ungewollt nach ISR eine selbstgeschriebene init routine auf


Autor: slorenz (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, liebe Gemeinde,

ich erlaube mir, eine Frage zu ISR gesteuerten PORT änderungen zu 
stellen.
Ich benutze das AVR STudio 4.13.528 mit c - Programmierung.

Prinzipiell scheinen die Port - Bits wie gewünscht (z.B. 1 s - hier 
nicht unbedingt diese Zeit) getoggled zu werden - Prescaler und Timer 
arbeiten.
Allerdings verstehe ich nicht, warum meine initialisierende Routine 
immer wieder aufgerufen wird.
Ich würde erwarten, dass die main Routine in der Enlosschleife 
weiterläuft,
aber ohne die init Routine aufzurufen.
Nach meinem Verständnis habe ich dem Prozessor über die Variable 
go2initial
nach dem ersten Aufruf untersagt, sich wieder zu initialisieren (meine 
initialisierungs- Routine).
Was mache ich falsch / wo liegt mein Denkfehler?
Ich muß hier doch nicht etwa mit "Bootloader " arbeiten?

Ich bedanke mich schon jetzt Recht herzlich.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Als allererstes:
Rücke deinen Code ein!
Ein optisch einigermassen ansprechender Code ist nicht einfach nur eine 
Fleissaufgabe, sondern hilft auch Fehler zu finden!
//#include <avr/io.h> 

aus welchem Grund benutzt du io.h nicht?
Das ist mehr als unklug! Das ist sogar ziemlich dämlich!
#define INT0_vect _VECTOR(1)
#define INT1_vect _VECTOR(2)
#define TIMER2_COMP_vect _VECTOR(3)
#define TIMER2_OVF_vect  _VECTOR(4)
#define TIMER1_CAPT_vect _VECTOR(5)
#define TIMER1_COMPA_vect _VECTOR(6)
#define TIMER1_COMPB_vect _VECTOR(7)
#define TIMER1_OVF_vect  _VECTOR(8)
#define TIMER0_OVF_vect  _VECTOR(9)
#define SPI_STC_vect _VECTOR(10)
#define USART_RXC_vect _VECTOR(11)
#define USART_UDRE_vect  _VECTOR(12)
#define USART_TXC_vect _VECTOR(13)
#define ADC_vect _VECTOR(14)
#define EE_RDY_vect  _VECTOR(15)
#define ANA_COMP_vect _VECTOR(16)
#define TWI_vect _VECTOR(17)
#define INT2_vect _VECTOR(18)
#define TIMER0_COMP_vect _VECTOR(19)
#define SPM_RDY_vect _VECTOR(20)

Nein.
Definiere dir das nicht selber! Dazu gibt es die vorgefertigen Includes, 
die dir diese Dinge definieren.
/* Timer/Counter0 Compare Match *///
ISR(TIMER0_COMP_vect)
{
PORTB=PORTB ^ 0xff;
go2initial=0;
reti();
};

go2initial brauchst du in Wirklichkeit nicht (dazu später mehr), und 
reti() rufst du nicht selber auf. Der Compiler weiß schon, dass er eine 
ISR Funktion mit einem reti anstelle eines ret abschliessen muss.

Funktionen werden NICHT mit einem ; abgeschlossen

--->
/* Timer/Counter0 Compare Match *///
ISR(TIMER0_COMP_vect)
{
  PORTB=PORTB ^ 0xff;
}

void initial(void) //Timer setzen
{
TCCR0=TCCR0|0x03; //prescaler
TCNT0 = 0x00;
OCR0 = 0x08;
TIMSK=TIMSK | 0x03;
//TOIE0=TRUE;
DDRB = 0xff;
go2initial=0;
//asm volatile("cli"::);
//sei();
return;
};

Ein return am Ende einer Funktion ist nicht notwendig, schadet aber auch 
nicht. Es ist aber unüblich eines zu schreiben.

Die main() kann man dann auch kürzer schreiben. Wozu der ganze Häckmäck 
mit der Hilfsvariablen? Wenn initial() nur einmal bei Programmstart 
ausgeführt werden soll, dann zieh doch den Aufruf einfach vor die 
while-Schleife und du hast den gewünschten Effekt. Simpel, einfach und 
doch geschmacklos.
int main(void){

  int b;

  initial();
  sei();

  while(1){          // Endlosschleife
    b=1;
  }
}

Autor: slorenz (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Als allererstes:
Rücke deinen Code ein!
Ein optisch einigermassen ansprechender Code ist nicht einfach nur eine
Fleissaufgabe, sondern hilft auch Fehler zu finden!

//#include <avr/io.h>

aus welchem Grund benutzt du io.h nicht?
Das ist mehr als unklug! Das ist sogar ziemlich dämlich!

              Soweit ich die Bibliothek angeschaut habe, wird io.h 
bereits in interrupt.h eingebunden - warum sollte ich es nochmal tun?
Um weiter zu kommen, habe ich es aber getan.

#define INT0_vect _VECTOR(1)
#define INT1_vect _VECTOR(2)
#define TIMER2_COMP_vect _VECTOR(3)
#define TIMER2_OVF_vect  _VECTOR(4)
#define TIMER1_CAPT_vect _VECTOR(5)
#define TIMER1_COMPA_vect _VECTOR(6)
#define TIMER1_COMPB_vect _VECTOR(7)
#define TIMER1_OVF_vect  _VECTOR(8)
#define TIMER0_OVF_vect  _VECTOR(9)
#define SPI_STC_vect _VECTOR(10)
#define USART_RXC_vect _VECTOR(11)
#define USART_UDRE_vect  _VECTOR(12)
#define USART_TXC_vect _VECTOR(13)
#define ADC_vect _VECTOR(14)
#define EE_RDY_vect  _VECTOR(15)
#define ANA_COMP_vect _VECTOR(16)
#define TWI_vect _VECTOR(17)
#define INT2_vect _VECTOR(18)
#define TIMER0_COMP_vect _VECTOR(19)
#define SPM_RDY_vect _VECTOR(20)

Nein.
Definiere dir das nicht selber! Dazu gibt es die vorgefertigen Includes,
die dir diese Dinge definieren.

          Dann nenne mir diesen include doch bitte. und schaden kann es 
doch eigentlich nicht - ich ersetzte doch nur Text in meinem Programm 
über den Präprozessor - die eigendlichen Definitionen packe ich doch gar 
nicht an - richtig?

/* Timer/Counter0 Compare Match *///
ISR(TIMER0_COMP_vect)
{
PORTB=PORTB ^ 0xff;
go2initial=0;
reti();
};

go2initial brauchst du in Wirklichkeit nicht (dazu später mehr), und
reti() rufst du nicht selber auf. Der Compiler weiß schon, dass er eine
ISR Funktion mit einem reti anstelle eines ret abschliessen muss.

Funktionen werden NICHT mit einem ; abgeschlossen
     Nun gut - habe ich berücksichtigt.
--->

/* Timer/Counter0 Compare Match *///
ISR(TIMER0_COMP_vect)
{
  PORTB=PORTB ^ 0xff;
}
      habe ich auch gemacht

void initial(void) //Timer setzen
{
TCCR0=TCCR0|0x03; //prescaler
TCNT0 = 0x00;
OCR0 = 0x08;
TIMSK=TIMSK | 0x03;
//TOIE0=TRUE;
DDRB = 0xff;
go2initial=0;
//asm volatile("cli"::);
//sei();
return;
};

Ein return am Ende einer Funktion ist nicht notwendig, schadet aber auch
nicht. Es ist aber unüblich eines zu schreiben.

Die main() kann man dann auch kürzer schreiben. Wozu der ganze Häckmäck
mit der Hilfsvariablen? Wenn initial() nur einmal bei Programmstart
ausgeführt werden soll, dann zieh doch den Aufruf einfach vor die
while-Schleife und du hast den gewünschten Effekt. Simpel, einfach und
doch geschmacklos.

int main(void){

  int b;

  initial();
  sei();

  while(1){          // Endlosschleife
    b=1;
  }
}


     Auch diese Idee hatte ich bereits (konntest du natürlich nicht 
wissen). Aber sowohl  mit deinem Vorschlag als auch mit meiner 
ursprünglichen Version wird immer in main zurückgesprungen und nicht an 
den Punkt nach initial();
Das ist ja gerade mein Problem.
die variablen hatte ich für die Probedurchläufe eingesetzt , um die 
Register in der Simulation besser beobachten zu können, wenn ich auf 
autostep stelle.

Die überarbeitete Version hänge ich an - übrigens handelt es sich um 
einen ATMEGA16.
Kannst du oder jemand anders noch irgendwelche Tipps geben?
Hinweis: Nun zählt der Counter bis 255, was ich eigentlich gar nicht so 
haben wollte.
meine überarbeitete Version habe ich angehängt. (version2)

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist ja auch alles kein Wunder. Du schaltest Overflow und
Compareint. frei. Und dann kommentierst du die Routine
für Overflow weg. Was meinst du wo der dann hinspringt?

Autor: Robert B. (goldcap) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ein C-Programm für einen AVR sollte immer mit

#include <avr/io.h>

beginnen, das setzt alle defines in Bezug auf controllerspezifische 
register,damit läuft der code auf jedem Atmel sofern die verwendeten 
Features vorhanden sind.

Wenn du interrupts benutzt schreibe eine weitere Zeile

#include <avr/interrupt.h>

darunter.
Es ist völlig unrelevant ob in interupt.h das io.h nochmal includiert 
wird, die includes regeln das ganz schön, dass sie nicht mehr als einmal 
durchlaufen werden.
Das ganze funktioniert aber auch nur wenn das MCU-Define den richtigen 
Wert für deinen verwendeten Controller hat. Das macht das AVR-Studio 
eigentlich automatisch wenn du das richtige Target ausgewählt hast.

Autor: slorenz (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, ihr Lieben,
Ist ja auch alles kein Wunder. Du schaltest Overflow und
Compareint. frei. Und dann kommentierst du die Routine
für Overflow weg.

Stimmt, das war nicht clever - ist korrigiert.
 Was meinst du wo der dann hinspringt?

Ich vermute ins Nirvana - aber warum bei mir immer wieder zu main?
Wird dann der "Nullvektor" der ISRs angesprungen?

Das ist aber auch nicht mehr so wichtig - ich nehme gerne noch einen 
Ratschlag an, ansonsten bin ich für die Antworten dankbar.

Meine jetzige Version habe ich angehängt - vielleicht kann jemand etwas 
damit anfangen.

Achso: Prinzipiell glaube ich, dass die (Haupt-)Lösung meines Problems 
tatsächlich darin bestand, die ein / mehrere reti am Ende der ISR zu 
löschen.
Hinzu kamen natürlich noch die auskommentierte ISR.
Danke nochmal für die Hilfe bei der Lösung der Aufgabe.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Wird dann der "Nullvektor" der ISRs angesprungen?

Er springt auf den Resetvektor. Adresse 0.

>Achso: Prinzipiell glaube ich, dass die (Haupt-)Lösung meines Problems
>tatsächlich darin bestand, die ein / mehrere reti am Ende der ISR zu
>löschen.

Das sei() was du da jetzt eingebaut hast ist ziemlich
genau so schädlich wie reti(). Weg damit!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
slorenz schrieb:

> #define INT0_vect _VECTOR(1)
> #define INT1_vect _VECTOR(2)
> #define TIMER2_COMP_vect _VECTOR(3)
> #define TIMER2_OVF_vect  _VECTOR(4)
> #define TIMER1_CAPT_vect _VECTOR(5)
> #define TIMER1_COMPA_vect _VECTOR(6)
> #define TIMER1_COMPB_vect _VECTOR(7)
> #define TIMER1_OVF_vect  _VECTOR(8)
> #define TIMER0_OVF_vect  _VECTOR(9)
> #define SPI_STC_vect _VECTOR(10)
> #define USART_RXC_vect _VECTOR(11)
> #define USART_UDRE_vect  _VECTOR(12)
> #define USART_TXC_vect _VECTOR(13)
> #define ADC_vect _VECTOR(14)
> #define EE_RDY_vect  _VECTOR(15)
> #define ANA_COMP_vect _VECTOR(16)
> #define TWI_vect _VECTOR(17)
> #define INT2_vect _VECTOR(18)
> #define TIMER0_COMP_vect _VECTOR(19)
> #define SPM_RDY_vect _VECTOR(20)
>
> Nein.
> Definiere dir das nicht selber! Dazu gibt es die vorgefertigen Includes,
> die dir diese Dinge definieren.
>
>           Dann nenne mir diesen include doch bitte.

io.h
interrupt.h

In einem von beiden sind sie drinnen, oder zumindest wird von dort ein 
File includiert, welche die richtigen #define für *deinen* Prozessor 
hat.
Änderst du den Prozessor, passen sich die #define da drinnen an.

> und schaden kann es
> doch eigentlich nicht

dann warte mal ab, bis du die falschen #define für einen anderen 
Prozessor benutzt.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
slorenz schrieb:
> Achso: Prinzipiell glaube ich, dass die (Haupt-)Lösung meines Problems
> tatsächlich darin bestand, die ein / mehrere reti am Ende der ISR zu
> löschen.

Man sollte eben nicht gedankenlos irgendwelchen Quatsch zusammencoden.
Hast Du denn nicht im "interrupt.h" gelesen, wofür das reti() gedacht 
ist:

/** \def reti()
    \ingroup avr_interrupts

    \code #include <avr/interrupt.h> \endcode

    Returns from an interrupt routine, enabling global interrupts. This 
should
    be the last command executed before leaving an ISR defined with the
ISR_NAKED
    attribute.


Ohne ISR_NAKED ergibt sich nämlich folgender Code:

ISR(TIMER0_COMP_vect)
{
  92:   1f 92           push    r1
  94:   0f 92           push    r0
  96:   0f b6           in      r0, 0x3f        ; 63
  98:   0f 92           push    r0
  9a:   11 24           eor     r1, r1
  9c:   8f 93           push    r24
  PORTB=PORTB ^0xff;
  9e:   88 b3           in      r24, 0x18       ; 24
  a0:   80 95           com     r24
  a2:   88 bb           out     0x18, r24       ; 24
  reti();
  a4:   18 95           reti
};
  a6:   8f 91           pop     r24
  a8:   0f 90           pop     r0
  aa:   0f be           out     0x3f, r0        ; 63
  ac:   0f 90           pop     r0
  ae:   1f 90           pop     r1
  b0:   18 95           reti

D.h. Dein unsinniges reti() springt zum zufälligen Inhalt von r24,SREG.
Und das richtige RETI ist damit toter Code.


Peter

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.