Arduino Pulsgenerator

Hallo,

Ich bin im Moment dran einen Pulsgenerator mit dem Ardunio Due zu programmieren.

Ziel ist es Pulse mit 1 MHz via Serial Monitor zu steuern.

Nun habe ich Folgendes Problem. Ich kann eine Abfolge von Zeichen in den Serial Monitor eingeben und entsprechende Impulse erzeugen, allerdings entstehen Pausen zwischen den Pulsen welche viel länger sind als die eigentlichen Impulse.

Nun weiß ich nicht wie ich diese Pausen eliminieren kann

#define NOP __asm__ __volatile__ ("nop\n\t");


  int pulse = 0 ;
  long i = 0;  
  int z =0;
  int l =0;

void setup() {                 
  pinMode(12, OUTPUT);
  pinMode(14, OUTPUT);
  pinMode(15, OUTPUT); 
 
  Serial.begin(115200);
 
  
  REG_PIOD_OWER = 0xFFFF; 
}

void loop() {
  

  
  
  
  while (Serial.available() > 0) {
     
     int pulse = Serial.read(); 
    
     switch (pulse) {
   
     case '0':
           
         //for(long i; i <100; i++){  
   
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    NOP
    NOP
    NOP  
    REG_PIOD_ODSR = 000000000; 
 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;
                       //     };
                          i=0;  
                          Serial.print("0");
    break; 
    
    
    
    
    case '1':
    
    //   for(int z; z <100 ; z++){  
    
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    
    NOP
    NOP
    NOP  
    REG_PIOD_ODSR = 000000000; 
  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;
                          //       }; 
                                z =0; 
                                Serial.print("1");
    break;
    
      case '2':
    
   //    for(int l; l <100; l++){  
    
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    
    NOP
    NOP
    NOP  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;
                           //    };  
                               l=0;
                               Serial.print("2");
    break;
 
            
    default:
    Serial.println("Bitte geben sie ein Pulssignal ein, welches aus 2, 0, 1 besteht!")  ;  
        

       }   
         } 

  }

WA000001.BMP (219 KB)

logikr:
Ziel ist es Pulse mit 1 MHz via Serial Monitor zu steuern.

Nun habe ich Folgendes Problem. Ich kann eine Abfolge von Zeichen in den Serial Monitor eingeben und entsprechende Impulse erzeugen, allerdings entstehen Pausen zwischen den Pulsen welche viel länger sind als die eigentlichen Impulse.

Bei 115200 Baud kannst Du maximal 11520 Zeichen pro Sekunde über die serielle Schnittstelle senden. Der zeitliche Mindestabstand zwischen zwei gesendeten (und auch empfangenen) Zeichen beträgt also:
1/11520 s = ca. 0,0000868 s = ca. 86,8 µs,

So wie Du es mit den über Serial gesendeten Zeichen @115200 Baud machst, kann also ein nachfolgender Impuls erst ca. knappe 90µs nach dem vorhergehenden erzeugt werden, weil der zeitliche Abstand zwischen zwei Zeichen @115200 Baud dieser Zeit entspricht.

Du mußt auf zeitlich kürzere Zeitabstände kommen, die Du verarbeiten möchtest?

Wenn es nur um die Zeit zwischen zwei Zeichen auf Serial geht, könntest Du mit Baudraten von 250000 oder 500000 noch etwas herausholen. Arduino-Boards (auch die mit 8-Bit Controller) unterstützen Baudraden bis 500000 Baud ebenso wie gängige PCs. Allerdings unterstützt der "Serielle Monitor" der Arduino-Software nur max. 115200, aber das ist nicht die maximal mögliche Baudrate.

Gäbe es auch die Möglichkeit die Werte der Eingabe Zwischenzuspeichern und danach schneller abzuarbeiten?

logikr:
Gäbe es auch die Möglichkeit die Werte der Eingabe Zwischenzuspeichern und danach schneller abzuarbeiten?

Natürlich kannst Du auch Werte zwischenspeichern und später abarbeiten.
Jedes Arduino-Board verfügt über RAM-Speicher.

