Trabajo en un proyecto pero tengo un problema.
Quiero hacer un programa que controle los dos UART en un PIC, cada UART a una velocidad de transmisión diferente. La idea es tomar una señal para UART1 (9600 baudios) y enviarla a la salida UART 2 (1200 baudios). En el momento hago un código para manejar los dos UART.
Adjunto el código, y esto tiene comentarios en la prueba de eco, y el uart funciona bien, cuando pongo datos en uart 2, estos datos están bien en la salida a UART 1, pero, cuando quiero poner datos en UART 1, para ver estos datos en la salida de uart 2, perdí muchos datos, por diferentes velocidades de transmisión. Espero que me entienda, mi problema es la pérdida de datos de alta tasa de baudios a baja tasa de baudios, espero su opinión sobre cómo resolver esto.
#if defined (__PIC24F__)
#include <p24FJ64GB002.h>
#endif
#include "xc.h"
_CONFIG4(DSBOREN_OFF & DSWDTEN_OFF)
_CONFIG3(WPDIS_WPDIS)
_CONFIG2(POSCMOD_NONE & OSCIOFNC_OFF & FNOSC_FRC & PLL96MHZ_OFF )
_CONFIG1(FWDTEN_OFF & JTAGEN_OFF)
int c,D;
int main(void){
//OSCILLATOR CONFIG
OSCCON=0X0000; //
CLKDIVbits.RCDIV0=0; //clock divider to 0
//PIN CONFIG
AD1PCFGL=0XFFFF; //ALL PINS DIGITAL
TRISA = 0X0000; //PORT A OUTPUT
TRISB = 0XFFFF; //PORT B INPUT
RPOR2bits.RP5R=3; // RP5 TX UART1
RPOR3bits.RP6R=5; // RP6 TX UART2
RPINR18bits.U1RXR=0; //RP0 RX UART1
RPINR19bits.U2RXR=2; //RP1 RX UART2
//----------------------------------------------------------------------------
//UART CONFIG
U1BRG=103;
U2BRG=832;
U1MODEbits.UARTEN = 1; // UART Enable
U1MODEbits.USIDL = 1;// Stop in Idle Mode Bit
U1MODEbits.IREN = 0; // IrDA Encoder and Decoder Disabled
U1MODEbits.RTSMD = 1; // UxRTS in SIMPLEX mode
U1MODEbits.UEN = 00; // Tx and Rx pins are used,UxCTS,UxRTS, BCLK are controlled by port latch
U1MODEbits.WAKE = 0; // Wake up disabled on sleep mode
U1MODEbits.LPBACK = 0; // Loopback is disabled
U1MODEbits.ABAUD = 0; // Baud rate measurement is disabled
U1MODEbits.RXINV = 0; // Idle state is '1'
U1MODEbits.BRGH =1; // High baurdate selected
U1MODEbits.PDSEL = 00 ; // No parity, 8bits
U1MODEbits.STSEL = 0; // 1 Stop bit
U2MODEbits.UARTEN = 1; // UART Enable
U2MODEbits.USIDL = 1;// Stop in Idle Mode Bit
U2MODEbits.IREN = 0; // IrDA Encoder and Decoder Disabled
U2MODEbits.RTSMD = 1; // UxRTS in SIMPLEX mode
U2MODEbits.UEN = 00; // Tx and Rx pins are used,UxCTS,UxRTS, BCLK are controlled by port latch
U2MODEbits.WAKE = 0; // Wake up disabled on sleep mode
U2MODEbits.LPBACK = 0; // Loopback is disabled
U2MODEbits.ABAUD = 0; // Baud rate measurement is disabled
U2MODEbits.RXINV = 0; // Idle state is '1'
U2MODEbits.BRGH =1; // High baurdate selected
U2MODEbits.PDSEL = 00; // No parity, 8bits
U2MODEbits.STSEL = 0; // 1 Stop bit
//------------------------------------------------------------------
//CONFIGURACION DE TRANSMISION, RECEPCION E INTERRUPCIONES DE LAS UART
U1STAbits.UTXINV = 0; // UxTX idle state is '0'
U1STAbits.UTXBRK = 0; // Sync Break Disabled
U1STAbits.UTXEN = 1; // UART1 Transmitter is enabled
U1STAbits.URXISEL = 00; // Interrupt flag bit is set when a charater is received
IEC0bits.U1TXIE = 0; // Disable UART1 Tx interrupt
U2STAbits.UTXINV = 0; // UxTX idle state is '0'
U2STAbits.UTXBRK = 0; // Sync Break Disabled
U2STAbits.UTXEN = 1; // UART2 Transmitter is enabled
U2STAbits.URXISEL = 00; // Interrupt flag bit is set when a charater is received
IEC1bits.U2TXIE=0; // Disable UART2 Tx interrupt
while(1){
// //ECHO TEST UART 2 1200 BAUDS
// //wait for byte
// while(!U2STAbits.URXDA);
// c=U2RXREG;//get byte
// //wait for empty spot in transmit buffer
// while(U2STAbits.UTXBF == 1);
// //echo received character back
// U2TXREG = c;
//// //ECHO TEST UART 1 9600 BAUDS
// //wait for byte
// while(!U1STAbits.URXDA);
// D=U1RXREG;//get byte
// //wait for empty spot in transmit buffer
// while(U1STAbits.UTXBF == 1);
// //echo received character back
// U1TXREG = D;
//TEST TO PUT UT DATA FROM UART 2 1200 IN OUTPUT UART1 9600, ITS PART IS OK
while(!U2STAbits.URXDA);
D=U2RXREG;//get byte
//wait for empty spot in transmit buffer
while(U2STAbits.UTXBF == 1);
//echo received character back
U1TXREG = D;
}
return 0;
}
Por lo que entiendo que estás preguntando, tienes 2 UART a diferentes velocidades. Envías datos al UART rápido, y este los envía a través del UART lento por ti, ¿y el problema que tienes es que pierdes datos porque no se envían lo suficientemente rápido?
De acuerdo. La respuesta es usar un sistema llamado "Store and Forward". Esto se ha utilizado durante muchos años en concentradores Ethernet 10/100, donde los datos que ingresan pueden ser 10 veces más rápidos que los datos que salen.
Básicamente, se trata de tener un búfer grande (normalmente circular) que se llena con el UART rápido y sale del UART lento.
Realmente solo funciona si tiene una forma de datos de "ráfaga", es decir, no está enviando datos todo el tiempo, sino enviando paquetes de fragmentos con demoras intermedias. Esto permite que el UART lento se ponga al día y haga espacio en el búfer circular para más datos.
En un sistema perfecto, usaría un apretón de manos para decirle al remitente rápido que deje de enviar por un tiempo. Lo mejor es el protocolo de enlace de hardware, en el que se utiliza una línea de E/S para señalar al remitente que se trata de datos "Listos para enviar" (CTS). Algunos chips (PIC32) tienen esta funcionalidad incorporada con pines CTS/RTS dedicados, pero es lo suficientemente simple como para emularla en aquellos que no la tienen.
Otra alternativa es utilizar el protocolo de enlace de software, también conocido como XON/XOFF, donde el PIC24 enviaría un carácter XOFF cuando su búfer esté casi lleno y un carácter XON cuando se esté vacía de nuevo. Estos niveles se conocen como "marca de agua alta" y "marca de agua baja" respectivamente, ya que todo el sistema se puede imaginar como un tanque que se llena con una tubería de gran diámetro y un pequeño orificio en el fondo que gotea agua. Una válvula cerraría el agua en la "marca de agua alta" y permitiría que fluya nuevamente en la "marca de agua baja".
Tenga en cuenta que la marca de agua alta no es lo mismo que el búfer lleno, solo "casi" lleno, ya que el protocolo de enlace del software no es perfecto y algunos datos aún pueden ingresar después de enviar XOF debido a cualquier búfer entre el software del remitente y el hardware del receptor.
Mientras espera un lugar vacío en el búfer tx para el UART lento, es probable que esté dejando que el búfer rx del UART más rápido se desborde al no procesar esos bytes lo suficientemente rápido. Una forma típica basada en software de hacer esto es crear su propio búfer en su software y leerlo/escribirlo sin bloquear la espera de la disponibilidad de rx/tx (otras soluciones son el protocolo de enlace como se describe en la respuesta de Majenko ) .
Un búfer circular es generalmente una solución fácil de implementar. Algo así como, pseudo-código:
unsigned char buffer[128];
int rxposition = 0, txposition = 0;
while (1) {
/* If RX data, read it into our buffer. Otherwise do not wait. */
if (U2STAbits.URXDA) {
buffer[rxposition++] = U2RXREG;
rxposition &= 127; /* Optimization of: rxposition %= sizeof(buffer); for size 128 */
}
/* If TX available and we have data to write, write it. Otherwise do not wait. */
if (!U2STAbits.UTXBF && rxposition != txposition) {
U1TXREG = buffer[txposition++];
txposition &= 127; /* Optimization of: txposition %= sizeof(buffer); for size 128 */
}
}
El fragmento anterior no contiene protección contra desbordamientos del búfer de entrada y tiene fines ilustrativos (ciertamente, desbordará el búfer de entrada si transmite datos continuamente al UART rápido; su velocidad de datos promedio al UART rápido todavía tiene que ser <= la lenta baudios para hacer posible su tarea), aunque vale la pena señalar que es posible que no necesite ningún tipo de protección adicional si dejar caer ~ sizeof(buffer)
bloques arbitrarios de bytes en un desbordamiento es un comportamiento aceptable. Se eligió un tamaño de búfer de potencia de 2 solo para optimizar la operación del módulo, pero cualquier cosa servirá siempre que su búfer sea lo suficientemente grande para manejar su situación.
gabriel alzate