Serial Einleseproblem - manchmal mit falschen Zeichen

Hallo,

mein ATtiny841 sendet erstmal testweise ständig Daten.
Diese möchte ich auf meinem Mega2560 erstmal ordentlich empfangen.

Auf dem Oszi mit RS232 Decodierung paßt alles. Nach jedem Zeichen oder String sehe ich ein LF dazwischen.
Die Daten selbst stimmen auch. Soweit alles i.O.

Aber im IDE seriellen Monitor kommt viel Müll zur Anzeige.
Warum weiß ich nun nicht. Übersehe ich irgendwas?
Oder liegst daran der ATtiny ohne Pause zu schnell sendet?
Nur dann dürften doch "nur" Zeichen bzw. Ziffern fehlen und kein Müll dazu kommen?
Im Grunde darf nur ein U oder 735079 angezeigt werden.
Aber das sieht leider so aus:

735079079
U9
U
RU
73MRU
73MRU
73MRU
7350SRU
735079079
U9
U
U
7RU
7RU
735RU
73507N5079
U9
U
RU
73MRU
73507N5079

Habe die Baudrate vom ATtiny schon von 250k auf 9600 gesenkt. Hilft nicht.

const int SERIAL_BUFFER_SIZE = 33;
char serialBuffer2[SERIAL_BUFFER_SIZE];

void setup()  { 
  Serial.begin(38400);
  Serial2.begin(9600);
}

  
void loop() {           

  if( read_Serial_2() == true )  {
    Serial.println(serialBuffer2);
  }

}   


// ****** Funktionen ******* //
 
bool read_Serial_2()
{
  static byte index;

  if (Serial2.available() > 0)  {   
    char c = Serial2.read();
    if (c >= 32 && index < SERIAL_BUFFER_SIZE - 1)
      {
       serialBuffer2[index++] = c;
      }
      else if ( (c == '\n' || c == '\r') && index > 0) {
        serialBuffer2[index] = '\0';
        index = 0;
        return true;
      }
  }
  return false;
}

und das vom ATtiny841

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdlib.h>

#define F_CPU 8000000UL  // Systemtakt in Hz

/* 
  UART Berechnungen des Wertes für das Baudratenregister aus Taktrate und gewünschter Baudrate
*/
#define BAUD 9600UL    // gewünschte Baudrate
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // sauber runden
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // reale Baudrate
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD)		// Fehler in Promille, 1000 = kein Fehler.
#if ((BAUD_ERROR<995) || (BAUD_ERROR>1005))
  #error Systematischer Fehler der Baudrate greosser 0,5% und damit zu hoch! 
#endif


/* *** Funktion Deklarationen *** */

void UART1_Init();				// Pin 8,9, TxD1/RxD1
void UART1_sendChar(unsigned char data);
void UART1_sendString (const char *string);
void UART1_sendLong(uint32_t zahl);


int main(void)
{  
	UART1_Init();		
	
    while (1) 
    {   
	UART1_sendChar('U');    UART1_sendString("\n");  // Linefeed 
	UART1_sendLong(735079); UART1_sendString("\n");
		
    }
}


/* *** Funktionen *** */

void UART1_Init()
{
	/* Set baud rate */
	UBRR1H = UBRR_VAL >> 8;
	UBRR1L = UBRR_VAL & 0xFF;
	UCSR1B = (1<<RXEN1)|(1<<TXEN1);		// enable receiver and transmitter 
	UCSR1C = (1<<UCSZ11)|(1<<UCSZ10);	// set frame format: 8data, 1stop bit
}


void UART1_sendChar( unsigned char data )
{
	while ( !( UCSR1A & (1<<UDRE1)) )	// wait for empty transmit buffer 
	;
	UDR1 = data;	// Put data into buffer, sends the data
}


void UART1_sendString (const char *string)
{						// Vergleich auf ASCII Zeichen '\0' (NUL)
	while (*string != 0x00) {		// "String-Endezeichen" (Null-Terminator)
		UART1_sendChar(*string);	// vorderstes Zeichen senden
		string++;
	}
}


void UART1_sendLong(uint32_t zahl)
{
	// convert eine long Zahl zu einem String
	char string[33];
	ltoa(zahl, string, 10);        // convert long to string, radix=10
	UART1_sendString(string);	
}

