Я действительно борюсь со связью UART с моим PIC32MX110F016 . Это первый раз, когда я пытаюсь реализовать связь UART с семейством PIC32MX, но мне это сложно, и я не знаю, почему это не работает должным образом. Поэтому я решил опубликовать весь свой код в виде учебника (шаг за шагом), чтобы получить помощь от вас, ребята. Я надеюсь, что это поможет в будущем другим людям, столкнувшимся с той же проблемой.
Итак, сначала я импортировал библиотеки и объявил конфиги этого микроконтроллера:
#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
Затем я реализовал свою функцию uartconfig():
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
функцию для отправки данных через UART:
void command_print(char *buffer){
while(*buffer != (char)0)
{
while(!UARTTransmitterIsReady(UART1));
UARTSendDataByte(UART1, *buffer++);
}
UARTSendDataByte(UART1, '\r');
while(!UARTTransmissionHasCompleted(UART1));
}
Я решил создать структуру, чтобы создать буфер для вывода TX/RX (теперь я просто использую 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;
В своей подпрограмме обслуживания прерываний ISR
я решил игнорировать эту U1TX
часть и всегда сбрасывать флаг. Для U1RX
я определил как:
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));
}
}
Наконец, my main(void)
определяется как:
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);
}
На самом деле мой PIC работает нормально, и мое прерывание срабатывает. Что я не могу понять, так это причину, по которой мой код никогда не получает более одного символа в части RXReg
(а именно U1RXREG
) внутри ISR. Я сбрасываю флаг к концу ISR и думаю, что все настроено правильно. Дайте мне знать, что я должен сделать, чтобы правильно получить свой кадр, а не только первый символ. Я знаю, что UART хорошо спроектирован, и если я попытаюсь отправить другую команду, "SF,1"
регистр RX даст мне другой символ.
РЕДАКТИРОВАТЬ: я не достигаю того, чего хочу. Я теряю символы в прерывании, поэтому подключаю CTS
+ RTS
, но, к сожалению, не получаю лучших результатов. Кто-нибудь может помочь мне с конфигурацией CTS
+ RTS
для семейства PIC32mx? Я знаю, что мне нужно скрестить CTS с RTS и RTS с CTS от микроконтроллера к «другому» компоненту. Моя проблема больше связана с функциями/конфигурациями, которые мне нужно делать.
При скорости 115200 бод, без контроля четности и с 1 стартовым и стоповым битом (всего 10 бит) требуется 86 микросекунд, чтобы данные поступили в ваш RX-буфер с другого конца.
Глядя на ваш ISR, я вижу, что вы обрабатываете много инструкций в своем ISR.
Сценарий, который может произойти, таков: появляется ваш первый персонаж (т.е. «А»),
Прерывание срабатывает,
ошибок не было (переполнение, четность и т.д.),
теперь приходят и остальные символы ("ОК\r\n"),
устанавливается флаг переполнения,
вы очищаете прерывание RX (но вы не вводите ISR снова, потому что больше не будут получены символы).
Решения по отладке: 1. Используйте метод управления потоком (ACK для каждого байта).
3. Избегайте вызовов функций в ISR.
4. Вы можете включить прерывание для ошибок переполнения, чтобы вам не нужно было явно писать процедуру для прерывания. Если возникает ошибка переполнения, просто проверьте состояние флага прерывания, очистите флаг и отбросьте данные Rx. Это поможет вам сократить обработку таких ошибок в ISR, поскольку их можно проверить в самом основном цикле. Просто скопируйте полученные данные в буфер и увеличьте счетчик. Это может помочь.
фугу
акваланг
брахи
акваланг
оправдывающий
акваланг
U1RXREG
.pjc50
акваланг