Funktionsgenerator

Hallo liebe Gemeinde,
ich möchte einen Funktionsgenerator mit einem Arduino Due bauen und habe da ein paar kleinere Probleme.

Ich soll für ein Schulprojekt mehrer Signale, als Testsignale ausgeben:
-Rauschen
-Quadrat
-Rampe
-Peek

  • usw.

Hier beispielsweise eine Rampe die von 0 bis 100% geht (also 0-4095 Schritten), in einer bestimmten Zeit.
Die Funktionen an sich sind nicht das Problem. Leider scheiter ich gerade an der Zeit.
Die Signale sollen jeweils in 1s, 5s, 10s, 20s, und 50s von 0-100% gehen und sie sollen nicht wiederholt werden. Nur einmalig in der Zeit x von 0-100% gehen.

Ich habe es schon mit den Befehl delay(x), delayMicroseconds(x) usw. versucht, hat aber leider nicht funktioniert. Habe mich auch schon durch die Foren und andere Suchmaschinen gearbeitet, jedoch ohne Erfolg.

Kann mir jemand einen Denkanstoß geben?

int saw[] = {
    0x22, 0x44, 0x66, 0x88, 0xaa, 0xcc, 0xee, 0x110, 0x132, 0x154,
    0x176, 0x198, 0x1ba, 0x1dc, 0x1fe, 0x220, 0x242, 0x264, 0x286, 0x2a8,
    0x2ca, 0x2ec, 0x30e, 0x330, 0x352, 0x374, 0x396, 0x3b8, 0x3da, 0x3fc,
    0x41e, 0x440, 0x462, 0x484, 0x4a6, 0x4c8, 0x4ea, 0x50c, 0x52e, 0x550,
    0x572, 0x594, 0x5b6, 0x5d8, 0x5fa, 0x61c, 0x63e, 0x660, 0x682, 0x6a4,
    0x6c6, 0x6e8, 0x70a, 0x72c, 0x74e, 0x770, 0x792, 0x7b4, 0x7d6, 0x7f8,
    0x81a, 0x83c, 0x85e, 0x880, 0x8a2, 0x8c4, 0x8e6, 0x908, 0x92a, 0x94c,
    0x96e, 0x990, 0x9b2, 0x9d4, 0x9f6, 0xa18, 0xa3a, 0xa5c, 0xa7e, 0xaa0,
    0xac2, 0xae4, 0xb06, 0xb28, 0xb4a, 0xb6c, 0xb8e, 0xbb0, 0xbd2, 0xbf4,
    0xc16, 0xc38, 0xc5a, 0xc7c, 0xc9e, 0xcc0, 0xce2, 0xd04, 0xd26, 0xd48,
    0xd6a, 0xd8c, 0xdae, 0xdd0, 0xdf2, 0xe14, 0xe36, 0xe58, 0xe7a, 0xe9c,
    0xebe, 0xee0, 0xf02, 0xf24, 0xf46, 0xf68, 0xf8a, 0xfac, 0xfce, 0xff0
  };

int j=0;
// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin 13 as an output.
  
  pinMode(23, OUTPUT);
  pinMode(24, INPUT);
  pinMode(DAC0, OUTPUT);
}

// the loop function runs over and over again forever
void loop() 
{
  
  digitalWrite(23,LOW);  

  if(digitalRead(24)==LOW) // Wenn Pin 24 LOW
  {
    if(j<=120)            // Solange j kleiner 120 
    {
      j++;
      
         for ( int i=0;i<120;i++)  // Array auslesen
             {
             analogWriteResolution(12); // 12 Bit
             analogWrite(DAC0,saw[i]);  // gebe Werte aus
             delay(1000);                // Warte 1 Sekunde
             }
     }
     if(j>=120)                          // Wenn j größer gleich 120
     {
             analogWriteResolution(12);  // schreibe max Wert
             analogWrite(DAC0,4095);
     }       

    }
    }

