Comunicación usando el puerto serie



1. Introducción:

 El puerto serie es una interfaz de comunicación que transmite la información bit a bit. Es un sistema que se lleva usando muchos años y nos será muy útil para hacer "debug" o monitorización de nuestra aplicación.

 La comunicación serie puede ser compleja, pero nosotros vamos a realizar una comunicación más sencilla usando los pines RX y TX. Para que la comunicación funcione, debemos llevar una referencia de nivel de señal; para esto, debemos unir las Gnd de ambos interlocutores.

 La comunicación serie estándar, usa niveles de tensión en torno a +-12Vcc. Los uControladores no soportan estos niveles directamente por lo tanto, para poder comunicar un uControlador con un elemento estándar, debemos adaptar los niveles y para esto se usan integrados como el MAX3232. Este integrado ya viene montado en nuestra placa.

Si quisiésemos comunicar dos uControladores directamente, podríamos conectarlos sin este integrado ya que ambos funcionan con niveles TTL.

 El estándar RS232 está definido para trabajar a corta distancia (15m como máximo). Si quisiéramos alcanzar más, podríamos usar un RS485 que permite distancias mayores a 1Km. Para esto, cambiaríamos el MAX3232 por el MAX485 y necesitamos un pin del uControlador como control.




2. Conexiones:


 Como podemos observar, los pines usados para la comunicación serie son RC7 como RX (línea recepción datos) y RC6 como TX (línea transmisión datos). Estas líneas deben ir cruzadas; es decir, RX nodo1 con TX nodo2 y TX nodo1 con RX nodo2.

 Nuestra placa en el conector DB9 tiene TX en el pin 2, RX en el pin 3 y Gnd en el pin 5. Para conectar directamente al PC, usaremos un cable macho-hembra pin a pin (sin cruzar ya que el puerto de salida de la placa es hembra y conecta con un puerto macho en el pc).

En caso de no disponer de puerto serie en el PC, usaremos un conversor USB-RS232:


Nota: El sistema reconocerá el puerto como un puerto COM.


3. Librerías:

 Inicialmente revisamos las librerías existentes en el directorio MLA, pero tienen funciones muy simples; entonces buscando información vamos construyendo otras.
La comunicación a realizar, no se basará en interrupciones, sino que habrá que consultar el estado periódicamente.

3.1. Registros a configurar:




3.2. Configuración de los registros:

 Usando la _XTAL_FREQ y MULTIPLIER, despejamos el BAUD:


3.3. Usart.h:

					
/********************************************************************
*                   LIBRERIA USO USART
* 
*   - Funciones para transmision y recepcion de caracteres
 *******************************************************************/

#ifndef USART_H
#define USART_H

#include 
#include "config.h"
#include 

#define GetSystemClock() _XTAL_FREQ     //Indica la frecuencia del micro para calcular el baud rate

#define UART_TRISTx   TRISCbits.TRISC6  //Indica los pines de RX y TX
#define UART_TRISRx   TRISCbits.TRISC7
#define UART_Tx       PORTCbits.RC6
#define UART_Rx       PORTCbits.RC7
#define BAUD          19200             //Indica la frecuencia para la comunicacion
#define MULTIPLIER 16UL                 //Indica el multiplicador 64UL, 16UL or 4UL
#define HIGH_SPEED 1                    //Indica el BRGH. Segun la velocidad necesitamos h o l. Ver datasheet



//The two registers that control the USART are RCSTA and TXSTA, which are mnemonics 
//for "receive status" and "transmit status".
    
//Setting SPEN = 1 enables the serial port, setting CREN = 1 enables (continuous) reception, 
//and setting TXEN = 1 enables transmitting.
    
//RCSTA = 0b10010000; // 0x90 (SPEN RX9 SREN CREN ADEN FERR OERR RX9D)
//TXSTA = 0b00100000; // 0x20 (CSRC TX9 TXEN SYNC - BRGH TRMT TX9D)

#define UART_ENABLE   RCSTAbits.SPEN
#define UART_RECEP_ENABLE   RCSTAbits.CREN
#define UART_TRANS_ENABLE   TXSTAbits.TXEN
#define UART_RCSTA RCSTA1
#define UART_TXSTA TXSTA1
#define RCSTA_DEFAULT 0x90
#define TXSTA_DEFAULT 0x20


