DESCRIPCIÓN
La comunicación UART puede transmitir o recibir datos bit a bit, es por eso que recibe el nombre de comunicación serial, entre dos microcontroladores o también hacia un computador. La conexión a la PC es bajo el estándar de comunicación RS232, En esta sección se explicaran a detalle todos los registros involucrados con este tipo de comunicación y se realizaran ejemplos prácticos. A continuación se describen las características de este módulo UART.
- Operación Síncrona y Asíncrona.
- Operación Full Dúplex en modo Asíncrono.
- Operación Half Dúplex en operación Síncrona Maestro-Esclavo.
- Operación de 8 o 9 bits.
- Generador de Baud-Rate de Alta y Baja
- Calibración Automática de Velocidad de Baudios.
- Detección Automática de Recepción de datos.
- Detección de errores de OverRun y Frame (datos sobrescritos y dato invalido respectivamente).
- 2 Interrupciones independientes; TX completado, RX completado.
En las siguientes imágenes se detallaran los registros involucrados al UART
CONFIGURAR BAUD-RATE
Para una correcta Transmisión/Recepción y sin pérdida de datos, es necesario configurar correctamente el Baud-Rate a través de los registros SPBRGH y SPBRG. En la siguiente tabla se muestra las ecuaciones para los modos Síncronos y Asíncronos.
Vamos a realizar un ejemplo para despejar un poco nuestras dudas. Si tenemos una Fosc=48Mhz y queremos unos Baudios de 9600 bps. Calcularemos el valor que debemos escribir en el registro SPBRG en modo 8 bits y baja Velocidad; BRG=0 y BRG16=0, con la fórmula vista anteriormente.
Como podemos apreciar el resultado no es exacto, esto nos lleva a calcular el error con la siguiente ecuación.
A continuación se explicarán los PASOS para la Transmisión/Recepción de datos a través de la USART
- Configurar las líneas pin RX y pin TX como entrada y salida respectivamente, a través del registro TRISC.
- Configurar el modo Síncrono o Asíncrono.
- Configurar el Baud-Rate del USART a través del registro UBRRH y
- Configurar Tamaño de byte 8/9 bits.
- Habilitar la Transmisión y Recepción a través de los bits TXEN y RCEN respectivamente.
- Habilitar la Interrupción de Transmisión/Recepción a través de los bits TXIE y RCIE respectivamente (opcional).
PROCESO DE TRANSMISIÓN DE DATOS
Para enviar un dato no basta con escribir el valor que se desea enviar en el registro TXREG. Sin embargo, si se quiere enviar varios datos consecutivos debe tenerse cuidado de NO escribir un nuevo valor en TXREG antes de que el valor anterior haya sido enviado. Para ello es necesario saber si el registro TXREG ha quedado libre o está vacío. Esto puede hacerse de 2 formas.
- Por Sondeo: En este caso el programa debe monitorizar el estado del bit TXIF. Si este bit está a “1” significa que TXREG está vacío y por tanto podemos escribir el siguiente dato.
- Por Interrupción: En este caso se habilita la Interrupción a través del bit TXIE, entonces se producirá una interrupción cada vez que el registro TXREG esté vacío. Por tanto esto nos permite detectar cuando TXREG está libre para enviar un nuevo dato, sin embargo si habilitamos dicha Interrupción cuando NO estamos Transmitiendo datos se generarán Interrupciones continuas mientras TXREG este vacío. Por tanto solo se debe habilitar esta Interrupción después de haber escrito un nuevo dato en el registro TXREG y se deshabilitará cuando se ha escrito el ultimo
PROCESO DE RECPCIÓN DE DATOS
Para recibir un dato no basta con leer el valor en el registro RCREG, es necesario esperar a que la recepción del dato se haya completado correctamente para poder realizar el proceso de lectura del registro. Esto puede hacerse de 2 formas.
- Por Sondeo: En este caso el programa debe monitorizar el estado del bit RCIF. Si este bit está a “1” significa que el dato recibido podrá ser leído del registro RCREG.
- Por Interrupción: En este caso se habilita la Interrupción a través del bit RCIE, entonces se producirá una interrupción cada vez que el registro RCREG posea un nuevo Por tanto esto nos permite detectar cuando RCREG está listo para ser leído.
EJEMPLO N°1 – COMUNICACIÓN UART PIC18F4550 CON COMPUTADOR
En este ejemplo enviaran datos del controlador pic18f4550 hacia el computador a través del protocolo de comunicación RS232, utilizaremos como interfaz el driver MAX232 (datasheet). Primero, utilizaremos el pic18f4550 solo como transmisor y pode ende solo configuramos el pin RC6 como salida de datos serial. Luego, los baudios sera igual a 9600 que es apropiado trabajo con el oscilador interno Fosc = 8mhz. Por ultimo, los datos a enviar serán una secuencia de caracteres igual a 0123456789... A continuación se muestra el circuito de conexión y se describe el código.
Código principal MAIN
#define _XTAL_FREQ 8000000L
#include
#include "fuses.h"
#define BAUD 9600
unsigned char var = '0';
void main(void) {
//Configura Fosc = 8Mhz interno
OSCCONbits.IRCF = 0b111; //Configura oscilador interno (FOSC = 8Mhz)
OSCCONbits.SCS = 0b10; // Fuente de Fosc del sistema = interno
//Configura UART a 9600 baudios
TRISCbits.RC6 = 0; // Pin RC6 como salida digital para TX.
TXSTAbits.TX9 = 0; // Modo-8bits.
TXSTAbits.TXEN = 1; // Habilita Transmisión.
TXSTAbits.SYNC = 0; // Modo-Asíncrono.
TXSTAbits.BRGH = 0; // Modo-Baja Velocidad de Baudios.
BAUDCONbits.BRG16 = 0; // Baudios modo-8bits.
RCSTAbits.SPEN = 1; // Hbilita el Módulo SSP como UART.
// Escribe el valor necesario para configurar los Baudios a 9600.
SPBRG = (unsigned char) (((_XTAL_FREQ / BAUD) / 64) - 1);
while (1) {
// espera a que el registro de transmisión este disponible o vacio.
while (!TXSTAbits.TRMT) {
}
// escribe el dato que se enviará a través de TX.
TXREG = var;
LATCbits.LATC0 = !PORTCbits.RC0;
if (++var > 122) { // 0,1,2,3,4.......
while (!TXSTAbits.TRMT) {
}
TXREG = 13;
var = 48;
}
__delay_ms(100);
}
}
EJEMPLO N°2 – ENVIAR DATOS DEL SENSOR TEMPERATURA LM35 HACIA UN COMPUTADOR
En este siguiente ejemplo se enviarán los datos leídos del sensor de temperatura LM35, que estará conectado al pin RA0 hacia un computador, se utilizara el protocolo de comunicación RS232 y la misma configuración del ejemplo anterior. La secuencia de datos a enviar sera igual a la siguiente «temp = xxx grados», como se puede apreciar primero se enviarán una serie de caracteres y luego el valor de temperatura. A continuación se muestra el circuito de conexión y se describe el código.
Código principal MAIN
#define _XTAL_FREQ 8000000L
#include
#include "fuses.h"
char buffer_TX[] = "Temp: xxx grados\r";
int value_adc;
double temp;
char lm35;
void main(void) {
//Configura Fosc = 8Mhz interno
OSCCONbits.IRCF = 0b111; //Configura oscilador interno (FOSC = 8Mhz)
OSCCONbits.SCS = 0b10; // Fuente de Fosc del sistema = interno
//Configura UART a 9600 baudios
TRISCbits.RC6 = 0; // Pin RC6 como salida digital para TX.
TXSTAbits.TX9 = 0; // Modo-8bits.
TXSTAbits.TXEN = 1; // Habilita Transmisión.
TXSTAbits.SYNC = 0; // Modo-Asíncrono.
TXSTAbits.BRGH = 0; // Modo-Baja Velocidad de Baudios.
BAUDCONbits.BRG16 = 0; // Baudios modo-8bits.
RCSTAbits.SPEN = 1; // Hbilita el Módulo SSP como UART.
SPBRG = (unsigned char) (((_XTAL_FREQ / 9600) / 64) - 1); //baudios = 9600
//ADC = 10bits, Tad = 1us, Tacq = 4us, Vref = 5v-0v, RA=ANALOG
ADCON1bits.PCFG = 0b1110; // Configura el Puerto como Entrada Analógica.
ADCON1bits.VCFG = 0b00; // Selecciona Voltajes de Referencia (5v-0v).
ADCON0bits.CHS = 0b0000; // Selecciona el Canal Analógico.
ADCON2bits.ACQT = 0b010; // Tiempo de Adquisición 4Tad.
ADCON2bits.ADCS = 0b001; // Tiempo de Conversión Fosc/8.
ADCON2bits.ADFM = 1; // Justificación derecha (modo-10bits).
ADCON0bits.ADON = 1; // Habilita el Módulo AD.
while (1) {
//Inicia el proceso de conversión ADC.
ADCON0bits.GO_DONE = 1; //Inicia la COnversió AD.
while (ADCON0bits.GO_DONE); // Espera a que termine la conversión AD.
value_adc = ADRESH; // Lectura de valor AD.
value_adc = (value_adc << 8) + ADRESL;
temp = value_adc;
temp = (temp * 500.0) / 1023.0;
lm35 = (char) temp;
buffer_TX[6] = (lm35 / 100) + '0';
buffer_TX[7] = (lm35 % 100) / 10 + '0';
buffer_TX[8] = (lm35 % 100) % 10 + '0';
//Inicia el proceso de transmisión TX.
for (int i = 0; i < 17; i++) {
// espera a que el registro de transmisión este disponible o vacio.
while (!TXSTAbits.TRMT) {
}
// escribe el dato que se enviará a través de TX.
TXREG = buffer_TX[i];
}
__delay_ms(100);
}
}
Código FUSES
// CONFIG1L
#pragma config PLLDIV = 1 // PLL Prescaler Selection bits (No prescale (4 MHz oscillator input drives PLL directly))
#pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2])
#pragma config USBDIV = 1 // USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1) (USB clock source comes directly from the primary oscillator block with no postscale)
// CONFIG1H
#pragma config FOSC = INTOSCIO_EC// Oscillator Selection bits (Internal oscillator, port function on RA6, EC used by USB (INTIO))
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = ON // Internal/External Oscillator Switchover bit (Oscillator Switchover mode enabled)
// CONFIG2L
#pragma config PWRT = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOR = OFF // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config BORV = 3 // Brown-out Reset Voltage bits (Minimum setting 2.05V)
#pragma config VREGEN = OFF // USB Voltage Regulator Enable bit (USB voltage regulator disabled)
// CONFIG2H
#pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)
// CONFIG3H
#pragma config CCP2MX = ON // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = OFF // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config LPT1OSC = OFF // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = OFF // MCLR Pin Enable bit (RE3 input pin enabled; MCLR pin disabled)
// CONFIG4L
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config ICPRT = OFF // Dedicated In-Circuit Debug/Programming Port (ICPORT) Enable bit (ICPORT disabled)
#pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))
// CONFIG5L
#pragma config CP0 = OFF // Code Protection bit (Block 0 (000800-001FFFh) is not code-protected)
#pragma config CP1 = OFF // Code Protection bit (Block 1 (002000-003FFFh) is not code-protected)
#pragma config CP2 = OFF // Code Protection bit (Block 2 (004000-005FFFh) is not code-protected)
#pragma config CP3 = OFF // Code Protection bit (Block 3 (006000-007FFFh) is not code-protected)
// CONFIG5H
#pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-0007FFh) is not code-protected)
#pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM is not code-protected)
// CONFIG6L
#pragma config WRT0 = OFF // Write Protection bit (Block 0 (000800-001FFFh) is not write-protected)
#pragma config WRT1 = OFF // Write Protection bit (Block 1 (002000-003FFFh) is not write-protected)
#pragma config WRT2 = OFF // Write Protection bit (Block 2 (004000-005FFFh) is not write-protected)
#pragma config WRT3 = OFF // Write Protection bit (Block 3 (006000-007FFFh) is not write-protected)
// CONFIG6H
#pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) are not write-protected)
#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot block (000000-0007FFh) is not write-protected)
#pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM is not write-protected)
// CONFIG7L
#pragma config EBTR0 = OFF // Table Read Protection bit (Block 0 (000800-001FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF // Table Read Protection bit (Block 1 (002000-003FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF // Table Read Protection bit (Block 2 (004000-005FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF // Table Read Protection bit (Block 3 (006000-007FFFh) is not protected from table reads executed in other blocks)
// CONFIG7H
#pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) is not protected from table reads executed in other blocks)
EmerXd
Una pergunta, este metodo de comunicación se puede utilizar con los pines C4 y C5? ya que no hay manera de hacer que estos pines se utilicen como salida, hablando del PIC18F4550, o si conoce algun otro metodo para usarlos como salidas. Saludos.
admin
Hola estimado, si puede conectarlos a los pines RC4 y RC5. Previamente debe deshabilitar el modulo USB y configurar los pines como IO digitales.