Forum: Mikrocontroller und Digitale Elektronik PWM Sinus 440 Hz funktioniert nicht


von Heinz (Gast)


Lesenswert?

Hallo

ich habe hier einen ATmega8 @ 16 Mhz.


Mit diesem möchte ich ein 440 Hz Sinussignal per PWM ausgeben.

Timer 2 ist auf fast PWM geschaltet.

Es wird vorher eine Tabelle mit 20 verschiedenen Sinuswerten berechnet.


Der Timer1 COMPA Interrupt gibt der PWM jeweils den nächsten berechneten 
Sinuswert. Dieser Interrupt wird alle T=1/(440Hz*20 Schritte) ausgelöst.

Somit sollte an OC2 ein 440 Hz Sinussignal anliegen.

Leider habe ich kein Scope hier sondern nur einen Lautsprecher. Der 
Ausgang geht an 2 Transistoren (Endstufe) und von dort aus an den 
Lautsprecher. Es ist nichts zu hören.


Vielleicht kann mit ja jemand von euch helfen. Ich bedanke mich schonmal 
im vorraus.


Hier der Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <math.h>
4
5
#define pi 3.1415926
6
7
void init(void);
8
9
unsigned int anzahlWerte=20;
10
unsigned char sinusWerte[20];
11
12
unsigned int step=0;
13
14
ISR(TIMER1_COMPA_vect)
15
{
16
    OCR1AL=sinusWerte[step];
17
  step++;
18
  if(step==20) step=0;
19
}
20
21
22
23
int main(void)
24
{
25
26
  init();
27
  while(1);
28
  return 0;
29
}
30
31
void init(void)
32
{
33
  int i;
34
  for(i=0;i<anzahlWerte;i++)
35
    sinusWerte[i]=(unsigned char)(127.5+127.5*sin(2.0*pi*i/anzahlWerte));
36
  DDRB=0b00001000;    // PWM Ausgang OC2
37
  TCCR2=(1<<WGM21)|(1<<WGM20)|(1<<COM21)|(1<<CS20);  // Fast PWM, non invertig mode, no prescaler
38
  OCR2=128;  // Lautsprecher aus: PWM auf 50%
39
  
40
  TCCR1A=(1<<WGM12);  // CTC
41
  TCCR1B=(1<<CS11);  // CLK/8
42
  OCR1AL=227;      // Entspricht Sinus mit ca 440 Hz
43
  sei();
44
}

von Heinz (Gast)


Lesenswert?

Einen Fehler habe ich entdeckt.


Im Interrupt muss es natürlich

OCR2=sinusWerte[step];

statt

OCR1AL=sinusWerte[step];

heißen.


Leider funktioniert es trotzdem noch nicht.

von Heinz (Gast)


Lesenswert?

So, noch ein Fehler; ich hatte den Interrupt nicht aktiviert.


TIMSK=(1<<OCIE1A);


habe ich in der init() Funktion hinzugefügt.

Der Ausgang wird an einer LED getestet und es leuchtet mit ca 1,5 Hz.


Um diesen jetzt auf 440 Hz zu bringen muss TCNT1 beim Aufruf des 
Interrupt resettet werden.


Ich dachte dies würde durch
1
TCCR1A=(1<<WGM12);  // CTC
 passieren. Leider macht ers nicht. Vielleicht kann mir jemand sagen was 
ich falsch gemacht habe?

von hans (Gast)


Lesenswert?

versuchs mal mit 16BIT (also nicht H/L)

OCR1A=227;      // Entspricht Sinus mit ca 440 Hz

Der Compiler setzt das dann passend um.

gruß hans

von Heinz (Gast)


Lesenswert?

Hallo! Danke soweit.

Hab alles umgeändert. Ändert aber nichts daran, dass TCNT1 nicht 
gelöscht wird. Ich bin soweit der 440 Hz Ton ausgeben zu können:

ISR(TIMER1_COMPA_vect)
{
  TCNT1=0;
    OCR2=sinusWerte[step];
  step++;
  if(step==20) step=0;
}


Ich dachte durch das

TCCR1A=(1<<WGM12);  // CTC

wäre TCNT1=0; unnötig. Leider wird TCNT1 nur gelöscht wenn ich es selber 
in den Interrupt reinschreibe. Dann sind auch die 440 Hz zu hören.

von hans (Gast)


Lesenswert?

das Bit WGM12 ist in TCCR1B (wenn mein Datenblatt stimmt).

  TCCR1A=0;
  TCCR1B=(1<<CS11)|(1<<WGM12); // CLK/8, CTC

und es läuft (denke ich)

gruß hans

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.