PIC UART Interrupt wird nicht ausgelöst

Ich habe PIC16F628A, den ich von UART lesen möchte. Ohne Interrupts liest es die ersten 3 Bytes einwandfrei, trifft aber auf ein OERR. Um dem entgegenzuwirken, dachte ich, ein Interrupt wäre gut und lädt alle empfangenen Bytes in eine Puffervariable, die später eingelesen werden kann (Ringpuffer vom Array-Typ char). Aber der Interrupt löst nicht aus und mir gehen die Ideen aus.

CMCON = 0x07;           //16F627/8 spcial function reg (RAx is port)
CCP1CON = 0b00000000;   //Capt/Comp/PWM off

OPTION_REG = 0b00000000;

T1CON = 0;
INTCON = 0;
PIR1 = 0;
GIE = 0;

PIE1 = 0;

BRGH = 1;   /* high baud rate */
SPBRG = 19200;  /* set the baud rate */

SYNC = 0; //Async
TXEN = 0; //Disable transmit
TXIE = 0; //Disable transmit interrupt
RCIE = 1; //Enable Receive interrupt
SPEN = 1; //Enable serial pins
CREN = 1; //Enable continuous receive
SREN = 0;
TX9  = ninebits?1:0;    /* 8- or 9-bit transmission */
RX9  = ninebits?1:0;    /* 8- or 9-bit reception */

PEIE = 1; //Enable external interrupt
GIE = 1; //Enable global interrupt

Ich habe meinen Interrupt vereinfacht, um ein Licht einzuschalten:

extern interrupt isr(void)
{
    RB5 = 1;
}

Aber es triggert nicht. Das Projekt liest einen Barcode-Scanner über Seriell und verarbeitet den Barcode. Kann jemand Hilfe anbieten?

BEARBEITEN

Ok, da du es scheinbar nicht verstehst. Ich werde die tatsächlichen Routinen posten:

void initialize()
{
    CMCON = 0x07;           //16F627/8 spcial function reg (RAx is port)
    CCP1CON = 0b00000000;   //Capt/Comp/PWM off

    OPTION_REG = 0b00000000;

    T1CON = 0;
    INTCON = 0;
    PIR1 = 0;
    GIE = 0;
    PEIE = 0;
    PIE1 = 0;

    sci_Init(BAUDRATE ,SCI_EIGHT);// Baud set and Bit set

    TMR0 = 1000;
    T0IE = 0;
    PEIE = 1; //Enable external interrupt
    GIE = 1; //Enable global interrupt

    //Set inputs to input
    SetButtons();

    //Set relays to output
    SetRelays();

    TRISB5 = 0;

    LEDStatus = 0;
}

unsigned char sci_Init(unsigned long int baud, unsigned char ninebits)
{
    int X;
    unsigned long tmp;

    /* calculate and set baud rate register */
    /* for asynchronous mode */
    tmp = 16UL * baud;
    X = (int)(FOSC/tmp) - 1;
    if((X>255) || (X<0))
    {
        tmp = 64UL * baud;
        X = (int)(FOSC/tmp) - 1;
        if((X>255) || (X<0))
        {
            return 1;   /* panic - baud rate unobtainable */
        }
        else
            BRGH = 0;   /* low baud rate */
    }
    else
        BRGH = 1;   /* high baud rate */
    SPBRG = X;  /* set the baud rate */

    SYNC = 0; //Async
    TXEN = 0; //Disable transmit
    TXIE = 0; //Disable transmit interrupt
    RCIE = 1; //Enable Receive interrupt
    SPEN = 1; //Enable serial pins
    CREN = 1; //Enable continuous receive
    SREN = 0;
    TX9  = ninebits?1:0;    /* 8- or 9-bit transmission */
    RX9  = ninebits?1:0;    /* 8- or 9-bit reception */

    rxBuffIndex = 0;
    rxBuffRead = 0;

    return 1;
}

void sci_LoadBuffer(void)
{
    rxBuffer[rxBuffIndex] = RCREG;

    rxBuffIndex = ++rxBuffIndex % MAXBUFFER;
}

