PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer/Counter und PWM Channles



ricola
26.06.2007, 14:42
Hallo,

mal eine Verständnisfrage: Ich benutze einen ATMEGA16
zur Erzeugung von 4 PWM für 4 Motoren. Jetzt würde ich
gerne noch einen Timer benutzen, zum Beispiel um noch
eine Status-LED blinken zu lassen. Geht das jetzt überhaupt
noch, oder blockieren meine 4 PWM jetzt alle Timer/Counter
Kanäle, von denen der ATMEGA16 ja nur 4 Stück hat (2x8bit,
1x16bit,1xreal_time_counter[?])???

Sind Interupt-Routinen davon auch betroffen?

Gruß
RICOLA

Lunarman
26.06.2007, 16:58
Wieso Interrupt? benötigt ein Timer einen Interrupt???
Auf jeden Fall belegen deine 4 PWMs da alle 4 Timer. Du kannst höchstens noch einen Softwaretimer machen, aber frag jemand anders, wie das funzt. C kann ich nicht so gut.

wkrug
26.06.2007, 17:58
Wenn einer deiner Timer durchläuft und nicht durch einen PWM Mode automatisch wieder genullt wird, oder rückwärts läuft, kannst du den Timer Overflow Interrupt dieses Timers aktivieren und einen Zähler hochzählen.
Wenn dieser Zähler dann einen bestimmten Wert erreicht hat kannst Du den Zustand eines Ausgangs toggeln den Zählerstand des Softwarezählers (nicht! das TCNT Register) auf 0 setzen und damit eine LED zum blinken bringen.
Die Routine braucht nur ein paar Bytes und dürfte den Ablauf deines Programmes nicht allzusehr stören.

ricola
27.06.2007, 12:30
hallo wgrug,

das ist genau was ich brauche! könntest du es noch ein wenig konkretisieren bitte!? In etwa so hier? Geht dann das PWM noch?

// Initialisierung:
TCCR2 = (1<<CS22);
TCNT2 = 183;
TIMSK |= (1<<TOIE2);


SIGNAL(SIG_SIG_OVERFLOW2)
{
countTimer2++;
}

Danke und Gruß
RICOLA

wkrug
27.06.2007, 16:35
hallo wgrug,

das ist genau was ich brauche! könntest du es noch ein wenig konkretisieren bitte!? In etwa so hier? Geht dann das PWM noch?

// Initialisierung:
TCCR2 = (1<<CS22);
TCNT2 = 183;
TIMSK |= (1<<TOIE2);


SIGNAL(SIG_SIG_OVERFLOW2)
{
countTimer2++;
}
Die Antwort hast Du dir mit diesem Post vermutlich schon selbst gegeben.
Mit dem Timer 2 wird das nicht gehen wenn auf dieses Register auch noch anderweitig geschrieben wird und dadurch kein Überlauf zstande kommt?
Es kommt auch auf den gewählten PWM Mode an.
Diese Modes kenne ich:
Bei manchen Modes Zählt das TCNT2 Register bis zum Comparewert hoch und wird dann Hardwaremässig genullt - CTC.
In einem anderen PWM Mode Zählt der Zähler bis zum Comparewert vorwärts und dann wieder rückwärts.
In wieder einem anderen Mode Zählt der Zähler bis 0xFF und dann wieder auf 0x00.
Alle diese Modes erzeugen normalerweise keinen! Timer Overflow Interrupt und sind somit nicht geeignet.


Das TCNT2 Register muss Hochzählen bis der Zählerstand von 0xFF wieder auf 0x00 Überläuft, nur dann wird ein Timer Overflow Interrupt erzeugt (=Fast PWM Mode + Phase Correct PWM Mode).
Hast Du in einem deiner Timer, diesen PWM Mode eingestellt ???
Wenn nicht wird es so nicht funktionieren.

Eine weitere Option wäre es einen Comparematch Interrupt freizugeben und hier den Zähler hochzuzählen.
Das hätte aber den Nachteil, das bei Extremwerten des PWM (0x00 + 0xFF) unter Umständen dieser Interrupt nicht anspricht.

ricola
27.06.2007, 17:46
hmmm, ich initialisiere den PWM-Kanal mit

// 8bit Kanal
TCCR0 = (1<<WGM00)|(1<<COM01)|(1<<CS01);

??

Gruß
RICOLA

wkrug
28.06.2007, 19:13
// 8bit Kanal
TCCR0 = (1<<WGM00)|(1<<COM01)|(1<<CS01);
Mit diesen Einstellungen wird kein Timer Overflow Interrupt generiert, wohl aber ein Comparematch Interupt.
Du musst diesen Interrupt nur im TIMSK freigeben die Vektoren in deinem Compiler anlegen und darin die Comparematch Routine (deine blinkende Led) anlegen.

ricola
29.06.2007, 14:32
hmmm, ich lese dazu folgendes:

When the OCIE0 bit is written to one, and the I-bit in
the Status Register is set (one), the Timer/Counter0
Compare Match interrupt is enabled.

When the I-bit in SREG, OCIE0 (Timer/Counter0 Compare
Match Interrupt Enable), and OCF0 are set (one), the
Timer/Counter0 Compare Match Interrupt is executed.

also folgender Code?

TIMSK = (1<<OCIE0);
SREG = (1<<I);
TIFR = (1<<OCF0);

das mit den vektoren verstehe ich aber nicht. wo lege
ich die denn im compiler an? und wo ist die funktion, die
jetzt von dem interrupt aufgerufen wird?

ich finde das hier:
No:20 Addr:$026 TIMER0 COMP Timer/Counter0 Compare Match


DANKE!!

Gruß
RICOLA

wkrug
29.06.2007, 18:01
Mit dem I Flag im SREG gibt es ein eigenes Assembler Kommando

#asm ("SEI");

Wie bei deinem Compiler Interrupts angelegt werden kann ich Dir nicht sagen, sollte aber auf jeden Fall im Compiler Handbuch stehen.

Bei Codevision geht das so:

interrupt [EXT_INT0] void ext_int0_isr(void)
{
dein Code;
}

Ist aber bei jedem Compiler anders.

ricola
04.07.2007, 20:48
Hallo,

war eigentlich ganz einfach, musste nur

TIMSK |= (1<<OCIE1A);
sei();

eingeben und hatte dann schon den SIG_OUTPUT_COMPARE1A
Compare Match Timer an. PWM funktionieren noch tadellos. Muss
mir halt nur die Zeitbasis selber mit Inkrementen mitzählen.

Danke also!

PS: Das Anlegen der Vektoren mach avr-gcc ganz von allein!

Gruß
RICOLA