PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Programm springt immer wieder in Init



xaM_Max
14.02.2012, 22:24
Hallo

Ich hätte eine kleine Frage und zwar hab ich folgendes Programm bei dem mit der Zeit die Pulsbreite von Timer2 erhöht werden soll:



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

//Funktionsdeklaration
void init();
void init_timer0();
void init_timer2();

//Timer0:
#define T0_TEILER64 TCCR0|=0x03;TCCR0 &=0xFB
#define T0_NORMAL TCCR0&=0x87
#define T0_RESET TCNT0=0
#define T0_OVL_INT TIMSK|=0x01;SREG|=0x80

//Timer2:
#define T2_INT_OVL_ENABLE TIMSK|=0x40;SREG|=0x80
#define T2_FAST_PWM_EIN TCCR2&=0x00;TCCR2|=0x68
#define T2_PULSBREITE OCR2
#define T2_TEILER_1 TCCR2&=0xF8;TCCR2|=0x07

int main()//
{
//Initialisierung der Baugruppen)
init();
init_timer0();
init_timer2();
// Hintergrundschleife bzw. Hintergrundprozess
do
{

}
while(1);


return 0;
}

void init()
{
DDRA &=0x00;
//PB5 als Ausgang konfigurieren
DDRD |=0xFF;
}

void init_timer0()
{
//Normalbetrieb einstellen
T0_NORMAL;
//Teiler (64) einstellen
T0_TEILER64;
//Zählerstand Reset
T0_RESET;
//Interrupt freischalten (Überlaufinterrupt freischalten)
T0_OVL_INT;
}

void init_timer2()
{
// PWM-Betrieb einstellen
T2_FAST_PWM_EIN;
// Pulsbreite auf 0 einstellen
T2_PULSBREITE = 0;
// Maximale Frequenz - Teiler
T2_TEILER_1;
// Overflow Interrupt freigeben
T2_INT_OVL_ENABLE;
}

//ISR für Timer0 Überlauf (alle 2ms)
ISR(TIMER0_OVF_vect)
{
static unsigned char zaehler=0;

zaehler ++;

if(zaehler >= 49)//ca alle 98ms
{
zaehler = 0;
if(T2_PULSBREITE<=250)
{

T2_PULSBREITE += 5;
}
}
}



Das Problem ist das wenn die Variable zaehler den Wert 16 erreicht das Programm wieder zu init springt und dann wieder init_timer0 und init_timer2 durchläuft und das ganze wieder von vorne beginnt.

Vielleicht weiß jemand wo da der Fehler liegt!

Ich bin totaler Anfänger und weiß auch nicht ob ich hier in diesem Forum mit dieser Frage richtig bin...

Aber ich würde mich über die Lösung des Problems freuen!!! :)

Thomas E.
14.02.2012, 23:13
Sollte das nicht in die Abteilung für C?

ePyx
15.02.2012, 05:50
Füge mal die ISR für Timer 2 ein. Ist die nicht vorhanden läuft das Programm ab der Sprungadresse des IRQ weiter und geht ohne reti ( das macht unter anderem der ISR-Block) nicht zurück sondern läuft weiter. Etwas weiter oben im Speicher liegt deine Init und wird ausgeführt.


Sollte das nicht in die Abteilung für C?

Ja.

MagicWSmoke
15.02.2012, 07:47
läuft das Programm ab der Sprungadresse des IRQ weiter und geht ohne reti ( das macht unter anderem der ISR-Block) nicht zurück sondern läuft weiter.
Es ist zwar richtig, dass der TO die ISR vergessen hat, aber so wie Du das beschreibst funktioniert das in der Regel nicht.

Das Verhalten des Programms würde zufällig werden, wenn ein nicht definierter Interrupt wild im Speicher läuft, deshalb werden alle Interrupts ohne ISR auf einen Fehlervektor umgeleitet, welcher dann selbst wieder auf den Resetvektor umleitet. Der µC bekommt also 'nen SW-reset und das ist der Grund, warum die Init's erneut ausgeführt werden.

Findest Du hier unter default Interrupt:
http://www.rn-wissen.de/index.php/Avr-gcc#default_Interrupt