Oktopoden:
Ich habe es schon mit den Befehl delay(x), delayMicroseconds(x) usw. versucht, hat aber leider nicht funktioniert. Habe mich auch schon durch die Foren und andere Suchmaschinen gearbeitet, jedoch ohne Erfolg.

Kann mir jemand einen Denkanstoß geben?

Deine Schleife:

 for ( int i=0;i<120;i++)  // Array auslesen
             {
             analogWriteResolution(12); // 12 Bit
             analogWrite(DAC0,saw[i]);  // gebe Werte aus
             delay(1000);                // Warte 1 Sekunde
             }

wartet 120 mal eine Sekunde.
Gesamtlaufzeit der Schleife 120 Sekunden (plus ein paar Mikrosekunden extra für den Kram, der außer dem delay() sonst noch ausgeführt wird).

Soweit die Theorie...
Habe das Delay() jetz mal auf 250 gesetzt um somit eine gesamt Schleifendurchlaufzeit von 30 Sekunden zu erhalten.

Im Anhang das aufgenommen Bild vom Osziloskope.

Daran sieht man, dass das Signal zwar generiert wird, jedoch nicht über die gesamte Strecke, sondern nur am Anfang.

Er fängt mit der Kurve an, dann wartet er 30 Sekunden und danach kommt die nächste Kurve.
Ich möchte jedoch über die gesamte Strecke die Kurve.

Sprich von der Idee her, war ich auf dem richtige Weg, nur die Umsetzung ist noch fehlerhaft ?!

Hallo,

eine sehr gute Einleitung zu diesem Thema, mit Erklärungen der Theorie, findest Du hier: Beschreibung

Ich denke, es könnte sie für Dich lohnen, Dich da mal einzulesen.

Gruß,
Ralf

Oktopoden:
Sprich von der Idee her, war ich auf dem richtige Weg, nur die Umsetzung ist noch fehlerhaft ?!

Es ist ja nicht so, dass es im Playground nichts zum Thema "DUE" und "Funktionsgenerator" gäbe:
http://arduino.cc/en/Tutorial/DueSimpleWaveformGenerator

Ob Du Dir das wohl schon mal angesehen hast?

Und ob das Beispiel nicht einfach von einem Regelbereich 1Hz bis 170Hz auf den von Dir gewünschten Bereich von 0.02Hz bis 1Hz änderbar wäre?

Dieses Beispiel habe ich mir natürlich angeguckt und auch zu meinen Zwecken umprogrammiert. Das ist ja der entstande Code, siehe oben:

Deswegen hatte ich ja auch die For-Schleife genommen, da ich mir gedacht habe, dass er nach jeden geschriebenden Wert eine Pause von Wert x macht.
Um so die Periode langzuziehen und so meine gewünschten Werte zu bekommen.

Im Anhang sind mal ein paar Beispiele, mit den verschiedenden Zeiten die ich bei delay() eingeben hatte, bzw. in diesem Fall delayMicroseconds();
Bild 2 delayMicroseconds(1000) Gesamtzeit 64ms
Bild 3 delayMicroseconds(10000) Geamtzeit 640 ms
Bild 4 delayMicroseconds(100000) Gesamtzeit 6,4s

Man kann Anhand der aufgenommenden Grafiken sehen, dass das Signal irgendwann verschwindet.

Wo genau liegt mein Fehler?
Oder muss ich auf die Taktfrequenz zugreifen?

Danke für die bisherige Hilfe

Hallo,

sollen alle Bilder eine Rampe sein mit 3 verschiedenen "Anstiegszeiten"?
Das 2. und 3. sieht eher nach einer e Funktion aus.
Meine Vermutung. Entweder mußt Du für jede Signalform ein eigenes Array anlegen. Oder Du mußt die Zeitabstände je nach Signalform flexibel ändern während der Ausgabe.

Bsp. array[0,1,2,3,4,5,6,7,8,9]
Zeitabstand dazwischen eine Sekunde, man erhält einen geradlinigen Anstieg.
Variiert man den den Zeitabstand nach jeder Ausgabe bekommt andere Formen hin.
Oder eben man läßt den Zeitabstand konstant und legt verschiedene Arrays fest. Solange RAM vorhanden ist,

