Hallo Leute, wie jeder hier benötige auch ich Hilfe. Ich habe schon einige "kleine" AVR-Spielereien gemacht und wollte jetzt mal etwas anspruchsvolleres versuchen. Und zwar möchte ich mit einem ATmega einen Mehrkanal-DAC füttern, dieser soll zunächst - ein Sinus mit variabler Frequenz erzeugen - ein zweiter Kanal soll ein identschisches Signal, aber mit variabler Phasenverschiebung (0-90°) erzeugen Nach einigem stöbern hier in diesem Forum habe ich auch viele interessante anregungen bekommen. Nur fehlt mir eindeutig das knowhow über eine LookUp-Table, die wie ein Kreis ausgelesen werden kann. Sehr interessant wird dies, wenn das zweite phasenverschobene Signal erzeugt werden soll. Wenn mir jemand helfen könnte wäre ich sehr dankbar.
suche mal nach DDS, direct digital synthesis und dem Phase Accumulator. Deinen "Kreis" einer Lookuptable kannst ganz einfach erreich indem du diese Tabelle aus 256 Werten definierst und an einer Speichergrenze die durch 256 teilbat ist positionisert. Dein Zeiger auf den akteullen Wert wird also bei einem Inkrement nach exakt 255 Zyklen überlaufen und dann wieder bei dem Index 0 der Tabelle von vorne beginnen. Du darfst halt nur diesen 16 Bit Zeiger nicht im Highbyte modizieren, due inkrementierst also nur die untersten 8 Bits dieses Zeigers. Gruß Hagen
@ Hagen Danke für deine Hilfe. Mit der größe der Tabelle habe ich es verstanden nur nicht dass ich die noch zwingend an einer Speicheradresse (n*0xff) positionieren muss.? Genau so wie du es sagst, hab ich mir das auch gedacht, ich möchte dass ein Zeiger nach einem Überlauf automatisch wider bei Adresse NULL beginnt. Entschuldige, mir fehlt einfach die Erfahrung mit Zeigeroperationen, doch jetzt ist es wichtig geworden. Das mit dem 16bit Zeiger und der 8Bit-Adresse hab ich soweit auch verstanden. Wäre für eine Hilfe im Bezug auf die genannte Zeigeroperation dankbar. Kannst du mir da vielleicht weiterhelfen Hagen ... oder auch gern jemand anderes, der damit erfahrung hat.
Deine Tabelle beginnt im Flash zb an Addresse 0x1200 -> ergo 0x1200 mod 256 == 0. Dein Zeiger wird also mit 0x1200 initialisiert und nur jeweils +1 inkrementiert, nach exakt 256 Schritten beginnt er wieder von vorne WENN du nur die untersten 8 Bits dieses Zeiger um +1 inkrementierst. Somit wird eine 8 Bit Addition um+1 auf einen 16 Bit zeiger durchgeführt. Gruß hagen
@ Hagen ich glaug ich habs, ... man beim schreiben meines zweiten Beitrags kam mir ein Blitzgedanke. -Position des Datenfeldes mit 256 Werten an Bsp-Adresse 0x0300 -Pointer auf diese stelle Als Startadresse zeigen lassen -Pointer(Low-Byte) hochzählen max.Point-Wert=letzter Datenwert -Überlauf -> Pointer automatisch bei NULL und zeigt wieder auf Datenfeld Startwert ... @Hagen ist das so korrekt von mir verstanden worden? Das scheint mir jedenfalls einleuchtend. Wenn es jetzt aber statt 2^8 2^(10 od 12) werte sind, was dann... ist es dann etwas schwieriger oder wesentlich komplizierter? Ein oder zwei Codebeispiele ASM oder/und C wären aber trotzdem noch ganz hilfreich für die Pointerprogrammierung. Wäre wirklich echt super best regards littleCB
Oh krass @Hagen du bist ja schnell wie nix ... THX @ You
Am besten du suchst im WEB oder sogar hier im Wiki nach DDS und Phase Accumulator, ich bin mir 100% sicher das dort auch fertige Sourcen drinnen sind. Oder willst du die Sinus Schwingungen immer mit der gleichen Frequenz erzeugen ? Ansonsten hast du mich schon richtig verstanden :-) Gruß hagen
Hallo, Beispiel für (fast) beliebig viele bits: .equ nBits = 10 .equ nMask = (1<<nBits)-1 ; Erzeugt Einsen bis zur letzten ; verwendeten Bitstelle .equ nBaseAddr = 0x10000 ; Achtung: die niedrigen nBits müssen Null ; sein! .def rTemp0 = r16 ringInit: ; Initialisiert den Z-Pointer ldi zl, low(nBaseAddr) ; dieser darf nicht verändert werden ldi zh, high(nBaseAddr) ret ringGetNext: lpm ; Wert in r0 kopieren inc zl ; diese und die folgenden drei Zeilen brcc ringGetNext_0 ; können, sofern es der AVR unterstützt inc zh ; auch durch addiw zl, 1 ersetzt werden ringGetNext_0: ; nun ist zeigt z auf nächste Stelle mov rTemp0, zh ; noch auf überlauf testen andi rTemp0, high(nBaseAddr) breq ringGetNext_1 ; in hohem AddressIndex steht eine null ret ; sonst (<>0) ist kein überlauf ; stattgefunden ringGetNext_1: mov rTemp0, zl andi rTemp0, low(nBaseAddr) breq ringInit ; in niedrigem AddressIndex steht auch ; eine null -> Addresse neu laden ret ; kein überlauf vielleicht habe ich den Überlauf-Test ein wenig zu kompliziert gestaltet... leider habe ich auch grad keinen Testaufbau, um den Code zu testen, aber eigentlich sollte es schon gehen, etwa so. also: - lesen - erhöhen - überlauf testen AddressIndex ist der Index innerhalb der LookUp-Table. schöne Grüße, Clemens
Code & Erklärung für DDS mit dem AVR gibt's hier: http://www.mikrocontroller.net/articles/Digitaler_Funktionsgenerator
Sofern des der AVR unterstützt, gibt es auch das fertig LPM rd, Z+, das macht dann alles auf einmal. Falls nicht, ist es einfacher, rückwärts zu zählen, also mit dem letzten Wert anfangen und dann decrementieren, bis alles null ist. Dann entfällt die ganze Vergleicherei. Falls Speicherplatz ein Thema ist, reicht natürlich auch ein Viertel der Tabelle, die anderen Viertel lassen sich über Symmetrieen ausrechnen.
in C: uint8_t sin_table[COUNT]={...} int8_t sin(uint16_t angle) { uint8_t tmp = sin_table[angle % COUNT]; //Wird bei COUNT=2^x vom Compiler in ein AND optimiert. if ((angle % 4*COUNT) > 2*COUNT) return -tmp; else return tmp; } Ich hoffe das ich mich jetzt nicht irgendwie vertippt habe, oder nen denkfehler drin hab.
Doch, Denkfehler, fürchte ich. Wenn Angle zwischen COUNT und 2*COUNT liegt, darfst Du nicht tmp zurückgeben, sondern sin_table[COUNT - (angle % COUNT)] (Spiegelsymmetrie bei pi/2). Also: angle %= 4 * COUNT; switch (angle / COUNT) { case 0: return sin_table[angle]; case 1: return sin_table[2 * COUNT - angle]; case 2: return -sin_table[angle - 2 * COUNT]; case 3: return -sin_table[4 * COUNT - angle]; }
Ey echt super von euch Leute, das ist zunächst mehr Feedback als ich erwartet habe. Falls Ihr mal was habt, und ich was helfen kann, dann werde ich es gern tun, doch ich befürchte dass ich mit meinem derzeitigen Wissen noch sehr weit am Anfang stehe. So ich werde jetzt erstmal alle Beiträge nacheinander auf mich wirken lassen und vresuchen nachzuvollziehen. wird wohl etwas dauern ... ;-) special THX @all unpaid helper ;) littleCB
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.