Warum muss ich einen Moment warten, bevor ich serielle Daten an meinen AVR sende?

Ich habe einen AVR (ATMega644), der über eine serielle Verbindung mit einem Raspberry PI verbunden ist. Der AVR wird mit 5 V versorgt und die AVR => RPI Tx-Leitung verwendet einen 1k8/3k3-Spannungsteiler, um einen 3v3-Pegel zu erhalten.

Wenn die 10ms Wartezeit (XXX im Code) nicht vorhanden ist (laut Datenblatt muss ich gar nicht warten) erhalte ich diesen Unsinn (python repr() der empfangenen Daten):

 '\x00\xaa\x8a\x8a\xea\n'
 '\xe9\xf5%\xc5E\xd5\xa4\xfcBYE WORLD\r\n'

Wenn die Verzögerung von 10 ms da ist, erhalte ich Folgendes:

'\x00HELLO WORLD\r\n'
'BYE WORLD\r\n'

Das ist ziemlich gut. \0Ich würde jedoch gerne wissen, warum vor dem allerersten eigentlichen Datenbyte ( ) ein steht 'H'. Ich schicke niemals eine mit Sicherheit!

Meine Hauptfrage ist jedoch, warum die Verzögerung zwischen dem Initialisieren und dem Senden von Daten notwendig ist.

Hinweise: Mein F_CPU-Wert ist korrekt, ebenso die Fuses. Ich habe auch versucht, eine niedrigere Baudrate (4800) und einen anderen Chip zu verwenden.

Dies ist der Code, den ich verwende:

#include <avr/interrupt.h>
#include <util/delay.h>
#include <util/setbaud.h>


inline void uart_putc(char c)
{
    loop_until_bit_is_set(UCSR0A, UDRE0);
    UDR0 = c;
}


inline void uart_puts(const char *s)
{
    while (*s) {
        uart_putc(*s++);
    }
}


int main()
{
    // we don't need/use any interrupts
    cli();

    // -DF_CPU=18432000L -DBAUD=19200 used when compiling
    UBRR0H = UBRRH_VALUE;
    UBRR0L = UBRRL_VALUE;
    // 8 data bits
    UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01);
    // enable transmitter
    UCSR0B |= (1 << TXEN0);

    _delay_ms(10);  // XXX
    uart_puts("HELLO WORLD\r\n");
    _delay_ms(250);
    uart_puts("BYE WORLD\r\n");

    // do nothing
    while (1)
        ;

    return 0;
}
Klingt so, als ob sich die Ausgangspins in einem instabilen Zustand befinden, bevor der UART aktiviert wird. Versuchen Sie, sie vor dem Aktivieren in einen bekannten guten Zustand zu versetzen, z. B. Ausgang hoch.
Ich habe Output+Low und Input+Pullup ausprobiert - kein Unterschied. Die Verwendung von 330/180-Ohm-Widerständen, wie jemand im IRC vorgeschlagen hat, hat ebenfalls nichts geändert.
Update, es passiert nur, wenn das empfangende Ende mein Pi ist. Mit einer einfachen USB2Serial-Schnittstelle brauche ich die Verzögerung nicht - selbst wenn ich die Widerstände halte, um auf 3v3 herunterzukommen.
Leeren Sie den Eingangspuffer von RPi, bevor Sie beginnen. Es ist immer eine gute Idee, eine Art Handshake zu haben, bevor Sie mit dem Senden von Daten beginnen. Ich persönlich bevorzuge die Verwendung vordefinierter Datenrahmen.
Möglicherweise können Sie die Synchronisationsgeschwindigkeit verbessern, indem Sie (mehr) Stoppbits verwenden.

Antworten (2)

Im Grunde das, was Sie tun

// enable transmitter
UCSR0B |= (1 << TXEN0);

_delay_ms(10);  // XXX

fügt 10 ms Stoppbits ein ( 1). Dies hilft Ihrem Empfänger, sich mit dem Datenstrom (der praktischerweise mit einem Startbit beginnt 0) zu synchronisieren. Bis dahin ist der AVR-Pin hochohmig und füllt Ihren Eingangspuffer mit Müll, auf den Ihr Empfänger zu synchronisieren versucht.

Jedes Mal, wenn der Empfänger 10 Bits liest, die in den Rahmen passen (Startbit 0, 8 Datenbits, Stoppbit 1), werden die Datenbits in den Eingangspuffer geschoben. Nur wenn der Rahmen nicht übereinstimmt, werden Bits verworfen, bis eine passende 10-Bit-Zeichenfolge gefunden wird.