unsigned char sci_ReadBuffer()
{
    unsigned char byte;

    do
    {
        byte = rxBuffer[rxBuffRead];
    }while( byte == 0 ); //Block until valid data

    rxBuffer[rxBuffRead] = 0;
    rxBuffRead = (++rxBuffRead) % MAXBUFFER;

    return byte;
}

void interrupt isr(void)
{
    if(RCIF) sci_LoadBuffer();
    LEDStatus = 1;
}

Ich weiß, dass das nicht ALLES ist, aber das sollte ausreichen, um zu diagnostizieren, warum die Interrupts nicht ausgelöst werden. DAS IST ALLES WAS ICH BRAUCHE! Auslösen der Interrupts.

Ich verwende MPLab mit Hi-Tech C Compiler. Was aus dem Handbuch automatisch den Zustand speichert und beim Betreten / Verlassen des Interrupts wiederherstellt.

Meine eigentliche Interrupt-Funktion:void interrupt isr(void) { if(RCIF) sci_LoadBuffer(); LEDStatus = 1; } void sci_LoadBuffer(void) { rxBuffer[rxBuffIndex] = RCREG; rxBuffIndex = ++rxBuffIndex % MAXBUFFER; }
Entschuldigung für die Formatierung...
Formatierung behoben.
Ich bin mit PICs nicht vertraut, aber viele dieser Geräte haben irgendwo auch eine globale Interrupt-Maske, und manchmal gibt es im CPU-Kern selbst globale Aktivierungs- / Deaktivierungssteuerungen für Interrupts. Natürlich, wenn Sie in der Lage sind, Interrupts von anderen Quellen zu erhalten, dann schießt das diese Theorie ab. Etwas zum Nachdenken.
Es gibt viele mögliche Ursachen für Probleme. Ein Stack-Überlauf, Timing-Probleme, TRISxx falsch eingestellt, falsche Baudrate (SPBRG = 19200 sieht seltsam aus), etc... Kannst du einen Dump der SFRs knacken und posten?
Leute, diese Frage ist Zeitverschwendung. Das OP war seit dem 29. Juli nicht mehr hier. Sieht aus wie ein weiteres Drive-by-Poster.

Antworten (4)

TRISB1 muss auf 1 gesetzt werden, um RB1 (RX) als Eingang zu konfigurieren. Ich bin mir nicht sicher, was die Standardeinstellung ist, also kann es in Ordnung sein.

Sie müssen das Empfangsunterbrechungs-Flag (RCIF) löschen, indem Sie das Empfangsregister (RCREG) lesen. Da das Empfangsregister außerdem doppelt gepuffert ist, müssen Sie es möglicherweise mehr als einmal lesen.

Ihre Interrupt-Routine muss also eher so aussehen:

extern interrupt isr(void)
{
    while (RCIF)
    {
        char ch;

        RB5 = 1;
        ch = RCREG;    // normally would go into an array and increment a counter
    }
}

Ich weiß nicht, ob das Ihr einziges Problem ist, da Sie angeben, dass Sie überhaupt nicht in die Interrupt-Routine gelangen. Aber das obige ist der richtige Weg, um die Zeichen aus dem Empfangspuffer zu lesen.

=====================================

BEARBEITEN:

Ich weiß nicht, ob dies hilft oder nicht, aber in diesem Beitrag löscht der Code vor dem Aktivieren von Interrupts zuerst den FIFO. (Ihr Code löscht auch das RCIF-Flag, aber da es auf Ihrem Chip schreibgeschützt ist, ist das nicht erforderlich.)

ch = RCREG;    // clear FIFO  
ch = RCREG;
ch = RCREG;