Bei anderen C-Compilern dürfte das nicht viel anders sein.

ePyx
15.02.2012, 10:14
Kann nur aus meiner Erfahrung heraus antworten und diese lautet, ISR vergessen -> Dauerreset. Was auch recht lustig ist, wenn man durch die uneinheitlichen Bezeichnungen den falschen Interruptvektor nimmt, da man das Programm von einem µC auf einen anderen portiert hat.

Das mit dem reti beruhte auf Halbwissen und habe ich mir aus der Vorstellung eines ASM-Listing zusammengereimt. Was ohne den __default_interrupt__ auch stimmt.

MagicWSmoke
15.02.2012, 10:41
aus der Vorstellung eines ASM-Listing zusammengereimt. Was ohne den __default_interrupt__ auch stimmt.
Nein, ohne Einbinden eines eigenen Default-Vektors sieht's aus wie unten dargestellt.
Die undefinierten Interruptvektoren gehen standardmäßig auf einen Punkt zusammen, an diesem Punkt würde bei selbst definiertem Bad-Interrupthandler der Weitersprung darauf erfolgen, ansonsten geht's (wie im Listing) auf den Resetvektor. Mit RETI hat das nix zu tun.

L0000:
jmp __start ; L002A
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
jmp L0047
; L002A:
; ... startup code
call L0049
jmp L03C5
L0047:
jmp L0000
; main
L0049:
; ...
L03C5:
cli
L03C6:
rjmp L03C6

ePyx
15.02.2012, 11:10
Ansonsten geht's (wie im Listing) auf den Resetvektor.

Hab nichts anderes geschrieben.



Ist die nicht vorhanden läuft das Programm ab der Sprungadresse des IRQ weiter und geht ohne reti ( das macht unter anderem der ISR-Block) nicht zurück sondern läuft weiter. Etwas weiter oben im Speicher liegt deine Init und wird ausgeführt.


Durch das Einfügen einer rjmp Marke, wird der unter der Marke Code für die ISR abgearbeitet. Zum Schluss wird mit reti doch, zurück an die Stelle PCs die vor dem IRQ bearbeitet wurde, gesprungen. Letztendlich muss der C-Compiler doch Ähnliches erzeugen, denn es muss bzgl. der Funktionalität das Gleiche herauskommen.

Sprich, für mich definiert der ISR-Block den Interrupt-Einsprung und folglich auch den Rücksprung.

MagicWSmoke
15.02.2012, 12:10
Hab nichts anderes geschrieben.
Konnte (kann) ich so nicht verstehen.

Letztendlich muss der C-Compiler doch Ähnliches erzeugen, denn es muss bzgl. der Funktionalität das Gleiche herauskommen.
Nein, er muss nichts funktional Ähnliches erzeugen, denn bei einem Fehlen der ISR muss er nicht mehr unbedingt in den unterbrochenen Code zurückkehren. Dann kann direkt (die Bad-Vektor Marke mal ausgeklammert) vom jeweilig Interruptvektor auf den Reset-Vektor gesprungen werden. Das normalerweise ausgeführte RETI der ISR poppt die Rücksprungadresse in den Programmzähler und würde damit den Stack wieder in Ordnung bringen. Wenn's aber per JMP oder RJMP auf den Resetvektor geht, dann wird der Stack in Folge sowieso neu initialisiert und damit muss man darauf nicht mehr darauf achten.
Weis jetzt nicht, ob wir da aneinander vorbeireden...

Sprich, für mich definiert der ISR-Block den Interrupt-Einsprung und folglich auch den Rücksprung.
Bezeichnest Du mit ISR-Block die Interruptvektortabelle oder die ISR selbst ?
Ein Interrupt geht von der Interruptvektortabelle aus, aber er kehrt dorthin nicht mehr zurück, das ist der Unterschied zwischen einem Interruptaufruf und einem CALL/RCALL, bei dem der Rücksprung unmittelbar nach die Caller-Adresse erfolgt.

ePyx
15.02.2012, 12:14
Mit ISR-Block meinte ich eigentlich nur das Makro ISR ( ).

wkrug
15.02.2012, 15:24
Dee Watchdog ist nicht mit den Fuses auf "ENABLE" geschaltet?