Also wenn ich das aus der Kalten bei Null anfangen müßte, ich würde als Grundlage einen Timer verwenden. Mittels Timer würde ich die zeitlichen Abstände konstant halten bzw. ändern. Damit jede Signalwiederholung gleich aussieht.

Weiter habe ich mich damit noch nicht beschäftigt.

Also erstmal Ja, es ist jeweils die selbe Funktion(hier eine Rampe) mit verschiedenen "Wartezeiten" in der For-Schleife.

Das ist ja mein Problem, ich greife auf das selber Array(120 Werte) zu und möchte natürlich das gleiche Signal nur in verschiedenen Zeiten wieder ausgeben.
Mit meinen jetzigen Verständnis sollte das auch in der For-Schleife funktionieren.
Das Resultat sieht leider anders aus.

Ich habe mir natürlich auch das Thema Timer schon zur Hand genommen. Zu diesem Thema gibt es auch reichlich Theorie mit praktischen Beispielen. Ich habe mir auch das Datenblatt des Arduino Due zur Hand genommen und das Kapitel des Timers mir angeschaut, jedoch weiß ich nicht wie genau ich das Programmieren soll.

Ich hatte auch anhand von andere Beispielen versucht mir das Timer programmieren anzueignen, bin jedoch an der Begrifflichkeit gescheitert. Die Oberfläche ist mir einfach noch nicht vertraut.

http://2manyprojects.net/timer-interrupts

Mit diesem Beispiel hatte ich es auch schon versucht, jedoch wieder mal ohne Erfolg.

In moment weiß ich noch nicht ob rechts oder links gehen soll. Steh praktisch vor einer Blockade

Hallo,

was macht denn die Variable j bei Dir im Code?
Soll die die Stelle im Array zählen?
Wäre eigentlich überflüssig, weil das i in der for Schleife macht.
Vielleicht erhälst Du hierdurch eine immer größer werdende Schleifendurchlaufzeit mit entsprechender Auswirkung.
Müßte man mal mit millis ausstoppen und ausgeben lassen. Wird bestimmt immer größer und bleibt nicht konstanst bei Nahe einer Sekunde vom delay. Wobei das delay beim due bestimmt keine ms sind. Oder? Du hast doch keine Sekundenpausen. Deine Bilder sagen das die Kurven im ms Bereich liegen.

Vielleicht würde ich auch eine while schleife nehmen für den Pin 24, Taster nehme ich an, solange der LOW ist, wird nur die for schleife durchlaufen, bis entweder sie zu Ende ist, Array Ende, oder der Taster nicht mehr LOW ist.

Edit:
gesucht ... endlich gefunden ... ich hoffe das hilft, tiefer beschäftigt habe ich mich auch noch nicht damit.
http://forum.arduino.cc/index.php?topic=229737.new;topicseen#new
Es gibt aber wirklich viele Links im Internet. "Arduino Timer"

Die Variable j soll einfach die For-Schleife rausschmeißen
Sprich wenn der max Wert des Arrays erreicht ist, soll nur noch der max Wert ausgegeben werden, welcher in der if-Anweisung darunter festgelegt ist.

Um halt nur eine einmalig Steigung von 0-100% zu erreichen.
Dies geht auch, wenn ich den Code in das setup() schreiben, da ja dort der Code nur einmal abgearbeitet wird.

In Moment arbeite ich auch mit einem anderen Code um erstmal das Zeitproblem in den Griff zu bekommen. Also eine abgespeckte Version so zusagen:

