PIC16F877A: ¿Cómo mantener el controlador despierto?

Estoy usando Pic16f877a para una comunicación en serie. Tengo una aplicación basada en PC que envía datos al microcontrolador. El microcontrolador recibe los datos y los transmite a través de I2C.

Pero, estoy enfrentando un problema. Después de cada transmisión, tengo que reiniciar el microcontrolador para la próxima transmisión. Estoy usando ISR (rutina de servicio de interrupción) para recibir datos en serie. Pero ni siquiera se ha llamado a ISR para los próximos datos disponibles. Y tengo que terminar reiniciando el dispositivo.

Parte de mi código para referencia:

int main()
{
    UARTInit();
    idmInitI2C();

    TRISB7 = 0;
    bool toggleBit = false;
    while (1)
    {    
        RB7 = toggleBit;
//        __delay_us(10);

        if ( UART_GetRecvByteStatus() ) {
            UART_SetRecvByteStatus(false);              // Set Received flag False
            receiveDataPkt();                           // Receive Incoming data
        }

        if ( isDataPktReceived ) {
            initIDComm();
            isDataPktReceived = false;
        }

        toggleBit != toggleBit;
    }
    return 0;
}

void receiveDataPkt()
{
    char buffer = NULL;                             // Load character receive to output buffer
    int i = 0, j = 0;
    int buf_count = 0;                              // Count character received
    int dly = 50;                                   // Initialize delay duration local to this section

    initBuffers();

    while ( !TXSTAbits.TRMT );                      // Wait until Transmit shift Register is not Empty, 
                                                // a transmission is in   progress or queued in the transmit buffer

    while ( buf_count != MAX_PKT_SIZE ){

        buffer = UART_Read();                             // Read Data


        if ( buffer == 0x00 ){
             break;
        }

        if ( buf_count < MAX_BUF_SIZE ) {
            data_Pkt_1[ i ] = buffer;               // Store data to Char Array 
            i++;
        } else {
            data_Pkt_2[ j ] = buffer;               // Store data to Char Array
            j++;
        }

        if ( ( data_Pkt_1[ 1 ] == READ ) && ( data_Pkt_1[ 4 ] == ETX ) ){
            break;
        }
        buf_count++;                                // Increase Count
    }

    while (dly){                                    // delay
        dly--;
     }

    if (OERR){
        CREN = 0;
        CREN = 1;
    }
    RCIE = 1;                                       // Enable Receive Interrupt

    isDataPktReceived = true;
    }

 void interrupt ISR(void)
 {
     if (RCIF)
     {
         RCIE = 0;
         if ( OERR ){
            CREN = 0;
            CREN = 1;
         }

        UART_SetRecvByteStatus( true );         // Signal for Received Byte
    } 
}

¿Qué se puede hacer para resolver el problema? Quiero mantenerlo siempre despierto para que se pueda llamar a ISR para cada dato entrante.

EDITAR:

función UART_Read() para referencia:

char UART_Read()
{
    int count = 0;
    char data = 0x00;

    while ( !RCIF ){
        if ( count >= 10 ){
            break;
        }
        __delay_ms(10);
        count++;
    }

    if ( RCIF ){
        data = RCREG;
    }

    return data;
}

(También recibo un máximo de 133 bytes en una transacción).

Si no recuerdo mal, debe borrar el indicador de interrupción (RCIF = 0) y dejar la interrupción habilitada (RCIE = 1).
@ pjc50, gracias por la respuesta. Estoy configurando (RCIE=1) en la función receiveDataPkt(); por eso borré (RCIE=0) en ISR.
@David, la hoja de datos dice "El bit de indicador RCIF es un bit de solo lectura, que lo borra el hardware. Se borra cuando el registro RCREG se ha leído y está vacío".
¿ToggleBit != toggleBit; definitivamente hace lo que cree que hace o simplemente se evalúa como falso y no hace nada?

Respuestas (1)

Cuando un byte ingresa al ISR de recepción, si el indicador de interrupción está establecido, lo restablece y luego establece un indicador usando UART_SetRecvByteStatus( true ). El ISR también deshabilita la interrupción de recepción. No lee un byte del registro de recepción de UART en este momento. No es bueno.

En main, dentro del ciclo while(1), si el indicador RecvByteStatus está configurado, lo reinicia y llama a receiveDataPkt(). En esa función, dentro del ciclo while: while ( buf_count != MAX_PKT_SIZE ), realiza llamadas repetidas para leer el búfer UART.

Pero a excepción de la primera vez, realmente no sabe si un carácter está disponible (a menos que UART_Read() bloquee la espera de que el búfer de recepción esté lleno, y lo dudo). Mientras realiza todas estas llamadas a UART_Read(), la ISR no se activa porque la interrupción está deshabilitada.

Solo sale de receiveDataPkt() si ha recibido uno de dos caracteres especiales. Si faltan, seguirá recibiendo caracteres hasta que se llenen los búferes.

La forma en que esto debería funcionar es que debe dejar la interrupción habilitada, y debe colocar caracteres en un búfer circular dentro del ISR, y luego extraerlos en la función receiveDataPkt(). Esto implica el uso de dos punteros, uno para realizar un seguimiento del siguiente byte para el ISR y otro para extraer los bytes del búfer. Si no está familiarizado con los topes circulares, búsquelo .

gracias por tu sugerencia. Hablando francamente, no estoy familiarizado con Circular Buffer. Entonces, necesito estudiar sobre eso. También edité mi Pregunta, con la función UART_Read(). Por favor, eche un vistazo y bríndeme sus valiosas sugerencias.
@skg Gracias por agregar el código para UART_Read(). Es bueno que esté usando un contador para evitar tener que esperar eternamente por un carácter, sin embargo, 10 * 100 µs es solo 1 ms. Cuando sale, aún lee el contenido del registro de recepción, por lo que agregará el último carácter al búfer dos veces. Debe hacer que el tiempo de espera sea mucho más largo, tal vez 100 ms, y luego manejar mejor la condición de error (tal vez devolver 0). Además, el ciclo dly en receiveDataPkt será muy rápido (¿100 µs?), ¿Por qué no llamaste a __delay_us() en su lugar?
gracias. He modificado UART_Read() según sus sugerencias. También se modificó el paquete de datos recibido(). Se agregó verificación para el búfer, si el búfer == NULL luego se rompe. Por favor, eche un vistazo y bríndeme sus valiosas sugerencias.