serial auswerten und tft schreiben ?

hi @all,

ich lese von einer seriellen schnittstelle daten ein, speichere diese auf einer sd-card (serial-logger)
und zeige sie auf einem tft an ... so jedenfalls der wunschraum :~

das problem schein mir hier der speed zu sein, irgendwie schaffe ich es nicht schnell genug
mein loop zu durchlaufen und so verliere ich einfach daten die auf seriell rein kommen

sicher ist das ein grunsätzliches verständnisproblem von mir, kann mir da jemand auf die sprünge helfen ???

folgendes geht ohne probleme

void setup() {
    pinMode(OpenLogResetPin, OUTPUT);
    Serial2.begin(38400);
    Serial3.begin(19200, SERIAL_8N2);
    delay(100);
    LoggerInit();
}

void loop() {
    if ( Serial3.available() > 0 ) {
        Serial2.write( Serial3.read() );
    }
}

alles was ich über Serial3 reinschicke kommt sauber auf der sd-card an

wenn ich nur anfange einen sensor auszulesen verliere ich schon daten  :drooling_face:

void loop() {
    accel.getAcceleration(&sensorsData.ax, &sensorsData.ay, &sensorsData.az);
    if ( Serial3.available() > 0 ) {
        Serial2.write( Serial3.read() );
    }
}

wie schaffe ich es das ich keine daten von seriel verliere ?

Kein Plan wie die SD mit Arduino funktionieren, bislang reichte mir das Eeprom immer.

Aber bei dem Einlesen kann ich dennoch meckern :wink: Zum einen, ist es nötig, dass die Seriellen Schnittstellen mit unterschiedlichen Baudraten laufen? Das an Serial3 Angeschlossene Gerät scheint eine feste Baudrate zu haben.

Ich würde warten, bis die komplett angekommen sind und dann erst schreiben. Soll heißen, du ließt jedes Zeichen ein, bis '\n' oder '\r' kommt.

Entweder du kümmerst dich selber drum, das zu lernen, oder jemand erbahmt sich gleich. Habe gerade keinen passenden Code-Schnippsel hier rumliegen. Ggf. im Forum suchen, hatte da schon mal was.

Auf das einzige, auf was ich zugreifen kann, ist aus dem Kochbuch und da weiß ich nicht, wie es mit dem (c) aussieht :wink:

Dieses Thema kommt so gefühlt alle paar Tage dran:

const int SERIAL_BUFFER_SIZE = 31;
char serialBuffer[SERIAL_BUFFER_SIZE];

void loop()
{
	if(readSerial())
		displayPrintBuffer(serialBuffer);
}

bool readSerial()
{
	static byte index;

	while(Serial.available())
	{		
		char c = Serial3.read();
		
		if(c >= 32 && index < SERIAL_BUFFER_SIZE - 1)
		{
			serialBuffer[index++] = c;
		}
		else if(c == '\n')
		{
			serialBuffer[index] = '\0';
			index = 0;
			return true;
		}
	}
	return false;
}

void displayPrintBuffer(char* buffer)
{
	static byte previousLength;

	byte currentLength = strlen(buffer);
	if(currentLength < previousLength)
	{
		for(int i = currentLength; i < previousLength; i++)
			buffer[i] = ' ';
	}

	display.setColor(VGA_WHITE);
        display.setFont(BigFont);
	display.print(buffer, 0, 0);
	previousLength = currentLength;
}

Der Code in displayPrintBuffer() sorgt dafür, dass die Differenz zwischen vorheriger Übertragung und der aktuellen mit Leerzeichen aufgefüllt wird wenn die aktuelle kürzer ist. Sonst würde ein Teil des alten Textes stehen bleiben.

Hier bietet es sich auch an die Koordinaten ebenfalls als Parameter zu übergeben. Ich mehr das bei mir nicht, weil es bei meiner Anwendung eher eine Test-Methode ist.

Das solltest du aber erst machen nach dem du den Text aus der SD-Karte gespeichert hast. Also so:

if(readSerial())
{
    //speichere auf SD Karte    

    displayPrintBuffer(serialBuffer);
}

Den Serial Serial Monitor dazu so einstellen dass er ein Newline/Linefeed am Ende sendet!

ok ... ich bau mal einen buffer ein, bin gespannt ob das reicht ...

danke für die hinweise, melde nach einem test wieder ...

das problem ist, dass auf Serial3 ein binary-stream rein kommt,
ein datensatz startet immer mit 105, dann folgen 124byte daten

