PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : mega168 - INT0 - Timer2 - Programm Reset?!? :(



0tes_Gesetz
27.03.2006, 15:19
Hi.

- ATmega168
- AVR-Studio 4.12 SP1
- AVR-GCC 3.4.5
- AVR-DUDE 1.72 mit GUI 0.2.0

Mit folgendem Code wird Pin13 bei Programm-Start eingeschaltet und bei einem externen Interrupt - INT0 (mit steigender Flanke an Pin32) ausgeschaltet und bleibt dann auch da..
Verhält sich also genau wie erwartet.



/*
* Testprogramm um über Externen Interrupt ein Pin zu ändern...
* - ATmega168
* - AVR-Studio 4.12 SP1
* - AVR-GCC 3.4.5
* - AVR-DUDE 1.72 mit GUI 0.2.0
*/

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

volatile char done = 0;

ISR (INT0_vect) /* Externer Interrupt 0 löst aus.. */
{
PORTB = (0<<PB1); /* Pin 13 ausschalten für Interrupt-Test*/
}

int main (void)
{
if ( done == 0 ) /* "sicherstellen", dass Initialisierung nur 1 MAL stattfindet!!! */
{
/* clk_IO auf 8MHz setzen.. */
CLKPR = (1<<CLKPCE)|(0<<CLKPS3)|(0<<CLKPS2)|(0<<CLKPS1)|(0<<CLKPS0);
CLKPR = (0<<CLKPCE)|(0<<CLKPS3)|(0<<CLKPS2)|(0<<CLKPS1)|(0<<CLKPS0);

DDRD = (1<<DDD3)|(0<<DDD2); /* PinD3 als Ausgang */
DDRC = (0<<DDC0); /* PinC0 als Eingang */
DDRB = (1<<DDB3)|(1<<DDB1); /* PinB3 und B1 als Ausgang */

/* INT0 LevelChange, INT1 auf falling Edge scharf machen */
EICRA = (1<<ISC00)|(0<<ISC01)|(0<<ISC10)|(1<<ISC11);
/* INT0 enablen, INT1 disablen - da nicht benötigt */
EIMSK = (0<<INT1)|(1<<INT0);

// PCICR = (1<<PCIE2); /* PinChangeInterrupt 16-23 enabled */
// PCMSK2 = (1<<PCINT18);

PORTB = (1<<PB1); /* Pin 13 anschalten, für Interrupt-Test */
done = 1; /* Initialisierung abhaken */

sei(); /* Interrupts ON */
}

while (1 == 1) { } /* Loop forever */

return (0);
}


Wenn ich nun aber Timer2 (8Bit) in dem Initilisierungsteil auf Fast PWM setze mit einem Compare Wert von 0, dann wird der Pin13 spätestens nach 256 Taktzyklen wieder auf High gesetzt, nachdem INT0 funktioniert hat..
Hat jemand ne Idee, wodurch das verursacht wird?



/*
* Testprogramm um über Externen Interrupt ein Pin zu ändern...
* - ATmega168
* - AVR-Studio 4.12 SP1
* - AVR-GCC 3.4.5
* - AVR-DUDE 1.72 mit GUI 0.2.0
*/

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

volatile char done = 0;

ISR (INT0_vect) /* Externer Interrupt 0 löst aus.. */
{
PORTB = (0<<PB1); /* Pin 13 ausschalten für Interrupt-Test*/
}

int main (void)
{
if ( done == 0 ) /* "sicherstellen", dass Initialisierung nur 1 MAL stattfindet!!! */
{
/* clk_IO auf 8MHz setzen.. */
CLKPR = (1<<CLKPCE)|(0<<CLKPS3)|(0<<CLKPS2)|(0<<CLKPS1)|(0<<CLKPS0);
CLKPR = (0<<CLKPCE)|(0<<CLKPS3)|(0<<CLKPS2)|(0<<CLKPS1)|(0<<CLKPS0);

/* Timer2: CompareMatch A/B, FastPWM, Prescaler = 1 */
TCCR2A = (1<<COM2A1)|(0<<COM2A0)|(1<<COM2B1)|(1<<COM2B0)|(1<<WGM21)|(1<<WGM20);
TCCR2B = (0<<FOC2A)|(0<<FOC2B)|(0<<WGM22)|(0<<CS22)|(0<<CS21)|(1<<CS20);
TIMSK2 = (1<<OCIE2A)|(1<<OCIE2B)|(0<<TOIE2); /* Capture Overflow A/B Enablbe */

OCR2A = 0; /* Compare Match Values = 0 */
OCR2B = 0;

DDRD = (1<<DDD3)|(0<<DDD2); /* PinD3 als Ausgang */
DDRC = (0<<DDC0); /* PinC0 als Eingang */
DDRB = (1<<DDB3)|(1<<DDB1); /* PinB3 und B1 als Ausgang */

/* INT0 LevelChange, INT1 auf falling Edge scharf machen */
EICRA = (1<<ISC00)|(0<<ISC01)|(0<<ISC10)|(1<<ISC11);
/* INT0 enablen, INT1 disablen - da nicht benötigt */
EIMSK = (0<<INT1)|(1<<INT0);

// PCICR = (1<<PCIE2); /* PinChangeInterrupt 16-23 enabled */
// PCMSK2 = (1<<PCINT18);

PORTB = (1<<PB1); /* Pin 13 anschalten, für Interrupt-Test */
done = 1; /* Initialisierung abhaken */

sei(); /* Interrupts ON */
}

while (1 == 1) { } /* Loop forever */

return (0);
}


Für mich sieht das immer so aus, als ob der Chip einen Reset erfährt - besonders als ich in AVR-Studio den Code mal getestet hab.. da springt er nachdem der Timer (TCNT2) auf 256 gelaufen ist wieder an den Anfang von main {}.. genau deshalb hab ich ja die if-Abfrage fürs initialisieren eingfügt.. aber sie nutzt nichts.
Hilfe..


Und dann hab ich noch 2 Fragen

- AVRDUDE-Gui betreffend..
Wo muss ich rumstellen, damit der ATmega168 oben links in der Auswahl erscheint und ich ihn nicht immer selber unten in die Commandozeile eintragen muss?

-Worin besteht der Unterschied, wenn ich ein Register mit:
TIMSK2 |= (...
oder mit
TIMSK2 = (...
beschreibe?!

Vielen Dank
0tes_Gesetz

0tes_Gesetz
27.03.2006, 15:58
Hab grad herausgefunden, dass wenn ich die Anweisung:

"TIMSK2 = (1<<OCIE2A)|(1<<OCIE2B)|(0<<TOIE2); /* Capture Overflow A/B Enablbe */"

..weglasse, es dann so wie gedacht funktioniert.
Nur versteh ich jetzt nicht, wie das sein kann?!
TIMSK schaltet doch die Pins, welche ich für die Ausgabe des PWM-Signals brauche EIN, wenn ich dort OCIE auf 1 setze...
Ich bin verwirrt..

Die Pins die zur PWM Ausgabe gehören geben aber genau das PWM-Signal aus.. obwohl sie nach meiner Meinung nicht dafür freigeschaltet wurden, nachdem die Zeile da oben nun fehlt.

Mit anderen Worten:
Das Programm funktioniert jetzt wie gewollt, aber WARUM es das tut ist mir nicht klar...

Die beiden anderen Fragen bestehen auf jeden Fall noch.. ich würde mich freuen, wenn ich wenigstens darauf ne Antwort bekäme, falls das andere keiner weiß ;)

Danke

linux_80
27.03.2006, 18:36
Hallo,

wir haben da grad auch einen andren Thread in dem es M168 und AVRDude geht:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=18416

SprinterSB
27.03.2006, 18:59
1) Wenn du OCIE2A und OCIE2B aktivierst, solltest du den IRQs auch ihre ISRs spendieren. Ansonsten landest du beim Auftreten der IRQ bei __bad_interrupt, und dann bei Adresse 0.
2) das id (done==0) kannst du rauswerfen. Es schützt dich nicht vor mehrfachinitialisierungen durch einen Warmstart, denn im init-Code wird done auf 0 gesetzt. Willst du das verbeiden, musst du done dach .noinit lokatieren und MCUCSR auswerten, um es vernünftig zu initialisieren.

