Forum: Mikrocontroller und Digitale Elektronik PWM - OCR1A ändert nichts?


von Marcel (Gast)


Lesenswert?

Hallo!
Ich versuche gerade per PWM Töne auf einem Lautsprecher zu erzeugen. Die 
Tonhöhe würde ich dabei gerne über den OCR1 Wert verändern (Benutze 
einen ATMega16 und Timer1).

So initialisiere ich den Timer:

TCCR1A = (1<<WGM11)|(1<<WGM10)|(1<<COM1A1);
TCCR1B = (1<<CS11) ;
OCR1A = 0x0515;

Aber egal was ich in OCR1A schreibe, der Ton bleibt immer der gleiche 
:-(
Woran kann das liegen?

von Erklärer (Gast)


Lesenswert?

PWM ändert, wie der Name schon sagt, nur das Tastverhältnis, die 
Freuqenz bleibt gleich. Die du unterschiedliche Tonhöhen haben willst 
musst du das anders machen, z.B. CTC Mode

von Marcel (Gast)


Lesenswert?

Was genau ist denn der CTC Mode? Im AVR GCC Tutorial kann ich da auf 
anhieb nix finden :-(

von Karl H. (kbuchegg)


Lesenswert?

Marcel wrote:
> Was genau ist denn der CTC Mode?

CTC
Clear Timer on Compare

Bei erreichen eines bestimmten Zählerstandes, den du vorgeben
kannst, wird der Timer wieder auf 0 gesetzt.

> Im AVR GCC Tutorial kann ich da auf
> anhieb nix finden :-(

Dann wirds Zeit den mal auszuprobieren. CTC funktioniert fast
so wie der Overflow eines Timers. Nur dass du die Zahl vorgibst
an der dieser 'Overflow' ausgelöst werden soll, bei der
der Timer wieder auf 0 gesetzt wird. Ach ja. Der Interrupt
heist auch anders.

PS: Im AVR Gcc Tutorial wirst du über viele Bereiche deines
Prozessors nichts finden. Deshalb ist es auch so wichtig,
das Datenblatt seines Prozessors zur Hand zu haben. Dieses
Datenblatt kann man bei Atmel downloaden.

von Marcel (Gast)


Lesenswert?

Interrupt hab ich bisher garnicht benutzt, da gibt es ja einen extra 
output pin für's PWM.
Heißt das also ich mach jetzt einen Interrupt in dem ich einen 
bestimmten Pin umschalte, und stelle dann ein wie oft dieser Interrupt 
aufgerufen wird?
Hab ich das richtig verstanden? ;-)

von Marcel (Gast)


Lesenswert?

So, habe mal im Datenblatt nachgesehen. Leider kommt jetzt garnichts 
mehr aus dem Speaker (der nun an PortB hängt).
Hier die Timerinitialisierung:

TCCR1B = (1<<WGM12)|(1<<WGM13)|(1<<CS12);
OCR1A = 0x0015;

Und der Interrupt:

ISR(TIMER1_COMPA)
{
    PORTB = 255-PORTB;
}

von Karl H. (kbuchegg)


Lesenswert?

Marcel wrote:
> Interrupt hab ich bisher garnicht benutzt, da gibt es ja einen extra
> output pin für's PWM.

Schon. Aber PWM macht ja ganz was anderes.

> Heißt das also ich mach jetzt einen Interrupt in dem ich einen
> bestimmten Pin umschalte, und stelle dann ein wie oft dieser Interrupt
> aufgerufen wird?
> Hab ich das richtig verstanden? ;-)

So in etwa könnte man das sagen.
Du schreibst eine ISR (eine Interrupt Service Routine).
Diese ISR wird aufgerufen, wenn bestimmte Bedingungen
oder Ereignisse eintreten. Ein derartiges Ereignis ist
zb. das der Timer seinen vorgegebenen Wert erreicht hat
und jetzt auf 0 zurückgesetzt wird.

Darüber müsste es im Gcc Tutorial aber einen Abschnitt
geben.

von Karl H. (kbuchegg)


Lesenswert?

Marcel wrote:
> So, habe mal im Datenblatt nachgesehen. Leider kommt jetzt garnichts
> mehr aus dem Speaker (der nun an PortB hängt).
> Hier die Timerinitialisierung:
>
> TCCR1B = (1<<WGM12)|(1<<WGM13)|(1<<CS12);
> OCR1A = 0x0015;
>
> Und der Interrupt:
>
> ISR(TIMER1_COMPA)
> {
>     PORTB = 255-PORTB;
> }

Da fehlt aber noch einiges.
Es gibt in einem AVR viele Interrupt Quellen. Du musst also
entscheiden welche Interrupts zugelassen werden und welche
nicht. Und du musst die Interrupts generell freigeben.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmieren_mit_Interrupts

von Marcel (Gast)


Lesenswert?

Habe jetzt noch

TIMSK |= (1 << OCIE1A);

hinzugefügt, aber das half leider auch nichts :-(

von Karl H. (kbuchegg)


Lesenswert?

Marcel wrote:
> Habe jetzt noch
>
> TIMSK |= (1 << OCIE1A);
>
> hinzugefügt, aber das half leider auch nichts :-(

hast du einen
1
  sei();
gemacht?
1
...
2
3
int main()
4
{
5
   ....
6
   .... alles initialisieren
7
   ....
8
9
   sei();   // ab jetzt können Interrupts zuschlagen
10
11
   while( 1 ) {
12
      ....
13
   }
14
}

von Marcel (Gast)


Lesenswert?

yep, hab ich....

von Karl H. (kbuchegg)


Lesenswert?

Marcel wrote:
> yep, hab ich....


Und?
Zeigst du jetzt endlich mal dein Programm so wie es jetzt ist,
oder sollen wir weiter raten, was eventuell nicht stimmen könnte?

von Marcel (Gast)


Angehängte Dateien:

Lesenswert?

Oh, Entschuldigung. Hier ist das Programm

von Karl H. (kbuchegg)


Lesenswert?

Da fällt mir gleich mal auf

ISR(TIMER1_COMPA)

Der Name des Interrupts ist falsch. Interrupt Namen enden
immer auf '_vect', also kann das schon mal nicht TIMER1_COMPA
heissen.

von Karl H. (kbuchegg)


Lesenswert?

TCCR1B = (1<<WGM12)|(1<<WGM13)|(1<<CS12);
  TIMSK |= (1 << OCIE1A);
  OCR1A = 0x0015;


Wenn du WGM12 und WGM13 setzt, dann gilt als Topwert nicht
OCR1A sondern ICR1.

Quelle: Siehe Datenblatt

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.