PIC18 USART Interrupt für Empfang, löst nicht aus

Ich habe das Enhanced USART-Modul für einen PIC18F4331 eingerichtet und versucht, einen Schleifentest durchzuführen. Ich verwende MPLABX, programmiere in XC8 und verwende Pickit3 zum Debuggen und Überwachen serieller Pins mit einem Oszilloskop.

Ohne ins Detail zu gehen, ist dies im Grunde das, was ich tue:

1) In der Hauptfunktion sendet USART Werte (nur zum Debuggen) 2) Empfänger-Interrupt wird gesetzt, wenn er ausgelöst wird, stoppt er die Übertragung und springt zu ISR

Folgendes passiert, wenn ich TX mit RX verbinde:

1) USART überträgt gut. 2) Das Rx-Register empfängt ein Byte und setzt das Flag RCIF nach dem ersten STOP-Bit, aber die ISR triggert nicht. Daher läuft das RX-Register über, weil es nicht gelesen wurde. Das Programm geht gar nicht in die ISR.

Ich denke, dass das Problem darin bestehen könnte, dass es möglicherweise nicht möglich ist, einen Interrupt auszulösen, indem ein Byte empfangen wird, während USART sendet? Sie sind jedoch unabhängig, also verstehe ich nicht, warum ich es nicht tun konnte.

Mein Code:

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

}
"Das Programm geht gar nicht in den ISR." - haben Sie dies bestätigt, indem Sie einen Haltepunkt in der ISR verwendet haben?
Ja, ich habe es bestätigt. Ich werde das RCIF-Flag in der Hauptsache abfragen, anstatt den Interrupt zu verwenden, um zu sehen, ob es zumindest erkannt wird. Idealerweise möchte ich aber die ISR verwenden
Es funktioniert perfekt, wenn ich das RCIF-Flag in der Hauptsache abfrage, und es könnte die beste Option sein, da ich das, was ich in der ISR tun wollte, zu lange dauern kann. Warum es nicht zum ISR springt, ist mir jedoch ein Rätsel :S

Antworten (4)

Jeder Prozessor hat seine eigenen Besonderheiten bei der Interrupt-Behandlung.

Die PIC18F4331-Seite von Microchip enthält Links zu einem Errata-Dokument und dem PIC18F4331-Datenblatt . Das Datenblatt enthält insbesondere einige gute Tipps in Abschnitt 20 „Enhanced Universal Synchronous Asynchronous Receiver Transmitter (EUSART)“ und noch spezieller die 3 Schritte, die in Abschnitt 20.0 aufgeführt sind, und die 10 Schritte von „So richten Sie einen asynchronen Empfang ein“ in Abschnitt 20.3.2.

Ich habe ein paar Dinge geändert, die so aussehen, als könnten sie helfen:

// 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;
}

Anderer Code online:

" AN944: Verwenden des EUSART auf dem 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

Sagen Sie uns, wenn Sie jemals das wahre Problem herausgefunden haben, OK?

Wenn ich XC16 verwende (ich glaube nicht, dass XC8 viel anders ist), erstelle ich im Allgemeinen ein Projekt mit dem Projektassistenten, weil er eine Reihe nützlicher c- und h-Dateien hinzufügt.

Einer davon ist ein 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.                                                                   */
/*                                                                            */
/************************

** * ** * ** * ** * ** * ** * ** * ** * ** * *** /

Grundsätzlich sollte Ihr ISR in etwa so aussehen. Sie können das Handbuch lesen, um herauszufinden, was die verschiedenen Attribute bedeuten, aber das verwende ich für ein vorhandenes Projekt und es funktioniert :)

 void __attribute__((interrupt, no_auto_psv)) _U1RXInterrupt(void)
    {
        //do whatever you need to here
        IFS0bits.U1RXIF = 0; //clear UART1 RX interrupt flag
    }

Ich bin mir nicht sicher, wie XC8 mit Interrupt-Funktionen umgeht, aber in C18 müssen Sie eine #pragma-Compiler-Direktive verwenden, um für den Compiler anzugeben, dass eine bestimmte Funktion ein Interrupt-Handler ist. Dies platziert eine Sprunganweisung an den Interrupt-Handler an der richtigen Interrupt-Vektorstelle auf dem Teil. Sie sollten das Assembly-Listing überprüfen, um zu sehen, ob der Interrupt-Vektor richtig eingerichtet ist.

XC8 unterscheidet sich stark von C18 bei den Interrupt-Aufrufen. #pragmaEs müssen keine Aussagen verwendet werden.

Versuchen Sie, Interrupt-Prioritäten zu deaktivieren; ändern

RCONbits.IPEN   = 1; // ENABLE interrupt priority

Zu

RCONbits.IPEN   = 0; // DISABLE interrupt priority

oder behandeln Sie beide Prioritäten:

void interrupt high_priority HighIsr(void) //High priority interrupt
{
    //ISR - High
}

void interrupt low_priority LowIsr(void)   //Low priority interrupt
{
    //ISR - LOW
}
Ah. Die Frage wurde vor einem Jahr gestellt, entschuldigen Sie die "Reaktivierung". Wird es helfen, meine Antwort zu löschen?
Nein, es kann für zukünftige Besucher nützlich sein.