mein ansatz ist aktuell so, aber da verlier ich auch daten :drooling_face:

if ( Serial3.available() > 0 ) {
int inByte = Serial3.read();
if ( inByte == 105 ) { // wenn datensatz startet
int c = Serial3.readBytes(inBuffer, 124); // 124byte aus serial buffer lesen
if ( c == 124 ) { // haben wir 124byte gelesen ?
Serial2.print(inBuffer); // zum seriel-logger schicken
}
}
}

Immer wieder das gleiche. Serial ist langsam! In Zeichen dauert 1 / Baudrate * 10 Sekunden! Das ist eine Ewigkeit für einen µC.

Wenn ein Zeichen da ist, kannst du nicht gleich x mal read() machen. Der Rest ist da noch unterwegs. Du kannst aber auch nicht warten bis alles da ist, da der Eingangspuffer der Serial Klasse nur 64 Bytes hat.

Eine Lösung:
wenn du das Startbyte empfangen hast eine Statusvariable (boolean) auf true setzen. Dann auf diese abfragen und solange diese true ist, die Daten auf SD schreiben. Wenn deine 124 Byte da sind, die Variable wieder auf false setzten und auf das nächste Start-Byte warten.

Also sowas in der Art (schnell hingeschrieben, nicht getestet, selbst drüber nachdenken!):

void loop()
{
    static boolean startByte;
    static int count;

    if(Serial3.available())
    {
        int inByte = Serial3.read();
    
        if(startByte == false && inByte == 105)
        {
            startByte = true;
            count = 0;
        }
        else
       {
           Serial2.write(inByte);
           count++;

           if(count == 124)
               startByte = false;
       }
    }
}

Aber du musst jedes Byte einzeln behandeln und die Finger von Funktionen wie Serial.readBytes() lassen!

Auch merken: write() ist für Binärdaten. print() für ASCII

Der Code oben ist übrigens für Strings. Nicht für Binärdaten. Da die auf TFT schreiben wolltest hatte ich logischerweise gedacht, dass du da einen String schickst.

danke, dass bau ich mal schnell ein und schau ob ich hinkomme :~

Der Code oben ist übrigens für Strings. Nicht für Binärdaten.
Da die auf TFT schreiben wolltest hatte ich logischerweise gedacht, dass du da einen String schickst.

ich parse das gelese in ein struct und der wird dann angezeigt 8)

das funktioniert so ... danke

#define SIN Serial1
#define Logger Serial3
unsigned int OpenLogResetPin = 6;

void setup() {
pinMode(OpenLogResetPin, OUTPUT);
Serial.begin(115200);
Logger.begin(38400);
SIN.begin(19200, SERIAL_8N2);

delay(100);
LoggerInit();
}

void loop() {
static boolean startByte;
static int count;

if ( SIN.available() ) {
int inByte = SIN.read();
if(startByte == false && inByte == 105) {
startByte = true;
count = 0;
Logger.write(inByte); // die 105 mit in den logger schreiben
} else {
Logger.write(inByte);
count++;
if(count == 124)
startByte = false;
}
}
}