Hallo,

habe eine Kleinigkeit beim ATtiny geändert mit dem Linefeed und
serielle Ausgabe beim Mega zum seriellen Monitor auf 250k erhöht.
Es sieht etwas besser aus. Mal sehen, ich bau mal millis ein im ATtiny.
Eigentlich sieht es wie Übertragungsfehler aus? Komisch bleibt es.

U
735079
URU
735079
U
735079
U
735RU
735079
U
735079
U
735079
U
735RU
735079
U
735079
U
735079
U
735079
U
735079RU
735079
U
735079
U
735079
U
735079
URU
735079

int main(void)
{  
    UART1_Init();		
	
    while (1) 
    {   
	 UART1_sendChar('U');    UART1_sendChar('\n');  // Linefeed 
	 UART1_sendLong(735079); UART1_sendChar('\n'); 	
    }
}

Hallo,

hmmm, lasse ich z.Bsp. aller 100ms senden, dann gibts keine Fehler beim empfangen. Demnach liegt es wirklich am zu schnellen senden. Warum dann aber Zeichensalat rauskommt verstehe ich dennoch nicht. Wäre schön wenn mir das jemand erklären könnte.

Könnte auch hier liegen:

  if( read_Serial_2() == true )  {
    Serial.println(serialBuffer2);
  }

Weil du alles was du empfängst auch wieder sendest und vielleicht das Senden den Empfang stört. Ist aber reine Spekulation.

Hallo,

könnten die sich gegenseitig Interrupt mäßig behindern?
Eingelesen wird auf Serial 2 (50k) und ausgegeben auf Serial 0 (250k).

Würdest du das anders lösen? Die Situation das ich was anzeigen lassen möchte und genau in dem Moment neue Daten reinkommen kann immer mal auftreten. Zudem die UART doch einen 63Byte Buffer hat.

Das Sendeintervall müsste eigentlich nur eine Mindestgröße von 2ms haben, wenn ich richtig rechne.
Bei 50k Baudrate dauert doch ein Byte mit 1 Stopbit 180µs. t = 1 / 50000 * 9
Wenn ich insgesamt mit allen 9 Zeichen (U, ST, 735079) + jeweils LF übertrage, sind das 12 Zeichen, quasi am Stück.
Was rechnerisch 9 * 180µs dauern sollte, was 1,6ms ergibt.

Jetzt ist der UART Buffer mit 12 Zeichen gefüllt und hat in meinem Fall aktuell 500ms Zeit zum auslesen.
Zwischen Arduino und IDE sende ich mit 250k. Im Grunde dürfte selbst senden ohne Pause funktionieren, laut meiner Überlegung.

Senke ich das Sendeintervall auf 100ms, kommen ganz ganz ganz selten wieder falsche Zeichen mit.

Edit:
die UART sendet doch automatisch den Null-Terminator mit bzw. hängt den ran?

Doc_Arduino:
Edit:
die UART sendet doch automatisch den Null-Terminator mit bzw. hängt den ran?

Warum sollte er das tun? Den musst Du setzen.

Gruß Tommy

Ein Frame hat 10 Bytes. Nicht 9. 1 Start Bit. 8 Daten Bits. 1 Stop Bit. Ich dachte aber auch dass die Ausgabe der empfangenen Daten so schnell erfolgt dass das nichts macht.

Wenn es aber hilft nicht ständig zu senden, dann mache das einfach nicht. Das ist bei den aller meisten Anwendungen auch nicht nötig.

die UART sendet doch automatisch den Null-Terminator mit bzw. hängt den ran?

Sowie du das macht nicht. Aber den muss man auch gar nicht senden. Wenn man auf der Empfangsseite einen String einlesen will kann man das wieder per Hand anhängen. Was du du auch tust:

serialBuffer2[index] = '\0';

Natürlich kann man, wenn man möchte, auf Serial alle 256 möglichen Bytes (0x00 .. 0xff) übertragen.

Wenn lesbarer Text übertragen wird, ist ein '\n' als Endekennzeichen aber sinnvoller.
Serial.print() sendet jedenfalls normalerweise kein Null-Byte mit.

