PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Interruptbehandlung bei ATMega8



tholan
27.06.2006, 10:25
Hi,
ich bau mir gerade einen "Rhythmusrobotter" :)
aus dem Rhythmusteil einer alten Elektroorgel
und 'nem ATMega8 mit 16MHz.
Dazu brauche ich an den Pins PC0 -PC3 je einen Impuls
von ca 10- 40mSek. Mit aktivem Warten hab ich's nun schon
hingekriegt, wuerd's aber lieber mit 'nem Timer Overflow Interrupt
machen.
Ich habe nun den Prescaler von Timer 0 auf 1/1024
bei einer Quarzfrequenz von 16MHz gestellt:



int Timer_Inits(void)
{
//Timer Interrupt=(Quarzfreq 16000000/8Bit-Ueberlauf 256)/ Prescaler 1024= 16mS
//letzte 3 Bit von Timer Clock Control: Prescaler = Quarz/1024:
TCCR0 = (TCCR0 | (1 << CS00) | (1 << CS02)) & (~(1 << CS01));
//Timer Interrupt Mask Register Bit 1 setzen fuer Timer Overflow Interrupt enable:
TIMSK |=(1<<TOIE0);
return 0;
}

Das sollten dann ca. 16mSek für einen Überlauf sein.
(16M / 256) / 1024.
Meine Frage ist nun, kommt das hin mit der Initialisierungsroutine?
Mit der Interruptbehandlung komme ich noch nicht so klar,
welcher Vektor ist das nun: SIGNAL (SIG_OVERFLOW0) ?
und wie bekomme ich das in meinen Code rein?
Wann muß ich die Interrupts global enabeln?


int Bass_Drum(void)
{
PORTC |= (1<<PC1); //PC1=Port fuer Bass Drum
//hier muesste dann nach einem Timer 0 Overflow
//der Pin PC1 wieder ausgeschaltet werden.
return 0;
}

Danke schonmal,
tholan

PicNick
27.06.2006, 11:21
Das schaut recht vernünftig aus.
Enablen sei() an besten bevor du in die Hauptschleife kommst
while (ewig)
{
}

SIGNAL (SIG_OVERFLOW0) wird vom Timer angesprungen, die kannst du wie jede andere Funktion hinschreiben, wo du willst.


EDIT: keep rockin' !

SprinterSB
27.06.2006, 11:23
Die Initialisierung ist soweit ok. Es ist allerdings u.U. besser, TCCR0 wirklich zu setzen, damit alle Bits den gewünschten Wert haben. Sollte bei dir aber egal sein.

void Timer_Inits(void)
{
//Timer Interrupt=(Quarzfreq 16000000/8Bit-Ueberlauf 256)/ Prescaler 1024= 16mS
//letzte 3 Bit von Timer Clock Control: Prescaler = Quarz/1024:
TCCR0 = (1 << CS00) | (1 << CS02);
//Timer Interrupt Mask Register Bit 1 setzen fuer Timer Overflow Interrupt enable:
TIMSK |=(1<<TOIE0);
}

Wenn ich's recht sehe, willst du so was wie Timeouts machen: Nen Port an und nach ner bestimmten Zeit wieder aus, wahrscheinlich unterschiedliche Zeiten für die verschiedenen Ports...

Du könntest dir eine Struktur machen mit Countdown-Werten, die du setzt und die in der ISR bis aus 0 zurückgezählt werden, eine Einheit pro Tick (16ms):



typedef struct
{
uint8_t takt;
uint8_t bass;
...
} countdown_t;

volatile countdown_t countdown;

SIGNAL (SIG_OVERFLOW0)
{
uint8_t i = sizeof (countdown_t);
uint8_t * cd = (uint8_t *) &countdown;

cd += i;

do
{
uint8_t wert = *(--cd);

if (wert)
*cd = wert-1;
} while (--i);
}


Dadurch werden in jedem Tick die Elemente von countdown, die nicht 0 sind, um 1 erniedrigt.



int main()
{
ioinit();
Timer_Inits();
sei();

// Hauptschleife
while (1)
{
if (countdown.takt == 0)
{
countdown.takt = 200;
countdown.bass = 20;
PORTC |= (1 << 1);
}

if (countdown.bass == 0)
{
PORTC &= ~(1 << 1);
}
}

tholan
27.06.2006, 14:11
Hi und danke,
habe zur Veranschaulichung noch 'ne LED an PD5
gehängt und folgenden Testcode eingegeben:


#include<avr/io.h>
#include<avr/signal.h>
#define LED PD5 //Port fuer gruene LED

int Timer_Inits(void)
{
//Timer Interrupt=(Quarzfreq 16000000/8Bit Ueberlauf 256)/ Prescaler 1024= 16mS
//letzte 3 Bit von Timer Clock Control: Prescaler = Quarz/1024:
TCCR0 = (1 << CS00) | (1 << CS02);
//Timer Interrupt Mask Register Bit 1 setzen fuer Timer Overflow Interrupt enable:
TIMSK |=(1<<TOIE0);
return 0;
}

int Port_Inits(void)
{
DDRD |=(1<<LED); //Datenrichtungsregister fuer Pin5, PortD auf Ausgang
return 0;
}
SIGNAL (SIGOVERFLOW0)
{
PORTD |=(1<<LED);
}

int main(void)
{
Timer_Inits();
Port_Inits();
sei();
for(;;) //Warten auf Godot...
;
return 0;
}

Da sollte die LED doch angehen?
Der Compiler gibt keine Warnung,
aber bei der LED tut sich nix..
Hab ich noch irgendwas vergessen?

SprinterSB
27.06.2006, 14:43
Der ISR-Name muss genau stimmen, also SIG_OVERFLOW0.

tholan
27.06.2006, 15:14
Uups...
irgendwie hatte auf einmal nix mehr geklappt.
#include<avr/interrupt.h> hatte ich auch vergessen.
Weiß nur noch nicht, warum der Compiler nicht gemeckert hat,
aber egal: jetzt pfundst es.
Nu werd ich mich mal den Sternchen und Brezeln aus Deinem Beispiel
widmen, da ich noch längere Pausen für die Noten brauche.
Vielen Dank für den Code.

PicNick
27.06.2006, 15:17
@tholan: sag' nicht "sternchen und Brezeln" wenn der SprinterSb in der Nähe ist.
Das ist, als wenn du einem Tischtennis Champion sagst, er spiele Ping-Pong. :mrgreen:

SprinterSB
27.06.2006, 15:26
*lach* Jepp, es gibt nix schlimmeres als in Gegenwart eines Badminton-Spielers das Wort "Fedderball" zu sagen.

Ich sach aber auch immer "Brezel" und "Teppich" und "Schniedel" oder "Schlangilon".

PicNick
27.06.2006, 15:32
"Schneckennudel" SprinterSB:
Na, wenn du es so siehst, is ja nix passiert. Ich wollt halt nicht, daß er in Ungnade fällt.

SprinterSB
27.06.2006, 15:40
Nö, da braucht's schon viel schlimmeres wie Rosinen in den Apfelkuchen oder Sahne auf nen "Cappucino" oder Speck im Salat *ÖRGX*

tholan
27.06.2006, 15:47
Ähh Schneckennudel???
is das die Brezel??
...

PicNick
27.06.2006, 15:49
"Schneckennudel" = Klammeraffe = "@" :-)

tholan
27.06.2006, 15:53
Is schon schlimm mit diesen Fachtermini,
aber hier werden sie jedenfalls geholfen!