La interrupción de PIC UART no se activa

Tengo PIC16F628A que estoy tratando de leer desde UART. Sin interrupciones, lee bien los primeros 3 bytes pero alcanza un OERR. Para combatir esto, pensé que una interrupción sería buena y cargar los bytes recibidos en una variable de búfer que podría leerse más tarde (búfer de anillo de tipo char de matriz). Pero la interrupción no se activa y me he quedado sin ideas.

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

He simplificado mi interrupción para encender una luz:

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

Pero no es desencadenante. El proyecto está leyendo un escáner de código de barras en serie y procesando el código de barras. ¿Alguien puede ofrecer alguna ayuda?

EDITAR

Bueno, ya que parece que no entiendes. Voy a publicar las rutinas reales:

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

Sé que eso no es TODO, pero eso debería ser suficiente para diagnosticar por qué las interrupciones no se activan. ¡ESO ES TODO LO QUE NECESITO! Activación de las interrupciones.

Estoy usando MPLab con Hi-Tech C Compiler. Que del manual guarda automáticamente el estado y lo restaura al entrar/salir de la interrupción.

Mi verdadera función de interrupción:void interrupt isr(void) { if(RCIF) sci_LoadBuffer(); LEDStatus = 1; } void sci_LoadBuffer(void) { rxBuffer[rxBuffIndex] = RCREG; rxBuffIndex = ++rxBuffIndex % MAXBUFFER; }
Perdón por el formato...
formato arreglado.
No estoy familiarizado con los PIC, pero muchos de estos tipos de dispositivos también tienen una máscara de interrupción global en algún lugar y, a veces, dentro del núcleo de la CPU hay controles globales de activación/desactivación de interrupciones. Por supuesto, si puede obtener interrupciones de otras fuentes, eso descarta esa teoría. Algo sobre lo que pensar.
Hay muchas posibles fuentes de problemas. Un desbordamiento de pila, problemas de tiempo, TRISxx configurado incorrectamente, Baudrate incorrecto (SPBRG = 19200 parece extraño), etc. ¿Puedes romper y publicar un volcado de los SFR?
Amigos, esta pregunta es una pérdida de tiempo. El OP no ha vuelto aquí desde el 29 de julio. Parece otro cartel de drive-by.

Respuestas (4)

TRISB1 debe establecerse en 1 para configurar RB1 (RX) como entrada. No estoy seguro de cuál es el valor predeterminado, por lo que puede estar bien.

Debe borrar el indicador de interrupción de recepción (RCIF) leyendo el registro de recepción (RCREG). Además, dado que el registro de recepción tiene doble búfer, es posible que deba leerlo más de una vez.

Por lo tanto, su rutina de interrupción debe parecerse más a esto:

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

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

No sé si ese es su único problema, ya que indica que no está entrando en la rutina de interrupción en absoluto. Pero lo anterior es la forma correcta de leer los caracteres del búfer de recepción.

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

EDITAR:

No sé si esto ayudará o no, pero en esta publicación , antes de habilitar las interrupciones, el código primero borra el FIFO. (Su código también borra el indicador RCIF, pero dado que es de solo lectura en su chip, no es necesario).

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

// then enable interruupts ...
Mencioné que pude obtener caracteres del búfer de recepción sin interrupciones usando el mismo tipo de código: unsigned char sci_GetByte() { while(!RCIF) continue; //Block until data in return RCREG; }mi problema es intentar que se activen las interrupciones

Bien, dos cosas.

Primero, dentro de su rutina de interrupción, generalmente debe borrar el indicador IF RCIF para permitir que la interrupción se dispare nuevamente.

Sin embargo, esa no es la razón por la que la interrupción no se activa en absoluto.

El problema con su código es que está definiendo una función como una interrupción, lo cual está bien, que hace que el compilador empuje las cosas a la pila automáticamente y las elimine después de que finalice la rutina. También finaliza la función con un comando de "regreso de interrupción" en lugar de un simple comando de "retorno".

Lo que no hace es vincular la función al vector de interrupción. Por lo general, solo hay una pequeña cantidad de espacio alrededor del área del vector de interrupción, por lo que es normal colocar un goto en la dirección del vector de interrupción que llama el nombre de su rutina de interrupción.

Dependiendo de su compilador, hay varias formas de hacerlo. Le sugiero que lea el manual de su compilador sobre los vectores de interrupción y el código de muestra.

No leí toda tu publicación larga, pero me di cuenta de esto al hojear:

isr de interrupción externa (vacío)
{
    RB5 = 1;
}

Esto definitivamente está mal. No sé cuál es la condición de interrupción, pero no la estás eliminando. El procesador se bloqueará en la primera interrupción porque volverá a ingresar a la rutina de interrupción inmediatamente después de que se complete porque la condición de interrupción aún está activa.

¿La mayoría de los PIC modernos no borran automáticamente la condición de interrupción? No he trabajado con PIC16, pero parece una carga innecesaria para el programador. Como mínimo, este código podría ser generado automáticamente por el compilador...
@Kevin: No, el procesador que ingresa a la rutina de interrupción no borra la condición de interrupción en un PIC o cualquier otro procesador que haya visto. Deshabilita temporalmente las interrupciones, pero se vuelven a habilitar al final de una rutina de interrupción normal. En un PIC 16, esto se hace con la instrucción RETFIE. No, no quieres que un compilador haga esto por ti. En algunos casos, es importante borrar la condición de interrupción en la secuencia correcta con otras interacciones con el dispositivo.
Interesante; el TI DSP con el que he estado trabajando recientemente y el Cortex-M3 con el que trabajé antes borraron automáticamente el indicador de interrupción. Aunque creo recordar que había opciones para deshabilitar esta funcionalidad...
@Kevin: ¿Está seguro de que se eliminó el indicador de interrupción para el periférico específico , o simplemente se estableció un indicador general en el borde de ataque de cualquier interrupción?
El MSP430 también borra automáticamente los indicadores de interrupción que tienen una sola fuente y además borra, por ejemplo, la interrupción de transmisión UART cuando se escribe el búfer de transmisión.
@Andrekr: algunas de las interrupciones de PIC se eliminan con cosas como leer el registro del receptor UART, pero aún debe hacerlo. Simplemente establecer RB5 en 1 no borrará ninguna interrupción.
El bit de bandera RCIF es un bit de solo lectura que el hardware borra. Se borra cuando se ha leído el registro RCREG y está vacío. Hoja de datos: PIC16F877A Página: 117.

¿Ha intentado mirar la señal RS-232 en un osciloscopio para ver si la velocidad en baudios es correcta? Intente transmitir algunos caracteres desde el PIC para asegurarse de que el UART tenga la configuración de velocidad en baudios correcta.