Zur Geschwindigkeit: 8N1 sind 10 bit je Zeichen, wie Serenifly beschrieben hat.
Ausserdem ist nie garantiert, dass das Stopbit nicht etwas länger dauert als die übrigen Bits.

Hallo,

okay, dass Startbit hatte ich in der Rechnung vergessen, macht das Kraut jedoch nicht fetter in der Rechnung. :wink:
Aber richtig war der Einwand, muss ja alles korrekt sein, wenn dann.

Den Null-Terminator hatte ich mit dem Stopbit verwechselt. Mit ging es in der Überlegung darum, dass nicht doch bei der Übertragung was fehlt. Aber das Frame ist ja vom Startbit und Stopbit eingerahmt. Alles i.O. Bei all meinen Überlegungen im Problem vertieft verhaue ich manchmal was. Den Null-Terminator gibts ja nur auf der Codeseite. Nicht in der UART selbst. Sorry.

Nach weiteren grübeln fiel es mir ein an was es liegen könnte. Am Takt vom ATtiny. Der taktet mit seinen internen 8MHz. Die ganze Übung ist nur ein Teil vom großen Ganzen, der automatischen Takt-Syncronisierung vom ATtiny auf den "Master". Mir fiel wieder ein, dass der ATtiny unkalibriert mit 5V mit 8,2MHz statt 8MHz taktet, was 2,5% Abweichung sind. Da ich das schon einmal alles ausgemessen hatte, habe ich das OSCCAL0 Register von default 41 auf 36 geändert und nun kann ich ohne Pause senden und habe keine Zeichenfehler mehr. Wie geil ist das denn ... :slight_smile:
Am Ende soll er sich selbst kalibrieren. Ohne meine Vorgabe.

Der Repeat Modus fehlt noch und ich wollte mir erstmal Zwischenwerte übertragen lassen.
Damit begann das Problem. Code abgespeckt und alles rausgewurfen was nicht gebraucht wurde. :o

Nur der Oszi Decoder zeigt nun Müll an. Der kommt scheinbar mit 50k Baud nicht klar obwohl eingestellt. Das Rigol einzustellen ist eh eine kleine Wissenschaft für sich. Ob er überhaupt was decodieren kann hängt auch von horizontalen Zeitbasis ab.
Der Logic Analyzer zeigt alles korrekt an.
Das Übertragungsende ist der serielle IDE Monitor, davon habe ich nun auch noch 750k Zeilen durchsucht, alles korrekt.
Mehr kann ich nicht testen. Jetzt sollte alles passen.

Danke für die tolle Unterstützung.

Hallo,

eine Frage habe ich noch. Die Funktion hier ist doch so i.O., oder?
Habe ich durch viel lesen zusammengebaut. Es sollen Zahl im long Bereich übertragen werden.
Nicht das da noch ein versteckter Fehler drin ist den ich jetzt noch nicht mitbekomme.

void UART1_sendLong(uint32_t zahl)
{
	// convert eine long Zahl zu einem String
	char string[33];
	ltoa(zahl, string, 10);        // convert long to string, radix=10
	UART1_sendString(string);	
}

Mir fiel wieder ein, dass der ATtiny unkalibriert mit 5V mit 8,2MHz statt 8MHz taktet, was 2,5% Abweichung sind

Ist eigentlich offensichtlich wenn mal darauf kommt

eine Frage habe ich noch. Die Funktion hier ist doch so i.O., oder?

Bei unsigned long solltest du aber ultoa() nehmen. Nicht ltoa(). Oder long statt unsigned long bei Parameter wenn du negative Zahlen brauchst

Der Puffer ist etwas größer als er sein müsste.

Hallo,

die Lösung war wirklich nicht einfach, wenn die Gedanken abgelenkt waren.
Seit gestern "bastel" ich daran. Ende gut alles gut.

unsignes long statt long, geht klar Meister.

Puffer 33, haha ja, hatte 32Bits mit 32Byte verwechselt + eins für den Null-Terminator ... :confused:
Okay, das können max. 10 Ziffern sein + Null-Terminator sollten 11 Byte ausreichen. :slight_smile:

Ich mach dann mal morgen weiter ... Danke fürs drüber schauen.