Außerdem könntest Du über Serial auch bereits bei derselben Baudrate die vierfache Menge an Daten übertragen wie Du es machst. Deinem Code entnehme nich, dass Du nur drei verschiedene Pulszustände übertragen möchtest, 0,1 oder 2, und so etwas läßt sich bereits in nur 2 Bits binär codieren:

00 = 0
01 = 1
10 = 2
11 = 3 = invalid

Über Serial wird als kleinste Einheit aber immer 1 Byte = 8 Bits übertragen. D.h. wenn Du die Pulsfolge 0112 übertragen möchtest, könntest Du diese vier Pulse binär in einem einzigen Byte übertragen:

 0 1 1 2  (Pulse-ID)
00010110 (Binär codiert in einem Byte)

So kannst Du in einem einzigen Byte zwischen 1 und 4 Impulsen übertragen, indem Du in einem Byte mehr als nur eine einzelne Impulsinformation überträgst.

Aber Du kannst übertragene Bytes natürlich auch im RAM zwischenpuffern und später verarbeiten. Die Art des benötigten Speichers nennt sich FIFO-Puffer (FIFO = First IN First OUT) und steht dafür, dass später die Informationen als erstes aus dem Puffer rausgezogen werden, die auch als erstes hineingepackt wurden.

gibt es Beispiele für die Implementierung eines FIFO auf dem Due habe auf der Arduino Seite leider nichts gefunden

Implementierung eines FIFO auf dem Due habe auf der Arduino Seite leider nichts gefunden

Dann schau mal hier: http://forum.arduino.cc/index.php/topic,45305.0.html

Hat aber mit Arduino eigentlich nichts zu tun:

http://www.asawicki.info/news_1468_circular_buffer_of_raw_binary_data_in_c.html
...

Kannst ihn auch statisch aufbauen, ohne malloc bzw new.
Und alle anderen möglichen Vereinfachungen ( du willst nur einzelne Bytes lesen/schreiben, hast keine Sychronisationsprobleme )
treffen bei dir auch zu...

Ja, immer daran denken dass solche allgemeinen Sachen nicht Arduino-spezifisch sind und dass hier auch nur in C/C++ programmiert wird. FIFOs sind eine Standard Datenstruktur in der Informatik. Entsprechend gibt es da zig Beispiele die man einfach implementieren kann. In diesem Fall muss man nur aufpassen, dass man eine erwischt die auf Array Basis implementiert ist und nicht als verkettete Liste.

In diesem Fall muss man nur aufpassen, dass man eine erwischt die auf Array Basis implementiert ist und nicht als verkettete Liste

Das ist generell das Problem beim Software Suchen:
Man findet was, fragt sich "muss das so kompliziert gemacht werden?", und quält sich ewig mit dem Verständnis "warum das da so kompliziert ist", bis man entweder tatsächlich was gelernt hat oder merkt "das brauch ich nicht".

Interessant wird es im Fehlerfall, wenn der Puffer voll wird:
Altes ungelesen überschreiben ? Neues verwerfen ? Kann man das Schreiben verzögern (und dadurch einen Überlauf woanders hin legen?) Fehlerkennung einbauen ? ( und wie drauf reagieren? ) ???
Wenn man da spezielle Wünsche hat, kriegt man die eh nicht erfüllt ohne Selber Schreiben

Ansonsten für den einfachen byte-fifo : Passendes Puffer-Array, zwei Zeiger, ein paar if, fertig :wink:

In deinem Fall hat Serial übrigens den FIFO - Puffer schon eingebaut. Du musst nicht sofort alles lesen was da ist. Wenn dir 64 byte als Puffer grade recht sind, heisst deine FIFO Leseoperation [b]Serial.read() [/b]

Ok vielen Dank. Dann werde ich mich daran mal probieren :slight_smile:

ich habe nun den FiFo realisiert nun habe ich aber das Problem, dass ich die Werte die ich eingelesen habe und zu puls übertragen kann nicht in dem Switch ausgewertet wird

#include <SimpleFIFO.h>
#define NOP __asm__ __volatile__ ("nop\n\t");

 SimpleFIFO<int,4096> sFIFO; //Bestimmt Buffergröße
 char x;
 boolean stringComplete = false;  // whether the string is complete
 int pulse;



void setup() {
  Serial.begin(9600);
  pinMode(12, OUTPUT);
  pinMode(14, OUTPUT);
  pinMode(15, OUTPUT);
 
}


 void serialEvent() {
   
 while (Serial.available()) {
    
 char x = Serial.read(); // einlesen Char aus Serial
 int z = atoi(&x);  // umwandeln char zu int
  //Serial.print(z); // ausgabe int
 sFIFO.enqueue(z); // int in FIFO schreiben
    
    if (x == '\r') {  // erkennung Return
      stringComplete = true;
    }
    
    
  if (stringComplete) { // wenn return eingegeben
      int epsilon;  //anzahl Elemente
      epsilon = sFIFO.count();
      int beta;
      beta = epsilon -1; //korrekturfaktor für enterzeichen
   
      for (int i=0; i<beta; i++) {   //ausgabe der Elemente des FIFO
       /*Serial.print("Aktuelles Element: ");
      Serial.println(sFIFO.dequeue());
      Serial.println("Anzahl Elemente ");
      Serial.println(sFIFO.count()); */
      
      int pulse = sFIFO.dequeue();
      Serial.print(pulse);
                                }
  
  Serial.println("Alle Werte ausgegeben!");  //neue initierung des FIFO
  sFIFO.flush();
  Serial.println("Speicher neu initiert: "); 
 
    stringComplete = false; }
 
  }
    }
    
    
void pulsgen(int pulse) {
  
    switch (pulse) {
   
     case '0':
           
        
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    REG_PIOD_ODSR = 100110000;
    NOP
    NOP
    NOP  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;
                       //     };
                           
                          Serial.println("impuls 0");
    break; 
    
    
    
    
    case '1':
    
   
    
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    REG_PIOD_ODSR = 100100000;
    
    NOP
    NOP
    NOP  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;
                          //       }; 
                                
                                Serial.println("impuls 1");
    break;
    
      case '2':
    

    
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    REG_PIOD_ODSR = 100010000;
    
    NOP
    NOP
    NOP  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;  
    REG_PIOD_ODSR = 000000000; 
    REG_PIOD_ODSR = 000000000;
                           //    };  
                               
                               Serial.println("impuls 2");
    break;
 
            
    default:
    Serial.println("Bitte geben sie ein Pulssignal ein, welches aus 2, 0, 1 besteht!")  ;  
        

       }   
}

void loop() {
  

 
 if(stringComplete) {
 
  void pulsgen(int pulse);
       }
  //nothing
}

denke es hängt mit der übergage der variable puls zusammen weiß aber leider nicht wie ich diesen fehler beheben kann

char x = Serial.read(); // einlesen Char aus Serial
 int z = atoi(&x);  // umwandeln char zu int

Das ist falsch. atoi() ist für C Strings. Also Null-terminierte char Arrays! Du hast da einen einzelnen char. Falls das korrekt läuft, ist das reines Glück.

Um ein ASCII Zeichen in eine Zahl zu wandeln musst du lediglich das machen:

int z = Serial.read() - '0';

'0' hat den ASCII Wert 48. Wenn man das also abzieht hat man die Zahl in Dezimal.

Und du solltest diese Umwandlung an das Abspeichern im Puffer auch erst machen nachdem du auf das Endzeichen abgefragt hat und es kein Endzeichen ist:

char x = Serial.read();

if (x == '\r')
{
      stringComplete = true;
}
else
{
      sFIFO.enqueue(x - '0');
}

Dann ist dein richtiger Fehler hier:

case '0':

Was jetzt? Du wandelst die ASCII Zeichen vorher in Zahlen um. Wieso fragst du dann hier wieder auf ein ASCII Zeichen ab? Da steht 0 drin und nicht '0'

Wenn du nur Zahlen von 0-9 speichern willst, reicht übrigens byte. Du hast auf dem Due zwar massig RAM, aber ein int hat da 4 Bytes.