... nur löst es das problem nicht =(
sobald ich den tft-kram dazunehme verlier ich ca. 90% daten ...

#include <EEPROM.h>
#include <SPI.h>
#include <GD2.h>

#define SIN Serial1
#define Logger Serial3
unsigned int OpenLogResetPin = 6;

void setup() {
pinMode(OpenLogResetPin, OUTPUT);
Serial.begin(115200);
Logger.begin(38400);
SIN.begin(19200, SERIAL_8N2);

GD.begin();
GD.ClearColorRGB(0xff0000);
GD.Clear();
GD.swap();

delay(100);
LoggerInit();
}

void loop() {
GD.ClearColorRGB(0x0000ff);
GD.Clear();
GD.cmd_number(240, 136, 30, 10|OPT_CENTER, millis());
GD.swap();

static boolean startByte;
static int count;

if ( SIN.available() ) {
int inByte = SIN.read();
if(startByte == false && inByte == 105) {
startByte = true;
count = 0;
Logger.write(inByte); // die 105 mit in den logger schreiben
} else {
Logger.write(inByte);
count++;
if(count == 124)
startByte = false;
}
}
}

kann es sein das sich hier serial und spi vom tft in die quere kommen ???

Wieso löscht du bei jedem loop() Durchlauf das Display? Sowas wie clear() ist langsam, egal ob man ein LCD oder TFT hat und man sollte das nicht verwenden. Sondern immer einfach nur den Teil überschreiben den man braucht.

loop() läuft sehr schnell durch. Da alle paar 100µs oder ms was auf das Display zu schreiben ist nicht gut. Wenn du z.B. alle 1 Sekunde was machen willst kann du das machen:

void loop()
{
    static unsigned long previousMillis;

    if(millis() - previousMillis > 1000)
    {
          previousMillis = millis();
  
          //Code hier
    }
}

Aber auch da auf clear() verzichten wenn es geht

EDIT:
falsche Klammer nach "previousMillis" entfernt

als display verwende ich einen gameduino2, da schreibst du auf eine versteckte bitplane und
wenn du fertig hast schaltest du einfach mit GD.swap() um, das clear ist da leider pflicht :drooling_face:

auch nur jede sec zu schreiben bringt bei einem permanenten serial-stream ja nix, dann verlier
ich halt jede sec einige daten ... was auch schlecht ist :relaxed:

hello world schaut beim gameduino2 so aus ...

#include <EEPROM.h>
#include <SPI.h>
#include <GD2.h>

void setup()
{
GD.begin();
}

void loop()
{
GD.ClearColorRGB(0x103000);
GD.Clear();
GD.cmd_text(240, 136, 31, OPT_CENTER, "Hello world");
GD.swap();
}

Ok, dann ist es nicht so schlimm :slight_smile:

auch nur jede sec zu schreiben bringt bei einem permanenten serial-stream ja nix, dann verlier ich halt jede sec einige daten ... was auch schlecht ist

Ich habe eher den Verdacht dass du durch das ständige Display schreiben zu sonst nichts mehr kommst. Auch wenn das Display die Daten puffert und etwas Arbeit abnimmt. Kenne mich aber mit dem Gameduino jedoch nicht aus.

Ständig auf das Display zu schreiben bringt so oder so nichts. So schnell kannst du gar nicht zusehen.

Serenifly:
Ok, dann ist es nicht so schlimm :slight_smile:

auch nur jede sec zu schreiben bringt bei einem permanenten serial-stream ja nix, dann verlier ich halt jede sec einige daten ... was auch schlecht ist

Ich habe eher den Verdacht dass du durch das ständige Display schreiben zu sonst nichts mehr kommst. Auch wenn das Display die Daten puffert und etwas Arbeit abnimmt. Kenne mich aber mit dem Gameduino jedoch nicht aus.

Ständig auf das Display zu schreiben bringt so oder so nichts. So schnell kannst du gar nicht zusehen.

ja, ich bekomme aller 100ms einen neuen datensatz via SIN, die daten sollten auch aufs display, da werden halt zeiger in gauges
bewegt und sollen nicht springen oder ruckeln ... ich könnte also aller 100ms oder 200ms oder was auch immer zeichnen,
was aber das problem nicht behebt das ich dabei daten verliere ...

der gameduino2 ist ürigends so schnell, das du bei GD.cmd_number(240, 136, 30, 10|OPT_CENTER, millis()); unter 10ms bist,
da siehst du die einerstelle durch rauschen ...

Daten verlierst du wenn du den seriellen Eingangspuffer nicht schnell genug leerst. Der hat wie gesagt 64 Bytes. Wenn er dann voll ist weil du zu lange andere Sachen machst als den Puffer per read() auszulesen überschreibt er alte Daten.

Dem Controller also Zeit zu lassen den Puffer auszulesen sollte theoretisch das Problem beheben oder verbessern. Wenn es daran liegt....

Die Baudrate etwas runter zusetzen wäre hier vielleicht auch keine schlechte Idee. Dann hast du mehr Zeit bis der Puffer voll ist.

In der IDE 1.5.7 BETA kann man den Puffer auch per Hand vergrößern:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino\HardwareSerial.h

hab ich schon :roll_eyes: und hilft nix ...

$> grep RX_BUFFER_SIZE hardware/teensy/cores/teensy/HardwareSerial.cpp
//#define RX_BUFFER_SIZE 64
#define RX_BUFFER_SIZE 255

ok, das display macht updates mit 60 herz, das reicht aber natürlich nicht um alle
seriellen daten zu erwischen, also muss man in einem loop immer alle verfügbaren daten
lesen, dann passt es ... wenn nicht noch ein sensor den loop aufhält :grin:

aus
if ( SIN.available() ) {
int inByte = SIN.read();

wird also richtiger weise
while ( SIN.available() ) {
int inByte = SIN.read();

danke für die anregungen ...