mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Ring-LookUp-Table für 2 unabhängige Sinussignale


Autor: Christian B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Christian B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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.

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Christian B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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

Autor: Christian B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh krass @Hagen

du bist ja schnell wie nix ...


THX @ You

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Clemens (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Code & Erklärung für DDS mit dem AVR gibt's hier:
http://www.mikrocontroller.net/articles/Digitaler_...

Autor: Philipp Sªsse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: R2D2 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Philipp Sªsse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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];
 }

Autor: Christian B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.