UART.El módulo
USART es utilizado para comunicación serial con dispositivos periféricos o computadoras, utilizando protocolos tales copmo RS232, RS485, LIN o IrDA. Soporta control de flujo por hardware con los pines
UxCTS y
UxRTS, además incluye decodificación y codificación IrDA.
Las características de este módulo son:
• Full-Duplex, 8 o 9 bits de datos.
• Para datos de 8 bits se puede asignar paridad par, impar o ninguna.
• 1 o 2 bits STOP.
• Auto-Baud Rate.
• Opción de control de flujo mediante hardware, pines UxCTS y UxRTS.
• Generador de baud Rate con preescaler de 16-bits.
• Rango de Baud Rate de 10 Mbps a 38 bps a 40 MIPS.
• Buffer de 4 posiciones FIFO.
• Detección de error de paridad, error de cuadro y error de sobre-escritura.
• Soporte para modo de 9-bits con detección de dirección.
• Modo Loopback, devuelve inmediatamente el carácter recibido.
• Interrupción por transmisión y recepción.
• Codificador y decodificador IrDA.
• Soporte para bus LIN.
Registros de control.Los registros utilizados para el control del módulo UART son:
• UxMODE:
o Habilita o deshabilita modulo UART.
o Habilita o deshabilita codificación y decodificación IrDA.
o Habilita o deshabilita pines UzRTS y UxCTS.
o Configura el modo de operación designado al pin UxRTS.
o Configura la polaridad del pin UxRx.
o Selecciona tipo de baud rate.
o Selecciona número de datos, paridad y bit de Stop.
• UxSTA:
o Selecciona el modo de interrupción de transmisión.
o Selecciona modo de interrupción de recepción.
o Habilita o deshabilita transmisión.
o Controles para modo de detección de direccionamiento.
o Indicadores varios de estado de buffer de transmisión y recepción, y errores.
• UxRXREG:
o Guarda el dato recibido.
• UxTXREG:
o Para cargar datos a transmitir.
• UxBRG:
o Para determinar Baud Rate.
Baud rate.Para determinar el baud rate tenemos 2 opciones, baud rate de alta velocidad BRGH=1 o de baja velocidad. Las ecuaciones asociadas son: (UxBRG de 16-bits)
Configuración de la USART.La
USART usa el formato estándar
NRZ, con un bit de Start, 8 o 9 bits de datos y 1 o 2 bits de Stop. Además tenemos la posibilidad de configurar paridad como par, impar o ninguna. Esto lo configuramos mediante los bits
PDSEL<1:0> y STSEL. (UxMODE)El módulo USART es habilitado mediante el seteo del bit
UARTEN (UxMODE) y el bit
UTXEN (UxSTA). Una vez habilitado, los pines
UxTX y
UxRX son configurados como salida y entrada respectivamente, sustituyendo los valores seteados al TRIS correspondiente.
Para deshabilitar el módulo se debe borrar el bit UARTEN (UxMODE), al deshabilitarlo los pines se comportan con I/O adoptando la configuración del TRIS. Además se borra el buffer, el baud rate se restablece y también todos los bits de estados y errores son reseteados.
Transmisión.El modo de funcionamiento es más o menos similar a las otras familias, difiere en que hay 3 modos de selección de la interrupción:
• UTXISEL<1:0>=00, el bit UxTXIF es seteado cuando un carácter es transferido desde el Buffer al registro UxTSR, esto implica que una posición esta libre en el buffer.
• UTXISEL<1:0>=01, el bit UxTXIF es seteado cuando el ultimo carácter es transferido desde el registro UxTSR, esto implica que todas las operaciones de transmisión han sido completadas.
• UTXISEL<1:0>=10, el bit UxTXIF es seteado cuando el carácter es transferido al registro UxTSR y el buffer de transmisión está vacio.
Pasos a seguir para la transmisión.1. Inicializar Baud Rate cargando el valor apropiado a UxBRG.
2. Setear el numero de bits de datos, numero de bits de Stop y seleccionar paridad.
3. Si se trabajará con interrupciones seleccionar entre los 3 modos de operación, habilitar mediante bit UxTIE y seleccionar nivel de prioridad (UxTXIP<2:0>).
4. Habilitar modulo UART setenado bit UARTEN.
5. Habilitar transmisión setenado el bit UTXEN.
6. El bit UxTXIF debe ser borrado por software en la rutina de servicio de interrupción.
7. Cargar el dato en el registro UxTXREG. Si se ha seleccionado transmisión de 9-bits se debe cargar un Word y sino un byte. Se pueden cargar datos hasta que el bit UxSTA sea seteado a uno indicando buffer lleno.
Recepción.Al igual que el bloque de transmisión, no hay nada de nuevo en el bloque de recepción, el principio de funcionamiento se mantiene. Las interrupciones pueden configurarse de los siguientes modos:
• URXISEL<1:0>=00 o 01. La interrupción es generada cada vez que un dato es transferido desde el registro UxRSR al buffer de recepción. Puede haber uno o más caracteres en el buffer.
• URXISEL<1:0>=10. La interrupción es generada cuando un dato es transferido desde el registro UxRSR al buffer, y como resultado, el buffer tiene 3 de 4 caracteres.
• URXISEL<1:0>=11. La interrupción es generada cuando un dato es transferido desde el registro UxRSR al buffer, y como resultado, el buffer tiene 4 caracteres.
Estos modos pueden ser cambiando durante la operación. Tenemos los bits URXDA y UxRXIF que indican el estado del registro UxRXREG, y el bit RIDLE (UxSTA<4>) que muestra el estado del registro UxRSR. Cuando el registro UxRSR esta vacio, el bit RIDLE está en 1.
Pasos a seguir en la recepción.1. Inicializar Baud Rate.
2. Configurar el número de bits de datos, Stop y determinar paridad.
3. Si se utilizará interrupción determinar el modo mediante los bits URXISEL, habilitar la interrupción mendiante el bit UxRXIE, y establecer prioridad (UxRXIP).
4. Habilitar modulo UART seteando bit UARTEN.
5. Si la interrupción no está habilitada, se debe recibir por poleo mediante el bit URXDA. Si se usa interrupción, el bit UxRXIF debe ser borrado por software.
6. Leer dato desde buffer, si se ha seleccionado trabajar con 9-bits se recibe un Word, sino un byte.
Hay varias otras operaciones que se pueden realizar que dependerán de la aplicación a desarrollar, como transmisión a 9-bits, detectar automáticamente dirección, modo Loopback, auto-Baud Rate, operación con control de flujo mediante hardware, soporte infrarrojo, soporte LIN, ect. cuya información esta bien detallada en el datasheet del dispositivo.
Ejemplo:Configuramos UART1 en 9600:8:N:1 para enviar un texto de inicialización y luego por medio de interrupción capturar dato enviado por PC y luego reenviar el mismo dato. Tambien debemos asignar los pines del periferico, en este caso Rx a RP9 y Tx a RP8.
Configurando bits a bits:
/* ********* UART en C30 *************
\Autor: Suky
\Fecha: 09/01/10
*/
#include <p24hj128gp502.h>
/* ** *********************************************************************************** ** */
_FOSCSEL(IESO_OFF & FNOSC_PRI); // Oscilador primario
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF & POSCMD_XT); // Conmutación de Clock habilitad, Fail-Safe Clock des-habilitado, OSC2 Clout, Cristal XT.
_FWDT(FWDTEN_OFF);// Watchdog des-habilitado.
_FPOR(FPWRT_PWR2);// Power-on Reset 2ms.
/* ** *********************************************************************************** ** */
#include <uart.h>
char DataUART;
char KbhitUART;
/* ** *********************************************************************************** ** */
// Definciones para calculo de Baud Rate.-
#define FCY 40000000 // MHz
#define BAUDRATE 9600
#define BRGHigh 1
#if BRGHigh
#define BRGVAL ((FCY/BAUDRATE)/4)-1
#else
#define BRGVAL ((FCY/BAUDRATE)/16)-1
#endif
/* ** *********************************************************************************** ** */
void __attribute__((__interrupt__, __shadow__)) _U1RXInterrupt(void){
DataUART=getcUART1();
KbhitUART=1;
_U1RXIF=0; // Borramos flag.
}
/* ** *********************************************************************************** ** */
main(void){
const char Texto[]= "Probando comunicación serial...\r\nPIC24HJ128GP502 xD ...\r\n";
// Configuramos PLL para trabajar a 40 MIPS con Cristal de 4MHz.-
PLLFBD = 0x004E; // M=80.
CLKDIV = 0x0000; //N1=2, N2=2.
// Cambiamos clock para incorporar PLL.-
__builtin_write_OSCCONH(0b011); // Indicamos cambio a clock primario con PLL.-
__builtin_write_OSCCONL(0x01); // Iniciamos cambio.-
while(OSCCONbits.OSWEN == 1) {}; // Esperamos a que se termine el cambio de clock.
// Habilitamos escritura sobre registros RPINRx y RPORX.
__builtin_write_OSCCONL(OSCCON & ~(0x40));
RPINR18bits.U1RXR = 9; //Asignamos pin recepción UART1 a RP9.-
RPOR4bits. RP8R = 0b00011; // Asignamos RP8 al pin de transmisión UART1.
// Bloqueamos escritura sobre registros RPINRx y RPORX.
__builtin_write_OSCCONL(OSCCON |0x40);
U1MODEbits.USIDL=1; // Al pasar al modo Sleep, apagar modulo.
U1MODEbits.IREN=0; // Codificacion/decodificacion IrDA deshabilitado.
U1MODEbits.RTSMD=1; // RTS en modo simple.
U1MODEbits.UEN=0b00; // Tx/Rx habilitado, CTS/RTS deshabilitados.
U1MODEbits.WAKE=0; // Wake-up deshabilitado.
U1MODEbits.LPBACK=0; // Modo LoopBack deshabilitado.
U1MODEbits.ABAUD=0; // Auto-Baud rate deshabilitado.
U1MODEbits.URXINV=0; // Modo normal de pin RX, en reposo = 1.
U1MODEbits.BRGH=BRGHigh; // Mode seleccionado en define.-
U1MODEbits.PDSEL=0b00; // 8 bits- sin paridad.
U1MODEbits.STSEL=0; // 1 bit de Stop.
U1STAbits.UTXISEL1=1; // Interrupcion por transimision no usada.
U1STAbits.UTXISEL0=1; // Interrupcion por transimision no usada.
U1STAbits.UTXINV=0; // Pin Tx en reposo igual a 1.
U1STAbits.UTXBRK=0; // Break deshabilitado.
U1STAbits.URXISEL=0b00; // Interrumpir cuando se recibe un caracter.
U1STAbits.ADDEN=0; // Auto-Address deshabilitado.
U1STAbits.OERR=0; // Borramos bits de error por overflow.
U1BRG =BRGVAL; // Baud Rate determinado en defines.
IPC2bits.U1RXIP=0b01; // Fijamos nivel de prioridad.
IFS0bits.U1RXIF=0; // Borramos flag.
IEC0bits.U1RXIE=1; // habilitamos interrupcion por recepción.
U1MODEbits.UARTEN=1;// Encendemos modulo.
U1STAbits.UTXEN=1; // Transmision habilitada.
KbhitUART=0;
putsUART1(Texto);
while(1){
if(KbhitUART==1){
KbhitUART=0;
putcUART1(DataUART);
}
}
}
Para el control de UART C30 dispone de la librería uart.h la cual tiene las siguientes funciones:
• BusyUARTx
• CloseUARTx
• ConfigIntUARTx
• DataRdyUARTx
• getsUARTx
• OpenUARTx [dsPIC30F]
• OpenUARTx [dsPIC33F/PIC24H]
• putsUARTx
• ReadUARTx o getcUARTx
• WriteUARTx o putcUARTx
/* ********* UART en C30 *************
\Autor: Suky
\Fecha: 09/01/10
*/
#include <p24hj128gp502.h>
/* ** *********************************************************************************** ** */
_FOSCSEL(IESO_OFF & FNOSC_PRI); // Oscilador primario
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF & POSCMD_XT); // Conmutación de Clock habilitad, Fail-Safe Clock des-habilitado, OSC2 Clout, Cristal XT.
_FWDT(FWDTEN_OFF);// Watchdog des-habilitado.
_FPOR(FPWRT_PWR2);// Power-on Reset 2ms.
/* ** *********************************************************************************** ** */
#include <uart.h>
char DataUART;
char KbhitUART;
/* ** *********************************************************************************** ** */
// Definciones para calculo de Baud Rate.-
#define FCY 40000000 // MHz
#define BAUDRATE 9600
#define BRGHigh 1
#if BRGHigh
#define BRGVAL ((FCY/BAUDRATE)/4)-1
#else
#define BRGVAL ((FCY/BAUDRATE)/16)-1
#endif
/* ** *********************************************************************************** ** */
void __attribute__((__interrupt__, __shadow__)) _U1RXInterrupt(void){
DataUART=getcUART1();
KbhitUART=1;
_U1RXIF=0; // Borramos flag.
}
/* ** *********************************************************************************** ** */
main(void){
const char Texto[]= "Probando comunicación serial...\r\nPIC24HJ128GP502 xD ...\r\n";
// Configuramos PLL para trabajar a 40 MIPS con Cristal de 4MHz.-
PLLFBD = 0x004E; // M=80.
CLKDIV = 0x0000; //N1=2, N2=2.
// Cambiamos clock para incorporar PLL.-
__builtin_write_OSCCONH(0b011); // Indicamos cambio a clock primario con PLL.-
__builtin_write_OSCCONL(0x01); // Iniciamos cambio.-
while(OSCCONbits.OSWEN == 1) {}; // Esperamos a que se termine el cambio de clock.
// Habilitamos escritura sobre registros RPINRx y RPORX.
__builtin_write_OSCCONL(OSCCON & ~(0x40));
RPINR18bits.U1RXR = 9; //Asignamos pin recepción UART1 a RP9.-
RPOR4bits. RP8R = 0b00011; // Asignamos RP8 al pin de transmisión UART1.
// Bloqueamos escritura sobre registros RPINRx y RPORX.
__builtin_write_OSCCONL(OSCCON |0x40);
/* ** Utilizando las funciones definidas en C30 ** */
OpenUART1(UART_EN & UART_IDLE_STOP & UART_IrDA_DISABLE & UART_MODE_SIMPLEX &
UART_UEN_00 & UART_DIS_WAKE & UART_DIS_LOOPBACK & UART_UXRX_IDLE_ONE &
UART_DIS_ABAUD & UART_NO_PAR_8BIT & UART_BRGH_FOUR & UART_1STOPBIT,
UART_INT_TX & UART_IrDA_POL_INV_ZERO & UART_SYNC_BREAK_DISABLED &
UART_TX_ENABLE & UART_INT_RX_CHAR & UART_ADR_DETECT_DIS & UART_RX_OVERRUN_CLEAR,
BRGVAL);
SetPriorityIntU1RX(1);
EnableIntU1RX;
KbhitUART=0;
putsUART1(Texto);
while(1){
if(KbhitUART==1){
KbhitUART=0;
putcUART1(DataUART);
}
}
}
Uso del printf en C30.Para utilizar printf en nuestros proyectos se debe agregar la librería
stdio.h, pero además se debe inicializar el
Heap Size, yendo a
Project/Buil Options/Project, y en la solapa
MPLAB LINK30 llenar el campo, yo he colocado 256. Este tips me lo ha dado el compañero
Nocturno.