PIC24FJ64GB002 UART-Brücke

Ich arbeite in einem Projekt, aber ich habe ein Problem.

Ich möchte ein Programm erstellen, das die beiden UART in einem PIC antreibt, wobei jeder UART eine andere Baudrate hat. Die Idee ist, ein Signal für UART1 (9600 Baud) zu nehmen und an den UART 2-Ausgang (1200 Baud) zu senden. Im Moment mache ich einen Code, um die beiden UART zu fahren.

Ich hänge den Code an, und dieser hat Kommentare im Echotest, und die uarts laufen ok, wenn ich Daten in uart 2 einfüge, sind diese Daten in der Ausgabe an UART 1 in Ordnung, aber wenn ich Daten in UART 1 einfügen möchte, Um diese Daten in der Ausgabe von UART 2 zu sehen, habe ich viele Daten durch unterschiedliche Baudraten verloren. Ich hoffe, machen Sie mich verständlich, mein Problem ist der Datenverlust von hoher Baudrate zu niedriger Baudrate, ich erwarte Ihre Meinung darüber, wie dies gelöst werden kann.

#if defined (__PIC24F__)
#include <p24FJ64GB002.h>
#endif
#include "xc.h"

_CONFIG4(DSBOREN_OFF & DSWDTEN_OFF)
_CONFIG3(WPDIS_WPDIS)
_CONFIG2(POSCMOD_NONE & OSCIOFNC_OFF & FNOSC_FRC & PLL96MHZ_OFF )
_CONFIG1(FWDTEN_OFF & JTAGEN_OFF)

 int c,D;


int main(void){


    //OSCILLATOR CONFIG
    OSCCON=0X0000;          //
    CLKDIVbits.RCDIV0=0; //clock divider to 0

    //PIN CONFIG

    AD1PCFGL=0XFFFF;            //ALL PINS DIGITAL
    TRISA = 0X0000;                  //PORT A OUTPUT
    TRISB = 0XFFFF;                  //PORT B INPUT

    RPOR2bits.RP5R=3;           // RP5  TX UART1
    RPOR3bits.RP6R=5;           // RP6  TX UART2

    RPINR18bits.U1RXR=0;        //RP0  RX UART1
    RPINR19bits.U2RXR=2;        //RP1  RX UART2

    //----------------------------------------------------------------------------

    //UART CONFIG

    U1BRG=103;
    U2BRG=832;

    U1MODEbits.UARTEN = 1; // UART Enable
    U1MODEbits.USIDL = 1;// Stop in Idle Mode Bit
    U1MODEbits.IREN = 0; // IrDA Encoder and Decoder Disabled
    U1MODEbits.RTSMD = 1; // UxRTS in SIMPLEX mode
    U1MODEbits.UEN = 00; // Tx and Rx pins are used,UxCTS,UxRTS, BCLK are controlled by port latch
    U1MODEbits.WAKE = 0; // Wake up disabled on sleep mode
    U1MODEbits.LPBACK = 0; // Loopback is disabled
    U1MODEbits.ABAUD = 0; // Baud rate measurement is disabled
    U1MODEbits.RXINV = 0; // Idle state is '1'
    U1MODEbits.BRGH =1; // High baurdate selected
    U1MODEbits.PDSEL = 00 ; // No parity, 8bits
    U1MODEbits.STSEL = 0; // 1 Stop bit

    U2MODEbits.UARTEN = 1; // UART Enable
    U2MODEbits.USIDL = 1;// Stop in Idle Mode Bit
    U2MODEbits.IREN = 0; // IrDA Encoder and Decoder Disabled
    U2MODEbits.RTSMD = 1; // UxRTS in SIMPLEX mode
    U2MODEbits.UEN = 00; // Tx and Rx pins are used,UxCTS,UxRTS, BCLK are controlled by port latch
    U2MODEbits.WAKE = 0; // Wake up disabled on sleep mode
    U2MODEbits.LPBACK = 0; // Loopback is disabled
    U2MODEbits.ABAUD = 0; // Baud rate measurement is disabled
    U2MODEbits.RXINV = 0; // Idle state is '1'
    U2MODEbits.BRGH =1; // High baurdate selected
    U2MODEbits.PDSEL = 00; // No parity, 8bits
    U2MODEbits.STSEL = 0; // 1 Stop bit

 //------------------------------------------------------------------

    //CONFIGURACION DE TRANSMISION, RECEPCION E INTERRUPCIONES DE LAS UART

    U1STAbits.UTXINV = 0; // UxTX idle state is '0'
    U1STAbits.UTXBRK = 0; // Sync Break Disabled
    U1STAbits.UTXEN = 1; // UART1 Transmitter  is enabled
    U1STAbits.URXISEL = 00; // Interrupt flag bit is set when a charater is received
    IEC0bits.U1TXIE = 0; // Disable UART1 Tx interrupt

    U2STAbits.UTXINV = 0; // UxTX idle state is '0'
    U2STAbits.UTXBRK = 0; // Sync Break Disabled
    U2STAbits.UTXEN = 1; // UART2 Transmitter  is enabled
    U2STAbits.URXISEL = 00; // Interrupt flag bit is set when a charater is received
    IEC1bits.U2TXIE=0;      // Disable UART2 Tx interrupt

         while(1){
//         //ECHO TEST UART 2 1200 BAUDS
//         //wait for byte
//         while(!U2STAbits.URXDA);
//         c=U2RXREG;//get byte
//         //wait for empty spot in transmit buffer
//         while(U2STAbits.UTXBF == 1);
//         //echo received character back
//         U2TXREG = c;


////         //ECHO TEST UART 1 9600 BAUDS
//         //wait for byte
//         while(!U1STAbits.URXDA);
//         D=U1RXREG;//get byte
//         //wait for empty spot in transmit buffer
//         while(U1STAbits.UTXBF == 1);
//         //echo received character back
//         U1TXREG = D;

//TEST TO PUT UT DATA FROM UART 2 1200 IN OUTPUT UART1 9600, ITS PART IS OK

         while(!U2STAbits.URXDA);
         D=U2RXREG;//get byte
         //wait for empty spot in transmit buffer
         while(U2STAbits.UTXBF == 1);
         //echo received character back
         U1TXREG = D;

         }

    return 0;
}

