Hallo,
nach etwas genauerer Beschäftigung gebe ich den Vorrednern Recht - man gut mit PWM arbeiten. Ich habe mir nun überlegt den Timer mit dem IRQ im Vergleichs-Modus des Timers 2 laufen zu lassen. Ich habe dazu eine globale Variable definiert, die bei jedem IRQ herunter gezählt wird. Ist sie 0 wird der Timer2 und der IRQ ausgeschaltet.
Ich habe nur noch ein Problem mit der Tondauer. Übergebe ich sie in Sekunden funktioniert alles, Übergebe ich sie in Millisekunden höre ich nur einen kurzen Ton. Warum?
Hier mal der Code:
Code:
/* TODO
Der OC2 Port muss als Ausgang definiert werden
Timer/Counter Control Register – TCCR2:
	Wir Wählen Mode 2 CTC also WGM21 (1)	WGM20 (0) 
	Wir benötigen den wechsel an OC2 also muss COM21 0 und COM20 1 sein
	Nun muss der Prescaler gesetzt werden.
	Table 54. Clock Select Bit Description
		CS22 	CS21 	CS20 	Description
		0 		0 		0 		No clock source (Timer/Counter stopped).
		0 		0 		1 		clkT2S/(No prescaling)
		0 		1 		0 		clkT2S/8 (From prescaler)
		0 		1 		1 		clkT2S/32 (From prescaler)
		1 		0 		0 		clkT2S/64 (From prescaler)
		1 		0 		1 		clkT2S/128 (From prescaler)
		1 		1 		0 		clkT2S/256 (From prescaler)
		1 		1 		1 		clkT2S/1024 (From prescaler)

Output Compare Register – OCR2 Hier setzen wir die Länge des Zählerveergleichs ein

Die Quelle für den Takt des Timers lassen wir auf default

Special Function IO Register – SFIOR brauchen wir nicht zu beachten

Timer/Counter Interrupt Mask Register – TIMSK
• Bit 7 – OCIE2 wird auf 1 gesetzt um den Interupt zu aktivieren, wenn der Vergleich stimmt
	(Compare)
*/

void Soundirq (unsigned int Ton, unsigned int Zeit)
{
	unsigned int Impulsanz;			
	unsigned long Impulsanz_L;
	unsigned int Laenge_L;			
	unsigned char tmp_sreg;  		// temporaerer Speicher fuer das Statusregister des IRQ
	unsigned char Laenge;			// Wie lange soll der Timer 2 zählen?
	
	/* Wenn ich mich nicht verrechnet habe ist bei 16 MHZ ein Prescaler von 1024 sinnvoll
		16Mhz / 1024 = 15625 Hz 
		Dies ist aber nur die doppelte Frequenz. Also kann der höchste Ton eine Frequenz
		von ca 7,8 kHz erreicht werden.
		Die niedrigste Frequenz ergibt sich aus diesem Wert durch 255 geteilt.
		Also ist der tiefste Ton also 30Hz
		Die Formel für die Länge des Comperatorregisters OCR2 ergibt sich:
		Laenge = f_quarz / (2* Ton * Prescaler)
		also ergibt sich mit den ausgerechneten Konstanten: Laenge = 7812 / Ton
	*/	
	
	Laenge_L = 7812 /  Ton; 	// Wie lang ist eine halbe Periodendauer
	Impulsanz_L = (2 * Ton * Zeit) / 1000; // Wieviele Interupte sind nötig
	Impulsanz = Impulsanz_L;
	Laenge = Laenge_L;
	TCCR2 |= (1 << WGM21) | (0 << WGM20) | (0 << COM21) | (1 << COM20);
									// Ein IRQ muss in einer Periode 2 mal ausgelöst werden
	DDRD |= (1 << DDD7); 			// Port D.7 auf Ausgang legen
	tmp_sreg = SREG;   				// Statusregister (also auch das IRQ-Flag darin) sichern
	cli();             				// Interrupts global deaktivieren
	gSounddauer = Impulsanz;
	OCR2 = Laenge;
	TCCR2 |= (1 << CS22) | (1 << CS21) | (1 <<	CS20);	// Prescaler auf 1024 setzen 
	TIMSK |= (1 << OCIE2);			// Timerinterupt einschalten
	SREG = tmp_sreg;     			// Status-Register wieder herstellen und auch das IRQ-Flag
									// auf gesicherten Zustand setzen
	sei();							// Interupt wieder einschalten - falls er nicht schon an war
}

/*
Timer 2 ausschalten. Es werden keine Interupts durch ihn ausgelöst
*/
void Soundirq_aus(void)
{
	unsigned char tmp_sreg;  		// temporaerer Speicher fuer das Statusregister
	tmp_sreg = SREG;   				// Statusregister (also auch das IRQ-Flag darin) sichern
	cli();             				// Interrupts global deaktivieren
	TCCR2 = 0;						// Timer 2 wird ausgeschaltet
	TIMSK &= (0 << OCIE2);			// Timerinterupt ausschalten
	SREG = tmp_sreg;     			// Status-Register wieder herstellen und auch das IRQ-Flag
									// auf gesicherten Zustand setzen
}


/* 
Timer2 Compare Match IRQ Routine
Wird benutzt um den Ton nur eine bestimme Zeit laufen zu lassen
PWM möglich oder Port jeweils Invertieren
*/	
ISR(TIMER2_COMP_vect)
{
	if (gSounddauer > 1)
	{
		gSounddauer--;				// Anzahl der Impulse veringern, so dass der Ton beendet wird	
		//PORTD^=(1<<PD7); 			// invertiert Bit 7 an Port D (nichtnötig wenn PWM benutzt wird)
	}
	else
	{
		Soundirq_aus();					// Timer 2 ausschalten
	}
}
kann mir jemand erklären warum: Impulsanz_L = (2 * Ton * Zeit) / 1000;
ein falsches Ergebnis liefert?
Danke
Gruß
Stefan