AD9833 DDS in c ohne SPI

#2409807
Lesenswert?
• ▲
▼
Hallo,

Vielen Dank für den tollen Code! Ich hab den DDS-Chip sofort zum Laufen 
bekommen.
Nun möchte ich jedoch auch ein Rampen- und Rechtecksignal erzeugen.
Leider finde ich nicht heraus, wo sich die Steuerbits im Code befinden.
Könntest du mir bitte sagen, wie ich das D1 (Mode) und das D5 (OPBITEN) 
Bit umschalte.

Schöne Grüße,
Florian
Gast #2630065
Lesenswert?
• ▲
▼
Vielen Dank für Deine Mühen, vielleicht findest Du noch Zeit, die 
Berechnung des FTW ohne float zu schaffen.
Beitrag "Re: Frage zur C Syntax"
Beitrag "Re: Rechnen mit AVR"

Außerdem ist es ein leichtes, die Restriktion aufzuheben, dass die 
SPI-Pins auf einem Port liegen müssen:
MOSIport, SSport und SCKport definieren.

Schieben für SPI (mask ist zugleich Bitzähler):
  mask=0x80;do if(data&mask)setData;else rstData;while((mask/=2));

hier könnte auch ein else stehen:
  if (reg == FREQ0){tosend |= (1<<14);}
  if (reg == FREQ1){tosend |= (1<<15);}
und das AND braucht man bei unsigned nicht, schieben allein reicht:
  tosend = (regist & ~16383)>>14;
(Firma: fritzler-avr.de) #2630081
Lesenswert?
• ▲
▼
>Schieben für SPI (mask ist zugleich Bitzähler):
>mask=0x80;do if(data&mask)setData;else rstData;while((mask/=2));
Kannste das mal in C highlighten? Mir verknoten grade die Augen.

Wollts erst mit uint32_t machen, aber der AVR GCC mag wohl das 
Multiplizieren von 2 32bit Variablen nicht. Jedenfals kam nur Mumpitz 
bei raus.

Natürlich ist die Restriktion aufzuheben, wird nur nicht oft vorkomen, 
dass der AD9833 an 2 - 3 Ports hängt.

Hm ja das und ist da sinnfrei, schieb die nicht ausgewählten bits ja eh 
raus.

Danke für die Kritik, wenn du mir die Knoten aus den Augen nimmst, wird 
das umgesetzt.
Gast #2631675
Lesenswert?
• ▲
▼
dem PI2 würde ich ein paar Stellen mehr genehmigen:
#define pi2    6,2831853


> Wollts erst mit uint32_t machen, aber der AVR GCC mag wohl
> das Multiplizieren von 2 32bit Variablen nicht.
> Jedenfals kam nur Mumpitz bei raus.
Kann sein, dass man die 64-bit erst aktivieren muss.
Suche mal danach, ich weiß es nicht auswendig.
Damals habe ich es in Asm gelöst.

Aber Du kannst zumindest die Division wegsparen, da konst/MCLK konstant 
ist und zur Compiletime berechnet werden kann. Also:

#define konst1 ((double)konst/(double)MCLK)
void DDS_freq(uint32_t freq, uint8_t reg){
  uint32_t regist = freq * konst1;
Da stellt sich die Frage, ob man freq nicht mit einem Bruchteil eines Hz 
angeben will, z.B. 1/8 Hz, d.b. konst1 muss dann noch mit 8 
multipliziert werden.


void DDS_write(uint16_t data){
  SPIPORT &= ~(1<<SS);
  DDS_writebyte((uint8_t)(data>>8));
  DDS_writebyte((uint8_t)(data & 255));
  SPIPORT |= (1<<SS);
}
wird zu

#define SPIssPORT PORTB
#define SPImoPORT PORTB
#define SPIscPORT PORTB

void DDS_write(uint16_t data){
  uint16_t mask = 0x8000; //Maske und Bytezähler in einem
  SPIssPORT &= ~(1<<SS); //SSEL low
  do{  if(data&mask)SPImoPORT |=  (1<<MOSI); //SDATA high
    else         SPImoPORT &= ~(1<<MOSI); //SDATA low
    SPIscPORT &= ~(1<<SCK); //CLK low
    SPIscPORT |=  (1<<SCK); //CLK high
  }while((mask/=2)!=0);
  SPIssPORT |=  (1<<SS); //SSEL high
}
(data&mask) ist eine Kurzform für ((data&mask)!=0)
und writebyte entfällt ganz.

und noch was wichtiges:
void DDS_phase(uint16_t phase, uint8_t reg){
  uint16_t regist = (uint16_t) (phase*konst2)/pi2;
  tosend |= (1<<15) | (1<<14);
  if (reg == PHASE1){tosend |= (1<<13);}
  DDS_write(tosend | regist);
}
Das kann falsch sein, wenn vorher in der globalen Variable tosend etwas 
drinsteht!
also entweder
  tosend = (1<<15) | (1<<14);  (ohne |= )

oder kürzer

  tosend  = (uint16_t) (phase*konst2)/pi2;
  tosend |= (1<<15) | (1<<14);
  if (reg == PHASE1){tosend |= (1<<13);}
  DDS_write(tosend);
Gast #2643574
Lesenswert?
• ▲
▼
> Der Vorcompiler setzt doch nur den Text ein.
Richtig.
Und der Compiler berechnet den Quotienten, da beide Operanden bekannt 
und konstant sind. Das #define ändert an der Berechnung nichts, Du 
könntest genauso gut direkt hinschreiben und richtig klammern.
Oder eine echte Konstante deklarieren.

Das Zusammenfassen gilt übrigens auch beim Berechnen der Phasen:
  tosend  = (uint16_t) (phase*konst2)/pi2;
besser:
  tosend  = (uint16_t) phase*(konst2/pi2);

Bitte sei so gut und verbessere den Code auf Deiner Seite, damit 
zumindest der Fehler bei der Berechnung der Phase berichtigt ist, bevor 
sich der Code zu stark verbreitet.

Antwort schreiben

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.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.