// then enable interruupts ...
Ich erwähnte, dass ich mit der gleichen Art von Code ohne Interrupts Zeichen aus dem Empfangspuffer holen konnte: unsigned char sci_GetByte() { while(!RCIF) continue; //Block until data in return RCREG; }Mein Problem besteht darin, Interrupts zum Auslösen zu bringen

Okay, zwei Dinge.

Zunächst müssen Sie in Ihrer Interrupt-Routine normalerweise das IF-Flag RCIF löschen, damit der Interrupt erneut ausgelöst werden kann.

Das ist jedoch nicht der Grund, warum der Interrupt überhaupt nicht ausgelöst wird.

Das Problem mit Ihrem Code ist, dass Sie eine Funktion als Interrupt definieren - was in Ordnung ist -, der den Compiler veranlasst, Dinge automatisch für Sie auf den Stack zu schieben und sie nach Beendigung der Routine abzulegen. Es beendet die Funktion auch mit einem "Return from Interrupt"-Befehl anstelle eines einfachen "Return"-Befehls.

Was es nicht tut, ist die Funktion in den Interrupt-Vektor einzubinden. Um den Bereich des Interrupt-Vektors herum ist normalerweise nur wenig Platz, daher ist es normal, an der Adresse des Interrupt-Vektors ein goto zu platzieren , das den Namen Ihrer Interrupt-Routine aufruft.

Abhängig von Ihrem Compiler gibt es eine Reihe von Möglichkeiten, dies zu tun. Ich schlage vor, Sie lesen das Handbuch für Ihren Compiler über Interrupt-Vektoren und den Beispielcode dafür.

Ich habe deinen langen Beitrag nicht ganz gelesen, aber beim Überfliegen ist mir folgendes aufgefallen:

externer Interrupt isr(void)
{
    RB5 = 1;
}

Das ist definitiv falsch. Ich weiß nicht, was die Unterbrechungsbedingung ist, aber Sie löschen sie nicht. Der Prozessor bleibt beim ersten Interrupt hängen, da er unmittelbar nach Abschluss wieder in die Interrupt-Routine eintritt, da die Interrupt-Bedingung noch aktiv ist.

Löschen die meisten modernen PICs den Interrupt-Zustand nicht automatisch? Ich habe nicht mit PIC16s gearbeitet, aber das scheint eine unnötige Belastung für den Programmierer zu sein. Zumindest könnte dieser Code automatisch vom Compiler generiert werden ...
@Kevin: Nein, der Prozessor, der in die Interrupt-Routine eintritt, löscht die Interrupt-Bedingung auf einem PIC oder einem anderen Prozessor, den ich mir jemals angesehen habe, nicht. Es deaktiviert vorübergehend Interrupts, aber diese werden am Ende einer normalen Interrupt-Routine wieder aktiviert. Auf einem PIC 16 erfolgt dies mit dem RETFIE-Befehl. Nein, Sie möchten nicht, dass ein Compiler dies für Sie erledigt. In einigen Fällen ist es wichtig, die Unterbrechungsbedingung in der richtigen Reihenfolge mit anderen Interaktionen mit dem Gerät zu löschen.
Interessant; Der TI DSP, mit dem ich kürzlich gearbeitet habe, und der Cortex-M3, mit dem ich zuvor gearbeitet habe, haben das Interrupt-Flag automatisch gelöscht. Ich meine mich zu erinnern, dass es Optionen gab, diese Funktionalität zu deaktivieren, obwohl ...
@Kevin: Sind Sie sicher, dass das Interrupt-Flag für das bestimmte Peripheriegerät gelöscht wurde oder nur ein allgemeines Flag an der Vorderkante eines Interrupts gesetzt wurde?
Der MSP430 löscht auch automatisch Interrupt-Flags, die eine einzige Quelle haben, und außerdem löscht er beispielsweise den UART-Sende-Interrupt, wenn der Sendepuffer geschrieben wird.
@Andrekr: Einige der PIC-Interrupts werden durch Dinge wie das Lesen des UART-Empfängerregisters gelöscht, aber das müssen Sie noch tun. Durch einfaches Setzen von RB5 auf 1 wird kein Interrupt gelöscht.
Das Flag-Bit RCIF ist ein Nur-Lese-Bit, das von der Hardware gelöscht wird. Es wird gelöscht, wenn das RCREG-Register gelesen wurde und leer ist. Datenblatt: PIC16F877A Seite: 117.

Haben Sie versucht, das RS-232-Signal auf einem Oszilloskop zu überprüfen, um festzustellen, ob die Baudrate korrekt ist? Versuchen Sie, einige Zeichen vom PIC zu übertragen, um sicherzustellen, dass der UART die richtige Baudrateneinstellung hat.