Hallo, ich habe hier ein Arduino-Board mit einem ATmega328P, das ich jedoch in C programmiere. Nun habe ich einen Lautsprecher, den ich gerne ansteuern möchte. Einfache Rechtecksignale sind kein Problem, da habe ich mir bereits einige Funktionen geschrieben, mit denen ich (wenn auch nur sehr geringfügig) die Lautstärke bei gleichbleibender Frequenz ändern kann sowie +- 3Hz eine Frequenz ausgeben kann. Bei den nächsten Schritten habe ich aber Probleme: Wie kann ich zwei Töne gleichzeitig ausgeben (über einen Lautsprecher)? Wenn ich zwei Frequenzen gleichzeitig über einen Pin ausgebe, dann bekomme ich üblicherweise nur den oberen Ton und ein "Rattern" (eher so ein Knacksen) auf Höhe des unteren Tons zu hören. Wie macht man so etwas üblicherweise? Und: mein Ziel ist es, auch Audio-Dateien wiederzugeben. Allerdings ohne externe SD Card. Dafür muss ich natürlich die Qualität der Datei extrem vermindern, meine Schritte waren folgende: mp3-Datei auf mono umstellen, auf 1000Hz heruntersamplen und als headerless raw-file in unsigned 8-bit gespeichert. Um die dann direkt in den Code einbetten zu können, habe ich mithilfe von xdd (Linux commandline hex editor) den Inhalt in Hex-Werte umgewandelt und in ein gültiges C-Array gepackt. Mein Problem ist jetzt, wie ich diese Werte ausgeben kann. Wie ermittle ich die benötigten Frequenzen? Danke für jede Hilfe!
Arduino und Atmega328 sind hier meiner Meinung nach völlig ungeeignet. Ein ARM mit I²S wäre hier z.B. angebrachter. Du begibst dich hier auf einn Irrweg.
A. Audio schrieb: > mp3-Datei auf mono umstellen, auf 1000Hz heruntersamplen Da das Abtasttheorem nicht so einfach ausser Kraft zu setzen ist, wird auf die Art die höchste in der Datei wiederzugebende Frequenz bei etwa 500Hz sein, abgesehen von dem Problem, die 1kHz Samplefrequenz vom Ausgang fernzuhalten. Deswegen ist die niedrigste Samplefrequenz, die man so benutzt, bei ca. 8kHz. Dann geht wenigstens Sprache oder der schlechteste Mittelwellensender der Welt.
:
Bearbeitet durch User
A. Audio schrieb: > Wie ermittle ich die benötigten Frequenzen? Du brauchst genau eine Frequenz, und die hast Du bereits festgelegt - das ist die Samplerate. Deine Audiosamples musst Du mit genau dieser Datenrate an einen DAC übergeben, und aus dem DAC kommt dann Dein gewünschtes Audiosignal heraus. Problem: Dein Atmega328 hat keinen eingebauten DAC. Mit einer entsprechend höhergetakteten PWM lässt sich ein DAC nachbilden; Du brauchst, da Du 8-Bit-Samples hast, eine 8-Bit-PWM, was bedeutet, daß deren Frequenz das 256fache Deiner Samplerate betragen muss. Bei 1 kHz Samplerate sind das also 256 kHz.
Du kannst auch einen ganzen Port opfern und dort ein sog. R 2xR Netzwerk dran machen. Das ist sozusagen ein passiver D/A-Wandler. MIT gleichen SMD-Widerständen kriegt man das auch einigermaßen klein hin. Ich habe das mal für ein Lokomoteufelchen (Modelleisenbahn) gebraucht, damit der Lokführer Sprüche zum Besten geben konnte. Ich muß gucken, wo ich das habe -auf dem Rechner hier ist es nicht. MfG Paul
Das ist tatsächlich eine gute und pragmatische Idee. Hier die Grundlagen dazu: https://de.wikipedia.org/wiki/R2R-Netzwerk
Curby23523 N. schrieb: > Arduino und Atmega328 sind hier meiner Meinung nach völlig > ungeeignet. > Ein ARM mit I²S wäre hier z.B. angebrachter. Du begibst dich hier auf > einn Irrweg. ARM sind schon bestellt, dauert aber noch. Die sind dann mein nächster Schritt. Allerdings gibt es genug Videos, die unter Beweis stellen, dass das eigentlich auch mit einem ATmega gehen müsste. Der verwendete Code ist da eigentlich immer die Audio.h Lib aus der Arduino IDE. Matthias S. schrieb: > A. Audio schrieb: >> mp3-Datei auf mono umstellen, auf 1000Hz heruntersamplen > > Da das Abtasttheorem nicht so einfach ausser Kraft zu setzen ist, wird > auf die Art die höchste in der Datei wiederzugebende Frequenz bei etwa > 500Hz sein, abgesehen von dem Problem, die 1kHz Samplefrequenz vom > Ausgang fernzuhalten. > Deswegen ist die niedrigste Samplefrequenz, die man so benutzt, bei ca. > 8kHz. Dann geht wenigstens Sprache oder der schlechteste > Mittelwellensender der Welt. Das es grausig klingt, weiß ich auch. Die SD Card Module sind auch schon bestellt, ich wollte nur schon einmal vorab den Code fertigen. Und dafür müsste ja eigentlich erst einmal auch eine Sampling Rate von 1000Hz reichen, oder nicht? Man erkennt zumindest am PC einigermaßen, was gemeint ist. Es geht hier auch nur um kurze Töne von 1-2s. Rufus Τ. F. schrieb: > A. Audio schrieb: >> Wie ermittle ich die benötigten Frequenzen? > > Du brauchst genau eine Frequenz, und die hast Du bereits festgelegt - > das ist die Samplerate. > > Deine Audiosamples musst Du mit genau dieser Datenrate an einen DAC > übergeben, und aus dem DAC kommt dann Dein gewünschtes Audiosignal > heraus. > > Problem: Dein Atmega328 hat keinen eingebauten DAC. > > Mit einer entsprechend höhergetakteten PWM lässt sich ein DAC > nachbilden; Du brauchst, da Du 8-Bit-Samples hast, eine 8-Bit-PWM, was > bedeutet, daß deren Frequenz das 256fache Deiner Samplerate betragen > muss. > > Bei 1 kHz Samplerate sind das also 256 kHz. Wieso muss diese das 256-fache der Samplingrate betragen? Es müsste doch auch reichen, wenn PWM mit z.B. 32kHz läuft. Da lassen sich doch auch bequem 8-bit drauflegen, oder nicht? Und 32kHz wären eigentlich noch im Machbaren. Paul B. schrieb: > Du kannst auch einen ganzen Port opfern und dort ein sog. R 2xR > Netzwerk > dran machen. Das ist sozusagen ein passiver D/A-Wandler. MIT gleichen > SMD-Widerständen kriegt man das auch einigermaßen klein hin. Ich habe > das mal für ein Lokomoteufelchen (Modelleisenbahn) gebraucht, damit der > Lokführer Sprüche zum Besten geben konnte. > > Ich muß gucken, wo ich das habe -auf dem Rechner hier ist es nicht. > > MfG Paul Ich kann leider max. 2 Pins dafür opfern. Alle anderen sind bereits anderweitig verplant. Wobei das mit Sicherheit auch mal interessant wäre. Rufus Τ. F. schrieb: > Das ist tatsächlich eine gute und pragmatische Idee. > > Hier die Grundlagen dazu: > > https://de.wikipedia.org/wiki/R2R-Netzwerk Aber wohl leider nicht möglich, da ich nicht so viele Pins frei habe.
A. Audio schrieb: > Ich kann leider max. 2 Pins dafür opfern. Alle anderen sind bereits > anderweitig verplant. Daraus schließe ich, daß der Kontroller auch noch eine Menge anderer Sachen machen muß bzw. soll. Denke aber daran, daß so eine Sprach- bzw. Musikausgabe den ganzen Mann fordert. Jede Unterbrechung oder Verzögerung ist dann sehr störend hörbar. MfG Paul
Die anderen Sachen sind weder zeitkritisch noch allzu rechenaufwendig. Das wird auch die Interrupts nicht verzögern, da ansonsten keinerlei Interrupts verwendet werden (nur in dem gleichen Interrupt noch andere Sachen; ein bisschen wie in IRMP und IRSND). Es gibt einfach einen Interrupt, in denen verschiedene Interrupt-Funktionen aufgerufen werden. Es wäre mir also lieb, wenn es möglich wäre, das schon über Software zu implementieren. Wie gesagt, die Arduino Lib schafft das ja auch irgendwie. Was sonst vllt. noch möglich wäre, wäre ein zweiter µC, der nur für die Soundausgabe zuständig ist und den ich über SPI (das lässt sich ja, da schon benutzt, mit nur einem weiteren SS-Pin machen). Oder was meint ihr sonst noch?
Wenn Du noch zwei Pins frei hast, kannst Du ein Schieberegister nehmen, z.B. 74xx595 und ein R2R-Netzwerk, z.B. https://www.digikey.de/product-detail/de/bourns-inc/4310R-R2R-103LF/4310R-R2R-103LF-ND/3741102
Ist denn ein Schieberegister schnell genug? Ich habe zwar etliche hier herumliegen, aber ehrlich gesagt noch nie intensiver damit gearbeitet. Ich habe jetzt allerdings folgendes: ___. . . . . ._____ |. . | . . . . . . |. . . .| |. . |______|. . . .|____ |--------------||-------------| 32kHz Wenn ich jetzt in 256 verschiedenen Stufen die Breite des high-pegels bei einer Frequenz von 32kHz verändere, stimmt das dann? Jetzt wird nämlich ein Ton ausgegeben, der aber aufgrund seiner Kürze und Ungenauigkeit (600Hz) nicht einfach zu identifizieren ist. Durch die sehr kleinen (und damit eher schlechten) Lautsprecher wird das wohl vermutlich auch noch einmal verfälscht. Ansonsten bleibt mir wohl nichts anderes übrig, als auf das SD Module zu warten (nicht wundern, diese Pins habe ich bereits einberechnet; die kann ich deshalb nicht für die Soundausgabe nutzen). Kann das aber theoretisch stimmen? PS: Es ist ganz schön schwer, hier drinnen mit Zeichen zu zeichnen, wenn das Ergebnis ganz anders aussieht als im Editor.
A. Audio schrieb: > _. . . . . ._____ > |. . | . . . . . . |. . . .| > |. . |______|. . . .|____ > > |--------------||-------------| > 32kHz > PS: Es ist ganz schön schwer, hier drinnen mit Zeichen zu zeichnen, wenn > das Ergebnis ganz anders aussieht als im Editor. Jetzt kam sogar noch etwas anderes heraus als in der Vorschau gezeigt wurde. -.- Noch ein Versuch, ansonsten hoffe ich, dass ihr wisst, was ich meine: 256 verschiedene Breiten |--| . . .|----| _......._____ |..|......|....| |..|______|....|____ |---------||--------| 32kHz
A. Audio schrieb: > 256 verschiedene Breiten > |--| . . .|----| > _......._____ > |..|......|....| > |..|______|....|____ > > |---------||--------| > 32kHz Ich gebe es auf... Und entschuldigt bitte die mehrfachen Beiträge, die letzten beiden können gerne gelöscht werden.
A. Audio schrieb: > PS: Es ist ganz schön schwer, hier drinnen mit Zeichen zu zeichnen, wenn > das Ergebnis ganz anders aussieht als im Editor. Da gibts einen Tipp, der über jedem Eingabefeld für einen neuen Beitrag steht: Formatierung Wenn man da drauf klickt: https://www.mikrocontroller.net/articles/Formatierung_im_Forum die 'pre' tags wären brauchbar, dann kommts so raus, wie mans eintippt. Aber in eckige Klammern...
:
Bearbeitet durch User
Stimmt, ich habe nicht daran gedacht, Code-Tags dafür zu nutzen.
1 | > 256 verschiedene Breiten |
2 | |--| . . .|----| |
3 | |
4 | ___......._____ |
5 | |..|......|....| |
6 | |..|______|....|____ |
7 | |
8 | |---------||--------| |
9 | 32kHz 32kHz |
Jetzt aber. Danke für den Tipp. Auch wenn die "Skizze" wohl vermutlich nicht allzu hilfreich ist.
A. Audio schrieb: > Wie kann ich zwei Töne gleichzeitig ausgeben (über einen Lautsprecher)? > Wenn ich zwei Frequenzen gleichzeitig über einen Pin ausgebe, dann > bekomme ich üblicherweise nur den oberen Ton und ein "Rattern" (eher so > ein Knacksen) auf Höhe des unteren Tons zu hören. Hier hilft DDS. Aber zuerst was wichtiges: Arduino kannst du natürlich benutzen, aber nur als Board. Programmieren in Arduino-Umgebung bringt hier nichts, Programm wird zu langsam und es fehlt vieles in Arduino, was du brauchst. Deshalb nimm so etwas wie AVR Studio 4.19, noch ISP-Programmer, und noch ein bißchen "C" studieren. Wie kannst du einen Ton mit sehr, sehr genauer Frequenz ausgeben: 1. richte ein Timer so, daß du Interrupts mit ca. 20 bis 50 kHz hast. 2. nimm zwei Variablen. Eine wird Frequenzwert haben, weitere zählen, beide als unsigned long. Wenn wir Interrupt-Frequenz als Fd und Soll-Frequenz als Fv notieren, kannst du Frequenzwert so berechnen: K = (Fv/Fd)*2^32 In Interrupt wird immer gemacht:
1 | volatile unsigned long wert, freq; |
2 | wert = Fv*24294967296/Fd; |
3 | ISR: |
4 | freq += wert; |
weiter kannst du obere z.B. 8 bit von freq nehmen und als Frequenzausgang benutzen. Z.B. in PORTB schreiben, wo R-2R-Matrix angeschlossen wird. So einfach bekommst du Sägezahn. Willst du Sinus, so mach eine Sinustabelle, z.B. so:
1 | const unsigned char sinus_table[256] PROGMEM = { |
2 | 128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 162, 165, 167, 170, 173, |
3 | 176, 179, 182, 185, 188, 190, 193, 196, 198, 201, 203, 206, 208, 211, 213, 215, |
4 | 218, 220, 222, 224, 226, 228, 230, 232, 234, 235, 237, 238, 240, 241, 243, 244, |
5 | 245, 246, 248, 249, 250, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255, |
6 | 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 251, 250, 250, 249, 248, 246, |
7 | 245, 244, 243, 241, 240, 238, 237, 235, 234, 232, 230, 228, 226, 224, 222, 220, |
8 | 218, 215, 213, 211, 208, 206, 203, 201, 198, 196, 193, 190, 188, 185, 182, 179, |
9 | 176, 173, 170, 167, 165, 162, 158, 155, 152, 149, 146, 143, 140, 137, 134, 131, |
10 | 128, 124, 121, 118, 115, 112, 109, 106, 103, 100, 097, 093, 090, 088, 085, 082, |
11 | 079, 076, 073, 070, 067, 065, 062, 059, 057, 054, 052, 049, 047, 044, 042, 040, |
12 | 037, 035, 033, 031, 029, 027, 025, 023, 021, 020, 018, 017, 015, 014, 012, 011, |
13 | 010, 009, 007, 006, 005, 005, 004, 003, 002, 002, 001, 001, 001, 000, 000, 000, |
14 | 000, 000, 000, 000, 001, 001, 001, 002, 002, 003, 004, 005, 005, 006, 007, 009, |
15 | 010, 011, 012, 014, 015, 017, 018, 020, 021, 023, 025, 027, 029, 031, 033, 035, |
16 | 037, 040, 042, 044, 047, 049, 052, 054, 057, 059, 062, 065, 067, 070, 073, 076, |
17 | 079, 082, 085, 088, 090, 093, 097, 100, 103, 106, 109, 112, 115, 118, 121, 124 |
18 | };
|
weiter wird gemacht:
1 | PORTB = pgm_read_byte (&sinus_table[(unsigned char)(freq>>24)]); |
und Sinus ist da! Genauigkeit von Frequenz (abgesehen von Quarz-Toleranz) ist Fd/2^32, bei Fd = 50 kHz wird das 0,00001164... Hz. Nun deine Aufgabe, zwei Frequenzen auszugeben: nimm zweimal wert und freq, und addiere, was du aus der Sinus-Tabelle nimmst. Willst du statt Sinus etwas anderes, kein Problem: mache eine andere Tabelle.
:
Bearbeitet durch User
Servus, man braucht keine R2R-Matrix und viele Portausgänge! Mit einem PWM-Ausgang und Pulsbreitenmodulation, wie oben in den ASCII-Skizzen schon gezeigt, geht das wunderbar und kann sich auch hören lassen. Wenigstens ein simples RC-Filter sollte man aber schon dafür spendieren, sonst klingt es wirklich grausig. Hier habe ich das mal simuliert - ein 1kHz Sinuston wird mit 31.25kHz in Impulslängen zerlegt. Die Spannung an V3 wäre das Signal, das per Timer-PWM (z.B. ein 8-Bit Timer mit 8 MHz Clock) ausgegeben werden kann. Die WAV-Datei ist das Signal vom out.
Beitrag #5363799 wurde vom Autor gelöscht.
Maxim B. schrieb: > A. Audio schrieb: >> Wie kann ich zwei Töne gleichzeitig ausgeben (über einen Lautsprecher)? >> Wenn ich zwei Frequenzen gleichzeitig über einen Pin ausgebe, dann >> bekomme ich üblicherweise nur den oberen Ton und ein "Rattern" (eher so >> ein Knacksen) auf Höhe des unteren Tons zu hören. > > Hier hilft DDS. > Aber zuerst was wichtiges: > Arduino kannst du natürlich benutzen, aber nur als Board. Programmieren > in Arduino-Umgebung bringt hier nichts, Programm wird zu langsam und es > fehlt vieles in Arduino, was du brauchst. > > Deshalb nimm so etwas wie AVR Studio 4.19, noch ISP-Programmer, und noch > ein bißchen "C" studieren. Wie anfangs gesagt, ich nutze bereits C. DDS scheitert, wenn ich das richtig nachgelesen habe, an einem fehlenden DA-Wandler. > Wie kannst du einen Ton mit sehr, sehr genauer Frequenz ausgeben: > 1. richte ein Timer so, daß du Interrupts mit ca. 20 bis 50 kHz hast. > 2. nimm zwei Variablen. Eine wird Frequenzwert haben, weitere zählen, > beide als unsigned long. Wenn wir Interrupt-Frequenz als Fd und > Soll-Frequenz als Fv notieren, kannst du Frequenzwert so berechnen: K = > (Fv/Fd)*2^32 > > In Interrupt wird immer gemacht:volatile unsigned long wert, freq; > wert = Fv*24294967296/Fd; > ISR: > freq += wert; > weiter kannst du obere z.B. 8 bit von freq nehmen und als > Frequenzausgang benutzen. Z.B. in PORTB schreiben, wo R-2R-Matrix > angeschlossen wird. > So einfach bekommst du Sägezahn. Mit Sägezahn meinst du vermutlich ein Rechteck-Signal, oder? Weiterhin verstehe ich irgendwie deine Rechnung nicht ganz. Weshalb *2^32? Ich habe es bisher immer so gemacht: counter = INTERRUPTS_PER_S frequency 2; Dann in der ISR counter heruntergezählt und bei 0 den Pin getoggled. Um einen Wert auszugeben habe ich dazu folgendes ergänzt: counter = INTERRUPTS_PER_S / frequency; value_counter = INTERRUPTS_PER_S value 0xFF counter 255/256.; Beides in der ISR heruntergezählt und bei 0 von value_counter den Pin auf low gesetzt und bei counter == 0 den value_counter wieder eingestellt. Mein Problem ist, dass INTERRUPTS_PER_S bei großen Frequenzen natürlich zu klein ist. Wenn du mir deinen Ansatz noch einmal erklärst, kann ich das vllt. einbauen. Wobei ich dabei ehrlich gesagt auch die Gefahr sehe, dass die Werte zu groß werden. Was genau ist denn dann eigentlich freq für ein Wert, warum verwende ich nur die obersten 8 bits? > Willst du Sinus, so mach eine > Sinustabelle, z.B. so:const unsigned char sinus_table[256] PROGMEM = { > 128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 162, 165, 167, > 170, 173, > 176, 179, 182, 185, 188, 190, 193, 196, 198, 201, 203, 206, 208, 211, > 213, 215, > 218, 220, 222, 224, 226, 228, 230, 232, 234, 235, 237, 238, 240, 241, > 243, 244, > 245, 246, 248, 249, 250, 250, 251, 252, 253, 253, 254, 254, 254, 255, > 255, 255, > 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 251, 250, 250, 249, > 248, 246, > 245, 244, 243, 241, 240, 238, 237, 235, 234, 232, 230, 228, 226, 224, > 222, 220, > 218, 215, 213, 211, 208, 206, 203, 201, 198, 196, 193, 190, 188, 185, > 182, 179, > 176, 173, 170, 167, 165, 162, 158, 155, 152, 149, 146, 143, 140, 137, > 134, 131, > 128, 124, 121, 118, 115, 112, 109, 106, 103, 100, 097, 093, 090, 088, > 085, 082, > 079, 076, 073, 070, 067, 065, 062, 059, 057, 054, 052, 049, 047, 044, > 042, 040, > 037, 035, 033, 031, 029, 027, 025, 023, 021, 020, 018, 017, 015, 014, > 012, 011, > 010, 009, 007, 006, 005, 005, 004, 003, 002, 002, 001, 001, 001, 000, > 000, 000, > 000, 000, 000, 000, 001, 001, 001, 002, 002, 003, 004, 005, 005, 006, > 007, 009, > 010, 011, 012, 014, 015, 017, 018, 020, 021, 023, 025, 027, 029, 031, > 033, 035, > 037, 040, 042, 044, 047, 049, 052, 054, 057, 059, 062, 065, 067, 070, > 073, 076, > 079, 082, 085, 088, 090, 093, 097, 100, 103, 106, 109, 112, 115, 118, > 121, 124 > }; > weiter wird gemacht:PORTB = pgm_read_byte (&sinus_table[(unsigned > char)(freq>>24)]);und Sinus ist da! Hier ist das Prolbem, dass ich nicht den ganzen PORTB frei habe. Und ich will auch nicht einfach nur einen konstanten Ton erzeugen. Es geht darum, zwei Töne auf einem Lautsprecher ausgeben zu können, also quasi einen Akkord und letztendlich auch darum, ein (kleines) Audiofile abspielen zu können.
A. Audio schrieb: > counter = INTERRUPTS_PER_S frequency 2; > Dann in der ISR counter heruntergezählt und bei 0 den Pin getoggled. > Um einen Wert auszugeben habe ich dazu folgendes ergänzt: > counter = INTERRUPTS_PER_S / frequency; > value_counter = INTERRUPTS_PER_S value 0xFF counter 255/256.; Das heißt natürlich:
1 | counter = INTERRUPTS_PER_S / frequency / 2; |
und
1 | value_counter = INTERRUPTS_PER_S / (value / 0xFF * counter * 255/256.); |
Und noch ein Problem: Wenn man eine MP3-Datei im raw-format abspeichert, dann ist die 0 ja in der Mitte, also unsigned bei 127. Entsprechend müsste ich ja eigentlich bei 127 0 ausgeben und bei 126 -1. Aber ich kann über PWM ja nicht -1 ausgeben. Gibt es dafür noch eine Lösung? So hat man natürlich immer, wenn eigentlich 0 ausgegeben werden soll 127 und somit ein leichtes Rauschen.
A. Audio schrieb: > DDS scheitert, wenn ich das richtig nachgelesen habe, an einem fehlenden > DA-Wandler. Du solltest die "Klangsynthese" von der Ausgabe getrennt betrachten. Ob Du nun die Werte an einen integrierten DAC, Port mit R2R-Netzwerk oder PWM-Generator übergibst, ändert doch nichts an der Berechnung der Wellenform. Dementsprechend scheitert auch das DDS-Verfahren nicht, weil kein integrierter DAC vorhanden ist. A. Audio schrieb: > Mein Problem ist, dass INTERRUPTS_PER_S bei großen Frequenzen natürlich > zu klein ist. Die Interrupts werden bei DDS nicht häufiger, wenn die Frequenz des Audio-Signals erhöht wird. Die Interrupts laufen fest mit der Sample-Frequenz (z.B. 32kHz), egal, ob Du einen 1kHz oder 5kHz Ton (oder auch beide gleichzeitig) erzeugen willst.
:
Bearbeitet durch User
A. Audio schrieb: > value_counter = INTERRUPTS_PER_S / (value / 0xFF counter 255/256.); Mir scheint, Du willst die 8-Bit PWM per Software in Interrupts erzeugen - dazu bräuchtest Du ja dann tatsächlich eine Interrupt-Frequenz von 256*PWM-Frequenz - dieser Ansatz ist natürlich gleich zum Scheitern verurteilt! Die PWM muss natürlich mit Hardware-Unterstützung gemacht werden (Timer mit Output Compare). Bin jetzt nicht so der Spezialist, was die Möglichkeiten der AVR-Peripherie angeht. Beim PIC würde ich das PWM Modul direkt benutzen - da muss dann jeweils nur der aktuelle Ausgabewert in ein Register geschrieben werden. Wenn das so beim AVR nicht geht(*), wäre die zweitbeste Methode eben ein Interrupt beim Match des Timers mit dem OCR-Register. Das sind dann aber auch nur jeweils ein Interrupt pro PWM-Zyklus und nicht 256. A. Audio schrieb: > So hat man natürlich immer, wenn eigentlich 0 ausgegeben werden > soll 127 und somit ein leichtes Rauschen. Kein Rauschen, sondern die PWM-Frequenz mit mehr oder weniger großer Amplitude, je nach Charakteristik des nachgeschalteteten Tiefpasses. Wenn die PWM-Frequenz aber über der Hörgrenze liegt (> 20kHz), dürften die Reste der PWM-Frequenz auf dem Signal nicht stören. (*) Edit: habe gerade mal ins kurz ins Datenblatt geguckt! Natürlich hat der Controller auch brauchbare Hardware-PWM Peripherie. Geht also auch voll Hardwareseitig!
:
Bearbeitet durch User
Thomas E. schrieb: > A. Audio schrieb: >> DDS scheitert, wenn ich das richtig nachgelesen habe, an einem fehlenden >> DA-Wandler. > > Du solltest die "Klangsynthese" von der Ausgabe getrennt betrachten. Ob > Du nun die Werte an einen integrierten DAC, Port mit R2R-Netzwerk oder > PWM-Generator übergibst, ändert doch nichts an der Berechnung der > Wellenform. > Dementsprechend scheitert auch das DDS-Verfahren nicht, weil kein > integrierter DAC vorhanden ist. > > A. Audio schrieb: >> Mein Problem ist, dass INTERRUPTS_PER_S bei großen Frequenzen natürlich >> zu klein ist. > > Die Interrupts werden bei DDS nicht häufiger, wenn die Frequenz des > Audio-Signals erhöht wird. Die Interrupts laufen fest mit der > Sample-Frequenz (z.B. 32kHz), egal, ob Du einen 1kHz oder 5kHz Ton (oder > auch beide gleichzeitig) erzeugen willst. Ich probiere es einmal aus. Allerdings folgendes Problem: Maxim B. schrieb: > volatile unsigned long wert, freq; > wert = Fv*24294967296/Fd; > ISR: > freq += wert; Dafür reichen uint32_t nicht aus. Das bräuchte min. 64 Bits. Und dann ist das freq>>24 natürlich sinnlos. Weshalb überhaupt * 24294967296? 24294967296 != 2^32, und ich dachte 2^32 soll man verwenden? Wobei man damit natürlich erst recht nicht mit einem uint32_t hinkommt. Thomas E. schrieb: > A. Audio schrieb: >> So hat man natürlich immer, wenn eigentlich 0 ausgegeben werden >> soll 127 und somit ein leichtes Rauschen. > > Kein Rauschen, sondern die PWM-Frequenz mit mehr oder weniger großer > Amplitude, je nach Charakteristik des nachgeschalteteten Tiefpasses. > Wenn die PWM-Frequenz aber über der Hörgrenze liegt (> 20kHz), dürften > die Reste der PWM-Frequenz auf dem Signal nicht stören. Ich verstehe nur irgendwie das Prinzip dahinter nicht. Wenn ich den Wert 127 analog ausgebe mit 255 Stufen, dann bin ich ja bei 50% * U. Dabei steht 127 doch eigentlich für keinerlei Ton. Und bei 0 bin ich dafür bei 0% * U. Also kein Ton, obwohl ja eigentlich sehr wohl ein Ton da sein müsste mithilfe einer negativen Spannung, oder nicht? > (*) Edit: habe gerade mal ins kurz ins Datenblatt geguckt! Natürlich hat > der Controller auch brauchbare Hardware-PWM Peripherie. Geht also auch > voll Hardwareseitig! Ich habe auch noch einmal ins Datenblatt geschaut und ein wenig gegooglet. Tatsächlich ist es möglich, auch Duty-Cycles einzustellen mit OCRnA und OCRnB. Daran habe ich gar nicht gedacht, dass ich ja auch einfach zwei Register kombinieren kann. Danke für den Hinweis. Ich ging ehrlich gesagt davon aus, dass es nur möglich ist, Rechtecksignale mit 50% Duty zu erstellen. Auf die Kombination von zweien bin ich nicht gekommen.
A. Audio schrieb: > Weshalb überhaupt * 24294967296? keine Ahnung, wie er auf diese Zahl kommt. Gibt ja auch als Hex-Zahl (5A817C800) nicht viel Sinn. Ich würde sagen: klammere Dich nicht an diese Zahl sondern versuche, das Prinzip zu verstehen. Wenn Du nicht unbedingt eine extrem fein granulierbare Frequenzeinstellung benötigst, reicht evtl. auch eine 16-Bit Rechnung. Das Prinzip ist, daß man in der ISR mit fester Ausgabe-Samplerate (z.B. alle 32µs) den Lesezeiger für den Samplespeicher (z.B. Sinus-Daten) um einen gewissen Betrag weiterstellen muss, abhängig von der gewünschten Tonhöhe. Wenn man mit ganzen Zahlen rechnet, geht das normalerweise nur in ganzzahligen Schritten, d.h. die Sinuswelle könnte man nur mit einfacher, doppelter, dreifacher... Frequenz ausgeben. Für andere Verhältnissse (z.B. *1,5 oder *0,75) braucht man Nachkommastellen. Man könnte mit float rechnen, aber das will man aus Performance-Gründen hier eher nicht. Also benutzt man Festkomma-Arithmetik und nimmt eine lange Integer-Variable, von der die oberen Bits als Vorkommastellen (->Sinus-Sampleadresse) und die niedrigeren Bits als Nachkommastellen behandelt werden. A. Audio schrieb: > Also kein Ton, obwohl ja eigentlich sehr wohl > ein Ton da sein müsste mithilfe einer negativen Spannung, oder nicht? Durch eine simple Gleichspannung entsteht nie ein Ton. Der Ton entsteht durch eine zyklische Änderung der Spannung, und dabei ist dann aber egal, ob sich die Spannung im Bereich -1 und +1 Volt ändert, oder zwischen 0V und 2V. Auch ein DAC, wie er in vielen µCs eingebaut ist, oder ein R2R-Netzwerk am Port-Ausgang kann i.d.R. keine negative Spannung ausgeben. Da aber ein Tonsignal positive und negative Halbwellen hat, setzt man hier den "Ruhepegel" eben auf die Hälfte der maximal möglichen Ausgangsspannung. So kann sich die Spannung relativ dazu in beide Richtungen ändern. Der Verstärker gibt nur den verstärkten Wechelspannungs-Anteil an den Lautsprecher, dafür ist also egal, wo der absolute Ruhepegel liegt.
:
Bearbeitet durch User
Autor: A. Audio (Gast) Datum: 24.03.2018 15:13 >Hier ist das Prolbem, dass ich nicht den ganzen PORTB frei habe. Und ich >will auch nicht einfach nur einen konstanten Ton erzeugen. Es geht >darum, zwei Töne auf einem Lautsprecher ausgeben zu können, also quasi >einen Akkord und letztendlich auch darum, ein (kleines) Audiofile >abspielen zu können. PWM und DDS eignet sich gut dafür: Beitrag "17 Kanal Avr Synthesizer in Asm"
A. Audio schrieb: > mein Ziel ist es, auch Audio-Dateien wiederzugeben. > Allerdings ohne externe SD Card. > Dafür muss ich natürlich die Qualität der Datei extrem vermindern, meine > Schritte waren folgende: Schau mal, wie so etwas in der klassischen digitalen Telefonie gemacht wird. Die Signale werden mit einer Auflösung von etwa 14 Bit mit 8kHz gesampelt. Dann werden sie mit einer PCM-Codierung (A-law oder µ-Law) auf 8 Bit komprimiert. Das gibt auf eine serielle umgerechnet eine Datenrate von 64 kBit pro Sekunde oder einen Speicherbedarf von 8 kByte. Audacity kann solche Daten aus eigentlich jedem anderen Format herstellen. Wie kann man das möglichst simple wiedergeben? Als DAC benutzt man PWM. Um mit der Qualität in die Nähe der Aufnahme zu kommen, sollte die PWM bei einer Frequenz von 8 kHz eine Auflösung von 11-12 Bit haben, mehr als 14 bringt aber auch nichts. Jetzt muß man nur im PWM Interrupt alle 125µs (die 8kHz) ein Sample von PCM auf linear decodieren und auf die PWM geben. Das decodieren geht leichter, als es die Formeln vermuten lasse. Da die PCM-Samples nur 8 Bit haben, kann man für das Decodieren eine Tabelle verwenden. Das sind 256 16Bit Integer, also ein halbes k. Diese kann man sich leicht vorher, sowohl für A-Law als auch für µ-Law auf dem PC ausrechnen. Das Decodieren ist dann nur noch ein Tabellenzugriff, das schafft wirklich jeder µC. Das Ausgangssignal hat die klassische Telefonbandbreite von 300Hz bis 3,2kHz. Das Signal aus der PWM hat aber eine Problem, es enthält hohe Anteile an der PWM-Frequenz von 8kHz, die hörbar ist. Für einen DAC mit einer PWM braucht man sowieso ein Filter, hier sollte es eine höhere Ordnung haben. Die Belastung des µC ist marginal: nächstes Sample lesen, Tabellenzugriff und Schreiben des PWM Registers. Und das alle 125µs. Und die Qualität ist eher besser als ein Walkman. Ich hab sowas mal gebaut und das PWM_Signal gegenphasig auf ein paar parallelgeschaltete Busbuffer gegeben. Dann ein paar LC-Filter und einen Lautsprecher, so ein Class-D für Arme. Ich hielt das Ergebniss für brauchbar. Ist länger geworden, als ich gedacht hatte MfG Klaus
Klaus schrieb: > sollte die PWM > bei einer Frequenz von 8 kHz eine Auflösung von 11-12 Bit haben, Wozu denn eine so hohe Auflösung? Bei 8kHz ist das Sampleraster schon derart grob, daß einen da eine hohe Auflösung (> 60dB SNR) bei der Qualität auch nicht mehr groß 'rausreisst. Ich würde da eher auf eine höhere Abtastfrequenz gehen und die PWM-Frequenz möglichst erhöhen, damit man keinen so steilflankigen Tiefpass nachschalten muss. Für Telefonqualität reicht doch SNR = 48 dB (8 Bit Aufösung) locker. Evtl. wäre es sogar in der Praxis besser, noch ein Bit zugunsten einer höheren PWM-Frequenz zu opfern. Ein 7-Bit Timer mit 16 MHz gibt 125kHz, davon bleibt selbst mit einem simplen, 1-stufigen RC-Filter nicht mehr viel übrig. Also, mein "Rezept" für brauchbare Qualität mit geringem Aufwand wäre: 8-Bit samplen, aber dafür >= 16kHz Abtastrate (relativ weit weg vom Nutzsignal) und noch höhere PWM Frequenz (sehr weit weg vom Nutzsignal). Beim Telefon wird wahrscheinlich mit einer höheren Auflösung gesampled, um den Dynamikbereich zu erhöhen, d.h. es soll ja auch noch etwas zu verstehen sein, wenn der Sprecher mal etwas leisere Töne anschlägt. Zur Ausgabe eines Signaltons braucht es das aber nicht, da man den immer mit optimaler (Voll-)Aussteuerung generieren kann.
:
Bearbeitet durch User
Thomas E. schrieb: > A. Audio schrieb: >> Weshalb überhaupt * 24294967296? > > keine Ahnung, wie er auf diese Zahl kommt. Gibt ja auch als Hex-Zahl > (5A817C800) nicht viel Sinn. Ich würde sagen: klammere Dich nicht an > diese Zahl sondern versuche, das Prinzip zu verstehen. Wenn Du nicht > unbedingt eine extrem fein granulierbare Frequenzeinstellung benötigst, > reicht evtl. auch eine 16-Bit Rechnung. > Das Prinzip ist, daß man in der ISR mit fester Ausgabe-Samplerate (z.B. > alle 32µs) den Lesezeiger für den Samplespeicher (z.B. Sinus-Daten) um > einen gewissen Betrag weiterstellen muss, abhängig von der gewünschten > Tonhöhe. Wenn man mit ganzen Zahlen rechnet, geht das normalerweise nur > in ganzzahligen Schritten, d.h. die Sinuswelle könnte man nur mit > einfacher, doppelter, dreifacher... Frequenz ausgeben. > Für andere Verhältnissse (z.B. *1,5 oder *0,75) braucht man > Nachkommastellen. Man könnte mit float rechnen, aber das will man aus > Performance-Gründen hier eher nicht. Also benutzt man > Festkomma-Arithmetik und nimmt eine lange Integer-Variable, von der die > oberen Bits als Vorkommastellen (->Sinus-Sampleadresse) und die > niedrigeren Bits als Nachkommastellen behandelt werden. Okay, jetzt habe ich es, denke ich, verstanden. Einfach:
1 | uint32_t counter = 0; |
2 | uint32_t value = sampling_rate * 65536 / 20000; |
3 | counter += value; |
4 | if(counter < size) |
5 | analog_output(counter>>16); |
6 | else |
7 | stop(); |
Müsste soweit eigentlich auch stimmen. > A. Audio schrieb: >> Also kein Ton, obwohl ja eigentlich sehr wohl >> ein Ton da sein müsste mithilfe einer negativen Spannung, oder nicht? > > Durch eine simple Gleichspannung entsteht nie ein Ton. Der Ton entsteht > durch eine zyklische Änderung der Spannung, und dabei ist dann aber > egal, ob sich die Spannung im Bereich -1 und +1 Volt ändert, oder > zwischen 0V und 2V. Auch ein DAC, wie er in vielen µCs eingebaut ist, > oder ein R2R-Netzwerk am Port-Ausgang kann i.d.R. keine negative > Spannung ausgeben. Da aber ein Tonsignal positive und negative > Halbwellen hat, setzt man hier den "Ruhepegel" eben auf die Hälfte der > maximal möglichen Ausgangsspannung. So kann sich die Spannung relativ > dazu in beide Richtungen ändern. Der Verstärker gibt nur den verstärkten > Wechelspannungs-Anteil an den Lautsprecher, dafür ist also egal, wo der > absolute Ruhepegel liegt. Okay, das ist soweit klar. Mein Problem ist aber, dass, wenn ich 0x80 (=128) länger ausgebe, einen konstanten Ton erhalte. Und bei dem, was ich ausgebe, kommt nur ziemlicher Schwachsinn heraus. Nur bei 0x00 wird nichts ausgegeben. Die Werte gebe ich so aus:
1 | void analog_init() |
2 | { |
3 | TCCR0B = (1 << CS02); |
4 | TCCR0A = (1 << WGM01); |
5 | OCR0A = 0xFF; |
6 | OCR0B = 0x80; |
7 | TIMSK0 |= (1 << OCIE0A) | (1 << OCIE0B); |
8 | } |
9 | |
10 | void analog_output(uint8_t value) |
11 | { |
12 | OCR0B = audio_[(uint8_t)(rate_counter >> 16)]; |
13 | } |
Dabei ist audio_ das Array mit den Werten aus der mp3, die ich ausgeben will. chris schrieb: > Beitrag "17 Kanal Avr Synthesizer in Asm" Mein Problem ist das ASM. Ich kann zwar die Grundlagen, aber es ist für mich sehr anstrengend. Ich kann aber ja einmal durchschauen, ob ich nicht doch etwas finde, das ich verstehe und wiederverwenden kann. Klaus schrieb: > A. Audio schrieb: >> mein Ziel ist es, auch Audio-Dateien wiederzugeben. >> Allerdings ohne externe SD Card. >> Dafür muss ich natürlich die Qualität der Datei extrem vermindern, meine >> Schritte waren folgende: > > Schau mal, wie so etwas in der klassischen digitalen Telefonie gemacht > wird. Die Signale werden mit einer Auflösung von etwa 14 Bit mit 8kHz > gesampelt. Dann werden sie mit einer PCM-Codierung (A-law oder µ-Law) > auf 8 Bit komprimiert. Das gibt auf eine serielle umgerechnet eine > Datenrate von 64 kBit pro Sekunde oder einen Speicherbedarf von 8 kByte. > Audacity kann solche Daten aus eigentlich jedem anderen Format > herstellen. > > Wie kann man das möglichst simple wiedergeben? Als DAC benutzt man PWM. > Um mit der Qualität in die Nähe der Aufnahme zu kommen, sollte die PWM > bei einer Frequenz von 8 kHz eine Auflösung von 11-12 Bit haben, mehr > als 14 bringt aber auch nichts. Jetzt muß man nur im PWM Interrupt alle > 125µs (die 8kHz) ein Sample von PCM auf linear decodieren und auf die > PWM geben. > > Das decodieren geht leichter, als es die Formeln vermuten lasse. Da die > PCM-Samples nur 8 Bit haben, kann man für das Decodieren eine Tabelle > verwenden. Das sind 256 16Bit Integer, also ein halbes k. Diese kann man > sich leicht vorher, sowohl für A-Law als auch für µ-Law auf dem PC > ausrechnen. Das Decodieren ist dann nur noch ein Tabellenzugriff, das > schafft wirklich jeder µC. > > Das Ausgangssignal hat die klassische Telefonbandbreite von 300Hz bis > 3,2kHz. Das Signal aus der PWM hat aber eine Problem, es enthält hohe > Anteile an der PWM-Frequenz von 8kHz, die hörbar ist. Für einen DAC mit > einer PWM braucht man sowieso ein Filter, hier sollte es eine höhere > Ordnung haben. > > Die Belastung des µC ist marginal: nächstes Sample lesen, > Tabellenzugriff und Schreiben des PWM Registers. Und das alle 125µs. Und > die Qualität ist eher besser als ein Walkman. Ich hab sowas mal gebaut > und das PWM_Signal gegenphasig auf ein paar parallelgeschaltete > Busbuffer gegeben. Dann ein paar LC-Filter und einen Lautsprecher, so > ein Class-D für Arme. Ich hielt das Ergebniss für brauchbar. > > Ist länger geworden, als ich gedacht hatte > > MfG Klaus Ich werde es mir einmal ansehen, danke für den Tipp. Allerdings habe ich ja derzeit noch Probleme mit der Ausgabe.
A. Audio schrieb: > Mein Problem ist aber, dass, wenn ich 0x80 (=128) länger ausgebe, einen > konstanten Ton erhalte. Du hast nicht verstanden, wie die DAC-Nachbildung mit PWM funktioniert, d.h. Du hast das zur Glättung nötige RC-Glied (Tiefpass) am Ausgang weggelassen. Das, was Du als Wert der PWM übergibst, entspricht einem Spannungspegel am Ausgang - 0 ist der geringste, 255 der größte und 128 der mittlere Pegel.
A. Audio schrieb: > Maxim B. schrieb: > Mit Sägezahn meinst du vermutlich ein Rechteck-Signal, oder? Oder. Sägezahn ist kein Rechteck. > Weiterhin verstehe ich irgendwie deine Rechnung nicht ganz. > Weshalb *2^32? Weil max. Zahl in unsigned long 2^32-1 ist. Bei neueren Toolchains geht auch mit __uint24, für so eine Verwendung ist Genauigkeit von 2^24 ausreichend. > Ich habe es bisher immer so gemacht: > counter = INTERRUPTS_PER_S frequency 2; > Dann in der ISR counter heruntergezählt und bei 0 den Pin getoggled. Das ist kein DDS, das ist etwas anderes. Viel weniger genau, was Frequenz betrifft. Z.B. 0,01 cent Genauigkeit kann man so nicht erreichen - gut wenn es unterhalb 2-3 cent bleibt. >> warum verwende ich nur die obersten 8 bits? Weil das reicht. Du kannst statt char auch int verwenden, nur mehr Speicherplatz und etwas langsamer. Wenn mehr als 2 Töne gleichzeitig, dann auch bei F_CPU = 20 MHz muß du Fd unter 32 kHz herabsetzen. > Hier ist das Prolbem, dass ich nicht den ganzen PORTB frei habe. Dann nimm ein Register, so wie 574, damit alle Ausgänge synchron funktionieren - und nimm die Pins, die du frei hast. Es wird nur ein bißchen langsamer. Oder mit SPI und 595-Register. Z.B. so ist das möglich (zum Frage, warum obere byte nur auf 240 beschränkt: so ist bequemer, gängige Obertöne für Wave-Tabelle zu berechnen: 16' = 480, 8' = 240, 5 1/3' = 160, 2/3' = 20):
1 | // main.h
|
2 | #ifndef MAIN_H
|
3 | #define MAIN_H 1
|
4 | |
5 | #ifndef F_CPU // Quarz 20 MHz.
|
6 | #define F_CPU 20000000UL // CPU_F fuer Verzoegerungen
|
7 | #endif
|
8 | |
9 | #ifndef FLAGG
|
10 | #define FLAGG GPIOR0 /* fuer Ereignisse */ |
11 | #define F_PULS 0 /* Puls 32 KHz, timer 3 interrupt */ |
12 | |
13 | #define FLAG_REG GPIOR1
|
14 | #define F_GED16 0
|
15 | #define F_PR8 1
|
16 | #endif
|
17 | |
18 | #define SPI_MOSI PB5
|
19 | #define SPI_MISO PB6
|
20 | #define SPI_SCK PB7
|
21 | #define SPI_SS PB4
|
22 | #define SPI_DDR DDRB
|
23 | #define SPI_PORT PORTB
|
24 | |
25 | //static inline unsigned char SPI_MasterTransmit(unsigned char data)
|
26 | static inline void SPI_MasterTransmit(unsigned char data) |
27 | {
|
28 | /* Start transmission */
|
29 | SPDR = data; |
30 | /* Wait for transmission complete */
|
31 | while(!(SPSR & (1<<SPIF))); |
32 | // return SPDR;
|
33 | }
|
34 | |
35 | static inline void SPI_init(void){ |
36 | SPI_PORT |= (1<<SPI_SS)|(1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_MISO); |
37 | SPI_DDR |= (1<<SPI_SS)|(1<<SPI_MOSI)|(1<<SPI_SCK); |
38 | SPI_DDR &= ~(1<<SPI_MISO); |
39 | SPCR = (1<<SPE)|(1<<MSTR); |
40 | SPSR = 1; |
41 | SPI_MasterTransmit(~0); |
42 | }
|
43 | |
44 | #endif /* MAIN_H */ |
45 | |
46 | |
47 | // main.c
|
48 | |
49 | #include <avr/io.h> // Muss immer sein |
50 | #include <stdio.h> // Die Ein- und Ausgabefunktionen, |
51 | // Typen und Makros
|
52 | #include <stdlib.h> // Funktionen zur Umwandlung von Zahlen, |
53 | // fuer Speicherverwaltung und aehnliche Aufgaben.
|
54 | #include <string.h> // Funktionen fuer Zeichenketten |
55 | #include <inttypes.h> // Fuer Datentyp |
56 | #include <avr/interrupt.h> // Fuer Interrupts |
57 | #include <avr/eeprom.h> // Fuer EEPROM |
58 | #include <avr/pgmspace.h> // Fuer Flash |
59 | #include <util/delay.h> // Fuer Verzoegerungen |
60 | |
61 | #include "main.h" // Allgemeine Programmablauf |
62 | #include "timer3.h" // Timer 3 |
63 | |
64 | const __flash signed int ged_16[480] = { |
65 | 0,4,8,12,16,20,23,27,30,33,36,38,40,42,44,45, |
66 | 47,48,48,49,49,50,50,50,50,50,50,50,50,49,49,49, |
67 | 49,49,49,49,49,49,49,49,50,50,50,50,50,50,50,49, |
68 | 49,49,49,49,48,48,48,47,47,47,46,46,46,46,45,45, |
69 | 45,45,45,46,46,46,46,47,47,47,48,48,48,49,49,49, |
70 | 49,49,50,50,50,50,50,50,50,49,49,49,49,49,49,49, |
71 | 49,49,49,49,50,50,50,50,50,50,50,50,49,49,48,48, |
72 | 47,45,44,42,40,38,36,33,30,27,23,20,16,12,8,4, |
73 | 0,-4,-8,-12,-16,-20,-23,-27,-30,-33,-36,-38,-40,-42,-44,-45, |
74 | -47,-48,-48,-49,-49,-50,-50,-50,-50,-50,-50,-50,-50,-49,-49,-49, |
75 | -49,-49,-49,-49,-49,-49,-49,-49,-50,-50,-50,-50,-50,-50,-50,-49, |
76 | -49,-49,-49,-49,-48,-48,-48,-47,-47,-47,-46,-46,-46,-46,-45,-45, |
77 | -45,-45,-45,-46,-46,-46,-46,-47,-47,-47,-48,-48,-48,-49,-49,-49, |
78 | -49,-49,-50,-50,-50,-50,-50,-50,-50,-49,-49,-49,-49,-49,-49,-49, |
79 | -49,-49,-49,-49,-50,-50,-50,-50,-50,-50,-50,-50,-49,-49,-48,-48, |
80 | -47,-45,-44,-42,-40,-38,-36,-33,-30,-27,-23,-20,-16,-12,-8,-4, |
81 | 0,4,8,12,16,20,23,27,30,33,36,38,40,42,44,45, |
82 | 47,48,48,49,49,50,50,50,50,50,50,50,50,49,49,49, |
83 | 49,49,49,49,49,49,49,49,50,50,50,50,50,50,50,49, |
84 | 49,49,49,49,48,48,48,47,47,47,46,46,46,46,45,45, |
85 | 45,45,45,46,46,46,46,47,47,47,48,48,48,49,49,49, |
86 | 49,49,50,50,50,50,50,50,50,49,49,49,49,49,49,49, |
87 | 49,49,49,49,50,50,50,50,50,50,50,50,49,49,48,48, |
88 | 47,45,44,42,40,38,36,33,30,27,23,20,16,12,8,4, |
89 | 0,-4,-8,-12,-16,-20,-23,-27,-30,-33,-36,-38,-40,-42,-44,-45, |
90 | -47,-48,-48,-49,-49,-50,-50,-50,-50,-50,-50,-50,-50,-49,-49,-49, |
91 | -49,-49,-49,-49,-49,-49,-49,-49,-50,-50,-50,-50,-50,-50,-50,-49, |
92 | -49,-49,-49,-49,-48,-48,-48,-47,-47,-47,-46,-46,-46,-46,-45,-45, |
93 | -45,-45,-45,-46,-46,-46,-46,-47,-47,-47,-48,-48,-48,-49,-49,-49, |
94 | -49,-49,-50,-50,-50,-50,-50,-50,-50,-49,-49,-49,-49,-49,-49,-49 |
95 | };
|
96 | |
97 | const __flash signed int pr_8[480] = { |
98 | 0,4,8,12,16,20,23,27,30,33,36,38,40,42,44,45, |
99 | 47,48,48,49,49,50,50,50,50,50,50,50,50,49,49,49, |
100 | 49,49,49,49,49,49,49,49,50,50,50,50,50,50,50,49, |
101 | 49,49,49,49,48,48,48,47,47,47,46,46,46,46,45,45, |
102 | 45,45,45,46,46,46,46,47,47,47,48,48,48,49,49,49, |
103 | 49,49,50,50,50,50,50,50,50,49,49,49,49,49,49,49, |
104 | 49,49,49,49,50,50,50,50,50,50,50,50,49,49,48,48, |
105 | 47,45,44,42,40,38,36,33,30,27,23,20,16,12,8,4, |
106 | 0,-4,-8,-12,-16,-20,-23,-27,-30,-33,-36,-38,-40,-42,-44,-45, |
107 | -47,-48,-48,-49,-49,-50,-50,-50,-50,-50,-50,-50,-50,-49,-49,-49, |
108 | -49,-49,-49,-49,-49,-49,-49,-49,-50,-50,-50,-50,-50,-50,-50,-49, |
109 | -49,-49,-49,-49,-48,-48,-48,-47,-47,-47,-46,-46,-46,-46,-45,-45, |
110 | -45,-45,-45,-46,-46,-46,-46,-47,-47,-47,-48,-48,-48,-49,-49,-49, |
111 | -49,-49,-50,-50,-50,-50,-50,-50,-50,-49,-49,-49,-49,-49,-49,-49, |
112 | -49,-49,-49,-49,-50,-50,-50,-50,-50,-50,-50,-50,-49,-49,-48,-48, |
113 | -47,-45,-44,-42,-40,-38,-36,-33,-30,-27,-23,-20,-16,-12,-8,-4, |
114 | 0,4,8,12,16,20,23,27,30,33,36,38,40,42,44,45, |
115 | 47,48,48,49,49,50,50,50,50,50,50,50,50,49,49,49, |
116 | 49,49,49,49,49,49,49,49,50,50,50,50,50,50,50,49, |
117 | 49,49,49,49,48,48,48,47,47,47,46,46,46,46,45,45, |
118 | 45,45,45,46,46,46,46,47,47,47,48,48,48,49,49,49, |
119 | 49,49,50,50,50,50,50,50,50,49,49,49,49,49,49,49, |
120 | 49,49,49,49,50,50,50,50,50,50,50,50,49,49,48,48, |
121 | 47,45,44,42,40,38,36,33,30,27,23,20,16,12,8,4, |
122 | 0,-4,-8,-12,-16,-20,-23,-27,-30,-33,-36,-38,-40,-42,-44,-45, |
123 | -47,-48,-48,-49,-49,-50,-50,-50,-50,-50,-50,-50,-50,-49,-49,-49, |
124 | -49,-49,-49,-49,-49,-49,-49,-49,-50,-50,-50,-50,-50,-50,-50,-49, |
125 | -49,-49,-49,-49,-48,-48,-48,-47,-47,-47,-46,-46,-46,-46,-45,-45, |
126 | -45,-45,-45,-46,-46,-46,-46,-47,-47,-47,-48,-48,-48,-49,-49,-49, |
127 | -49,-49,-50,-50,-50,-50,-50,-50,-50,-49,-49,-49,-49,-49,-49,-49 |
128 | };
|
129 | |
130 | |
131 | __uint24 ton_0 = 0; |
132 | __uint24 ton_1 = 0; |
133 | |
134 | volatile __uint24 kton_0 = 184549; // a1 |
135 | volatile __uint24 kton_1 = 109734; // c1 |
136 | |
137 | |
138 | ISR(TIMER3_COMPA_vect, ISR_NAKED){ // Timer 0 interrupt. |
139 | |
140 | FLAGG |= (1<<F_PULS); // Flag fuer Puls einsetzen |
141 | |
142 | reti(); // da ISR_NAKED |
143 | }
|
144 | |
145 | /**********************************************************/
|
146 | // Hauptprogramm
|
147 | |
148 | int main(void){ |
149 | DDRA = ~0; |
150 | DDRC = ~0; |
151 | SPI_init(); |
152 | TIMER0_init(); |
153 | FLAG_REG = (1<<F_GED16)|(1<<F_PR8)|(1<<F_GED8)|(1<<F_PR4)|(1<<F_FL4)|(1<<F_QU3)|(1<<F_PR2)|(1<<F_QU1_2); |
154 | |
155 | while(1){ |
156 | signed int aa=0; |
157 | unsigned int bb; |
158 | |
159 | if( FLAGG & (1<<F_PULS) ){ |
160 | FLAGG &= ~(1<<F_PULS); // Flag fuer Puls = 0 |
161 | |
162 | SPI_PORT |= (1<<SPI_SS); |
163 | |
164 | ton_0 += kton_0; |
165 | // max MSB = 240
|
166 | if((unsigned char)(ton_0 >> 16) >= 0xf0) ton_0 -= 0xf00000; |
167 | bb = (ton_0 >> 8)&& 0x1ff; |
168 | aa = 0; |
169 | |
170 | if(FLAG_REG & (1<<F_GED16)) aa = ged_16[bb]; |
171 | if(FLAG_REG & (1<<F_PR8)) aa += pr_8[bb]; |
172 | |
173 | SPI_PORT &= ~(1<<SPI_SS); |
174 | aa = aa >> 1; |
175 | aa = aa >> 1; |
176 | aa = aa >> 1; |
177 | SPDR = aa; |
178 | |
179 | |
180 | ton_1 += kton_1; |
181 | // max MSB = 240
|
182 | if((unsigned char)(ton_0 >> 16) >= 0xf0) ton_0 -= 0xf00000; |
183 | bb = (ton_1 >> 8)&& 0x1ff; |
184 | aa = 0; |
185 | |
186 | if(FLAG_REG & (1<<F_GED16)) aa = ged_16[bb]; |
187 | if(FLAG_REG & (1<<F_PR8)) aa += pr_8[bb]; |
188 | |
189 | while(!(SPSR & (1<<SPIF))); |
190 | aa = aa >> 1; |
191 | aa = aa >> 1; |
192 | aa = aa >> 1; |
193 | SPDR = aa; |
194 | |
195 | }
|
196 | }
|
197 | return 0; |
198 | }
|
:
Bearbeitet durch User
A. Audio schrieb: > Dabei ist audio_ das Array mit den Werten aus der mp3, die ich ausgeben > will. Nur mal zur Klarstellung: Eine MP3-Datei kannst Du so nicht direkt ausgeben! Die musst Du vorher schon dekodieren und die Samples als Wellenform abspeichern.
Ich vermute/hoffe, daß das hier impliziert, daß in ein Wave-Format gewandelt wurde: A. Audio schrieb: > Dafür muss ich natürlich die Qualität der Datei extrem vermindern, meine > Schritte waren folgende: > mp3-Datei auf mono umstellen, auf 1000Hz heruntersamplen und als > headerless raw-file in unsigned 8-bit gespeichert.
>> mp3-Datei auf mono umstellen, auf 1000Hz heruntersamplen und als >> headerless raw-file in unsigned 8-bit gespeichert. Das kann AVR nicht schaffen. Dafür zu schwache Leistung Wenn Datei im voraus auf dem Computer so vorbereitet, dass AVR wirklich nur WAV 8-bit bekommt - dann ist das möglich. Aber auch an Grenze. Es gibt zwar eine Variante mit ATtiny85 oder 861A und PWM, aber die haben PWM-Taktfrequenz bis 64 MHz! Das hat ATmega328P nicht. Dazu noch: was soll bedeuten "auf 1000Hz heruntersamplen"? Theorie sagt, dann ist Klang max. 500 Hz möglich. Praxis sagt aber, dass 500 Hz zu viele Verzerrungen haben wird, praktisch gelingt es mehr oder weniger sauber mit höchstens 200 Hz. Braucht jemand wirklich so einen Klang???
:
Bearbeitet durch User
A. Audio schrieb: > Ich werde es mir einmal ansehen, danke für den Tipp. > Allerdings habe ich ja derzeit noch Probleme mit der Ausgabe. Ich hab meinen Ansatz mal skiziert. Statt 7404 hab einen HC240 achtfach Buffer genommen. Die Kondensatoren sind im Bereich 1µF, die Spulen hab ich aus der Grabbelkiste. Ich bin nicht so der Filterexperte, ich hab probiert statt zu rechnen. Das funktioniert natürlich mit jedem PWM Signal, solange die Filterfrequenz und die PWM Frequenz passen. MfG Klaus
Rufus Τ. F. schrieb: > A. Audio schrieb: >> Mein Problem ist aber, dass, wenn ich 0x80 (=128) länger ausgebe, einen >> konstanten Ton erhalte. > > Du hast nicht verstanden, wie die DAC-Nachbildung mit PWM funktioniert, > d.h. Du hast das zur Glättung nötige RC-Glied (Tiefpass) am Ausgang > weggelassen. > > Das, was Du als Wert der PWM übergibst, entspricht einem Spannungspegel > am Ausgang - 0 ist der geringste, 255 der größte und 128 der mittlere > Pegel. Maxim B. schrieb: >> Weiterhin verstehe ich irgendwie deine Rechnung nicht ganz. >> Weshalb *2^32? > Weil max. Zahl in unsigned long 2^32-1 ist. > Bei neueren Toolchains geht auch mit __uint24, für so eine Verwendung > ist Genauigkeit von 2^24 ausreichend. > >> Ich habe es bisher immer so gemacht: >> counter = INTERRUPTS_PER_S frequency 2; >> Dann in der ISR counter heruntergezählt und bei 0 den Pin getoggled. > Das ist kein DDS, das ist etwas anderes. Viel weniger genau, was > Frequenz betrifft. Z.B. 0,01 cent Genauigkeit kann man so nicht > erreichen - gut wenn es unterhalb 2-3 cent bleibt. > >>> warum verwende ich nur die obersten 8 bits? > Weil das reicht. Du kannst statt char auch int verwenden, nur mehr > Speicherplatz und etwas langsamer. Wenn mehr als 2 Töne gleichzeitig, > dann auch bei F_CPU = 20 MHz muß du Fd unter 32 kHz herabsetzen. Thomas E. schrieb: > A. Audio schrieb: >> Dabei ist audio_ das Array mit den Werten aus der mp3, die ich ausgeben >> will. > > Nur mal zur Klarstellung: Eine MP3-Datei kannst Du so nicht direkt > ausgeben! Die musst Du vorher schon dekodieren und die Samples als > Wellenform abspeichern. Rufus Τ. F. schrieb: > Ich vermute/hoffe, daß das hier impliziert, daß in ein Wave-Format > gewandelt wurde: > > A. Audio schrieb: >> Dafür muss ich natürlich die Qualität der Datei extrem vermindern, meine >> Schritte waren folgende: >> mp3-Datei auf mono umstellen, auf 1000Hz heruntersamplen und als >> headerless raw-file in unsigned 8-bit gespeichert. Ja. Die Samples wurden raw ohne Header in unsigned 8-bit values abgespeichert. Maxim B. schrieb: >>> mp3-Datei auf mono umstellen, auf 1000Hz heruntersamplen und > als >>> headerless raw-file in unsigned 8-bit gespeichert. > Das kann AVR nicht schaffen. Dafür zu schwache Leistung > Wenn Datei im voraus auf dem Computer so vorbereitet, dass AVR wirklich > nur WAV 8-bit bekommt - dann ist das möglich. Aber auch an Grenze. > > Es gibt zwar eine Variante mit ATtiny85 oder 861A und PWM, aber die > haben PWM-Taktfrequenz bis 64 MHz! Das hat ATmega328P nicht. > > Dazu noch: was soll bedeuten "auf 1000Hz heruntersamplen"? Theorie sagt, > dann ist Klang max. 500 Hz möglich. Praxis sagt aber, dass 500 Hz zu > viele Verzerrungen haben wird, praktisch gelingt es mehr oder weniger > sauber mit höchstens 200 Hz. Braucht jemand wirklich so einen Klang??? Sampling Rate auf 1000Hz stellen. Natürlich klingt es grottig. Allerdings wollte ich zumindest die Software schon einmal fertigstellen, während das SD Card module noch auf dem Weg zu mir ist. Gibt da ja offensichtlich genug zu tun. Klaus schrieb: > A. Audio schrieb: >> Ich werde es mir einmal ansehen, danke für den Tipp. >> Allerdings habe ich ja derzeit noch Probleme mit der Ausgabe. > > Ich hab meinen Ansatz mal skiziert. Statt 7404 hab einen HC240 achtfach > Buffer genommen. Die Kondensatoren sind im Bereich 1µF, die Spulen hab > ich aus der Grabbelkiste. Ich bin nicht so der Filterexperte, ich hab > probiert statt zu rechnen. Das funktioniert natürlich mit jedem PWM > Signal, solange die Filterfrequenz und die PWM Frequenz passen. > > MfG Klaus Danke. Allerdings habe ich gerade keinerlei freie Inverter da und diskret nachbauen ist vermutlich bei 7 Invertern ein wenig zu aufwendig. Wofür sind die denn eigentlich da in der Schaltung? Allerdings habe ich jetzt auch einmal einen Tiefpass-Filter mit einfachem RC-Glied eingebaut (den habe ich tatsächlich vergessen). Mit Filter ist allerdings eigentlich einfach nur alles leiser. Egal ob "nichts" (=0x80) oder anderes. Bei 0x80 kommt somit auch weiterhin ein ziemlich hohes Piepen (wobei laut Berechnungen und auch Multimeter die Frequenz bei 62kHz liegt und somit eigentlich unhörbar sein müsste) und der Rest ist einfach nur unglaublich leise. Und ein Operationsverstärker wird die 0.2-0.3A nicht überleben. Ich habe Kondensatoren von 10nF bis 2.2mF probiert. Je größer, desto leiser natürlich. Aber wahlweise man hört gar nichts mehr - weder von der eigentlichen Ausgabe noch von dem "Nullpunkt" bei 0x80 - oder eben immer dieses hohe Piepsen. Gibt es irgendeine Möglichkeit, wie man nur das Piepsen (ca. 62.7kHz, 2.5V) herausfiltert? Oder soll ich einfach, wenn ich gerade nichts ausgebe, die Spannung dann einfach doch auf konstant 0V setzen? Thomas E. schrieb: > Klaus schrieb: >> sollte die PWM >> bei einer Frequenz von 8 kHz eine Auflösung von 11-12 Bit haben, > > Wozu denn eine so hohe Auflösung? Bei 8kHz ist das Sampleraster schon > derart grob, daß einen da eine hohe Auflösung (> 60dB SNR) bei der > Qualität auch nicht mehr groß 'rausreisst. Ich würde da eher auf eine > höhere Abtastfrequenz gehen und die PWM-Frequenz möglichst erhöhen, > damit man keinen so steilflankigen Tiefpass nachschalten muss. Für > Telefonqualität reicht doch SNR = 48 dB (8 Bit Aufösung) locker. Evtl. > wäre es sogar in der Praxis besser, noch ein Bit zugunsten einer höheren > PWM-Frequenz zu opfern. Ein 7-Bit Timer mit 16 MHz gibt 125kHz, davon > bleibt selbst mit einem simplen, 1-stufigen RC-Filter nicht mehr viel > übrig. > Also, mein "Rezept" für brauchbare Qualität mit geringem Aufwand wäre: > 8-Bit samplen, aber dafür >= 16kHz Abtastrate (relativ weit weg vom > Nutzsignal) und noch höhere PWM Frequenz (sehr weit weg vom Nutzsignal). > > Beim Telefon wird wahrscheinlich mit einer höheren Auflösung gesampled, > um den Dynamikbereich zu erhöhen, d.h. es soll ja auch noch etwas zu > verstehen sein, wenn der Sprecher mal etwas leisere Töne anschlägt. Zur > Ausgabe eines Signaltons braucht es das aber nicht, da man den immer mit > optimaler (Voll-)Aussteuerung generieren kann. Den Beitrag hier habe ich letztes Mal offensichtlich übersehen. Das Problem ist, dass die Abtastrate eben genau so speicherraubend ist. Aber ich versuche sonst einfach einmal, ein kürzeres Beispiel zu nehmen, das ich aber einfach ganz oft wiederhole. Dann kann ich zumindest schauen, ob die Tonhöhe getroffen wird. Danke euch allen auch noch einmal für eure Geduld.
Thomas E. schrieb: > Klaus schrieb: >> sollte die PWM >> bei einer Frequenz von 8 kHz eine Auflösung von 11-12 Bit haben, > > Wozu denn eine so hohe Auflösung? Bei 8kHz ist das Sampleraster schon > derart grob, daß einen da eine hohe Auflösung (> 60dB SNR) bei der > Qualität auch nicht mehr groß 'rausreisst. Ich würde da eher auf eine > höhere Abtastfrequenz gehen und die PWM-Frequenz möglichst erhöhen, > damit man keinen so steilflankigen Tiefpass nachschalten muss. Es geht nicht darum was du würdest, es geht danach was im weltweiten Telefonnetz gemacht wird. Ich hab beschrieben, wie man leicht diese Signale erzeugen (audacity) und ausgeben kann. Die Dynamik kannst du auch gut brauchen, wenn du digital die Lautstärke ändern willst. A. Audio schrieb: > Wofür > sind die denn eigentlich da in der Schaltung? Die liefern den Strom für den Lautsprecher, ein Class-D Verstärker für Arme, wie ich schrieb. Das für den Class-D nötige Filter ist auch gleichzeitig das Filter für die PWM Frequenz. MfG Klaus
Application Note AVR314 bei Microchip beschreibt die Ausgabe von DTMF (Touch-) Tönen mit jedem beliebigen AVR. Das sind also immer 2 Töne. Das ist sehr viel einfacher als die meisten Vorschläge, die bis jetzt gemacht wurden. Einfach mal anschauen.
Klaus: >Die Kondensatoren sind im Bereich 1µF, die Spulen hab >ich aus der Grabbelkiste. Hallo Klaus, die genauen Werte für LC wären interessant. Könntest Du eine Aufnahme mit-/ohne LC Filter machen? Mich würde interessieren, ob man den Unterschied gut hört.
chris schrieb: > die genauen Werte für LC wären interessant. Könntest Du eine Aufnahme > mit-/ohne LC Filter machen? Mich würde interessieren, ob man den > Unterschied gut hört. Ich hab den Aufbau nicht lauffähig. Aber ich kann dir sagen, ohne Filter hälst die 8kHz nicht aus, mit einer Stufe stört es, bei zwei Stufen ist es brauchbar. Die Lautstärke hat sich insgesamt kaum verändert. Die Drosseln sind aus einem Projekt übrig geblieben und haben so 1 bis 2 mHµ. Wenn man es richtig macht, könnte man wohl auch statt der zwei Drosseln pro Filterstufe eine Doppeldrossel nehmen. Ich bin nicht so der Filterspezialist, aber ich weiß, daß bei passiven Filtern die Ausgangsimpedanz des Treibers auf der einen und die Impedanz der Last, des Lautsprechers auf der anderen Seite eine wichtige Rolle spielt. MfG Klaus
Klaus schrieb: > Es geht nicht darum was du würdest, es geht danach was im weltweiten > Telefonnetz gemacht wird. So? Und wer bestimmt das, wonach es geht? Ich kann mich nicht erinnern, gelesen zu haben, daß der TO aus seinem AVR ein Telefon bauen will. Ob das, was im weltweiten Telefonnetz gemacht wird, auch wirklich das Ideal für seine Anwendung ist, kann man wohl kaum so einfach bestimmen, wie Du es tust. Geht es ihm eher um Sprachverständlichkeit bei großem Dynamikumfang oder um einen klirrarmen Sound eines akustischen Signals? Mit bloß 15 diskreten Werten im Bereich über der halben Amplitude wird jedenfalls ein Sinus z.B. schon ganz schön "verbogen", dh. es wird effektiv systembedingt ein Störsignal von min. 1/32 der Amplitude aufmoduliert. Und ist er gewillt, den Aufwand eines steilflankigen Tiefpasses höherer Ordnung zu treiben?
Thomas E. schrieb: > So? Und wer bestimmt das, wonach es geht? Ich kann mich nicht erinnern, > gelesen zu haben, daß der TO aus seinem AVR ein Telefon bauen will Er hat gefragt, wie man einfach audio mit seinem µC ausgeben kann. Und ich hab gesagt, ich hab das mal so gemacht. Das ist alles. Er hat dann noch Einzelheiten abgefragt. Das du alles besser kannst, ist klar. Trotzdem habe ich das nicht berücksichtig, als ich das mal gemacht und werde es auch nicht tun. Was der TO nun macht, ist sein Ding. MfG Klaus
Klaus schrieb: > Und > ich hab gesagt, ich hab das mal so gemacht. Das ist alles. Ja und? Habe ich irgendwo geschrieben, daß das falsch wäre? Ich habe auch nur geschrieben, wie ich es machen würde, und zwar aus diesem oder jenem Grund. Ich kann leider im Gegensatz zu Dir nicht schreiben, daß ich das schon so gemacht habe, weil das gelogen wäre. Ich habe aber nicht etwas in der Art geschrieben: "ist egal, was der Klaus macht oder vorschlägt, das macht man anders!" Das wäre in meinen Augen besserwisserisch. So, und jetzt schreibst Du "Es geht nicht darum was du würdest, es geht danach was im weltweiten Telefonnetz gemacht wird." und stellst mich als Besserwisser dar? Oder habe ich da vielleicht etwas falsch interpretiert?
Falk B. schrieb: > Beitrag "Re: Arduino Nano, SD Card, PCM" Sehr, sehr interessant! Vielen Dank! Ich experimentiere auch in so einer Richtung, wenn auch ein bißchen anderes (ein Sampler. Ich brauche etwas für Beerdigungen, was bessere Orgelklang liefert als ein Yamaha-Keyboard, aber von AA-Batterien auch läuft). Aber hier sehe ich gute Material auch für mich.
Curby23523 N. schrieb: > Arduino und Atmega328 sind hier meiner Meinung nach völlig ungeeignet echt? 1-bit PWM hatten schon der apple2 und auch der CBM mit VIA6222 klar hört sich das nicht so toll an wie vom Soundchip, aber es geht. A. Audio schrieb: > Nun habe ich einen Lautsprecher, den ich gerne ansteuern möchte. Beitrag "1-bit audio example program for Atmega" http://forum.arduino.cc/index.php?topic=455680.0
Bernd K. schrieb: > Du könntest statt R2R auch versuchen einen Delta Sigma DAC zu bauen. Aber nicht mit einem AVR und schon gar nicht in C. Für einigermaßen gute Audioqualität habe ich 30 MHz bei einem cortex M4 in Assembler benötigt und gut das doppelte in C.
A. Audio schrieb: > Bei 0x80 kommt somit auch weiterhin ein > ziemlich hohes Piepen (wobei laut Berechnungen und auch Multimeter die > Frequenz bei 62kHz liegt und somit eigentlich unhörbar sein müsste) Da ist sicher etwas anderes faul! Wenn Du keine Fledermaus bist, kannst Du 62 kHz nicht hören! A. Audio schrieb: > und > der Rest ist einfach nur unglaublich leise. Und ein Operationsverstärker > wird die 0.2-0.3A nicht überleben. Was denn für 0.2-0.3A? Woher kommen die und wie sieht Deine Schaltung hinter dem 62kHz Rechtecksignal überhaupt aus? Wie gesagt, egal, wie schlecht Dein Filter ist, von 62kHz dürfte vom menschlichen Ohr nichts wahrgenommen werden - da muss ein anderer Fehler vorliegen! Läuft Dein Programm vielleicht in einer Schleife und initialisiert die PWM ständig neu? Möglicherweise mit einer Rate, die im Tonfrequenzbereich liegt? A. Audio schrieb: > Das Problem ist, dass die Abtastrate eben genau so speicherraubend ist. Du kannst auch mit nur 8kHz samplen - meine 16kHz waren ja nur der Vorschlag, um weiter von der Nutzfrequenz wegzukommen, damit der Tiefpass einfacher wird. Wenn ich's richtig verstanden habe, sollen die Daten später sowieso von einer SD-Karte kommen, da ist der Speicherverbrauch dann ja auch nicht mehr so kritisch. Wichtiger ist wohl, bei der PWM-Frequenz im unhörbaren Bereich zu bleiben.
Thomas E. schrieb: > A. Audio schrieb: >> Bei 0x80 kommt somit auch weiterhin ein >> ziemlich hohes Piepen (wobei laut Berechnungen und auch Multimeter die >> Frequenz bei 62kHz liegt und somit eigentlich unhörbar sein müsste) > > Da ist sicher etwas anderes faul! Wenn Du keine Fledermaus bist, kannst > Du 62 kHz nicht hören! Ein Rechteck ist aber kein reiner Sinus. Zwischen allen mitschwingenden Harmonischen ist bestimmt was hörbares dabei.
Eric B. schrieb: > Ein Rechteck ist aber kein reiner Sinus. Zwischen allen mitschwingenden > Harmonischen ist bestimmt was hörbares dabei. Nein, da gibt es nichts unterhalb der Grundfrequenz, d.h. hier also nichts unter 62 kHz.
Hallo, Es gab hier mal das Projekt von Ulrich Radig (Beitrag "MegaLOL"). Wenn mich nicht alles täuscht wurde damit genau das vom TO gewünschte bereits gemacht. BG, Tom
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.