Я настроил модуль Enhanced USART для PIC18F4331 и пытался выполнить циклический тест. Я использую MPLABX, программирую в XC8, использую Pickit3 для отладки и мониторинга последовательных выводов с помощью осциллографа.
Не вдаваясь в подробности, в основном это то, что я делаю:
1) В основной функции USART передает значения (исключительно для отладки) 2) Установлен Receiver Interrupt, при срабатывании которого он прекращает передачу и переходит на ISR
Вот что происходит, когда я подключаю TX к RX:
1) USART передает нормально. 2) Регистр Rx получает байт и устанавливает флаг RCIF после первого бита STOP, но ISR не срабатывает. Следовательно, регистр RX переполняется, потому что он не был прочитан. Программа вообще не заходит в ISR.
Я думаю, что проблема может заключаться в том, что невозможно вызвать прерывание, получив байт во время передачи USART? Однако они независимы, поэтому я не понимаю, почему я не мог этого сделать.
Мой код:
int main(int argc, char *argv[]) {
//***********************Initializing Values****************************//
unsigned int ResultADC, FLAG;
unsigned char temp, idle; //High Byte result store, 8bits long
//***********************ADC and SPI Settings****************************//
Initialize_control(); //Initialize Control Configuration Pins
InitializeADC(); //Initialize ADC in Continuous Mode
USART_initialize(); //Initialize USART module
InitializeMasterSPI(); //Initialize SPI module
//***********************ADC Capture and Output to SPI******************//
while(1){ //While ADC buffer has something
//Enable transmission
TXREG = 0xff; //Debugger
while(!TXSTAbits.TRMT);//wait while TSR is full
TXREG = 0x0; //Debugger
while(!TXSTAbits.TRMT);//wait while TSR is full
}
return 0;
}
//////////////////INTERRUPT SERVICE ROUTINE/////////////////
static void interrupt isr(void){
//Disable Interrupt
PIE1bits.RCIE = 0;
int count;
//Read USART data
//PIR1bits.RCIF;//Data has been passed to RCREG
RX_Data[count] = RCREG; //Read RX register
count++;
//Reading RX_data clears RCIF, how to read more than 1 byte?
if (count==3){
//Use data for control
Control_Arduino(RX_Data);
count = 0;
}
PIE1bits.RCIE = 1;
}
//**********************Functions****************************//
void USART_initialize(void){
//Configuration TX and RX pins
TRISCbits.RC6 = 0; //TX output
TRISCbits.RC7 = 1; //RX input
//TXSTA: Transmit Status and Control Register
TXSTAbits.SYNC = 0; //Asynchronous mode
TXSTAbits.TX9 = 0; //8bit transmission
TXSTAbits.BRGH = 1; //Set HIGH Baud rate
TXSTAbits.TXEN = 1; //Enable transmitter
TXSTAbits.SENDB = 0; //Disable break
//RCSTA: Receive Status and Control Register
RCSTAbits.SPEN = 1; //Serial Port enabled
RCSTAbits.RX9 = 0; //8bit reception
RCSTAbits.CREN = 1; //Enables Receiver
//Test bits
// RCSTAbits.FERR = 0; //No framing error, cleared by reading
// RCSTAbits.OERR = 0; //No Overrun error, cleared by clearing CREN
//Disable receiver CREN 0
//BAUDCON Control register
BAUDCONbits.BRG16 = 1; //16bit baud rate generator
SPBRG = 0xCF; // Set to 19200 baud rate, 12Mhz, High Speed, BRG16
//Test bits
// BAUDCONbits.RCIDL = 0; //Receive in progress
// USART interrupts configuration
RCONbits.IPEN = 1; // ENABLE interrupt priority
INTCONbits.GIE = 1; // ENABLE interrupts
INTCONbits.PEIE = 1; // ENable peripheral interrupts.
PIE1bits.RCIE = 1; // ENABLE USART receive interrupt
PIE1bits.TXIE = 0; // disable USART TX interrupt
}
Каждый процессор имеет свои особенности обработки прерываний.
На странице Microchip PIC18F4331 есть ссылки на документ об ошибках и техническое описание PIC18F4331 . В частности, в техническом описании есть несколько полезных советов в разделе 20 «Расширенный универсальный синхронный асинхронный приемник-передатчик (EUSART)» и, в частности, 3 шага, перечисленные в разделе 20.0, и 10 шагов «Настройка асинхронного приема» в разделе 20.3.2.
Я изменил несколько вещей, которые выглядят так, как будто они могут помочь:
// WARNING: untested code
int main(void){
//***********************Initializing Values****************************//
unsigned int ResultADC, FLAG;
unsigned char temp, idle; //High Byte result store, 8bits long
//***********************ADC and SPI Settings****************************//
Initialize_control(); //Initialize Control Configuration Pins
InitializeADC(); //Initialize ADC in Continuous Mode
USART_initialize(); //Initialize USART module
InitializeMasterSPI(); //Initialize SPI module
//***********************ADC Capture and Output to SPI******************//
while(1){ //While ADC buffer has something
//Enable transmission
TXREG = 0xff; //Debugger
while(!TXSTAbits.TRMT);//wait while TSR is full
TXREG = 0x0; //Debugger
while(!TXSTAbits.TRMT);//wait while TSR is full
}
return 0;
}
//////////////////INTERRUPT SERVICE ROUTINE/////////////////
static void interrupt isr(void){
// The PIC hardware has already disabled global interrupts
// by the time it starts executing the ISR,
// so there's no need to do "PIE1bits.RCIE = 0;".
int count;
//Read USART data
//PIR1bits.RCIF;//Data has been passed to RCREG
RX_Data[count] = RCREG; //Read RX register
count++;
//Reading RCREG automatically clears the RX flag.
// so there's no need to do "PIR1bits.RCIF = 0;".
// Q: How to read more than 1 byte?
// A: FIGURE 20-5 of the datasheet
// Implies that there's only a 1 byte buffer.
// Therefore, to read more than 1 byte, we must:
// pull the current byte out of the hardware buffer,
// store it in a software buffer RX_Data[] in RAM,
// then return to normal background main loop
// until the next byte in the message
// triggers another interrupt.
// Would it be better to do the following in the main loop?
if (count==3){
//Use data for control
Control_Arduino(RX_Data);
count = 0;
}
/*
The datasheet p. 229 is a little confusing about
whether "CREN" should be set (step 5) or cleared (step 9).
p. 219 which clearly seems to say CREN should be set.
But maybe it needs to be cleared to flush out any errors,
and then be set?
Are the following 2 lines really necessary?
*/
RCSTAbits.CREN = 0; //clear error (if any)
RCSTAbits.CREN = 1; //Enables Receiver
// the PIC hardware enables global interrupts
// automatically during the return-from-interrupt,
// so there's no need to do a "PIE1bits.RCIE = 1;"
// See the datasheet section 10.0: "Interrupts" for details.
}
//**********************Functions****************************//
void USART_initialize(void){
//Configuration TX and RX pins
// *normally* we use a "0" to indicate "output",
// but the TX output pin is different, see p. 217 of datasheet
TRISCbits.RC6 = 1; //TX output
TRISCbits.RC7 = 1; //RX input
//TXSTA: Transmit Status and Control Register
TXSTAbits.SYNC = 0; //Asynchronous mode
TXSTAbits.TX9 = 0; //8bit transmission
TXSTAbits.BRGH = 1; //Set HIGH Baud rate
TXSTAbits.TXEN = 1; //Enable transmitter
TXSTAbits.SENDB = 0; //Disable break
//RCSTA: Receive Status and Control Register
RCSTAbits.SPEN = 1; //Serial Port enabled
RCSTAbits.RX9 = 0; //8bit reception
RCSTAbits.CREN = 1; //Enables Receiver
//Test bits
// RCSTAbits.FERR = 0; //No framing error, cleared by reading
// RCSTAbits.OERR = 0; //No Overrun error, cleared by clearing CREN
//Disable receiver CREN 0
//BAUDCON Control register
BAUDCONbits.BRG16 = 1; //16bit baud rate generator
SPBRG = 0xCF; // Set to 19200 baud rate, 12Mhz, High Speed, BRG16
//Test bits
// BAUDCONbits.RCIDL = 0; //Receive in progress
// USART interrupts configuration
RCONbits.IPEN = 1; // ENABLE interrupt priority
// (p. 4 of http://www.gooligum.com.au/tutorials/midrange/PIC_Mid_C_3.pdf )
ei(); // same as INTCONbits.GIE = 1; // ENABLE interrupts
INTCONbits.PEIE = 1; // ENable peripheral interrupts.
PIE1bits.RCIE = 1; // ENABLE USART receive interrupt
PIE1bits.TXIE = 0; // disable USART TX interrupt
// make sure the RX flag is clear
PIR1bits.RCIF = 0;
}
Другой код онлайн:
" AN944: Использование EUSART на PIC16F688 " http://www.gooligum.com.au/tutorials/midrange/PIC_Mid_C_3.pdf https://forum.sparkfun.com/viewtopic.php?t=7542 http:// panteltje.com/panteltje/pic/scope_pic/ http://www.microchip.com/forums/m411875.aspx http://www.enmcu.com/guides/autobaudratebasedoneusartmodule
Скажи нам, если ты когда-нибудь выяснишь настоящую проблему, хорошо?
Когда я использую XC16 (я не думаю, что XC8 сильно отличается), я обычно создаю проект с помощью мастера проектов, потому что он добавляет кучу полезных файлов c и h.
Один из них является interrupts.c.
/******************************************************************************/
/* Interrupt Vector Options */
/******************************************************************************/
/* */
/* Refer to the C30 (MPLAB C Compiler for PIC24F MCUs and dsPIC33F DSCs) User */
/* Guide for an up to date list of the available interrupt options. */
/* Alternately these names can be pulled from the device linker scripts. */
/* */
/* Primary Interrupt Vector Names: */
/* */
/* _INT0Interrupt _INT2Interrupt */
/* _IC1Interrupt _U2RXInterrupt */
/* _OC1Interrupt _U2TXInterrupt */
/* _T1Interrupt _SPI2Interrupt */
/* _IC2Interrupt _C1Interrupt */
/* _OC2Interrupt _IC3Interrupt */
/* _T2Interrupt _IC4Interrupt */
/* _T3Interrupt _IC5Interrupt */
/* _SPI1Interrupt _IC6Interrupt */
/* _U1RXInterrupt _OC5Interrupt */
/* _U1TXInterrupt _OC6Interrupt */
/* _ADCInterrupt _OC7Interrupt */
/* _NVMInterrupt _OC8Interrupt */
/* _SI2CInterrupt _INT3Interrupt */
/* _MI2CInterrupt _INT4Interrupt */
/* _CNInterrupt _C2Interrupt */
/* _INT1Interrupt _PWMInterrupt */
/* _IC7Interrupt _QEIInterrupt */
/* _IC8Interrupt _DCIInterrupt */
/* _OC3Interrupt _LVDInterrupt */
/* _OC4Interrupt _FLTAInterrupt */
/* _T4Interrupt _FLTBInterrupt */
/* _T5Interrupt */
/* */
/* For alternate interrupt vector naming, simply add 'Alt' between the prim. */
/* interrupt vector name '_' and the first character of the primary interrupt */
/* vector name. */
/* */
/* For example, the vector name _ADC2Interrupt becomes _AltADC2Interrupt in */
/* the alternate vector table. */
/* */
/* Example Syntax: */
/* */
/* void __attribute__((interrupt,auto_psv)) <Vector Name>(void) */
/* { */
/* <Clear Interrupt Flag> */
/* } */
/* */
/* For more comprehensive interrupt examples refer to the C30 (MPLAB C */
/* Compiler for PIC24 MCUs and dsPIC DSCs) User Guide in the */
/* <compiler installation directory>/doc directory for the latest compiler */
/* release. */
/* */
/************************
** * ** * ** * ** * ** * ** * ** * ** * ** * *** /
В основном ваш ISR должен выглядеть примерно так. Вы можете прочитать руководство, чтобы узнать, что означают различные атрибуты, но это то, что я использую для существующего проекта, и это работает :)
void __attribute__((interrupt, no_auto_psv)) _U1RXInterrupt(void)
{
//do whatever you need to here
IFS0bits.U1RXIF = 0; //clear UART1 RX interrupt flag
}
Я не уверен, как XC8 обрабатывает функции прерывания, но в C18 вы должны использовать директиву компилятора #pragma, чтобы указать компилятору, что конкретная функция является обработчиком прерывания. Это помещает инструкцию перехода к обработчику прерывания в правильном месте вектора прерывания на части. Вы должны проверить листинг сборки, чтобы убедиться, что вектор прерывания настроен правильно.
#pragma
заявления не должны использоваться.Попробуйте отключить приоритеты прерываний; изменять
RCONbits.IPEN = 1; // ENABLE interrupt priority
к
RCONbits.IPEN = 0; // DISABLE interrupt priority
или обрабатывать оба приоритета:
void interrupt high_priority HighIsr(void) //High priority interrupt
{
//ISR - High
}
void interrupt low_priority LowIsr(void) //Low priority interrupt
{
//ISR - LOW
}
Марк Б
Отруби.
Отруби.