Schwebende UART-Spannung auf benutzerdefinierter Leiterplatte?

Ich teste mein allererstes PCB-Design, das auf einem ATMega328 basiert, und bin beim UART auf ein unerwünschtes Verhalten gestoßen:

Wenn ich den UART über ein FTDI-USB-Kabel an meinen Computer angeschlossen habe, funktioniert er einwandfrei, aber wenn ich das Kabel von der Platine trenne, kann ich Eingaben auf die Rx-Leitung der Platine senden, indem ich einfach sowohl Rx als auch Masse mit einer Fingerspitze berühre gleiche Zeit.

Ich hatte tatsächlich schon früher ein Problem mit Fingern, die schlechte Eingaben verursachten, und die Antwort darauf war, dass ich schwebende Spannungen hatte.

Natürlich würden die Rx/Tx-Leitungen, wenn sie mit nichts verbunden sind, auch schwimmen, was meiner Meinung nach das gleiche Problem hier verursacht.

Ich brauche das wirklich, um zuverlässig zu sein - insbesondere möchte ich, dass der UART keine Eingaben enthält, wenn keine Eingaben gesendet werden.

Dann zwei Fragen:

  1. Was könnte dies verursachen?

  2. Was soll ich tun, um es zu beheben? Pull-up auf der Rx-Leitung?

Weitere Informationen: So habe ich getestet.

#include <avr/io.h>

#define USART_BAUDRATE 9600
#define F_CPU 16000000UL
#define UBRR_VALUE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

#define pin (PC3)

void initUART(void)
{
    // Set baud rate
    UBRR0H = (uint8_t)(UBRR_VALUE >> 8);
    UBRR0L = (uint8_t)UBRR_VALUE;
    // Set frame format to 8 data bits, no parity, 1 stop bit
    UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);
    //enable transmission and reception
    UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
}
void sendUARTByte(uint8_t data)
{
    // Wait for byte to be transmitted
    while (!(UCSR0A & (1<<UDRE0))) { }
    // Transmit data
    UDR0 = data;
}
uint8_t receiveUARTByte()
{
    // Wait for byte to be received
    while (!(UCSR0A & (1<<RXC0))) { }
    // Receive data
    return UDR0;
}
int main(void)
{
    uint8_t input = '!';

    DDRC = _BV(pin);
    PORTC = 0;

    initUART();
    while(1)
    {
        PORTC |= _BV(pin);
        sendUARTByte(input);
        input = receiveUARTByte();

        PORTC &= ~_BV(pin);
        sendUARTByte(input);
        input = receiveUARTByte();
    }
}

Im Wesentlichen wird nur umgeschaltet PC3(= pin), wenn eine Eingabe auf dem UART vorhanden ist, und die Eingabe einfach wieder auf die Ausgabe gespiegelt.

Es funktioniert einwandfrei, wenn es an meinen Computer angeschlossen ist, aber wenn ich dann die Rx-Leitung abtrenne und die Erdungsleitung auf ein anderes Pad verschiebe (damit ich die Rx- und Erdungsstifte gleichzeitig berühren kann), wird der Stift immer noch umgeschaltet bei einer hohen Frequenz, aber ich bekomme keine Ausgabe zurück zum Computer (obwohl die Tx- und Masseleitungen noch verbunden sind).

Hier ist auch der relevante Teil des Schaltplans:PCB-Schema

Der UART befindet sich in der Mitte links.

Antworten (2)

Es ist ziemlich üblich, zumindest den internen Pullup zu aktivieren und vielleicht einen stärkeren externen bereitzustellen. Schwebende Eingänge verursachen nicht nur falsche Signale; Ein Eingang in der Nähe der Übergangsspannung des Logikpegels kann dazu führen, dass ein Chip übermäßig viel Strom verbraucht, da sowohl der obere als auch der untere FET teilweise eingeschaltet werden können, was einen Leitpfad von der Versorgung zur Masse verursacht.

Auf einem ATmega können Sie beispielsweise den internen Pullup des primären seriellen Empfangspins wie folgt einstellen.

/* Idea copied from arduino bootloader - Enable internal pull-up 
resistor on pin D0 (RX), in order to supress line noise */
  DDRD &= ~_BV(PIND0);
  PORTD |= _BV(PIND0);
Wenn Sie wissen, wie es geht, könnten Sie Code bereitstellen, der den internen Pullup festlegt? Ich schaue durch das Datenblatt und bin mir nicht ganz sicher, wie es geht. (Ist es in Ordnung, wenn ich den Rx-Pin irgendwie manuell als Eingang im Code festlege, zusätzlich dazu, dass ich dem UART-Modul nur sage, dass es sich darum kümmern soll?)
Wenn Sie den UART-Code des Arduino-Kerns finden, glaube ich, dass dies der Fall ist. Wenn ich mich richtig erinnere, schreiben Sie bei einem AVR, um den Pullup auf einen Eingang einzustellen, das Ausgangsdatenregister für dieses Bit auf eine 1 und setzen es zusätzlich als Eingang im Datenrichtungsregister.
Oh warte, ich habe nur ein Datenelement verpasst – Rx ist der PD0-Pin! Ja, ich sollte nur in der Lage sein, PORTD = 1 und DDRD = 0 zu setzen (natürlich für Bit 0).
Super, es funktioniert!! Ich habe diese beiden Codezeilen tatsächlich nur eine Sekunde, bevor Sie Ihren Beitrag bearbeitet haben, herausgefunden, aber ich bin froh, dass ich sie damit noch einmal überprüfen konnte. Danke!

Ich hatte das gleiche Problem, als ich meine ATmega64-Leiterplatte individuell gestaltete.

Es funktionierte gut, wenn TX/RX über ein FTDI-USB-Kabel mit dem Computer verbunden war, und wenn ich FTDI vom Computer oder von der ATmega64-Platine trenne, schalteten die Controller-Ausgangspins ohne Eingabe um.

  1. Lösung: Ich hatte LM317 an Bord auf 3,7 V eingestellt. Ich habe TX/RX damit verbunden und das Problem war gelöst.

  2. Lösung: Ich habe eine zweite Platine mit stärkerer Masse und 3,7-V-Ebene entworfen, und TX/RX zeigte damals kein Problem. So können Sie die GND- und VCC - Ebene beim PCB-Design verbessern.