int Quatdrat[]={ 0x1,0x4,0x6,0x10,0x19,0x24,0x31,0x40,0x52,0x64,0x79,0x90,0xa9,0xc4,0xe1,0x100,0x121,
0x144,0x169,0x190,0x1b9,0x1e4,0x211,0x240,0x271,0x2a4,0x2d9,0x310,0x349,0x384,0x3c1,0x400,0x441,0x484,0x4c9,
0x510,0x559,0x5a4,0x5f1,0x640,0x691,0x6e4,0x739,0x790,0x7e9,0x844,0x8a1,0x900,0x961,0x9c4,0xa29,
0xa90,0xaf9,0xb64,0xbd1,0xc40,0xcb1,0xd24,0xd99,0xe10,0xe89,0xf04,0xf81,0xfff};

void setup() {
  // put your setup code here, to run once:
  pinMode(23, OUTPUT);
  pinMode(24, INPUT);
  pinMode(25, INPUT);
  pinMode(DAC0, OUTPUT);
   analogWriteResolution(12);
}

void loop() {
  // put your main code here, to run repeatedly:
  
  digitalWrite(23,LOW);  

  if(digitalRead(24)==LOW)
  {
 for ( int i=0;i<64;i++)
     {
    
     analogWrite(DAC0,Quatdrat[i]);
     delayMicroseconds(100000);
     
}
 
}
}

aber auch hier: je höher die Zeit in mein delay() oder delayMicroseconds() schreibe, desto ungenauer wird mein Signal.
Ich bekomme zwar die gewünschte Perioden dauer hin, aber das Signal wird nicht wiedergegeben wie ich das gerne hätte.

Noch ein paar Zusatzinfos:
Es soll mittels 2er Stellpotis, jeweils Funktion und Zeit eingestellt werden können.
Also für jede Funktion (Rampe,Quadrat,Peek, usw.) soll eine Zeit ausgewählt werden (1s,5s,10s, usw.)
und diese soll dann ausgegeben werden. (Einmaliger anstieg, keine Wiederholung!)
Später im Hardware-Bereich kommt dann noch Glättung, Invertierung und der andere Feinschliff.

Oktopoden:

 delayMicroseconds(100000);

Mit Deinem Aufruf der Funktion delayMicroseconds() scheinst Du Dich extrem weit außerhalb jeglicher Spezifikation für diese Funktion zu befinden. Siehe delayMicroseconds()

Also ich lese dort glasklar:

Currently, the largest value that will produce an accurate delay is 16383.
This could change in future Arduino releases. For delays longer than a few
thousand microseconds, you should use delay() instead.

Also würde ich mal versuchen, ein entsprechendes delay() lieber so zu erzeugen:

  delayMicroseconds(100);

Nur mal so.

Danke für den Hinweis.
Aber wie du an meine Code aus dem ersten Beitrag sehen kannst, dort habe ich delay() benutzt, spiele ich ein wenig mit den Befehlen, um irgendwie auf mein gewünschtes Ergebnis zu kommen.
Denn learning by doing.

Hier nochmal mein Aktueller code: Delay(10) bei 120 Werten im Array => 1,2 Sekunden pro Periode

und im Anhang das Oszi-Bild

int sprung[] = {0x22, 0x44, 0x66, 0x88, 0xaa, 0xcc, 0xee, 0x110, 0x132, 0x154,
    0x176, 0x198, 0x1ba, 0x1dc, 0x1fe, 0x220, 0x242, 0x264, 0x286, 0x2a8,
    0x2ca, 0x2ec, 0x30e, 0x330, 0x352, 0x374, 0x396, 0x3b8, 0x3da, 0x3fc,
    0x41e, 0x440, 0x462, 0x484, 0x4a6, 0x4c8, 0x4ea, 0x50c, 0x52e, 0x550,
    0x572, 0x594, 0x5b6, 0x5d8, 0x5fa, 0x61c, 0x63e, 0x660, 0x682, 0x6a4,
    0x6c6, 0x6e8, 0x70a, 0x72c, 0x74e, 0x770, 0x792, 0x7b4, 0x7d6, 0x7f8,
    0x81a, 0x83c, 0x85e, 0x880, 0x8a2, 0x8c4, 0x8e6, 0x908, 0x92a, 0x94c,
    0x96e, 0x990, 0x9b2, 0x9d4, 0x9f6, 0xa18, 0xa3a, 0xa5c, 0xa7e, 0xaa0,
    0xac2, 0xae4, 0xb06, 0xb28, 0xb4a, 0xb6c, 0xb8e, 0xbb0, 0xbd2, 0xbf4,
    0xc16, 0xc38, 0xc5a, 0xc7c, 0xc9e, 0xcc0, 0xce2, 0xd04, 0xd26, 0xd48,
    0xd6a, 0xd8c, 0xdae, 0xdd0, 0xdf2, 0xe14, 0xe36, 0xe58, 0xe7a, 0xe9c,
    0xebe, 0xee0, 0xf02, 0xf24, 0xf46, 0xf68, 0xf8a, 0xfac, 0xfce, 0xff0};