//Baud rate generator
//To set the baud rate, you will need to set the SPBRG register to a "divider" value 
    
//Low speed (BRGH=0): Baud Rate = Fosc / (64(X+1))
//High speed (BRGH=1): Baud Rate = Fosc / (16(X+1))
#define SPBRG   SPBRG1


#define RCIF          RC1IF     //Bandera que indica recepcion
#define TXIF          TX1IF     //Bandera que indica registro vacio



/******************************************************************************
*                       CONFIGURACION DEL PUERTO
* 
*   - Realiza la inicialización del puerto segun los valores anteriores
 *****************************************************************************/
void USART_Initialize();

/******************************************************************************
*                       ESCRIBIR CARACTER
* 
*   - Funcion que transmite un caracter cuando el buffer de salida esta libre
*   - La función "printf" llama por defecto a la funcion putch  
 *****************************************************************************/
void USART_putcUSART(char c);
void putch (char c);


/******************************************************************************
*                       ESTADO BUFFER SALIDA
* 
*   -  Función que devuelve el estado del buffer de salida
*      TRUE: Libre,  FALSE: Ocupado 
 *****************************************************************************/
bool UART_TX_Empty(void);


/******************************************************************************
*                       ESCRIBIR FRASE
* 
*   - Funcion encargada de escribir caracteres contenidos en un array usando
*     la función USART_putcUSART 
 *****************************************************************************/
void UART_Write_Text(char *text);


/******************************************************************************
*                       RECIBIDO ALGO
* 
*   - Funcion que devuelve el estado del buffer de entrada 
*     TRUE: Libre,  FALSE: Ocupado 
 *****************************************************************************/
bool UART_Data_Ready(void);


/******************************************************************************
*                       LEER CARACTER
* 
*   - Funcion que devuelve el caracter leido del buffer de entrada 
 *****************************************************************************/
unsigned char USART_getcUSART(void);


/******************************************************************************
*                       LEER CARACTER O ESPERAR CARACTER
* 
*   - Funcion que devuelve el caracter leido del buffer de entrada 
*   - Esta funcion se diferencia de la anterior que espera si no hay nada en
*     el buffer. Cuando lo reciba lo devuelve.  
 *****************************************************************************/
unsigned char USART_getcUSART2 (void);


/******************************************************************************
*                       LEER GRUPO DE CARACTERES
* 
*   - Funcion que guarda en un array el contenido del buffer de entrada
*   - Usa la funcion que espera por caracter en buffer y no termina hasta que 
*     haya completado el array. 
 *****************************************************************************/
void USART_ReadString(char *Output, unsigned int length);


/******************************************************************************
*                       LEER GRUPO DE CARACTERES
* 
*   - Funcion que guarda en un array el contenido del buffer de entrada
*   - Usa la funcion que espera por caracter en buffer y no termina hasta que 
*     encuentre el caracter fin de linea '\n'
 *****************************************************************************/
void USART_ReadString2(char *Output);



#endif //USART_H
 


3.4. Usart.c:


/********************************************************************
*                   LIBRERIA USO USART
* 
*   - Funciones para transmision y recepcion de caracteres
 *******************************************************************/

#include "usart.h"
#include 
#include 


/******************************************************************************
*                       CONFIGURACION DEL PUERTO
* 
*   - Realiza la inicialización del puerto según los defines de usart.h
 *****************************************************************************/

void USART_Initialize()
{
    
UART_TRISTx = 1;        //Configura TX como entrada
UART_TRISRx = 1;        //Configura RX como entrada - Inicialmente se configura como entrada
    
UART_ENABLE = 1;        //Habilita la comunicacion serie
UART_RECEP_ENABLE = 1;  //Habilita la recepcion serie continua
UART_TRANS_ENABLE = 1;  //Habilita la transmision serie
         
SPBRG = ((int)(_XTAL_FREQ/(MULTIPLIER * BAUD) -1)); //Inicializa el registro según los 
                                                    //parametros de usart.h


if (HIGH_SPEED == 1)
{
    RCSTA = (RCSTA_DEFAULT);
    TXSTA = (0x4 | TXSTA_DEFAULT);
}
else
{
    RCSTA = (RCSTA_DEFAULT);
    TXSTA = (0x0 | TXSTA_DEFAULT);
}
    

}

/******************************************************************************
*                       ESCRIBIR CARACTER
* 
*   - Funcion que transmite un caracter cuando el buffer de salida esta libre
*   - La función "printf" llama por defecto a la funcion putch  
 *****************************************************************************/
void USART_putcUSART(char c)
{
while(!TRMT);       // Espera a que el buffer de salida este libre
TXREG1 = c;         // Envia el caracter
}

void putch (char c)     //A esta funcion llama printf, deber ser nombrada asi
{
while(!TRMT);       // Espera a que el buffer de salida este libre
TXREG1 = c;         // Envia el caracter
}


/******************************************************************************
*                       ESTADO BUFFER SALIDA
* 
*   -  Función que devuelve el estado del buffer de salida
*      TRUE: Libre,  FALSE: Ocupado 
 *****************************************************************************/
bool UART_TX_Empty()
{
  return TRMT;      //Bit de estado del buffer de transmision
}


/******************************************************************************
*                       ESCRIBIR FRASE
* 
*   - Funcion encargada de escribir caracteres contenidos en un array usando
*     la función USART_putcUSART 
 *****************************************************************************/
void UART_Write_Text(char *text)
{
  int i;
  for(i=0;text[i]!='\0';i++)
    USART_putcUSART(text[i]);
}



/******************************************************************************
*                       RECIBIDO ALGO
* 
*   - Funcion que devuelve el estado del buffer de entrada 
*     TRUE: Libre,  FALSE: Ocupado 
 *****************************************************************************/
bool UART_Data_Ready()
{
  return RCIF;      //Bandera que indica que hemos recibido algo
}


/******************************************************************************
*                       LEER CARACTER
* 
*   - Funcion que devuelve el caracter leido del buffer de entrada 
 *****************************************************************************/
unsigned char USART_getcUSART ()
{
	char  c = 0;
        if (RCSTA1bits.OERR == 1) 
            { 
            RCSTA1bits.OERR = 0;      // clear overrun if it occurs
            RCSTA1bits.CREN = 0; 
            RCSTA1bits.CREN = 1; 
            }

	c = RCREG1;
    return c;
}


/******************************************************************************
*                       LEER CARACTER O ESPERAR CARACTER
* 
*   - Funcion que devuelve el caracter leido del buffer de entrada 
*   - Esta funcion se diferencia de la anterior que espera si no hay nada en
*     el buffer. Cuando lo reciba lo devuelve.  
 *****************************************************************************/
unsigned char USART_getcUSART2 ()
{
	char  c = 0;
    while (!PIR1bits.RCIF);
        if (RCSTA1bits.OERR == 1) 
            { 
            RCSTA1bits.OERR = 0;      // clear overrun if it occurs
            RCSTA1bits.CREN = 0; 
            RCSTA1bits.CREN = 1; 
            }

	c = RCREG1;
    return c;
}


/******************************************************************************
*                       LEER GRUPO DE CARACTERES
* 
*   - Funcion que guarda en un array el contenido del buffer de entrada
*   - Usa la funcion que espera por caracter en buffer y no termina hasta que 
*     haya completado el array. 
 *****************************************************************************/
void USART_ReadString(char *Output, unsigned int length)
{
  unsigned int i;
  for(int i = 0; i < length; i++ )
  {
  Output[i] = USART_getcUSART2();
  }
}

/******************************************************************************
*                       LEER GRUPO DE CARACTERES
* 
*   - Funcion que guarda en un array el contenido del buffer de entrada
*   - Usa la funcion que espera por caracter en buffer y no termina hasta que 
*     encuentre el caracter fin de linea '\n'
 *****************************************************************************/
void USART_ReadString2(char *Output)
{
    unsigned int i = 0;
    char caracter = 0;
    while(caracter != '\n')
    {
    caracter = USART_getcUSART2();
    Output[i] = caracter; 
    i++;
    }
}




4. Ejemplo 1: Escribir LCD desde puerto Serie:

Con esta práctica se integra el LCD con el puerto Serie. Nos pide que indroduzcamos un texto para pasárselo al display:


					/*
 * File:   main.c
 * Author: Eduardo
 *
 * Created on 5 de junio de 2017, 17:16
 */


#include 
#include "config.h"
#include "typedefs.h"
#include "usart.h"
#include "lcd.h"

//PROTOTIPO DE LAS FUNCIONES USADAS
void delay_ms(uint16_t);
void escucharMensaje(void);


void main(void) 
{
    USART_Initialize();     //Inicializamos el puerto Serie
    LCD_Initialize();       //Inicializamos el lcd
    delay_ms(500);

    
    printf("Introduce texto en el display \n");
    LCD_ClearScreen();
    LCD_PutString("Introduce texto", 15);
    
        
    while (true)
    {
    escucharMensaje();
    
    
    }
}



/******************************************************************************
*                       FUNCION RETARDO DE mS
* 
*   - Funcion que realiza un retardo en mS segun el valor que recibe
 *****************************************************************************/
void delay_ms(uint16_t i)
{
    for ( uint16_t x = 0; x < i; x ++ ) 
    { 
    __delay_ms (1); 
    }
}


/******************************************************************************
*            FUNCION QUE COMPRUEBA LO RECIBIDO Y CAMBIA EL LED
* 
*   - Si recibe algo por el puerto serie, cambia el led adecuado
 *****************************************************************************/
void escucharMensaje()
{
    if (UART_Data_Ready())      //Si hemos recibido algo por puerto serie
        {
        int lenght = 80;
        char Output[80];
        for (int i = 0; i < lenght; i++)
        {
            Output[i] = ' ';
        }
        USART_ReadString2(Output);
        LCD_ClearScreen();
        delay_ms(500);
        LCD_PutString(Output, lenght);
        printf("Has escrito: ");
        printf(Output);
        printf("\n");
        printf("Introduce texto en el display \n");
        }
}




5. Ejemplo 2: Monitorización y control desde Serie:

 Con esta práctica se permite el control de los led y se monitoriza el estado de los pulsadores.


					/*
 * File:   main.c
 * Author: Eduardo
 *
 * Created on 5 de junio de 2017, 17:16
 */


#include 
#include "config.h"
#include "typedefs.h"
#include "led.h"
#include "button.h"
#include "usart.h"

//PROTOTIPO DE LAS FUNCIONES USADAS
void delay_ms(uint16_t);
void escucharMensaje(void);

//VARIABLES UDADAS
unsigned long value = 0;
uint8_t a = 0;

void main(void) 
{
    USART_Initialize();               //Inicializamos el puerto Serie
    
    for (a=0; a<4; a++)
    {
        LED_Enable(LED_D1 + a);       //Habilitamos los led. Configura como salida los pines
        LED_Off(LED_D1 + a);          //Empezamos con todos los led apagados
        BUTTON_Enable(BUTTON_S1 + a); //Habilitamos los pulsadores. Configura como entrada los pines
    }
    
    
    printf("Pulsa 0 1 2 3 para cambiar estado del led \n");
    
        
    while (true)
    {
    escucharMensaje();
    
    for (a=0; a<4; a++)    
    {
        if (BUTTON_IsPressed(BUTTON_S1 + a))
        {
            LED_Toggle(LED_D1 + a);
            printf("Has cambiado el led: %c \n", a+'0');    //Si no convertimos a caracter el valor no lo
            delay_ms(500);                                  //imprime bien. Al sumarle el caracter '0' funciona
        }
    }
    }
}



/******************************************************************************
*                       FUNCION RETARDO DE mS
* 
*   - Funcion que realiza un retardo en mS segun el valor que recibe
 *****************************************************************************/
void delay_ms(uint16_t i)
{
    for ( uint16_t x=0; x < i; x++ ) 
    { 
    __delay_ms(1); 
    }
}


/******************************************************************************
*            FUNCION QUE COMPRUEBA LO RECIBIDO Y CAMBIA EL LED
* 
*   - Si recibe algo por el puerto serie, cambia el led adecuado
 *****************************************************************************/
void escucharMensaje()
{
    if (PIR1bits.RCIF)
        {
        char cadena2[15];
        USART_ReadString2(cadena2);
        int valor = cadena2[0] - '0';
        LED_Toggle(LED_D1 + valor);
        printf(cadena2);
        delay_ms(500);
        }
}




6. Descargas:

www.microedu.es

Si chove, non orballa!