0tes_Gesetz
28.03.2006, 09:06
@SprinterSB..
Danke, dein Punkt 1) erklärt das aufgetretene Verhalten vollständig.

Fehler liegt mit 100% Wahrscheinlichkeit bei mir in einer Missinterpretation des Datenblattes (Interrupts wollte ich ja gar nicht, nur die Pins mit PWM versorgen).. :)

Dein Punkt 2) ist mir klar, nachdem es sich um einen "Warmstart" handelt, kann das nichts nutzen... war ja auch nur drin, um ein Symptom zu bekämpfen..
Aber mit deiner Ursachenklärung hat sich das erledigt. ;)

@Linux_80..
Habs gelesen, aber beim EEPROM bin ich noch lange nicht und mit den oben angegebenen Tools funzt bei mir erstmal alles soweit.. man sollte ja schon mehr als dankbar sein, wenn es die Tools kostenlos gibt, da trage ich auch gerne mal "m168" per Hand in ne Kommandozeile ein, wenn's z.Zt. nicht besser geht ;)

--

Wäre nur noch die Sache mit der Registersetzung einmal mit " | " und einmal ohne.. worin besteht da der Unterschied?!

Danke
0tes_Gesetz

SprinterSB
28.03.2006, 09:15
a |= b;
ist eine Abkürzung für

a = a | b;

Es werden also in a die Bits gesetzt, die in b 1 sind (zu denen, die in a schon 1 sind).

a = b; ist eine Zuweisung, das ist was anderes.