Verständnisproblem Serielle Ausgabe von Zahlen

Gast #3622443
Lesenswert?

Möchte gerne einen Funktionsgenerator IC AD9850 seriell ansteuern.

Das Modul erwartet einen 40-Bit Wert (siehe Anhang).

Ich lese also in meinem C Programm einen Long Datentyp für die Frequenz 
ein, welcher 32Bit besitzt.

long Freq = 4;

Gebe ich also '4 Hz' ein müsste Freq folgendermaßen ausschauen:

0000 0000 0000 0000 0000 0000 0000 0100

Nun muss ich dem Modul seine 40-Bit Information übermitteln.

Also zuerst die 32 Stellen long Freq (LSB bis MSB), danach noch Phase 
usw.


Die 40Bit sollen am PB0 des AVR ankommen.
Doch wie zerlege ich die Zahl '4' binär und gebe sie nacheinander am PB0 
aus?


Bei Arduino gibt es einen Befehl "Shiftout" der das erledigt, aber darum 
lerne ich lieber mit AVR ;)


Vielen Dank!!
Angehängte Dateien:
Gast #3622485
Lesenswert?

Ja ich weiß wie man Bits setzt, löscht, verschiebt etc.
Aber verstehe echt nicht wie ich das auf das Beispiel bezogen umsetzten 
soll.


Wenn ich jetzt '4' senden möchte:

clk
PORTB &= ~ (1<<PB0);   //  1
clk
PORTB &= ~ (1<<PB0);   //  2
clk
PORTB |= (1<<PB0);   //  4
clk
PORTB &= ~ (1<<PB0);   //  8
clk
PORTB &= ~ (1<<PB0);   //  16

usw.
Bis das Register des Moduls voll ist..

Das ist natürlich Quatsch, aber vastehe nicht wie ich sonst '4' senden 
übermitteln soll?

Ich weiß, dass man Shiftoperatoren >> braucht, aber wie?
Gast #3622491
Lesenswert?

void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, 
uint8_t val)
{
      uint8_t i;

      for (i = 0; i < 8; i++)  {
            if (bitOrder == LSBFIRST)
                  digitalWrite(dataPin, !!(val & (1 << i)));
            else
                  digitalWrite(dataPin, !!(val & (1 << (7 - i))));

            digitalWrite(clockPin, HIGH);
            digitalWrite(clockPin, LOW);
      }
}



Wie ist das zu verstehen?
Gast #3622496
Lesenswert?

Walter schrieb:
> Ja ich weiß wie man Bits setzt, löscht, verschiebt etc.

Nein, weißt du nicht. Maximal hast du Code gesehen, wo sowas gemacht 
wird, verstanden hast du es aber offensichtlich nicht.

> Aber verstehe echt nicht wie ich das auf das Beispiel bezogen umsetzten
> soll.

Tja, man muß etwas eben wirklich verstehen, um es sinnvoll einsetzen zu 
können.

Da hilft nur eins: Lernen, bis du es wirklich verstanden hast. Nein, 
mit Copy&Paste von Code alleine lernt man exakt garnix, höchstens, wie 
man eine Copy&Paste-Operation durchführt. Das aber können auch Affen 
leisten, wenn man es ihnen ein paarmal zeigt...
Gast #3622511
Lesenswert?

!!(val & (1 << i)));         ist mir unklar..


val (=meine Frequenz z.B '400') wird mit 1 &verknüpft das immer um i 
Stellen weitergeschoben wird.


Was haben die beiden !! auf sich?

Ich kenne nur != ...ungleich
#3622630
Lesenswert?

Walter schrieb:
> !!(val & (1 << i)));         ist mir unklar..

val & (1 << i)

Angenommen val ist 10
Binär ist das 0000 1010
i ist  0

Dann ist val & (1 << i(0)) = 0000 0000
i++
val & (1 << i(1)) = 0000 0010
i++
val & (1 << i(2)) = 0000 0000
i++
val & (1 << i(3)) = 0000 1000
i++
val & (1 << i(4)) = 0000 0000
i++
val & (1 << i(5)) = 0000 0000
i++
val & (1 << i(6)) = 0000 0000
i++
val & (1 << i(7)) = 0000 0000

Die Ergebnisse sind also nacheinander 0, 2, 0, 8, 0, 0, 0, 0

Auf Datapin soll eine 0 oder 1 ausgegeben werden. Nullen hast du genug 
aber statt 1en hast du 2 und 8.

!(val & (1 << i))) macht aus 0 eine 1 und aus !0, nicht 0 also 
irgendwas, eine 0.

Also wenn das Ergebnis 0 ist, macht es daraus eine 1 wenn es !0 ist, 
eine 0