int  Time =0;
int i=0;
int j=0;
void setup() {
  // put your setup code here, to run once:
pinMode(DAC0,OUTPUT);
pinMode(23,OUTPUT);
pinMode(29,INPUT);
analogWriteResolution(12);
}

void loop() {
  // put your main code here, to run repeatedly:
  
  
  digitalWrite(23,LOW);
  if(digitalRead(24)==LOW ); 
  {
           for ( i=0;i<120;i++)
             {

             analogWrite(DAC0,sprung[i]);
             delay(10); 
            }    
              
    } 
    }

Nochmal zu den Timern:

TCCR0B = TCCR0B & 0b11111000 | <setting>; //Timer 0 (PWM pins 5 & 6) 
TCCR1B = TCCR1B & 0b11111000 | <setting>; //Timer 1 (PWM pins 9 & 10) 
TCCR2B = TCCR2B & 0b11111000 | <setting>; //Timer 2 (PWM pins 3 & 11) 

Available PWM Frequency Settings for Each Arduino System Timer 
Arduino Timer   <setting>   Divisor   Frequency (Hertz) 
0 (pins 5 and 6)   0x01   1   62500 
0 (pins 5 and 6)   0x02   8   7812.5 
0 (pins 5 and 6)   0x03   64   976.56 
0 (pins 5 and 6)   0x04   256 244.14 
0 (pins 5 and 6)   0x05   1024        61.04 
1 (pins 9 and 10)   0x01   1   31250 
1 (pins 9 and 10)   0x02   8   3906.25 
1 (pins 9 and 10)   0x03   64   488.28 
1 (pins 9 and 10)   0x04   256   122.07 
1 (pins 9 and 10)   0x05   1024   30.52 
2 (pins 3 and 11)   0x01   1   31250 
2 (pins 3 and 11)   0x02   8   3906.25 
2 (pins 3 and 11)   0x03   32   976.56 
2 (pins 3 and 11)   0x04   64   488.28 
2 (pins 3 and 11)   0x05   128   244.14 
2 (pins 3 and 11)   0x06   256   122.07 
2 (pins 3 and 11)   0x07   1024   30.52

So wie ich das hier rauslese, wird die Frequenz als PWM-Signal generiert?

Das PWM-Signal kann ich dann mittels Interrupt auf meinMaxWert unterbrechen?

Oktopoden:
Nochmal zu den Timern:

Bist Du jetzt dabei, einen 32-bit DUE zu programmieren?

Oder einen 8-Bit Atmega Controller wie den UNO oder MEGA?

Was Du da an Timer-Registern zusammenkopiert hast, sind Register von 8-Bit Atmega Controllern, die es beim DUE überhaupt nicht gibt.

Was steht denn links neben dem grünen Dreher auf dem Oszyloskop???

na? richtig AC. Stelle das Oszilloskop auf DC und Du wirst einen schönen Sägezahn haben.

Grüße Uwe

Moin,
ich habe zu diesem Thema mal eine PDF gefunden (nicht mit dem Due),
wo jemand beschreibt, wie man soetwas umsetzt kann.

Vlt. kannst du dadrin etwas verwendbares finden :wink:

Klick

Das war doch mal ein echter Hinweis

Danke!