PIC16F877A : Wie hält man den Controller wach?

Ich verwende Pic16f877a für eine serielle Kommunikation. Ich habe eine PC-basierte Anwendung, die Daten an den Mikrocontroller sendet. Der Mikrocontroller empfängt die Daten und überträgt sie über I2C.

Aber ich stehe vor einem Problem. Nach jeder Übertragung muss ich den Mikrocontroller für die nächste Übertragung zurücksetzen. Ich verwende ISR (Interrupt Service Routine) zum Empfangen von seriellen Daten. Aber auch ISR wird nicht für die nächsten verfügbaren Daten aufgerufen. Und ich muss am Ende das Gerät zurücksetzen.

Teil meines Codes als Referenz:

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

Was kann man tun um das Problem zu lösen?? Ich möchte es immer wach halten, damit ISR für alle eingehenden Daten aufgerufen werden kann.

BEARBEITEN:

Funktion UART_Read() als Referenz:

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

(Außerdem erhalte ich maximal 133 Bytes in einer Transaktion.)

Wenn ich mich recht erinnere, müssen Sie das Interrupt-Flag löschen (RCIF=0) und den Interrupt aktiviert lassen (RCIE=1).
@ pjc50, danke für die Antwort. Ich setze (RCIE=1) in der Funktion ReceiveDataPkt();deshalb habe ich (RCIE=0) unter ISR gelöscht.
@David, Datenblatt sagt: "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."
Tut toggleBit != toggleBit; tun Sie auf jeden Fall, was Sie denken, oder wird es einfach als falsch bewertet und nichts getan?

Antworten (1)

Wenn ein Byte in die Empfangs-ISR kommt und das Interrupt-Flag gesetzt ist, setzen Sie es zurück und setzen dann ein Flag mit UART_SetRecvByteStatus( true ). Die ISR deaktiviert auch die Empfangsunterbrechung. Sie lesen zu diesem Zeitpunkt kein Byte aus dem UART-Empfangsregister. Nicht gut.

Im Wesentlichen setzen Sie innerhalb der while(1)-Schleife, wenn das RecvByteStatus-Flag gesetzt ist, es zurück und rufen receiveDataPkt() auf. In dieser Funktion innerhalb der while-Schleife: while ( buf_count != MAX_PKT_SIZE ) führen Sie wiederholte Aufrufe durch, um den UART-Puffer zu lesen.

Aber außer beim ersten Mal wissen Sie nicht wirklich, ob ein Zeichen verfügbar ist (es sei denn, die UART_Read()-Blöcke warten darauf, dass der Empfangspuffer voll ist, und das bezweifle ich). Während Sie alle diese Aufrufe an UART_Read() machen, wird die ISR nicht ausgelöst, da der Interrupt deaktiviert ist.

Sie verlassen ReceiveDataPkt() nur, wenn Sie eines von zwei Sonderzeichen empfangen haben. Fehlen diese, erhalten Sie weiterhin Zeichen, bis die Puffer voll sind.

Dies sollte so funktionieren, dass Sie den Interrupt aktiviert lassen und Zeichen in einen Ringpuffer innerhalb der ISR einfügen und sie dann in der Funktion receiveDataPkt() abziehen sollten. Dies erfordert die Verwendung von zwei Zeigern, einen zum Verfolgen des nächsten Bytes für die ISR und einen anderen zum Herausziehen der Bytes aus dem Puffer. Wenn Sie mit Ringpuffern nicht vertraut sind, schlagen Sie nach .

danke für Ihren Vorschlag. Ehrlich gesagt kenne ich Circular Buffer nicht. Also muss ich darüber lernen. Ich habe auch meine Frage mit der Funktion UART_Read() bearbeitet. Bitte schauen Sie sich um und geben Sie mir Ihre wertvollen Anregungen.
@skg Danke für das Hinzufügen des Codes für UART_Read(). Es ist gut, dass Sie einen Zähler verwenden, um nicht ewig auf ein Zeichen zu warten, aber 10 * 100 µs sind nur 1 ms. Beim Beenden lesen Sie immer noch den Inhalt des Empfangsregisters, sodass Sie das letzte Zeichen zweimal zum Puffer hinzufügen. Sie müssen das Timeout viel länger machen, vielleicht 100 ms, und dann die Fehlerbedingung besser behandeln (vielleicht 0 zurückgeben). Auch die dly-Schleife in ReceiveDataPkt wird sehr schnell sein (100 µs?), warum haben Sie nicht stattdessen __delay_us() aufgerufen?
Danke. Ich habe UART_Read() gemäß Ihren Vorschlägen modifiziert. Auch geänderte ReceivedDataPkt(). Prüfung für den Puffer hinzugefügt, wenn Puffer == NULL, dann Unterbrechung. Bitte schauen Sie und geben Sie mir Ihre wertvollen Vorschläge.