Dies erklärt auch die Bedeutung der Verwendung von Start- und Stoppbits bei der asynchronen Übertragung. Dies erklärt auch, warum die Verwendung von 1,5 oder 2 Stoppbits die Synchronisationsgeschwindigkeit verbessert; die Wahrscheinlichkeit, dass empfangene Daten versehentlich in den Rahmen für ein einzelnes Byte passen, nahm ab.

Ich bin mir Ihrer spezifischen Hardware oder der Art und Weise, wie Ihre Software mit Ausnahmen umgeht, nicht bewusst, aber wenn Ihre Schaltung von einem undefinierten in einen definierten Zustand übergeht, müssen Sie dem System Zeit geben, mit den Zuständen umzugehen, die als Signale an der Grenze ankommen scheinen gültig zu sein, wenn sie sich beruhigen, sind es aber nicht. Die Verwendung einer USB2serial-Schnittstelle stellt wahrscheinlich sicher, dass der Konverterausgang immer in einen legalen Zustand versetzt wird, wenn illegale Eingaben empfangen werden, sodass es keine "Weckzeit" gibt - siehe unten. .

Länger: Wenn Ihre serielle Leitung aktiv, im Leerlauf ist und wie definiert arbeitet, befindet sie sich in einem definierten Zustand - hoch für ein System mit positiver Logik und niedrig für ein System mit negativer Logik. Systeme, die mit TTL (nominell 0/+5 V) oder Systemspannungspegeln (0/3 oder 0/3,3 oder 0/5 oder was auch immer) verbunden sind, sind normalerweise positive Logik. RS232 kehrt diese Logik um und ein Ruhezustand ist normalerweise niedrig. Wenn Sie mit TTL-Pegeln verbinden, ist der Pegel der Pegel - senden Sie 3V3 und Sie sehen 3V3 usw. Wenn Sie den Sender zu hoher Impedanz wechseln, wenn er deaktiviert ist, muss der Empfänger "entscheiden", was er mit dem Eingang tun soll. Es ist üblich, den Eingang mit einem Widerstand oder Äquivalent auf +V hochzuziehen, der groß genug ist (dh eine Last hat, die niedrig genug ist), dass er keine Auswirkung auf den normalen Betrieb hat. Unter gesperrten Bedingungen setzt es den Eingang auf "idle". Wenn Sie serielle USB-zu-RS@32- oder USB-zu-Logik-Level-Schnittstellen verwenden, kümmern sie sich normalerweise um solche Feinheiten. Wenn Sie sich direkt verbinden, müssen SIE entscheiden, was während des deaktivierten Zustands passiert, und wenn Sie dies nicht tun, wird Murphy es tun.

Wenn Ihre Software semi-Murphy-sicher ist und Sie ein langes niedriges Signal (illegal) empfangen, kann die Software es ablehnen. Weniger MP (Murphy Proof)-Software kann stattdessen geblödeln.

Wenn Sie von illegaler zu legaler Eingabe wechseln (z. B. nach einer Datensendeaktivierung), können die Pegel als Signal erscheinen, wenn sich die Schaltung stabilisiert.

Wenn Ihre Schaltung Zeitkonstanten mit Kondensatoren hat, die sich während des Betriebs auf einen geeigneten DC-Pegel aufladen, liegen sie möglicherweise auf Masse, wenn Sie zum ersten Mal Daten empfangen. Da sie auf den korrekten Wert aufgeladen werden, kann eine 1 oder 0 dazu neigen, falsch interpretiert zu werden. Normalerweise wird die Vorspannung in die eine oder andere Richtung gehen, so dass zB 1er zu 0 werden können, aber 0er in Ordnung sind. Aber wenn es Läufe von allen 1 oder allen 0 gibt, können diese während der Systemstabilisierung stärker von den Ladekondensatoren oder was auch immer beeinflusst werden.

In Ihrem Fall sind die Hexadezimalzahlen
AA 8A 8A EA
= 1010 1010, 1000 1010, 1000 1010, 1110 1010 wahrscheinlich als "ELLO" =
$45 $4C $4C $4F
= 0100 0101, 0100 1100, 0100 1100, 0100 1111 gemeint nicht klar, dass das eine durch falsche Dekodierung des anderen verursacht wird, ABER es ist wahrscheinlich.