Sinus sehr seltsam

Gast #2356677
Lesenswert?

Hallo,
es gibt viele Threads dazu, die mir alle nicht weiterhelfen.

ich möchte per pwm einen hörbaren Sinus mit verschiedenen Frequenzen 
realisieren.
ATtiny44a  3V

ich habe dieses Beispiel in die Register meines AVR's übersetzt:
http://www.infolexikon.de/blog/atmega-music/

ich habe keine Filterung und ein Piezo ist direkt zwischen Pin und 
Masse.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdio.h>
4
#include <stdint.h>
5
#include <avr/pgmspace.h>
6
#include <util/delay.h>
7
// Noten-Frequenzen
8
#define c 2
9
#define d 90
10
#define e 50000
11
#define p 0   // Pause
12
struct notendauer
13
{
14
uint16_t note;
15
uint16_t dauer;
16
};
17
struct notendauer entchen[3] =
18
{
19
{c,1200}, {d,1200}, {e,500}
20
};
21

22
// einfache Sinuswelle in 128 Werten
23
const uint8_t  sinewave[1][128] PROGMEM=
24
{
25
{
26
127, 
27
133, 
28
139, 
29
// ... für das Forum verkürzt, es sind wirklich 128 ...
30

31
115, 
32
121
33
}
34
};
35
uint16_t i=0;
36
uint8_t tone=0;
37
volatile uint16_t scale=523;
38

39
// Interrupt-Funktion, die den "Zeiger" hochzählt
40
// je nach gewünschter Frequenz wird "scale" verändert, 
41
// und somit die Sinuswelle schneller (hoher ton) 
42
// oder langsamer (tiefer Ton) abgelaufen
43
ISR(TIM1_COMPA_vect){
44
  OCR1A=pgm_read_byte(&sinewave[tone][(i>>8)]);
45
     i += scale;
46
}
47
int main(void)
48
{
49
    // PWM-INIT -----------------------------------
50
  // PA 6 als ausgang pwm ausgang 44a
51
  DDRA=(1<<PA6);  
52
  // Anfangswert der PWM
53
  OCR1A=0x80;  // 128  
54
  //Output compare OC1A 8 bit non inverted PWM
55
  TCCR1A=0x91;  
56
  // Timer ohne Prescaler starten
57
    TCCR1B=(1<<CS10); 
58
  
59
  // Einschalten des Ausgangs-Vergleichs-Interrupts auf OC1A (PA6)
60
      TIMSK1=(1<<OCIE1A);
61
  //enable global interrupts
62
  sei();
63
    // MAIN-LOOP ----------------------------------
64
    while(1)
65
    {
66
  // durch das Noten-Array laufen und nacheinander
67
  // die Töne in jeweiliger Länge abspielen
68
  // da "scale" global definiert ist, kann es einfach
69
  // hier geändert werden!
70
  for(int y=0;y<3;y++){
71
    scale = entchen[y].note;
72
//  scale = 9000;
73
  //  _delay_ms(entchen[y].dauer);
74
  _delay_ms(9000);
75

76
    // Interrupt kurz ausschalten
77
    cli();
78
    i=0;
79
    sei();
80
  }
81
    }
82
    return 0;
83
}


Das Problem ist, dass immer die gleiche Frequenz raus kommt. Wenn scale 
klein ist also so zwischen 2 und 90 höre ich diese Frequenz schwingend 
lauter und leiser werden. Wenn scale sehr groß ist, brummt es.
Wenn ich PROGMEM nicht verwende scheint alles schneller zu laufen: bei 
hohem scale hört man Rauschen (mit der alt bekannten Frequenz im 
Hintergrund) bei niedrigem scale hat man wieder den Tremolo-effekt.

Auch das Orginal klingt auf einem ATMEGA 8 nicht nach Alle meine 
Entchen.
Was ist da los?

kann mir jemand helfen?
Gast #2356683
Lesenswert?

Hi!
>ich habe keine Filterung
Aus dem Bauch heraus würde ich sagen das ist dein Problem weil du die 
Grundfreqenz der PWM überlagert hast. Obwohl, du hast ja 8-Bit PWM, 
wobei 1MHz/256=3,9KHz... da spielst du überhaupt kein Entchen. Mit 16MHz 
biste bei 62,4KHz, das könnte eher gehen. Vermutlich biste aber so bei 
1MHz und dein Tremolo könnte doch glatt der Ton sein. Musste halt etwas 
langsamer hören, da wirds schon passen ;)Welchen Grundtakt hat denn der 
Proz.?

