Cambio dinámico en la directiva #use RS232

Buenas a todos!, quisiera saber si se puede modificar los parametros del puerto serial rs232 en un pic en forma dinamica, (PIC18F4550, compilador CCS), por ejemplo, al iniciar el programa la instruccion por defecto seria la siguiente:
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,errors),
y por medio de una interrupcion externa cambiar los parametros de comunicacion, por ejemplo a:
#use rs232(baud=115200,parity=E,xmit=PIN_C6,rcv=PIN_C7,bits=8,errors), bueno y no solo la velocidad, sino tambien la paridad.
Lo he intentado pero al ejecutarlo se interrumpe cualquier comunicacion serial y es necesario reiniciar el microcontrolador de forma fisica
Muchas gracias. ...
 
Ambas partes tienen que cambiar a la vez, claro. Eso hay que sincronizarlo de algún modo.

Pero eso es un sistema bastante común en muchos equipos; ambas partes "hablan" a una velocidad universalmente admitida y se cambian a alta velocidad acorde a ambas partes.
Por ejemplo el protocolo de las SD es algo así; la tarjeta se inicializa a baja velocidad común a todas y luego se pasa a alta velocidad si ambas partes se ponen de acuerdo.

Si tu equipo no es "universal" lo logico es que desde el proincipio plantees a que velocidad te interesa ir y ya está.
Hace tiempo que no hago nada serio pero nunca he tenido problemas por ponerlo "a tope" desde el principio. (enlace local de 1m de cable)
 
Scooter dijo:
Supongo que sirve para cambiar la configuración en caliente. Si no hubiera ayuda por parte del compilador siempre se podrán ajustar los registros "a mano" a mitad del programa, eso si, sería trabajoso y poco 'legible' el código.
Así es, esa instrucción sirve para cambiar la velocidad en tiempo real.
Y sí, también se pueden modificar los registros.
dladystarlight dijo:
¿Alguien lo ha probado alguna vez? ¿No hay riesgo de pérdida de comunicación?
Pregunto desde la ignorancia, alguna vez lo pensé pero jamás me puse a probarlo.
Si funciona y también lo he probado, aunque no le he encontrado utilidad por el momento.
Ya que una vez comunicados los dispositivos, no veo razón de cambiar los parámetros del UART.

Aquí un ejemplo con un PIC pequeño, pero con EUSART:
PHP:
#include <12f1840.h>

#use delay (internal = 32 MHz)

#use RS232 (UART1)    // 9600, N, 8, 1

int8 dato;

int1 flag_rx = 0, flag_timer1 = 1;    // "flag_timer1" en 1 para mostrar el mensaje al inicio.


#INT_RDA
void sdi_rx_usart (void)
{
    dato = getc();
    
    flag_rx = 1;
}

#INT_TIMER1
void sdi_desborde_timer1 (void)
{    
    static int16 ticks_t1 = 0;
    
    if (++ticks_t1 > 0x1F3)    // 5 segundos.
    {
        flag_timer1 = 1;
        ticks_t1 = 0;
    }
    
    set_timer1(0xB1E0);
}

void main (void)
{
    enable_interrupts (INT_RDA);
    // Desborde del Timer 1 cada 10 mS @ 8 MHz.
    setup_timer_1(T1_INTERNAL|T1_DIV_BY_4);
    set_timer1(0xB1E0);
    enable_interrupts(INT_TIMER1);
    enable_interrupts (GLOBAL);
    
    while (TRUE)
    {
        if (flag_rx)
        {
            switch (dato)
            {
                case '0':
                    puts("HW USART a 1200 Bps.\r\n");
                    setup_uart(1200);
                    break;
                case '1':
                    puts("HW USART a 2400 Bps.\r\n");
                    setup_uart(2400);
                    break;
                case '2':
                    puts("HW USART a 4800 Bps.\r\n");
                    setup_uart(4800);
                    break;
                case '3':
                    puts("HW USART a 9600 Bps.\r\n");
                    setup_uart(9600);
                    break;
                case '4':
                    puts("HW USART a 14400 Bps.\r\n");
                    setup_uart(14400);
                    break;
                case '5':
                    puts("HW USART a 19200 Bps.\r\n");
                    setup_uart(19200);
                    break;
                case '6':
                    puts("HW USART a 28800 Bps.\r\n");
                    setup_uart(28800);
                    break;
                case '7':
                    puts("HW USART a 38400 Bps.\r\n");
                    setup_uart(38400);
                    break;
                case '8':
                    puts("HW USART a 57600 Bps.\r\n");
                    setup_uart(57600);
                    break;
                case '9':
                    puts("HW USART a 115200 Bps.\r\n");
                    setup_uart(115200);
            }
            flag_rx = 0;
        }
        
        if (flag_timer1)
        {    // Mostrar un mensaje cada 5 segundos.
            puts("Hola Mundo\r\nHello World\r\n");
            flag_timer1 = 0;
        }
    }
}
Como se puede ver, primero se envía el mensaje de cambio de baudrate, porque por lógica, si se establece primero el baudrate, el mensaje ya no sería legible para el receptor.
 
Última edición:
El uso podría ser que mantengas una línea de equipos desde hace años y no todo el mundo tenga el mismo terminal o los mismos equipos.
Se empieza la comunicación digamos a 9600 que es común a todos y si se ponen de acuerdo equipo y terminal pasan a una más alta para que sea más rápido.. eso y que tengas que transferir bloques grandes de datos por los que merezca la pena hacer todo este embrollo. Sí son cuatro comandos no ganas nada subiendo la velocidad.
 
