Ich habe wirklich Probleme mit einer UART-Kommunikation mit meinem PIC32MX110F016 . Es ist das erste Mal, dass ich versuche, eine UART-Kommunikation mit der PIC32MX-Familie zu implementieren, aber ich finde es schwierig und ich weiß nicht, warum es nicht richtig funktioniert. Also habe ich beschlossen, meinen gesamten Code in Form eines Tutorials (Schritt für Schritt) zu veröffentlichen, um etwas Hilfe von euch zu bekommen. Ich hoffe, es hilft in Zukunft anderen Menschen, die mit dem gleichen Problem konfrontiert sind.
Also habe ich zuerst die Bibliotheken importiert und diese Mikrocontroller-Konfigurationen deklariert:
#pragma config FNOSC = FRCPLL
#pragma config FPLLIDIV = DIV_2
#pragma config FPLLMUL = MUL_20
#pragma config FPLLODIV = DIV_2
#pragma config FPBDIV = DIV_1
#pragma config ICESEL = ICS_PGx2
#pragma config WDTPS = PS16384
#define GetSystemClock() (40000000ul)
#define GetPeripheralClock() (GetSystemClock())
#define BaudRate 115200
Dann habe ich meine Funktion uartconfig() implementiert:
void uartconfig(void){
PPSUnLock; // Allow PIN Mapping for BLE
PPSOutput(1, RPA0, U1TX); // MAP Tx to RA0 set to digital out
PPSInput (3, U1RX, RPA2); // MAP Rx to RA2 set to digital in
PPSOutput(4, RPA3, U1RTS);
PPSInput (2, U1CTS,RPA1);
PPSLock; // Prevent Accidental Mapping
#define UART1TX TRISAbits.TRISA0
#define UART1RX TRISAbits.TRISA2
#define CMD TRISBbits.TRISB5
UART1TX = 0;//output
UART1RX = 1;//input
DDPCONbits.JTAGEN = 0;
UARTConfigure(UART1, UART_ENABLE_PINS_CTS_RTS);
UARTSetFifoMode(UART1, UART_INTERRUPT_ON_TX_NOT_FULL | UART_INTERRUPT_ON_RX_NOT_EMPTY);
UARTSetLineControl(UART1, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1);
UARTSetDataRate(UART1, GetPeripheralClock(), BaudRate);
UARTEnable(UART1, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));
INTEnable(INT_SOURCE_UART_RX(UART1), INT_ENABLED);
INTSetVectorPriority(INT_VECTOR_UART(UART1), INT_PRIORITY_LEVEL_2);
INTSetVectorSubPriority(INT_VECTOR_UART(UART1), INT_SUB_PRIORITY_LEVEL_0);
// configure for multi-vectored mode
INTConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR);
INTEnableInterrupts();
}
command_print
Dann habe ich mich entschieden, eine Funktion zum Senden von Daten über UART zu erstellen :
void command_print(char *buffer){
while(*buffer != (char)0)
{
while(!UARTTransmitterIsReady(UART1));
UARTSendDataByte(UART1, *buffer++);
}
UARTSendDataByte(UART1, '\r');
while(!UARTTransmissionHasCompleted(UART1));
}
Ich habe mich entschieden, eine Struktur zu erstellen, um einen Puffer für den TX/RX-Pin zu erstellen (ab jetzt verwende ich nur noch den inputBuffer
):
typedef volatile struct UARTBuffer {
char outputBuffer[ UART_INPUT_BUFFER_SIZE ];
char inputBuffer[ UART_OUTPUT_BUFFER_SIZE ];
unsigned short int inputReaderPos;
unsigned short int inputWriterPos;
unsigned short int outputReaderPos;
unsigned short int outputWriterPos;
} UARTBuffer;
UARTBuffer UARTBuffer1;
In meiner Interrupt-Service-Routine ISR
habe ich beschlossen, den Teil zu ignorieren U1TX
und das Flag immer zu löschen. Für die U1RX
definierte ich die als:
void __ISR(_UART_1_VECTOR, ipl2)UART1HANDLER(void){
char c;
if ( INTGetFlag(INT_U1TX) )
{
INTClearFlag(INT_SOURCE_UART_TX(UART1));
}
if ( INTGetFlag(INT_U1RX) )
{
if( (U1STAbits.OERR == 1) || (U1STAbits.PERR == 1) || (U1STAbits.FERR == 1) ){
// Ignore
U1STAbits.OERR = 0;//clears if the Receive buffer has overflowed
U1STAbits.PERR = 0;//parity error
U1STAbits.FERR = 0;//framing error
U1RXREG;
}
else {
// Check if the buffer is all readed. If so, clear the buffer;
if( UARTBuffer1.inputWriterPos == UARTBuffer1.inputReaderPos ) {
UARTBuffer1.inputWriterPos = 0;
UARTBuffer1.inputReaderPos = 0;
}
if (UARTBuffer1.inputWriterPos >= UART_INPUT_BUFFER_SIZE){
// Buffer overflow
UARTBuffer1.inputWriterPos = 0;
UARTBuffer1.inputReaderPos = 0;
}
c = U1RXREG;
UARTBuffer1.inputBuffer[ UARTBuffer1.inputWriterPos++ ] = c;
}
INTClearFlag(INT_SOURCE_UART_RX(UART1));
}
}
Schließlich main(void)
ist my definiert als:
int32_t main(void) {
__asm__("EI");
UARTBuffer1.inputWriterPos = 0;
SYSTEMConfig(GetSystemClock(), SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
INTEnableSystemMultiVectoredInt(); //enable interrupts
uartconfig();
command_print("SF,1");
while (1);
}
Eigentlich läuft mein PIC normal und mein Interrupt wird ausgelöst. Was ich nicht verstehen kann, ist der Grund, warum mein Code nie mehr als ein Zeichen im RXReg
Teil (nämlich U1RXREG
) innerhalb der ISR erhält. Ich lösche die Flagge am Ende der ISR und ich denke, dass alles gut konfiguriert ist. Lassen Sie mich wissen, was ich tun soll, um meinen Rahmen richtig zu bekommen und nicht nur das erste Zeichen. Ich weiß, dass der UART gut gestaltet ist, und wenn ich versuche, einen anderen Befehl zu senden, als "SF,1"
das RX-Register mir ein anderes Zeichen gibt.
EDIT: Ich erreiche nicht, was ich will. Ich verliere Zeichen im Interrupt, also verbinde ich das CTS
+ RTS
, aber leider bekomme ich keine besseren Ergebnisse. Kann mir jemand bei der CTS
+ RTS
Konfiguration für die PIC32mx-Familie helfen? Ich weiß, dass ich den CTS mit dem RTS und den RTS mit dem CTS vom Mikrocontroller zur "anderen" Komponente kreuzen muss. Mein Problem hängt eher mit den Funktionen/Konfigurationen zusammen, die ich tun muss.
Bei einer Baudrate von 115200 ohne Parität und 1 Start- und Stoppbit (insgesamt 10 Bits) dauert es 86 Mikrosekunden, bis Daten vom anderen Ende in Ihrem RX-Puffer ankommen.
Wenn ich mir Ihre ISR ansehe, sehe ich, dass Sie viele Anweisungen in Ihrer ISR verarbeiten.
Das Szenario, das passieren könnte, ist folgendes: Ihr erster Charakter kommt an (dh "A"),
Interrupt wird ausgelöst,
es ist kein Fehler aufgetreten (Überlauf, Parität usw.),
jetzt kommen auch die restlichen Zeichen ("OK\r\n"),
Überlaufflag wird gesetzt,
Sie löschen den RX-Interrupt (aber Sie geben ISR nicht erneut ein, da keine weiteren Zeichen empfangen werden).
Debug-Lösungen: 1. Verwenden Sie die Flusssteuerungsmethode (ACK für jedes Byte)
3.Vermeiden Sie Funktionsaufrufe in der ISR.
4. Sie können den Interrupt für Überlauffehler aktivieren, sodass Sie nicht explizit eine Routine für den Interrupt schreiben müssen. Wenn ein Überlauffehler auftritt, überprüfen Sie einfach den Status des Interrupt-Flags und löschen Sie das Flag und verwerfen Sie die Rx-Daten. Dies hilft Ihnen, die Verarbeitung solcher Fehler in der ISR zu reduzieren, da sie in der Hauptschleife selbst überprüft werden können. Kopieren Sie einfach die empfangenen Daten in einen Puffer und erhöhen Sie einen Zähler. Das könnte helfen.
Pufffisch
Tauchen
brhans
Tauchen
justieren
Tauchen
U1RXREG
.pjc50
Tauchen