Schöne Nacht noch, Uwe
Gast #2356931
Lesenswert?

Guten Morgen,
Dankefür Antworten

> 1MHz und dein Tremolo könnte doch glatt der Ton sein. Musste halt etwas
> langsamer hören, da wirds schon passen ;)Welchen Grundtakt hat denn der
> Proz.?

über die Fuse sind 8MHZ eingestellt, im Datenblatt steht oben bei der 
Übersicht  0 – 10 MHz @ 2.7 – 5.5V  ich habe 3V und keinen externen 
Quarz.
wie kann ich Frequenz "messen"?
wenn ich statt 256 Sinusstützpunkten 128 nehme ist der Ton der gleiche, 
Tremolo aber schneller.

Bei höherem scale (z.B. 30000) rauscht es dann aber mit Grundton leise 
im Hintergrund. Auch ohne Filterung müsste ich doch was anderes hören. 
Oder nein, bei 30000 springt er 30000 Schritte weiter was kein Sinus 
mehr ist sondern Chaos?!??

Wenn nun der Tremolo mein Ton ist (was ich auch irgendwie glaube), wie 
bekomme ich ihn in den hörbaren bereich als Sinus???  Und warum höre ich 
einen Ton mit Tremolo? und nicht einfach nur Tremolo ohne Ton, also 
nichts?

>     cli();
>     sei();
>Wozu das?
im Original um Töne zu trennen, da ist noch ein kurzes delay drin um 
Pausen zwischen Tönen hervorzurufen, wenns weg ist ändert sich nichts.

>"von selbst" schwingen
der Piezo hat keine eingebaute Elektronik, es kommt raus was ich rein 
gebe.

thank you very much
Gast #2357283
Lesenswert?

die Fuse war auf 1MHZ
jetzt ist sie auf 8MHZ int. osz.
und der Atmega8 war dummerweise verpolt
neues Soundbeispiel
habe leider kein Oszi, aber Sound vergrößert sieht so aus wie auf dem 
Bild
ich weiß wirklich nicht warum das nicht genauso klingt wie in dem 
Beispiel von dem anderen Thread, von dem ich es ja habe. (.c datei 
unten) dieses hier springt auch nicht in den Tönen...
vielleicht könnt ihr mir einen Tipp wie ich weiter machen soll geben, 
mit Eurer Erfahrung + Hintergrundwissen?
Emulator hab ich leider auch keinen.
Was könnte noch falsch sein?
Klingt das so weil kein Filter dahinter?
danke
Angehängte Dateien:
Gast #2357323
Lesenswert?

Kann nicht gehen.
1
const uint8_t  sinewave[1][128] PROGMEM=
2
...
3
uint16_t i=0;
4
...
5
OCR1A=pgm_read_byte(&sinewave[tone][(i>>8)]);
6
i += scale;
Deine Sinustabelle enthält 128 Werte/Bytes. Nimm das im ersten Lauf 
maximale Ergebnis für i = 65375, schiebe 8 mal und Du hast einen Index 
von 255. Bisserl mehr Index als Inhalt :D
Gast #2357342
Lesenswert?

danke für die Antwort!
oh ok
das (i>>8) hab ich auch noch garnicht verstanden
schieben?
wie mache ich es besser?

bei kleinem scale (z.B. 30) müsste es trotzdem klappen, oder?
ich versuche gleich mal die frequenz raus zu finden mit der der Tremolo 
schwingt...
Gast #2357367
Lesenswert?

mit meinem tiny44a (ansatz von ganz oben) und codeänderungen:
#define c 1
#define d 900
#define e 50000
//...
const uint8_t  sinewave [32] =
// 32 werte hier
//...
OCR1A=pgm_read_byte(&sinewave[tone][(i>>8)]);
...
bekomme ich schon so etwas wie tiefe Töne hin.
drei verschiedene habe ich ja. sie verändern sich nach jedem durchlauf 
(höre soundbsp.)