Algunos PIC cuentan con EUSART (E = Enhanced "Mejorado") y tienen la característica de poder auto detectar el baudrate.
En el PIC18F4550 se encuentra en el registro BAUDCON (Baud Control)
Bit 0 = ABDEN (Auto-Baud Detect Enable bit)
La hoja de datos dijo:
ABDEN: Auto-Baud Detect Enable bit
Asynchronous mode:
1 = Enable baud rate measurement on the next character.
Requires reception of a Sync field (55h); cleared in hardware upon completion.
0 = Baud rate measurement disabled or completed.
Synchronous mode:
Unused in this mode.
Nunca he probado esta característica, pero parece una mejor opción.
 
Algunos PIC cuentan con EUSART (E = Enhanced "Mejorado") y tienen la característica de poder auto detectar el baudrate.
En el PIC18F4550 se encuentra en el registro BAUDCON (Baud Control)
Bit 0 = ABDEN (Auto-Baud Detect Enable bit)

Nunca he probado esta característica, pero parece una mejor opción.

Eso lo he visto hacer por soft, vi algún código pero la verdad es que no hice caso.
Si lo hace el hard, mejor que mejor.
 
Eso lo he visto hacer por soft, vi algún código pero la verdad es que no hice caso.
Sí, es que no es algo que se use comúnmente.
Supongo que la detección por software debe ser similar a la recuperación del valor de OSCCAL.
Si lo hace el hard, mejor que mejor.
Pues sí, es una ventaja pero tiene sus inconvenientes.
El proceso de auto detección no es permanente, se ejecuta únicamente cuando se escribe el bit ABDEN con 1.
Para la detección es necesario enviar el carácter U mayúscula (0x55)
Si no se realiza correctamente el proceso, el microcontrolador queda incomunicado hasta un reset.
Después del reset el sistema inicia con el baudrate definido por software.
Y no es conveniente que el microcontrolador se inicie con auto detección, porque siempre se tendrá que enviar el carácter de detección "U" al inicio.

Realicé una prueba con este código:
PHP:
#include <12f1840.h>

#use delay (internal = 32 MHz)

#use RS232 (UART1)    // Por defecto HW: 9600, 8, N, 1

int8 dato_rx;

#INT_RDA
void sdi_rx_eusart (void)
{
	dato_rx = getc();
   	
	putc(dato_rx);
   	
	// Si se recibe el carácter %, establecer el Auto-Baud Detect. (ABDEN = 1)
	// El bit 0 (ABDEN) del registro BAUDCON se pondrá en 0 cuando se logre la detección del baudrate.
	// La auto detección se lleva a cabo enviando el carácter U mayúscula = 0x55.
	if (dato_rx == '%') setup_uart (UART_AUTODETECT);
}
   	

void main (void)
{
	enable_interrupts (INT_RDA);
	enable_interrupts (GLOBAL);
   	
	while (TRUE);
}
Funciona perfectamente, pero teniendo cuidado de no enviar algo después de establecer la detección.
Después de establecer la auto detección se debe cambiar el baudrate y enviar la U.
Tras esto el microcontrolador ya está listo para comunicarse con el nuevo baudrate.
Probé desde 300 Bps (Más bajo no funciona) hasta 256000 Bps y todo OK.

Usé este PIC pequeño 12F1840 para probar, pero con cualquier otro con EUSART debe funcionar.
 
Hola a todos, gracias por sus respuestas, y gracias D@rkbytes, recien probe la instruccion que aconsejaste. He hecho pruebas con la modificacion de la velocidad dinamicamente y si funciona, lo que tengo en el codigo es lo siguiente:
if(Tecla2 == 0x02)
{
setup_uart(38400);
}
else if(Tecla2 == 0x45)
{
setup_uart(9600);
}

Ahora esto si modifica la velocidad del puerto, pero ademas estaba necesitando la modificacion de la paridad, entonces viendo la ayuda de CCS, vi que esta instruccion acepta algunos otros parametros, como:

setup_uart(baud, stream)
setup_uart(baud)
setup_uart(baud, stream, clock)

Donde en ninguno se podria cambiar la paridad, asi como de el tamanio de datos y los bits de stop, asi que en la directiva inicial de #use RS232, puse lo sigiuente:

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,errors,stream = UART_NO_PARIDAD)
#use rs232(baud=9600,parity=E,xmit=PIN_C6,rcv=PIN_C7,bits=8,errors,stream = UART_EVEN_PARIDAD)

con lo cual ya pude mandar a la instruccion setup_uart(baud, stream) el stream correspondiente, lo probe durante un dia completo con un simulador que cambia los parametros de envio y recepcion de forma constante y todo esta funcionando, y las intrucciones quedaron asi:

if(Tecla2 == 0x02)
{
setup_uart(38400, UART_NO_PARIDAD);
}
else if(Tecla2 == 0x45)
{
setup_uart(9600, UART_EVEN_PARIDAD);
}

Si hay alguna observacion por favor estare pendiente a sus respuestas, gracias por su colaboracion,
 
¿Y cómo es que recibes y transmites usando dos streams?
Ya que cada cambio de stream también requiere cambiar el modo de recepción y transmisión.

Y tienes dos posibles modos...
fgetc(UART_NO_PARIDAD);
fputc(dato, UART_NO_PARIDAD);
/*************************************/
fgetc(UART_EVEN_PARIDAD);
fputc(dato, UART_EVEN_PARIDAD);

Entonces también tendrías que identificar en qué modo se encuentra.
 
Atrás
Arriba