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 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 .
pjc50
skg
skg
Markus Ch