Hallo,
OC2 ?
Dann ist PWM dein Freund...
Schau mal unter Timer/Counter2
Gruß Sebastian
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
Hallo,
OC2 ?
Dann ist PWM dein Freund...
Schau mal unter Timer/Counter2
Gruß Sebastian
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
oder so geht es auch
wenn "nur" musik macht ist das ein alternative klar er macht nix anderes in der zeit.Code: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" ::); } } }
P: Meine Tochter (06.11.07) und https://www.carnine.de
M: Träumen hat nix mit Dummheit zu tun es ist die Möglichkeit neues zu erdenken
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.Oder kann man auch den PWM in einer bestimmten Frequenz für eine bestimmte Zeit laufen lassen und er schaltet sich automatisch ab?
Gruß Sebastian
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
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.
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
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:
kann mir jemand erklären warum: Impulsanz_L = (2 * Ton * Zeit) / 1000;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 } }
ein falsches Ergebnis liefert?
Danke
Gruß
Stefan
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.
Disclaimer: none. Sue me.
Lesezeichen