PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Lautsprecher auf rncontrol ansprechen



bergowitch
25.02.2006, 12:58
Hallo,
ich kämpfe immer noch mit C.
Ich möchte gerne den Lautsprecher ansteuern. Er hängt an PortD.7/OC2.
Mit Bascom geht das ganz einfach mit "Sound Portd.7 , 400 , 450".
So etwas hätte ich gerne auch in C. Aber ich verstehe einfach nicht was ich machen muss und werde aus dem Dantenblatt nicht schlau.
Kann mir jemand helfen oder einen Hinweis geben wo ich suchen muss?
Ich kann wohl den Port setzen warten und wieder auf 0 setzen und wieder warten, aber das ist wohl nicht im Sinne des Erfinders.
Im Prinzip müsste das doch über den Interupt gehen? Aber Ton soll nicht dauerhaft ertönen, so bräuchte man eine Zeitvariable die bei jedem Interupt verkleinert wird. Oder wie kann man das machen?
Danke
Gruß Stefan

izaseba
25.02.2006, 14:14
Hallo,
OC2 ?
Dann ist PWM dein Freund...
Schau mal unter Timer/Counter2

Gruß Sebastian

bergowitch
26.02.2006, 04:54
Hallo,
wie soll dasüber PWM funktionieren. Den müsste ich doch auch laufen lassen und warten bis die Tondauer vorbei ist und dann erst den AVR weiter beschäftigen. Oder kann man auch den PWM in einer bestimmten Frequenz für eine bestimmte Zeit laufen lassen und er schaltet sich automatisch ab?
gruß stefan

NumberFive
26.02.2006, 08:22
oder so geht es auch




SETBIT(DDRD,PD7); // Das ist der lautsprecher
Sound(100,2); // ca. 500 hz bei 16 Mhz wenn die Rechnung stimmt 500 hz = 2000 us
Sound(100,1); // ca. 250 hz bei 16 Mhz
Sound(100,2);

void Sound(WORD Count,WORD PulsTime)
{
//am PORTD Pin 7 ist bei der RN-Control ein lautsprecher
for(int x=0;x<Count;x++)
{
wait_ms(PulsTime);
SETBIT(PORTD,PD7);
wait_ms(PulsTime);
CLEARBIT(PORTD,PD7);
}
}

void wait_ms(int ms)
{
int t1,t2;
for(t1 = 0;t1 < ms; t1++)
{
for(t2 = 0 ;t2 < (137 * 16) ; t2++)
{
asm volatile("nop" ::);
}
}
}



wenn "nur" musik macht ist das ein alternative klar er macht nix anderes in der zeit.

izaseba
26.02.2006, 11:41
Oder kann man auch den PWM in einer bestimmten Frequenz für eine bestimmte Zeit laufen lassen und er schaltet sich automatisch ab?

Das kannst Du natürlich mit einem Timer erledigen, oder so wie Number Five schrieb mit Delay, kommt drauf an, ob Du eine Symphonie abspielen willst, oder eben hin und wieder einen Piep.

Gruß Sebastian

bergowitch
26.02.2006, 17:20
Danke numberfive,
so etwas habe ich auch schon wenn auch nicht ganz so schön so, aber ich würde den roboter gerne einen pieb ausgeben lassen, wenn er mit den Sensor z.B. einen Gegenstand gefunden hat und da wäre es günstig wenn der Roboter weiter arbeiten würde.
Mit dem PWM wirds bei genauerer Betrachtung auch schwierig - glaube ich - da die beiden PWMs für die Motoren benutzt werden.
Bleibt nur noch der letzte Timer, der über einen Interupt den Port setzt und löscht. Mir ist nur nicht klar welcher timer der letzte ist, wie man initialisiert und welcher interupt vektor der richtige ist. die zeit muss man wohl über einen zeiger setzen und pro interupt aufruf herunterzählen.
Vielen Dank für deine Hilfe
gruß
stefan

linux_80
26.02.2006, 18:36
Hallo,
der Lautsprecher hängt an OC2, das gehört zu Timer2, die Motoren laufen mit Timer1 PWM !
Wenn Du schon einen Timer übrig hast, kann man den auch gleich die Frequenz per PWM erzeugen lassen, und nur warten bis die Zeit rum ist, danach den Ton wieder ausmachen.

bergowitch
27.02.2006, 19:21
Aber das Warten gefällt mir einfch nicht. Ich hoffe in den nächsten Tagen Zeit zu haben und etwas genauer in die Interupt funktionen hineinzuschnuppern. Es muss einfach gehen und den Bot lahm zu legen...
Gruß
Stefan

bergowitch
05.03.2006, 21:40
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:


/* 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

SprinterSB
05.03.2006, 21:55
Wie sind denn Werte für Ton und Zeit?

Timer2 ist ja nur ein 8-Bit-Timer, evtl hast du ein Überlauf, und die Bits ab 8 aufwärts landen in der Tonne?

Evtl den Prescaler benutzen, denn werden die Werte kleiner.

bergowitch
06.03.2006, 05:45
Der Timer an sich kann es nicht sein, weil die Tonhöhe ja vom Prescaler und vom Vergleichswert der 8-Bit groß ist abhängt.
Die Rechnung soll ergeben wie lange der Ton zu hören sein soll. Dazu habe ich eine globale uint16 Variable genommen, in die der Wert von Impulsanz hineingeschrieben wird.
Bei jedem Interupt wird diese globale Variable dan Heruntergezählt.
Ich bin ratlos...
Gruß
Stefan