Antworten (2)

Soweit ich weiß, fragen Sie - Sie haben 2 UARTs mit unterschiedlichen Geschwindigkeiten. Sie senden Daten in den schnellen UART und er sendet sie für Sie durch den langsamen UART, und das Problem, das Sie haben, ist, dass Sie Daten verlieren, da sie nicht schnell genug gesendet werden?

OK. Die Antwort ist die Verwendung eines Systems namens "Store and Forward". Dies wird seit vielen Jahren in 10/100-Ethernet-Hubs verwendet, wo eingehende Daten zehnmal schneller sein können als ausgehende Daten.

Im Grunde geht es darum, dass Sie einen großen (normalerweise kreisförmigen) Puffer haben, der vom schnellen UART gefüllt wird und aus dem langsamen UART herausrieselt.

Es funktioniert nur wirklich, wenn Sie eine "Burst" -Form von Daten haben - dh Sie senden nicht die ganze Zeit Daten, sondern Pakete von Chunks mit Verzögerungen dazwischen. Dadurch kann der langsame UART aufholen und Platz im Ringpuffer für mehr Daten schaffen.

In einem perfekten System würden Sie dem schnellen Sender per Handshaking mitteilen, dass er für eine Weile aufhören soll zu senden. Am besten ist Hardware-Handshaking, bei dem eine IO-Leitung verwendet wird, um dem Sender zu signalisieren, dass es sich um "Clear To Send"-Daten (CTS) handelt. Einige Chips (PIC32) haben diese Funktionalität mit dedizierten CTS / RTS-Pins eingebaut, aber es ist einfach genug, sie auf denen zu emulieren, die dies nicht tun.

Eine andere Alternative ist die Verwendung von Software-Handshaking, auch bekannt als XON/XOFF, bei dem der PIC24 ein XOFF-Zeichen sendet, wenn sein Puffer fast voll ist, und ein XON-Zeichen, wenn er wieder leer wird. Diese Niveaus sind als "High Water Mark" bzw. "Low Water Mark" bekannt, da das gesamte System als ein Tank angesehen werden kann, der durch ein Rohr mit großer Bohrung und ein kleines Loch im Boden gefüllt wird, aus dem Wasser heraustropft. Ein Ventil würde das Wasser bei der „Hochwassermarke“ absperren und bei der „Niedrigwassermarke“ wieder fließen lassen.

Beachten Sie, dass die obere Grenze nicht mit einem vollen Puffer identisch ist, sondern nur „fast“ voll, da das Software-Handshaking nicht perfekt ist und einige Daten nach dem Senden von XOF aufgrund von Puffern zwischen der Software des Senders und noch eingehen können die Hardware des Empfängers.

Während Sie auf eine leere Stelle im Sendepuffer für den langsamen UART warten, lassen Sie wahrscheinlich den Empfangspuffer des schnelleren UART überlaufen, indem Sie diese Bytes nicht schnell genug verarbeiten. Ein typischer softwarebasierter Weg, dies zu tun, besteht darin, einen eigenen Puffer in Ihrer Software zu erstellen und darin zu lesen / daraus zu schreiben, ohne das Warten auf die RX/TX-Verfügbarkeit zu blockieren (andere Lösungen sind Handshaking, wie in Majenkos Antwort beschrieben ) .

Ein Ringpuffer ist im Allgemeinen eine einfach zu implementierende Lösung. So etwas wie Pseudo-Code:

unsigned char buffer[128];
int rxposition = 0, txposition = 0;

while (1) {

    /* If RX data, read it into our buffer. Otherwise do not wait. */
    if (U2STAbits.URXDA) {
        buffer[rxposition++] = U2RXREG;
        rxposition &= 127; /* Optimization of: rxposition %= sizeof(buffer); for size 128 */
    }

    /* If TX available and we have data to write, write it. Otherwise do not wait. */
    if (!U2STAbits.UTXBF && rxposition != txposition) {
        U1TXREG = buffer[txposition++];
        txposition &= 127; /* Optimization of: txposition %= sizeof(buffer); for size 128 */
    }

}

Das obige Snippet enthält keinen Schutz vor Überläufen des Eingangspuffers und dient der Veranschaulichung (Sie werden den Eingangspuffer sicherlich überlaufen lassen, wenn Sie kontinuierlich Daten zum schnellen UART streamen; Ihre durchschnittliche Datenrate zum schnellen UART muss immer noch <= sein langsam Baudrate, um Ihre Aufgabe zu ermöglichen) - obwohl es erwähnenswert ist, dass Sie möglicherweise keinen zusätzlichen Schutz benötigen, wenn das Verwerfen beliebiger sizeof(buffer)Byteblöcke bei einem Überlauf ein akzeptables Verhalten ist. Eine Potenz von 2 Puffergröße wurde nur gewählt, um die Modulo-Operation zu optimieren, aber alles ist möglich, solange Ihr Puffer groß genug ist, um Ihre Situation zu bewältigen.

Danke Jason, ich fahre fort, diese Option zu implementieren, bevor ich mehr über "Speichern und Weiterleiten" erfahre.