bestimmt liegt es wirklich an dem falschen "schieben" und an dem Takt 
des Prozessors. Mit 1MHZ muss ich doch trotzdem 20000Hz sinustöne 
erzeugen können???
Angehängte Dateien:
Gast #2357382
Lesenswert?

mit nur 32 stützpunkten
1 MHZ/32= 31,250 KHZ
32 reichen mir erstmal, soll nur etwas schöner als das rechteck klingen
wie ändere ich die Zeile
OCR1A=pgm_read_byte(&sinewave[tone][(i>>8)]);

bei
const uint8_t  sinewave [32] =
???
tausend dank für alle antworten, hab das gefühl ich bin kurz vor fertig
#2357486
Lesenswert?

William schrieb:

> wie mache ich es besser?

Indem du, wenn du das nächste mal Code klaust, den Code einfach nur auf 
das Allernotwendigste anpasst. D.h. andere Registernamen ausbügeln aber 
mehr nicht!

Dann lässt du diesen geklauten Code laufen und analysierst ihn. 
Eventuell machst du kleine Eingriffe um zu überprüfen, ob du verstanden 
hast wie der Code arbeitet. Nach dem Muster: Wenn ich das hier so 
ändere, dann müsste eigentlich das passieren. Tut es das auch?

Und erst dann fängst du an, größere Codeänderungen zu machen.
Ein offenbar notwendiges Array in der Größe zu ändern ist eine größere 
Änderung!
Gast #2357545
Lesenswert?

der geklaute Code lief ja auch schon nicht richtig, selbst auf dem im 
Original verwendeten Mega8 lief der Originalcode nicht richtig. Deshalb 
wundere ich mich ja.
Aber jetzt durch hin und her verändern (und eine Menge dabei lernen) 
habe ich schon was in die richtige Richtung hin bekommen.
>analysieren
>Wenn ich das hier so ändere, dann müsste eigentlich das passieren. Tut es das 
auch?
genau das mache ich...
>Um innerhalb des Indexes der Sinustabelle zu bleiben, muss man 9 mal
schieben
ok für welches array? 128 oder 32? wie rechne ich mir das selber aus?

der Controller hat auch einen 16 bit timer,kann ich damit mehr anfangen?
laut Datenblatt läuft der interne 8Mhz Oszillator bei 3V mit knapp 
7,8Mhz (attiny44a Datenblatt Seite 237)
wie finde ich heraus wie schnell er wirklich läuft?
kann ich es also gänzlich vergessen mit diesem speed z.B. 18kHZ als 
Sinus zu machen?
Wenn ich nur PWM in rechteck mache und den Comparewert ändere, geht das 
gut!
Gast #2357573
Lesenswert?

8bit: 0 bis 255, aber 256 werte
16bit: 0 bin 65535, aber 65536 werte

ich habe ja einen duty circle von 50%
also
OCR1A=0x80;  // 128

dann zählt er bis 128 hoch und liegt somit bei
7,8 MHZ / 128 =  60,9375 KHZ
rechne ich falsch?
oder 7,8MHZ/256= 30,49 KHZ
wie finde ich die geschwindigkeit des Prozessors in etwa ohne Oszi 
heraus?
Danke
#2357641
Lesenswert?

Hallo,

ich habe auch schon erfolgreich per PWM Töne erzeugt, nur nach einen 
etwas anderem Schema.

Du benötigst noch einen PWM TP-Filter, für den Morse-Übungsgenerator mit 
Mikroprozessor habe ich das so gemacht:

Schaltplan
- http://www.qrpforum.de/index.php?page=Attachment&attachmentID=8949

Steckbrett
- http://www.qrpforum.de/index.php?page=Attachment&attachmentID=9097

Der kleine atTiny85 läuft bei mir über den R/C Oszillator + PLL mit 
16MHz  und die beiden PWM-Kanäle mit 64MHz (PLL)!

Und so klingt das:

- http://www.qrpforum.de/index.php?page=Attachment&attachmentID=8945
Gast #2357667
Lesenswert?

hallo lieben Dank für all die Antworten
also sollte es besser CTC sein?
@Uwe S.
danke .für den Vorschlag, so werde ich es vielleicht das nächte Mal 
machen.
ich habe mich schon ziemlich auf diesen tiny hier vestgelegt und am 
Layout kann ich leider auch nix mehr ändern. Müsste damit doch auch 
klappen ...