Jetzt sind die Ergebnisse der Reihe nach 1, 0, 1, 0, 1, 1, 1, 1

Negiert man das jetzt zweimal
!!(val & (1 << i)))
Wird daraus 0, 1, 0, 1, 0, 0, 0, 0

Und da wo vorher 2 und 8 stand, steht jetzt 1. So wie man es braucht.

Schiebeergebnis: 0, 2, 0, 8, 0, 0, 0, 0
1. Negation:     1, 0, 1, 0, 1, 1, 1, 1
2. Negation:     0, 1, 0, 1, 0, 0, 0, 0

mfg.
Gast #3622871
Lesenswert?

Vielen Dank für die Hilfe!!
Bitmanipulation ist mir jetzt um einiges klarer geworden =)


Das Modul gibt jetzt auch schon brav einen Sinus aus, aber leider noch 
nicht die Frequenz die ich einstelle.

Kleine Werte --> sehr hohe Frequenzen
Hohe Werte    --> niedrige Frequenzen

Wo liegt der Fehler, weshalb es genau umgekehrt funktioniert?



-------------------------------------------------------------------
FUNKTIONIERENDER ARDUINO CODE
-------------------------------------------------------------------

//AD9850 DDS test

#define DDS_CLOCK 125000000

#define  CLOCK  8  //pin connections for DDS
#define  LOAD 9
#define  DATA  10
#define  RESET 11

void setup()
{
  pinMode (DATA,  OUTPUT);
  pinMode (CLOCK, OUTPUT);
  pinMode (LOAD,  OUTPUT);
  pinMode (RESET, OUTPUT);
  AD9850_init();
  AD9850_reset();

  SetFrequency(10000000);

}

void loop()
{

}

void SetFrequency(unsigned long frequency)
{
  unsigned long tuning_word = (frequency * pow(2, 32)) / DDS_CLOCK;
  digitalWrite (LOAD, LOW);

  shiftOut(DATA, CLOCK, LSBFIRST, tuning_word);
  shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 8);
  shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 16);
  shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 24);
  shiftOut(DATA, CLOCK, LSBFIRST, 0x0);
  digitalWrite (LOAD, HIGH);
}

void AD9850_init()
{

  digitalWrite(RESET, LOW);
  digitalWrite(CLOCK, LOW);
  digitalWrite(LOAD, LOW);
  digitalWrite(DATA, LOW);
}

void AD9850_reset()
{
  //reset sequence is:
  // CLOCK & LOAD = LOW
  //  Pulse RESET high for a few uS (use 5 uS here)
  //  Pulse CLOCK high for a few uS (use 5 uS here)
  //  Set DATA to ZERO and pulse LOAD for a few uS (use 5 uS here)

  // data sheet diagrams show only RESET and CLOCK being used to reset 
the device, but I see no output unless I also
  // toggle the LOAD line here.

  digitalWrite(CLOCK, LOW);
  digitalWrite(LOAD, LOW);

  digitalWrite(RESET, LOW);
  delay(5);
  digitalWrite(RESET, HIGH);  //pulse RESET
  delay(5);
  digitalWrite(RESET, LOW);
  delay(5);

  digitalWrite(CLOCK, LOW);
  delay(5);
  digitalWrite(CLOCK, HIGH);  //pulse CLOCK
  delay(5);
  digitalWrite(CLOCK, LOW);
  delay(5);
  digitalWrite(DATA, LOW);    //make sure DATA pin is LOW

    digitalWrite(LOAD, LOW);
  delay(5);
  digitalWrite(LOAD, HIGH);  //pulse LOAD
  delay(5);
  digitalWrite(LOAD, LOW);
  // Chip is RESET now
}
Gast #3622872
Lesenswert?

--------------------------------------------------------------
MEIN CODE
--------------------------------------------------------------



#include <math.h>
#include <avr/io.h>
#include <util/delay.h>
#include "mylcd.h"
#include "font6x8.h"




#define DDS_CLOCK 125000000




void AD9850_init()          //ALLE LEITUNGEN AUF LOW
{
PORTB &= ~(1<<PB0);      //CLK
PORTB &= ~(1<<PB1);      //LOAD
PORTB &= ~(1<<PB2);      //DATA
PORTB &= ~(1<<PB3);      //RST
}


void AD9850_reset()
{

PORTB &= ~(1<<PB0);      //CLK LOW
PORTB &= ~(1<<PB1);      //LOAD LOW

PORTB &= ~(1<<PB3);      //RST IMPULS
_delay_us(5);
PORTB |= (1<<PB3);
_delay_us(5);
PORTB &= ~(1<<PB3);

PORTB &= ~(1<<PB0);      //CLK IMPULS
_delay_us(5);
PORTB |= (1<<PB0);
_delay_us(5);
PORTB &= ~(1<<PB0);

PORTB &= ~(1<<PB2);      //DATA AUF LOW


PORTB &= ~(1<<PB1);      //LOAD IMPULS
_delay_us(5);
PORTB |= (1<<PB1);
_delay_us(5);
PORTB &= ~(1<<PB1);


}



void AD9850_Set_Frequency(uint16_t frequency)
{



PORTB &= ~(1<<PB1);      //LOAD
uint16_t tuning_word = (frequency * pow(2, 32)) / DDS_CLOCK; 
//BERECHNUNG


int i = 0 ;

            for(i=0;i<8;i++)    //ERSATZ FÜR SHIFTOUT
            {

                if((tuning_word & !!(1 << i)) == 1)
                {
                  PORTB|=(1<<PB2);    //DATA
                }

                else
                {
                  PORTB &= ~ (1<<PB2);
                }
PORTB |= (1<<PB0);   //CLK IMPULS
PORTB &=~ (1<<PB0);
            }
i=0;



            for(i=0;i<8;i++)
            {

                if(((tuning_word>>8) & !!(1 << i)) == 1)
                {
                  PORTB|=(1<<PB2);    //DATA
                }

                else
                {
                  PORTB &= ~ (1<<PB2);
                }

PORTB |= (1<<PB0);  //CLK IMPULS
PORTB &=~ (1<<PB0);
            }
i=0;


                for(i=0;i<8;i++)
                {

                    if(((tuning_word>>16) & !!(1 << i)) == 1)
                    {
                      PORTB|=(1<<PB2);  //DATA
                    }

                    else
                    {
                      PORTB &= ~ (1<<PB2);
                }
PORTB |= (1<<PB0);  //CLK IMPULS
PORTB &=~ (1<<PB0);
            }
i=0;


                for(i=0;i<8;i++)
                {

                    if(((tuning_word>>24) & !!(1 << i)) == 1)
                    {
                      PORTB|=(1<<PB2);   //DATA
                    }

                    else
                    {
                      PORTB &= ~ (1<<PB2);
                }

PORTB |= (1<<PB0);   //CLK IMPULS
PORTB &=~ (1<<PB0);
            }
i=0;


                for(i=0;i<8;i++)
                {

                    if(((0x0) & !!(1 << i)) == 1)
                    {
                      PORTB|=(1<<PB2);    //DATA
                    }

                    else
                    {
                      PORTB &= ~ (1<<PB2);
                              }

PORTB |= (1<<PB0);    //CLK IMPULS
PORTB &=~ (1<<PB0);
            }
i=0;
PORTB |= (1<<PB1);    //LOAD


}

int main (void)
{
DDRB=0b1111111;     //GESAMTEN PORT ALS AUSGANG

AD9850_init();
AD9850_reset();
AD9850_Set_Frequency(1=0);

}
Gast #3622908
Lesenswert?

1. Benutz code Tags
2. Überleg mal was du da machst!
2.1 Du benutzt uint16 obwohl du 24-32Bit shiftest? Nimm uint32
2.2 Die for-schleifen lassen sich zusammenfassen!

Ungetestet am Handy ges geschrieben:
[c]

void AD9850_Set_Frequency(uint32_t frequency)
{
PORTB &= ~(1<<PB1); //LOAD
uint32_t tuning_word = (frequency * pow(2, 32)) / DDS_CLOCK; 
//BERECHNUNG
int i = 0 ;
for(i=0;i<32;i++) //ERSATZ FÜR SHIFTOUT
{
if((tuning_word & !!(1 << i)) == 1)
{
PORTB|=(1<<PB2); //DATA
}
else
{
PORTB &= ~ (1<<PB2);
}
PORTB |= (1<<PB0); //CLK IMPULS
PORTB &=~ (1<<PB0);
}
i=0;
PORTB &= ~ (1<<PB2);
for(i=0;i<8;i++)
{
PORTB |= (1<<PB0); //CLK IMPULS
PORTB &=~ (1<<PB0);
}

PORTB |= (1<<PB1); //LOAD
}
Gast #3623402
Lesenswert?

Walter schrieb:
> Die 40Bit sollen am PB0 des AVR ankommen.
> Doch wie zerlege ich die Zahl '4' binär und gebe sie nacheinander am PB0
> aus?

Bist du wirklich so ungelenkig, daß du sowas nicht aus eigener Kraft 
hinbekommst?

void SageZahl(long Z)
{ long M;
  M = 1;
  while (M)
  { if (Z&M)
     SageNeEins();
    else
     SageNeNull();
    M = M<<1);
  }
}

Das läuft überall, egal ob AVR oder was anderes. Den Rest, also 
Optimierungen aller Art überlasse bitte dem jeweiligen Compiler.

W.S.

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