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).
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 .
pjc50
skg
skg
marca ch