serielle Kommunikation - UCSRn Register ?

Hallo,

ich mache mit der non blocking RS485 Lib von Nick Gammon und einem anderen Grundgerüst dazu von volvodani rum.
Funktioniert auch soweit. Das baue ich nun gerade weiter aus.
Umschaltung von senden auf empfangen funktioniert schon. Jetzt soll noch ein Timeout rein.
Jetzt fiel mir beim debuggen was auf.

Wegen Halbduplex Anwendung und umschalten zwischen senden/empfangen soll man die Register Flags auswerten.
UDREn … High, wenn Sende-Register leer
TXCn … High, wenn Transfer komplett

Das wird gemacht mit

while (!(UCSRnA & (1 << UDREn)) );
while (! (UCSRnA & (1 << TXCn)) );

Die Abfrage auf das UDREn schwankt zwischen 100 und 900 µs. Meistens ca. 120µs.
Wodurch kann das sein? Müßte doch ziemlich konstant sein.

Die Abfrage auf das TXCn liegt dagegen konstant bei sagenhaften 3744 µs.
Warum so hoch wenn die Daten innerhalb 1ms aus dem Buffer sind?
Oder wartet TXCn auf die Bestätigung vom Empfänger?

Ich verschicke 5 Byte, die Nick Lib macht daraus 10.

Hallo,

ich denke ich werfe zur Zeit etwas durcheinander. Kann sein das man die Flag Abfrage nur für Software Serial benötigt?
Je mehr ich das Datenblatt und Nicks Beschreibung lese umso durcheinander werde ich allerdings.
Auf der anderen Seite muß aber der Enable Pin zeitlich richtig gesteuert werden vom MAX485.

UDREn wird auch nie “1”, dennoch wird die while übersprungen. Verstehe ich nicht.
6. Bit = TXC
5. Bit = UDRE

void sendMessage(byte ADR) {

  message.adress = ADR;
  digitalWrite (DriverPinDB, HIGH);   // enable sending MAX485

  zeigeFormatiertesByte(UCSR2A);    // 1.
  unsigned long start = micros();
  
  myChannelSend.sendMsg ((byte *) &message, sizeof message); // Send my Message
  
  zeigeFormatiertesByte(UCSR2A);    // 2.
  
  unsigned long ende = micros(); Serial.println(ende-start);
  start = micros();
  
  while (! (UCSR2A & (1 << UDRE2)) );  // Wait for buffer empty
  zeigeFormatiertesByte(UCSR2A);    // 3. 
  
  //UCSR2A |= 1 << TXC2;  // mark transmission not complete  
  zeigeFormatiertesByte(UCSR2A);    // 4.     
  
  while (! (UCSR2A & (1 << TXC2)) );   // Wait for transfer complete
  
  zeigeFormatiertesByte(UCSR2A);    // 5.
  
  unsigned long ende = micros(); Serial.println(ende-start);
  
  digitalWrite (DriverPinDB, LOW);     // disable sending  MAX485
}

// ohne UCSR2A |= 1 << TXC2; // mark transmission not complete

Message send to Device #2
0110.0010 << Ausgangszustand
0000.0010 << nach/beim senden
808µs
0000.0010 << nach warten auf leeren Buffer
0000.0010 << vor warten auf kompletten Transfer
0110.0010 << nach warten auf kompletten Transfer
3948µs


// mit UCSR2A |= 1 << TXC2; // mark transmission not complete, *zeigt keine Wirkung *

Message send to Device #2
0110.0010 << Ausgangszustand
0000.0010 << nach/während senden
808µs
0000.0010 << nach warten auf leeren Buffer
0000.0010 << vor warten auf kompletten Transfer
0110.0010 << nach warten auf kompletten Transfer
3948µs

Hallo,

ich bau das nochmal komplett neu auf. Ihr müßte erstmal nicht antworten. Ggf. komme ich darauf zurück. Oder auch nicht.

hi,

auch wenn Du keine antwort magst... :)

falls es darum geht, daß der write-enable nicht zurückgesetzt wird, bevor alles draußen ist: natürlich mußt Du das auch bei hardware-serial prüfen. dazu gibt es die funktion Serial.flush. schau mal in die serial- (oder gleich stream-library), wie flush dort gelöst ist.

gruß stefan

Hallo Bär aus dem Eis,

kannst ruhig antworten. Wollte nur verhindern das jemand auf den nun alten Sketch eingeht, der nun hinfällig ist. Eben weil ich das Ding jetzt neu schreibe. Ohne jede Compilerwarnung etc. Bis jetzt klappt es. Eine funktionierende Kommunikation hin und her hatte ich gestern schon fertig. Aber mit unverstandener Compilerwarnung. Irgendwas war versaut gewesen. Und Nicks Lib verstehe ich nicht ganz. Der ist auch scheinbar nicht da.

Serial.flush, stimmt gibts auch noch. Macht bestimmt demzufolge das gleiche oder ähnlich. Ich brauchte jetzt nur eine Bestätigung das man das auch für Hardware Serial benötigt. War ganz schön durcheinander vorhin. Data-Overload sozusagen. Danke für die Bestätigung. Das macht einem wieder sicherer. :)

Die MAX485 sind noch nicht da, dauert noch, ich teste derzeit mit zwei Megas.

Du nimmst doch auch RS485? Nutzt du irgendwelche Prüfsummen oder ähnliches? Ich weis nämlich nicht ob Nicks Idee mit dem zusätzlichen senden der invertierten Daten und dann prüfen unbedingt notwendig ist. Die zu sendende Datenmenge wird damit verdoppelt. Ich meine/denke, die Differenzpegel Auswertung mit RS485 macht das doch schon sicher gegen Störungen. Bei reiner RS232 Verbindung würde ich das blind einsehen.

Hallo,

void HardwareSerial::flush()
{
  // If we have never written a byte, no need to flush. This special
  // case is needed since there is no way to force the TXC (transmit
  // complete) bit to 1 during initialization
  if (!_written)
    return;

  while (bit_is_set(*_ucsrb, UDRIE0) || bit_is_clear(*_ucsra, TXC0)) {
    if (bit_is_clear(SREG, SREG_I) && bit_is_set(*_ucsrb, UDRIE0))
    // Interrupts are globally disabled, but the DR empty
    // interrupt should be enabled, so poll the DR empty flag to
    // prevent deadlock
    if (bit_is_set(*_ucsra, UDRE0))
      _tx_udr_empty_irq();
  }
  // If we get here, nothing is queued anymore (DRIE is disabled) and
  // the hardware finished tranmission (TXC is set).
}

hmmm, kann ich nicht ganz lesen, auf alle Fälle fragen sie das TXC Flag ab. Was nicht gemacht wird ist, das TXC vor Prüfung manuell setzen. Das macht Nick und ich weis echt nicht warum er das macht. Ich möchte aber ungern hier über Nick reden, habe schon im anderen Teil an ihn gepostet.