nochmal: was ich möchte ist ein Sinus von irgendwas zwischen 12kHz und 
20kHz. schön wäre es wenn ich melodien machen könnte, muss aber nicht 
sein.

also ich bin jetzt nochmal alles durchgegangen und habe quälkot etwas 
besser lesbar gemacht (siehe unten)

nun bin ich wieder so weit wie am Anfang. Aufnahme habe ich mit 
hochgeladen. So klingt dieser Code. dies ist die Frequenz, die ich nun 
schon seit Tagen höre und es wäre super wenn ich die verändern könnte. 
Originalcode findet sich hier 
http://www.infolexikon.de/blog/atmega-music/


#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdint.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
// Noten-Frequenzen
#define c 1
#define d 90
#define e 4000
#define p 0   // Pause
struct notendauer
{
uint16_t note;
uint16_t dauer;
};
struct notendauer entchen[3] =
{
{c,1200}, {d,1200}, {e,500}
};
// einfache Sinuswelle in 256 diskreten Werten
const uint8_t  sinewave[1][256] PROGMEM=
{
{
0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0x 
ab,0xae,
0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0x 
d5,0xd8,
0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0x 
f3,0xf5,
0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0x 
ff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0x 
f8,0xf7,
0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0x 
de,0xdc,
0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0x 
b6,0xb3,
0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x 
86,0x83,
0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x 
54,0x51,
0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x 
2a,0x27,
0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x 
0c,0x0a,
0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x 
00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x 
07,0x08,
0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x 
21,0x23,
0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x 
49,0x4c,
0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x 
79,0x7c
}
};
uint16_t i=0;
uint8_t tone=0;
volatile uint16_t scale=523;
// Interrupt-Funktion, die den "Zeiger" hochzählt
// je nach gewünschter Frequenz wird "scale" verändert,
// und somit die Sinuswelle schneller (hoher ton)
// oder langsamer (tiefer Ton) abgelaufen
ISR(TIM1_COMPA_vect){
//  OCR1A=(&sinewave[tone][(i>>11)]);
  OCR1A=pgm_read_byte(&sinewave[tone][(i>>8)]);
     i += scale;
}
int main(void)
{
    // PWM-INIT -----------------------------------
  // PA 6 als ausgang pwm ausgang 44a
  DDRA=(1<<PA6);
  // Anfangswert der PWM
  OCR1A=128;
  //Output compare OC1A 8 bit non inverted PWM
  TCCR1A= (1<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (1<<COM1B0) | 
(1<<WGM10);
  // Timer ohne Prescaler starten
    TCCR1B=(1<<CS10) | (0<<WGM13) | (0<<WGM12);
  // Einschalten des Ausgangs-Vergleichs-Interrupts
      TIMSK1=(1<<OCIE1A);
  sei();
    // MAIN-LOOP ----------------------------------
    while(1)
    {
  // durch das Noten-Array laufen und nacheinander
  // die Töne in jeweiliger Länge abspielen
  // da "scale" global definiert ist, kann es einfach
  // hier geändert werden!
  for(int y=0;y<3;y++){
  scale = entchen[y].note;
  _delay_ms(7000);
    // Interrupt kurz ausschalten, gibt kurze Pause
    // so werden die Töne getrennt
/*
    cli();
    i=0;
    sei();
*/
  }
    }
    return 0;
}
Angehängte Dateien:
Gast #2357725
Lesenswert?

William schrieb:
> also sollte es besser CTC sein?

CTC könnte die Sache schon noch schneller machen, was halt die 
ISR-Ausführungszeit hergibt.

Nur, da Du diesen Code offensichtlich noch nicht recht verstehst, würde 
das noch 'ne Baustelle mehr, auf die Du verzichten solltest.
Wie schon gesagt, bei kleinerer Tabelle musst Du 9 mal schieben, hast Du 
das gemacht ?

Ansonsten fällt am Originalcode auf, daß auch OC1B aktiviert wird, aber 
ohne weitere Maßnahmen, wie DDR-Register auf Ausgang zu setzen. Sieht 
also etwas unausgereift aus. Sowas zeugt auch davon:

> TCCR1A=0x91;
> TCCR1B=0x01;

Versteht kein Mensch.

Wie wär's wenn Du Deinen kompletten Code als Anhang postest ? Dann ist 
der auch schöner formatiert und man kann auch einen Blick auf die 
Sinustabelle werfen.
Gast #2357770
Lesenswert?

hi

>da Du diesen Code offensichtlich noch nicht recht verstehst

um euch zu veranschaulichen was ich wie und nicht vielleicht verstehe, 
korrigiert mich wenn ich irgendwo falsch liege:

der Timer1 (16bit!!! bei tiny44a und auch bei mega8 im Original) wird 
ohne Prescaler (in Prozessorgeschwindigkeit) hochgezählt.
Bis wohin habe ich nicht verstanden. Wohl bei 16bit von 0 bis 65535.
Wenn der Timer "überläuft" wird das Interrupt aufgerufen.

Im Interrupt wird von einem Sinusstützwert auf einen anderen in dem 
array verwiesen (gezeigt?)

Das geschieht per DDS (weiß ich was das ist), das man über scale 
einstellt.
scale wiederum wird über das Notenarray geändert.
Das heißt per DDS wird die Sinuskurve steiler oder flacher, je nach 
scale, und somit die Frequenz höher oder tiefer.
Nachteil DDS: Auflösung ändert sich, das ist mir egal.

Das mit Pointer und schieben habe ich noch nicht ganz verstanden.Und 
warum da ein 2dimensionales Array genommen wird auch nicht.

kleine Tabelle und
>9 mal schieben
habe ich gemacht und ändert nichts

hier ist wieder die Original-große Tabelle
ich habe sie mal kleiner gemacht gehabt, weil wenn PROGMEM weg, also 
array in den RAM schreibe, ist RAM in meinem tiny dafür zu kein Platz.

Aus dem RAM lesen scheint schneller zu sein als aus dem Flash.
Array in RAM speichern, kein Problem. Aber auslesen? Wie mache ich das?
ist wieder die Zeile
OCR1A=pgm_read_byte(&sinewave[tone][(i>>8)]);

auch die Notendauer habe ich fest mit delay eingestellt weil die 
Rechnung vom Original zu groß für tiny ist.

>Sieht also etwas unausgereift aus.
finde ich leider auch. Allerdings habe ich nichts besseres gefunden

so, bei meinen ganzen Probehörungen vermute ich dass das  Scrollen im 
Sinusarray zu langsam ist? also Interrupt zu selten aufgerufen wird. 
allerdings wundere ich mich immernoch woher diese Frequenz kommt + 
aufmoduliertem Tremolo. Also zwei Frequenzen.

habt ihr was besseres oder eine theoretische Anleitung wie ich das 
selbst Programmiere, kann doch nicht so schwer sein... vielleicht am 
Besten ohne Pointer für mich? kann auch mit fester hoher Frequenz sein.
Angehängte Dateien:
Gast #2357795
Lesenswert?

und nochmal zum Geschwindigkeit ausrechnen:
8bit Timer weniger Auflösung, läuft schneller über
16bit Tmer höhere Auflösung, Überlauf seltener

bei unserer 8 bit Rechnung müsste man ja dann schon so rechnen:
 7,8MHz/(2*256) = 15,23kHz
2 mal 256 weil:
1 mal braucht Timer 256 Takte bis Überlauf
1 mal braucht eine volle Sinuswelle 256 mal diesen Überlauf, zumindest 
bei scale=1
oder
7,8 MHZ/256 hoch zwei = 119 Hz

hab ich jetzt richtig gerechnet?

also besser 8bit Timer?
15kHz ist etwas unter dem was ich wollte... wenns höher geht ist besser
Gast #2358438
Lesenswert?

William schrieb:
> Aus dem RAM lesen scheint schneller zu sein als aus dem Flash.

Das geht schnell genug.

William schrieb:
> habe es endlich geschafft
> mit CTC
> eindimensionalem sinusarray
> ohne notenarray
> und dem hochzählen und ändern von OCR1A in der while(1) schleife
> ohne ISR
> vielen dank nochmal an alle!

Dann stell' es doch ein, entweder Andere können daraus lernen, oder man 
kann erkennen, wo der vorherige Fehler lag.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren