serial.read /serial.available Abfrage zur Spannungssteuerung

Hallo liebe Community,
Ich hab ein vielleicht sogar software übergreifendes Problem.
Ich verwende einen Arduino Mega2650 und möchte Signale der Seriellen Schnittstelle0(also per USB verbunden) auslesen und diese dann Verarbeiten und mit einem DAC als Spannung weitergeben. (Ich habe es mit 115200 und jetzt 57600 Baud probiert um zu sehen ob es daran liegt.

Dazu habe ich zuerst getestet, ob es denn überhaupt funktioniert und die Lampe blinken lassen - ergo ich sehe, dass ein Signal ankommt.

#include <Wire.h>
#include <Adafruit_MCP4725.h>
#include <unistd.h>

Adafruit_MCP4725 dac;


int Eingang = 0;
int Ausgang;

void setup(void) 

{
  Serial.begin(115200); //öffnet die serielle Schnittstelle mit einer datenrate von 115200 bit/s
   
  dac.begin(0x60);    //Zuweisung der richtigen Adresse
  pinMode(6, OUTPUT); //setzt Pin 6 und 7 auf den Output modus, damit wir den Pin auf HIGH und LOW setzen können
  pinMode(7, OUTPUT);
  pinMode(13, OUTPUT);
  

}


void loop(void) {
if (Serial.available() >0) {
  Eingang=Serial.read(); 
  Ausgang=Eingang*2;
  if (Eingang>0)
{
  digitalWrite(13, HIGH);
  Serial.write(Ausgang);
  delay(200);
  digitalWrite(13, LOW);   

}
}
}

Funktioniert soweit und es blinkt in Abständen.

Sobald ich nun wirklich eine Spannung ausgeben möchte und mit dem Multimeter die Ausgegebene Spannung überprüfe, kommen da nur Hausnummern raus.

#include <Wire.h>
#include <Adafruit_MCP4725.h>
#include <unistd.h>

Adafruit_MCP4725 dac;

void SpannungAusgeben(int Spannung);

double Spannung=0; //Globale Variable die zur Speicherung der aktuellen Ausgabespannung verwendet wird

void setup(void) 

{
  Serial.begin(57600); //öffnet die serielle Schnittstelle mit einer datenrate von 57600 bit/s
   
  dac.begin(0x60);    //Zuweisung der richtigen Adresse
  pinMode(6, OUTPUT); //setzt Pin 6 und 7 auf den Output modus, damit wir den Pin auf HIGH und LOW setzen können
  pinMode(7, OUTPUT);
  //dac.setVoltage(50*0.001*4095/1.25, false); 
  pinMode(13, OUTPUT);
  
  SpannungAusgeben(Spannung);           
}

void SpannungAusgeben(int Span)             //Eine Void Funktion (Funktion ohne Rückgabewert), welche die Spannung ausgiebt.
{
 if (Span > 0)                              //Wenn die Spannung positiv ist, wird der 7er pin LOW gesetzt und der 6er Pin auf HIGH, somit wird die Spannung direkt ausgegeben
 {
  
  digitalWrite(7,LOW);
  digitalWrite(6,HIGH);
 
 } 
 else                                           //Wenn die Spannung nicht positiv ist, dann wird der 6er pin LOW gesetzt und der 7er Pin auf HIGH, somit wird die Spannung direkt ausgegeben
 {
  digitalWrite(6,LOW);
  digitalWrite(7,HIGH);
  Span=Span*(-1);
 }


  
dac.setVoltage(Span*0.001*4095/1.25, false);                 //Die Ausgabespannung muss von 0-1000V auf 0-5V verringert werden. Dies passiert durch die Division durch 1000 und Multiplikation mit 4095. Normalerweise ist das maximum 4096 bei 12 bit, aber dann gibt das Gerät etwas zu viel Spannung aus, ka warum. 
Serial.println(Spannung);

 }
 
void loop(void) {
if (Serial.available() >0) {
  Spannung=Serial.read(); 
 SpannungAusgeben(Spannung);


}
else 
{
  Serial.println ("Ausfall");
}
}

Zu meinem Code der die Schnittstelle anspricht (in Freebasic - lange Geschichte warum) aber ebenfalls hier:

CLS
DIM as Integer k1,k2, k3, k4, k5
k2=2000
k1=100
k3=300
k4=0
k5=-100

Do While (k1<2000)
Print "Test"
Sleep 1000
rem USB Schnittstelle öffnen
OPEN COM "COM3:57600,N,8,1,CS0,DS0,LF" AS #3

Print #3, k1
Print k1
sleep k2
Print #3, k4
print k4
sleep k2
Print #3, k3
print k3
sleep k2
Print #3, k5
print k5
sleep k2
Print #3, k4
print k4
sleep k2

Close #3

loop

Close #3
END

Ich habe es eben mit 115200 und 57600 Baud probiert, mit leider demselben Ergebnis.

Muss ich vielleicht die Bit die ankommen irgendwie umwandeln? also dass da tatsächlich nur eine Codewurst ankommt und ich die decodieren muss? oder mit von mir gewählten Start/Stopbits versehen?

EDIT: Es blinken manchmal TX, RX ganz kurz auf? Heißt das, dass etwas mit der Übergabe der Daten nicht passt?

if (Ausgang=Eingang*2)

Möchtest du wirklich hier eine Zuweisung, oder doch lieber einen Vergleich?

Das war nur als Bedingung um die Lampe wieder abzudrehen nach eben 1.5s - ich hätte das auch mit delay 1500 und danach Digital.Write(13, LOW) lösen können, komme ich jetzt drauf, hat seinen Zweck aber so erfüllt.
Das ganze Blinken war nur als Test ob ich ein Signal empfange.

Nun möchte ich eben das Signal weiterverarbeiten (zweiter Codeblock) und zur Ausgabe einer Spannung nutzen.

Oder zumindest einmal sehen, was denn genau ankommt.

Wenn das eine Antwort auf meine Frage war, dann hast du sie sehr gut verschlüsselt.

double Spannung=0;
Spannung=Serial.read();

Wenn du die Serial Doku lesen würdest, dann würdest du (evtl.) erfahren, dass Seral.read() ein Byte liest, und kein Double.

Danke erstmal, das mit Spannung habe ich übersehen, das war noch aus der vorigen Verwendung des Codes drin. - habe jetzt Spannung auf int gesetzt. Nun leuchtet die TX Leuchte durchgehend auf.

Meine Überlegung ist jetzt einfach nur einzulesen und das gelesen auszugeben (mit HTerm)

#include <Wire.h>
#include <Adafruit_MCP4725.h>
#include <unistd.h>


int Spannung=0; //Globale Variable die zur Speicherung der aktuellen Ausgabespannung verwendet wird

void setup(void) 

{
  Serial.begin(115200); //öffnet die serielle Schnittstelle mit einer datenrate von 115200 bit/s
}

void loop(void) {
if (Serial.available() > 0) {
  Spannung=Serial.read(); 
 Serial.print("received ");
 Serial.println(Spannung);

}
else 
{
  Serial.println ("Ausfall");
}
}

Ich glaube mir fehlt da gerade das grundlegende Verständnis WAS ich denn eigentlich sende (Ich denke ein Byte also 8Bit ohne Parität,1 Stopbit)
Das bedeutet ich muss mein ASCII in einen HEX Code umrechnen oder?

Das bedeutet ich muss mein ASCII in einen HEX Code umrechnen oder?

ASCII ist korrekt. Hex ist nicht nötig. Den Controller interessiert es nicht ob etwas Hex, Dezimal oder Binär ist. Das ist nur für Menschen interessant.

Normal schließt man dann eine Übertragung mit einem Linefeed ab um das Ende zu erkennen. Dann kann man eine Zeichenkette einlesen und am Ende konvertieren.

Quick & Dirty gibt es auch parseInt() und parseFloat(). Man sollte aber unbedingt mit setTimeOut() die Timeout Zeit gewaltig nach unten setzen. Sonst blockiert man immer für eine ganze Sekunde:

Serenifly:
Normal schließt man dann eine Übertragung mit einem Linefeed ab um das Ende zu erkennen. Dann kann man eine Zeichenkette einlesen und am Ende konvertieren.

Wo lege ich den Linefeed fest? Im Freebasic das etwas sendet?
Timeout zeit runter ist verständlich, weil jede Sekunde einmal lesen ist ja wirklich wenig, v.a. da muss ja auch genau dann gerade etwas kommen..

Serenifly:
Quick & Dirty gibt es auch parseInt() und parseFloat().

Ergo: Spannung= Serial.parseInt();?

Aus meiner Wühlkiste:
Ein rudimentärer Parser, gewürzt mit einem Hauch von Nebenläufigkeit.
Leicht für dein double angepasst.

#include <Streaming.h>


void verarbeite(double value)
{
  Serial << "Wert: "<< value << endl;
}

void serialEvent()
{
  constexpr  size_t size = 20;
  static size_t len  = 0;
  static char buffer[size];
  
  switch(int input = Serial.read())
  {
    case '\r': /* fall througth */
    case '\n': if(len)
               {
                  buffer[len] = 0; // Zeilenende
                  verarbeite(strtod(buffer,nullptr));
                  len = 0;
               }
               break;
               
    case '.': /* fall througth */               
    case '-': /* fall througth */               
    case 'e': /* fall througth */               
    case 'E': /* fall througth */               
    case '0' ... '9': buffer[len++] = input;
                      break;    

    default:  len = 0;                          
         
  }
  
  if(len >= size) len = 0; // moeglichen Bufferoverflow fangen
}

void setup() 
{
  Serial.begin(9600);
  Serial << "Start: "<< __FILE__ << endl;
}

void loop() 
{

}

Wenn das Streaming nicht schmeckt: Raus operieren!

Danke für deine Hilfe Combie!
(auch wenn ich deinen letzten Post nicht ganz durchblicke, daraus schlau werde, aaber ich habe es (auf meine Art) gelöst, sodass ich mit dem Serialmonitor die Commandos schicken und kontrollieren kann (Ausgangsspannung passt auch.

Hier noch mein Code (falls jemand jemals ebenfalls ein ähnliches Thema hat)

#include <Wire.h>
#include <Adafruit_MCP4725.h>
#include <unistd.h>
Adafruit_MCP4725 dac;

void SpannungAusgeben(int Spannung);

int Spannung=0; //Globale Variable die zur Speicherung der aktuellen Ausgabespannung verwendet wird

String Spannungstr;

void setup(void) 

{
  Serial.begin(115200); //öffnet die serielle Schnittstelle mit einer datenrate von 115200 bit/s
  Serial.setTimeout(100);
  dac.begin(0x60);    //Zuweisung der richtigen Adresse
  pinMode(6, OUTPUT); //setzt Pin 6 und 7 auf den Output modus, damit wir den Pin auf HIGH und LOW setzen können
  pinMode(7, OUTPUT);
  //dac.setVoltage(50*0.001*4095/1.25, false); 
  pinMode(13, OUTPUT);
  
  SpannungAusgeben(Spannung);           //Ein letztes mal muss hier nocheinmal die Spannung ausgegeben werden, damit der letzte wert auch noch ausgegeben wird.
}

void SpannungAusgeben(int Span)             //Eine Void Funktion (Funktion ohne Rückgabewert), welche die Spannung ausgiebt.
{
 if (Span > 0)                              //Wenn die Spannung positiv ist, wird der 7er pin LOW gesetzt und der 6er Pin auf HIGH, somit wird die Spannung direkt ausgegeben
 {
  
  digitalWrite(7,LOW);
  digitalWrite(6,HIGH);
 
 } 
 else                                           //Wenn die Spannung nicht positiv ist, dann wird der 6er pin LOW gesetzt und der 7er Pin auf HIGH, somit wird die Spannung direkt ausgegeben
 {
  digitalWrite(6,LOW);
  digitalWrite(7,HIGH);
  Span=Span*(-1);
 }

dac.setVoltage(Span*0.001*4095, false);                 //Die Ausgabespannung muss von 0-1000V auf 0-5V verringert werden. Dies passiert durch die Division durch 1000 und Multiplikation mit 4095. Normalerweise ist das maximum 4096 bei 12 bit, aber dann gibt das Gerät etwas zu viel Spannung aus, ka warum. 
Serial.println(Spannung);
 }
 
void loop(void) {
if (Serial.available() > 0) {
  Spannungstr=Serial.readString(); 

 SpannungAusgeben(Spannungstr.toInt());
 Serial.print("received ");
  Serial.println(Spannungstr);

}}

Jetzt muss ich nur noch das FB zum arbeiten überreden. :slight_smile: