Forum: Mikrocontroller und Digitale Elektronik Verständnisproblem Serielle Ausgabe von Zahlen


von Walter (Gast)


Angehängte Dateien:

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!!

von Mike (Gast)


Lesenswert?

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

Dann binde doch die Arduino Library ein und rufe "Shiftout" auf ;-)

von Jim M. (turboj)


Lesenswert?

Siehe: Bitmanipulation.

von Walter (Gast)


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?

von Walter (Gast)


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?

von c-hater (Gast)


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...

von Mike (Gast)


Lesenswert?

Walter schrieb:
> Wie ist das zu verstehen?

Was verstehst du daran nicht?

von Walter (Gast)


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

von Thomas E. (thomase)


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.

: Bearbeitet durch User
von короткое троль (Gast)


Lesenswert?

Der shiftoperator in C hat auch eine ausserst schrottige Schreibweise. 
Etwas vom idiotischten, das ich je sah.

von Uwe S. (de0508)


Lesenswert?

короткое троль schrieb:
> Der shiftoperator in C hat auch eine ausserst schrottige Schreibweise.
> Etwas vom idiotischten, das ich je sah.

Es ist so wie es ist und optisch und syntaktisch doch klar !

Was soll also dein Einschrieb ?

von Walter (Gast)


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
}

von Walter (Gast)


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);

}

von Walter (Gast)


Lesenswert?

Natürlich AD9850_Set_Frequency(100);

von fer T (Gast)


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
}

von fer T (Gast)


Lesenswert?

Sorry Punkt 1 nicht eingehalten, scheiß Handy...

von W.S. (Gast)


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.

von Walter (Gast)


Lesenswert?

Leider keine Lösung dafür im Internet/Buch gefunden:

frequenz = frequenz >>=1;

was macht dieser Ausdruck ">>=" , kenne nur ">>" ?

von Walter (Gast)


Lesenswert?

Ich schrub auch manchmal unter meinem Namen (Walter),
aber das geht jetzt nicht mehr, der Name ist jetzt verbrannt :-(

von Dirk B. (dirkb2)


Lesenswert?

Walter schrieb:
> frequenz = frequenz >>=1;

So wie du es da benutzt ist es falsch.

>>= ist so zu verstehen wie |= oder &= (die du ja mehrmals nutzt.)

frequenz = frequenz >> 1;
//oder kurz
frequenz >>= 1;

Aber nicht gemischt!

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
Noch kein Account? Hier anmelden.