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;
}
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.
Gabriel Alzate