Está en la página 1de 34

PONTIFICIA UNIVERSIDAD CATÓLICA DEL PERÚ

FACULTAD DE CIENCIAS E INGENIERÍA


SISTEMAS DIGITALES
IEE256 H0522 H0523
(Primer Semestre 2019)

RECEPTOR / TRANSMISOR UNIVERSAL ASÍNCRONO


(UART)
Para la resolución de los problemas planteados incluimos en los programas el archivo tm4c123gh6pm.h donde se
encuentra las definiciones de los registros del UART que vamos a utilizar:

//*****************************************************************************
//
// UART registers (UART0)
//
//*****************************************************************************
#define UART0_DR_R (*((volatile uint32_t *)0x4000C000))
#define UART0_RSR_R (*((volatile uint32_t *)0x4000C004))
#define UART0_ECR_R (*((volatile uint32_t *)0x4000C004))
#define UART0_FR_R (*((volatile uint32_t *)0x4000C018))
#define UART0_ILPR_R (*((volatile uint32_t *)0x4000C020))
#define UART0_IBRD_R (*((volatile uint32_t *)0x4000C024))
#define UART0_FBRD_R (*((volatile uint32_t *)0x4000C028))
#define UART0_LCRH_R (*((volatile uint32_t *)0x4000C02C))
#define UART0_CTL_R (*((volatile uint32_t *)0x4000C030))
#define UART0_IFLS_R (*((volatile uint32_t *)0x4000C034))
#define UART0_IM_R (*((volatile uint32_t *)0x4000C038))
#define UART0_RIS_R (*((volatile uint32_t *)0x4000C03C))
#define UART0_MIS_R (*((volatile uint32_t *)0x4000C040))
#define UART0_ICR_R (*((volatile uint32_t *)0x4000C044))
#define UART0_DMACTL_R (*((volatile uint32_t *)0x4000C048))
#define UART0_9BITADDR_R (*((volatile uint32_t *)0x4000C0A4))
#define UART0_9BITAMASK_R (*((volatile uint32_t *)0x4000C0A8))
#define UART0_PP_R (*((volatile uint32_t *)0x4000CFC0))
#define UART0_CC_R (*((volatile uint32_t *)0x4000CFC8))

//*****************************************************************************

Por otro lado, trabajaremos con la tarjeta Tiva C Launchpad que utiliza el UART0 para comunicación serial, el UART0
emplea los pines PA0 como receptor (U0RX) y PA1 como transmisor (U0TX), como se ve en el diagrama esquemático.
Los problemas están planteados para comunicar el microcontrolador con una computadora
personal donde se debe ejecutar un programa terminal serial. Se recomienda utilizar el terminal
PuTTY.

Al ejecutar el PuTTY debe configurar los


parámetros de comunicación serial, deben ser
iguales a los que configuró para el
microcontrolador:

También debe ingresar el puerto serial de la PC


al que está conectado el microcontrolador, para
saber cuál es debe ingresar al Administrador de
dispositivos de Windows y verificar los Puertos
(COM y LPT). En estos gráficos se ve que el
puerto serial que utiliza la PC para comunicarse
. con el microcontrolador es el COM9
PROBLEMAS RESUELTOS

PROBLEMA 01:
Tenemos conectado al microcontrolador TM4C123GH6PM una computadora personal en la que se está ejecutando un
programa de Terminal Serial, desarrollar un programa para el microcontrolador que realice un eco, es decir, cada dato
que reciba por el puerto serial lo debe transmitir por el mismo puerto. Los parámetros de comunicación deben ser 9600,
8, N, 1 y la frecuencia de reloj del sistema es de 16MHz.

SOLUCIÓN

Diagrama de flujo

a.- Programa principal:

INICIO

ConfigPtoSerial()

datoRx EsperaDato()

TransmiteDato(datoRx)

b.- Funciones

datoRx ← EsperaDato( ) TransmiteDato(datoTx)

INICIO INICIO

NO NO
¿Hay dato recibido? ¿Se puede transmitir?

SÍ SÍ

Leer datoRx del Pto Serial Escribir datoTx en Pto Serial

FIN FIN
Código del programa:

/****************************************************************************************/
/****************************************************************************************/
/***** PONTIFICIA UNIVERSIDAD CATÓLICA DEL PERÚ *****/
/***** FACULTAD DE CIENCIAS E INGENIERÍA *****/
/***** SISTEMAS DIGITALES *****/
/****************************************************************************************/
/***** Tema: Comunicación Serial UART *****/
/***** Proyecto: UART_P01_Eco *****/
/****************************************************************************************/
/***** Microcontrolador: TM4C123GH6PM *****/
/***** EvalBoard: Tiva C Series TM4C123G LaunchPad *****/
/***** Autor: Rolando Sánchez Ponce *****/
/***** Fecha: Octubre 2017 *****/
/***** Última revisión: Mayo 2019 *****/
/****************************************************************************************/
/***** Enunciado: *****/
/***** Se implementa un programa de eco utilizando el módulo UART0. Cada dato que *****/
/***** se recibe por el puerto serial se retransmite por el puerto serial. *****/
/***** Parámetros de comunicación: 9600, 8, N, 1 *****/
/***** Frecuencia de reloj del sistema 16MHz *****/
/****************************************************************************************/
/****************************************************************************************/
#include <stdint.h>
#include "tm4c123gh6pm.h"

/****************************************************************************************/
/***** F U N C I O N E S *****/
/****************************************************************************************/

/****************************************************************************************/
/***** InicializaPtoSerial() *****/
/****************************************************************************************/
/***** Configura el UART0 con los siguientes parámetros de comunicación serial: *****/
/***** 9600, 8, N, 1. Frecuencia del reloj del sistema 16MHz. *****/
/****************************************************************************************/
/***** ENTRADAS: Ninguna *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void InicializaPtoSerial(void){
// Activamos el reloj para el UART0
SYSCTL_RCGCUART_R |= SYSCTL_RCGCUART_R0;
while(!(SYSCTL_PRUART_R & SYSCTL_PRUART_R0));
// Inhabilitamos el UART0
UART0_CTL_R &= ~UART_CTL_UARTEN;
// Velocidad 9600bps (Fsysclk = 16MHz)
UART0_IBRD_R = (UART0_IBRD_R & 0xFFFF0000) | 104;
UART0_FBRD_R = (UART0_FBRD_R & 0xFFFFFFC0) | 11;
// 8, N, 1, FIFOs habilitados
UART0_LCRH_R = (UART0_LCRH_R & 0xFFFFFF00) | 0x70;
// Habilitamos el UART0, recepción y transmisión
UART0_CTL_R |= (UART_CTL_RXE | UART_CTL_TXE | UART_CTL_UARTEN);
// Activamos la señal de reloj para GPIOA
SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R0;
while(!(SYSCTL_PRGPIO_R & SYSCTL_PRGPIO_R0));
// Activamos funciones alternas para PA0 y PA1
GPIO_PORTA_AFSEL_R |= 0x03;
// Conectamos UART0 a PA0 y PA1
GPIO_PORTA_PCTL_R = (GPIO_PORTA_PCTL_R&0xFFFFFF00)|0x00000011;
// Desactivamos funciones analógicas en PA0 y PA1
GPIO_PORTA_AMSEL_R &= ~(0x03);
// Activamos funciones digitales en PA0 y PA1
GPIO_PORTA_DEN_R |= 0x03;
}
/****************************************************************************************/
/***** EsperaDato() *****/
/****************************************************************************************/
/***** Lee un dato recibido por el puerto serial, para esto espera que haya un dato *****/
/***** en el buffer de recepción del UART0 para leerlo. *****/
/****************************************************************************************/
/***** ENTRADAS: Ninguna *****/
/***** SALIDA: Dato recibido por el UART0 *****/
/****************************************************************************************/
uint8_t EsperaDato(void){
uint8_t datoRx;
while(UART0_FR_R & UART_FR_RXFE);
datoRx = (uint8_t)UART0_DR_R;
return datoRx;
}

/****************************************************************************************/
/***** TransmiteDato() *****/
/****************************************************************************************/
/***** Escribe un byte en el buffer de transmisión del UART0 para ser transmitido *****/
/***** por el puerto serial. Si el buffer estuviera lleno espera hasta que se pueda *****/
/***** escribir. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** datoTx: Dato a transmitir por el puerto serial *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void TransmiteDato(uint8_t datoTx){
while(UART0_FR_R & UART_FR_TXFF);
UART0_DR_R = datoTx;
}

/****************************************************************************************/
/***** P R O G R A M A P R I N C I P A L *****/
/****************************************************************************************/
int main(void){
uint8_t datoRx;
InicializaPtoSerial();
while(1){
datoRx = EsperaDato();
TransmiteDato(datoRx);
}
}

/****************************************************************************************/
/***** F I N D E L P R O G R A M A *****/
/****************************************************************************************/
Captura de pantalla:

PROBLEMA 02:
Se tiene conectado al módulo EK-TM4C123GXL una computadora personal en la que se está ejecutando un programa
Terminal Serial (PuTTY). Se quiere desarrollar un programa para el microcontrolador que espere recibir una cadena de
caracteres, finaliza la recepción de la cadena al recibir el carácter CR (el usuario en el terminal presiona la tecla ENTER),
una vez recibida la cadena la retransmite con todos sus caracteres alfabéticos en mayúsculas. Luego se espera el ingreso
de una nueva cadena de caracteres.
Los parámetros de comunicación deben ser 9600, 8, N, 1 y la frecuencia del reloj del sistema es de 16MHz.

SOLUCIÓN

Diagrama de flujo

a.- Programa principal

INICIO

ConfigPtoSerial()

EsperaCadena(MiCad[ ])

CadMayuscula(MiCad[ ])

TransmiteCadena(MiCad[ ])
b.- Funciones

INICIO

EsperaCadena(CadASCIIZ[ ]) hay1Caracter F
fin F
i 0

datoRx EsperaDato( )


¿datoRx = ENTER?

NO

SÍ NO
¿hay1Caracter? ¿hay1Caracter?

NO SÍ
hay1Caracter V CadASCIIZ[i] 0

TransmiteDato(datoRx) fin V

CadASCIIZ[i] datoRx

i i+1

NO
¿ fin ?


FIN

INICIO

i 0

TransmiteCadena(CadASCIIZ[ ])

¿CadASCIIZ[i] = 0?

NO

TransmiteDato(CadASCIIZ[i]) FIN

i i+1
CadMayusculas(CadASCIIZ[ ])

INICIO

i 0


¿CadASCIIZ[i] = 0?

NO FIN

NO
¿a CadASCIIZ[i] z?

CadASCIIZ[i] CadASCIIZ[i] – 20H

i i+1

Código del programa:

/****************************************************************************************/
/****************************************************************************************/
/***** PONTIFICIA UNIVERSIDAD CATÓLICA DEL PERÚ *****/
/***** FACULTAD DE CIENCIAS E INGENIERÍA *****/
/***** SISTEMAS DIGITALES *****/
/****************************************************************************************/
/***** Tema: Comunicación Serial UART *****/
/***** Proyecto: UART_P02_EcoCadMay *****/
/****************************************************************************************/
/***** Microcontrolador: TM4C123GH6PM *****/
/***** EvalBoard: Tiva C Series TM4C123G LaunchPad *****/
/***** Autor: Rolando Sánchez Ponce *****/
/***** Fecha: Octubre 2017 *****/
/***** Última revisión: Mayo 2019 *****/
/****************************************************************************************/
/***** Enunciado: *****/
/***** Se espera la recepción de una cadena de caracteres ASCII (eco por cada ca- *****/
/***** racter), una vez recibida se retransmite toda la cadena en mayúsculas. *****/
/***** Módulo: UART0. Parámetros de comunicación: 9600, 8, N, 1 *****/
/***** Frecuencia de reloj del sistema 16MHz *****/
/****************************************************************************************/
/****************************************************************************************/
#include <stdint.h>
#include "tm4c123gh6pm.h"

/****************************************************************************************/
/***** C O N S T A N T E S *****/
/****************************************************************************************/

/***** CONSTANTES BOOLEANAS *****/


#define FALSE 0
#define TRUE 1
/***** CONSTANTES PARA PARA CARACTERES ASCII *****/
#define LF 10 // Nueva línea
#define FF 12 // Nueva página
#define CR 13 // Retorno de carro

/****************************************************************************************/
/***** F U N C I O N E S *****/
/****************************************************************************************/

/****************************************************************************************/
/***** InicializaPtoSerial() *****/
/****************************************************************************************/
/***** Configura el UART0 con los siguientes parámetros de comunicación serial: *****/
/***** 9600, 8, N, 1. Frecuencia del reloj del sistema 16MHz. *****/
/****************************************************************************************/
/***** ENTRADAS: Ninguna *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void InicializaPtoSerial(void){
SYSCTL_RCGCUART_R |= SYSCTL_RCGCUART_R0;
while(!(SYSCTL_PRUART_R & SYSCTL_PRUART_R0));
UART0_CTL_R &= ~UART_CTL_UARTEN;
UART0_IBRD_R = (UART0_IBRD_R & 0xFFFF0000) | 104;
UART0_FBRD_R = (UART0_FBRD_R & 0xFFFFFFC0) | 11;
UART0_LCRH_R = (UART0_LCRH_R & 0xFFFFFF00) | 0x70;
UART0_CTL_R |= (UART_CTL_RXE | UART_CTL_TXE | UART_CTL_UARTEN);
SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R0;
while(!(SYSCTL_PRGPIO_R & SYSCTL_PRGPIO_R0));
GPIO_PORTA_AFSEL_R |= 0x03;
GPIO_PORTA_PCTL_R = (GPIO_PORTA_PCTL_R&0xFFFFFF00)|0x00000011;
GPIO_PORTA_AMSEL_R &= ~(0x03);
GPIO_PORTA_DEN_R |= 0x03;
}

/****************************************************************************************/
/***** EsperaDato() *****/
/****************************************************************************************/
/***** Lee un dato recibido por el puerto serial, para esto espera que haya un dato *****/
/***** en el buffer de recepción del UART0 para leerlo. *****/
/****************************************************************************************/
/***** ENTRADAS: Ninguna *****/
/***** SALIDA: Dato recibido por el UART0 *****/
/****************************************************************************************/
uint8_t EsperaDato(void){
uint8_t datoRx;
while(UART0_FR_R & UART_FR_RXFE);
datoRx = (uint8_t)UART0_DR_R;
return datoRx;
}

/****************************************************************************************/
/***** TransmiteDato() *****/
/****************************************************************************************/
/***** Escribe un byte en el buffer de transmisión del UART0 para ser transmitido *****/
/***** por el puerto serial. Si el buffer estuviera lleno espera hasta que se pueda *****/
/***** escribir. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** datoTx: Dato a transmitir por el puerto serial *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void TransmiteDato(uint8_t datoTx){
while(UART0_FR_R & UART_FR_TXFF);
UART0_DR_R = datoTx;
}
/****************************************************************************************/
/***** SiguienteLinea() *****/
/****************************************************************************************/
/***** Transmite los caracteres necesarios para posicionar el cursor de la pantalla *****/
/***** del terminal al inicio de la siguiente línea. *****/
/****************************************************************************************/
/***** ENTRADAS: Ninguna *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void SiguienteLinea(void){
// Transmitimos nueva línea (LF)
TransmiteDato(LF);
// Transmitimos retorno de carro (CR)
TransmiteDato(CR);
}

/****************************************************************************************/
/***** EsperaCadena() *****/
/****************************************************************************************/
/***** Recibe por el puerto serial una cadena de caracteres ASCII y la almacena en *****/
/***** un arreglo. El usuario ingresa ENTER para finalizar y debe ingresar por lo *****/
/***** menos un caracter antes del ENTER. La función inserta 0 al final de la cade- *****/
/***** na para que sea ASCIIZ. La función hace un eco por cada caracter recibido y *****/
/***** posiciona el cursor al inicio de la siguiente línea al salir. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** cadenaASCIIZ[]: Dirección de inicio de la cadena ASCIIZ a recibir. *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void EsperaCadena(uint8_t cadenaASCIIZ[]){
uint8_t datoRx;
uint8_t hay1CaracterFlag = FALSE;
uint8_t finFlag = FALSE;
uint8_t i = 0;
do{
// Esperamos recibir un dato por el puerto serial.
datoRx = EsperaDato();
// Si dato recibido es diferente de ENTER.
if(datoRx != CR){
if(!hay1CaracterFlag) hay1CaracterFlag = TRUE;
TransmiteDato(datoRx);
cadenaASCIIZ[i++] = datoRx;
}
// Si dato recibido es ENTER.
else if(hay1CaracterFlag){
cadenaASCIIZ[i] = 0;
SiguienteLinea();
finFlag = TRUE;
}
}while(!finFlag);
}

/****************************************************************************************/
/***** TransmiteCadena() *****/
/****************************************************************************************/
/***** Transmite por el puerto serial una cadena ASCIIZ. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** cadenaASCIIZ[]: Dirección de inicio de la cadena ASCIIZ a transmitir. *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void TransmiteCadena(const uint8_t cadenaASCIIZ[]){
uint8_t i;
for(i=0; cadenaASCIIZ[i]; i++){
TransmiteDato(cadenaASCIIZ[i]);
}
}

/****************************************************************************************/
/***** CadMayusculas() *****/
/****************************************************************************************/
/***** Convierte los caracteres en minúsculas de una cadena ASCIIZ a mayúsculas. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** cadenaASCIIZ[]: Dirección de inicio de la cadena ASCIIZ a convertir. *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void CadMayuscula(uint8_t cadenaASCIIZ[]){
uint8_t i;
for(i=0; cadenaASCIIZ[i]; i++){
if(('a'<=cadenaASCIIZ[i])&&(cadenaASCIIZ[i]<='z')){
cadenaASCIIZ[i]-=0x20;
}
}
}

/****************************************************************************************/
/***** P R O G R A M A P R I N C I P A L *****/
/****************************************************************************************/
int main(void){
uint8_t MiCadena[25];
InicializaPtoSerial();
while(1){
EsperaCadena(MiCadena);
CadMayuscula(MiCadena);
TransmiteCadena(MiCadena);
SiguienteLinea();
}
}

/****************************************************************************************/
/***** F I N D E L P R O G R A M A *****/
/****************************************************************************************/

BIBLIOTECA PARA MANEJAR EL UART0

Las funciones vistas en el ejercicio anterior son bastante comunes en el desarrollo de programas que utilicen
comunicación serial, por eso conviene desarrollar una biblioteca que las contenga.

Se ha desarrollado la biblioteca UART formada por los archivos UART.h y UART.c para facilitarnos la programación
en los programas siguientes. Aparte de las funciones vistas en el proyecto anterior la biblioteca incluye algunas funciones
más también útiles y comunes.

Los archivos están al final del presente documento.

Como ejemplo de la ayuda que brinda esta biblioteca rehagamos el ejercicio anterior utilizando sus funciones.
/****************************************************************************************/
/****************************************************************************************/
/***** PONTIFICIA UNIVERSIDAD CATÓLICA DEL PERÚ *****/
/***** FACULTAD DE CIENCIAS E INGENIERÍA *****/
/***** SISTEMAS DIGITALES *****/
/****************************************************************************************/
/***** Tema: Comunicación Serial UART *****/
/***** Proyecto: UART_P02b_EcoCadMay *****/
/****************************************************************************************/
/***** Microcontrolador: TM4C123GH6PM *****/
/***** EvalBoard: Tiva C Series TM4C123G LaunchPad *****/
/***** Autor: Rolando Sánchez Ponce *****/
/***** Fecha: Mayo 2019 *****/
/***** Última revisión: Mayo 2019 *****/
/****************************************************************************************/
/***** Enunciado: *****/
/***** Se espera la recepción de una cadena de caracteres ASCII (eco por cada ca- *****/
/***** racter), una vez recibida se retransmite toda la cadena en mayúsculas. *****/
/***** Módulo: UART0. Parámetros de comunicación: 9600, 8, N, 1 *****/
/***** Frecuencia de reloj del sistema 16MHz *****/
/***** Hace uso de las funciones de la biblioteca UART.h *****/
/****************************************************************************************/
/****************************************************************************************/
#include <stdint.h>
#include "tm4c123gh6pm.h"
#include "UART.h"

/****************************************************************************************/
/***** CadMayusculas() *****/
/****************************************************************************************/
/***** Convierte los caracteres en minúsculas de una cadena ASCIIZ a mayúsculas. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** cadenaASCIIZ[]: Dirección de inicio de la cadena ASCIIZ a convertir. *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void CadMayuscula(uint8_t cadenaASCIIZ[]){
uint8_t i;
for(i=0; cadenaASCIIZ[i]; i++){
if(('a'<=cadenaASCIIZ[i])&&(cadenaASCIIZ[i]<='z')){
cadenaASCIIZ[i]-=0x20;
}
}
}

/****************************************************************************************/
/***** P R O G R A M A P R I N C I P A L *****/
/****************************************************************************************/
int main(void){
uint8_t MiCadena[25];
UART_Inicializa();
while(1){
UART_EsperaCadena(MiCadena);
CadMayuscula(MiCadena);
UART_TransmiteCadena(MiCadena);
UART_SiguienteLinea();
}
}

/****************************************************************************************/
/***** F I N D E L P R O G R A M A *****/
/****************************************************************************************/
Captura de pantalla:

PROBLEMA 03:
Se tiene conectado al módulo EK-TM4C123GXL una computadora personal en la que se está ejecutando un programa
Terminal Serial (PuTTY). Desarrollar un programa que solicite el ingreso de un ángulo entre 0 y 90 grados para luego
mostrar el seno de dicho ángulo. Los parámetros de comunicación deben ser 9600, 8, N, 1 y la frecuencia del reloj del
sistema es de 16MHz.

SOLUCIÓN

Diagrama de flujo

a.- Programa principal:


INICIO

InicializaPtoSerial()

anguloX solicitaAngulo( )

senoX calculaSeno(anguloX)

transmiteSeno(senoX)
b.- Funciones

angulo ← solicitaAngulo( ) transmiteSeno(SenoX)

INICIO
INICIO

div10 10000
error F i 1

TxCadena( Ingrese angulo )


NO
¿i 5?
angulo esperaNumB10( )

SenoASCIIZ[i] SenoX÷div10 + 0
NO
¿angulo > 90?

SÍ SenoX resto(SenoX÷10)
div10 div10÷10
TxCadena( Error de rango )

error V i i+1


¿ error ?
NO SenoASCIIZ[i] 0
FIN SenoASCIIZ[0] SenoASCIIZ[1]
SenoASCIIZ[1] .

TxCadena( SenX = )

TxCadena(SenoASCII[ ])

FIN
numero ← esperaNumB10( )

INICIO

hay1Digito F
fin F
numero 0

datoRx EsperaDato( )


¿datoRx = ENTER?

NO

NO
NO ¿hay1Digito?
¿ 0' datoRx 9 ?


fin V

¿hay1Digito?

NO
hay1Digito V

TransmiteDato(datoRx)

numero 10×numero + datoRx- 0

NO
¿ fin ?


FIN
Código del programa:

/****************************************************************************************/
/****************************************************************************************/
/***** PONTIFICIA UNIVERSIDAD CATÓLICA DEL PERÚ *****/
/***** FACULTAD DE CIENCIAS E INGENIERÍA *****/
/***** SISTEMAS DIGITALES *****/
/****************************************************************************************/
/***** Tema: Comunicación Serial UART *****/
/***** Proyecto: UART_P03_SenX *****/
/****************************************************************************************/
/***** Microcontrolador: TM4C123GH6PM *****/
/***** EvalBoard: Tiva C Series TM4C123G LaunchPad *****/
/***** Autor: Rolando Sánchez Ponce *****/
/***** Fecha: Octubre 2017 *****/
/***** Última revisión: Mayo 2019 *****/
/****************************************************************************************/
/***** Enunciado: *****/
/***** Tenemos conectado al microcontrolador por el UART0 una computadora personal *****/
/***** donde se está ejecutando un programa terminal serial. Por medio del terminal *****/
/***** se solicita el ingreso de un ángulo entre 0 y 90 grados, luego se transmite *****/
/***** el seno de dicho ángulo. *****/
/***** Módulo: UART0. Parámetros de comunicación: 9600, 8, N, 1 *****/
/***** Frecuencia de reloj del sistema 16MHz *****/
/****************************************************************************************/
/****************************************************************************************/
#include <stdint.h>
#include "tm4c123gh6pm.h"
#include "UART.h"

/****************************************************************************************/
/***** P R O T O T I P O S D E F U N C I O N E S *****/
/****************************************************************************************/
uint8_t solicitaAngulo(void);
uint16_t calculaSeno(uint8_t x);
void transmiteSeno(uint16_t SenoX);

/****************************************************************************************/
/***** T A B L A S Y M E N S A J E S *****/
/****************************************************************************************/
const uint8_t MSG_SOLICITA[] = "Ingrese angulo X [00, 90]: \0";
const uint8_t MSG_RESULTADO[] = "SenX = \0";
const uint8_t MSG_ERROR[] = "Angulo fuera de rango!!\0";
const uint16_t TablaSeno[] = {0, 1736, 3420, 5000, 6428, 7660, 8680, 9397, 9848, 10000};

/****************************************************************************************/
/***** P R O G R A M A P R I N C I P A L *****/
/****************************************************************************************/
int main(void){
uint8_t anguloX;
uint16_t senoX;
UART_Inicializa();
while(1){
anguloX = solicitaAngulo();
senoX = calculaSeno(anguloX);
transmiteSeno(senoX);
}
}

/****************************************************************************************/
/***** F U N C I O N E S *****/
/****************************************************************************************/
/****************************************************************************************/
/***** solicitaAngulo() *****/
/****************************************************************************************/
/***** Solicita por el terminal el ingreso de un ángulo entre 0 y 90. Si recibe un *****/
/***** ángulo fuera del rango envía un mensaje de error y vuelve a solicitar el in- *****/
/***** del ángulo. Devuelve el ángulo ingresado. *****/
/****************************************************************************************/
/***** ENTRADAS: Ninguno *****/
/***** SALIDA: Ángulo recibido por el puerto serial entre 0 y 90. *****/
/****************************************************************************************/
uint8_t solicitaAngulo(void){
uint8_t errorFlag;
uint8_t angulo;
do{
errorFlag = FALSE;
// Solicitamos y leemos un ángulo
UART_TransmiteCadena(MSG_SOLICITA);
angulo = (uint8_t)UART_EsperaNumeroB10();
// Si ángulo mayor de 90 grados hay error
if(angulo>90){
UART_TransmiteCadena(MSG_ERROR);
UART_SiguienteLinea();
errorFlag = TRUE;
}
}while(errorFlag);
return angulo;
}

/****************************************************************************************/
/***** calculaSeno() *****/
/****************************************************************************************/
/***** Calcula mediante tablas de manera aproximada la función seno de un ángulo *****/
/***** entre 0 y 90 grados. Devuelve un número entero que es el seno del ángulo *****/
/***** multiplicado por 10000. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** x: Ángulo a evaluar. Rango [0, 90] *****/
/***** SALIDA: 10000*senx *****/
/****************************************************************************************/
/***** NOTA: Hace uso de la tabla TablaSeno[] *****/
/****************************************************************************************/
uint16_t calculaSeno(uint8_t x){
uint16_t senX;
uint8_t xi, xj;
if(x<90){ // x [0, 89]
xi=x/10; // xi [0, 8]
xj=xi+1; // xj [1, 9]
senX = (x-10*xi)*(TablaSeno[xj]-TablaSeno[xi])/10 + TablaSeno[xi];
}
else if(x==90) senX = TablaSeno[x/10];
return senX;
}

/****************************************************************************************/
/***** transmiteSeno() *****/
/****************************************************************************************/
/***** Recibe un número que corresponde al seno de un ángulo multiplicado por 10000 *****/
/***** Esta función forma con este número una cadena ASCIIZ con un formato de un *****/
/***** digito entero y cuatro decimales. Luego transmite la cadena formada por el *****/
/***** puerto serial. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** SenoX: Seno de un ángulo multiplicado por 10000. Rango [0, 10000] *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void transmiteSeno(uint16_t SenoX){
uint8_t SenoASCIIZ[8];
uint16_t div10;
uint8_t i;
if(SenoX <= 10000){
// Se forma una cadena ASCIIZ con el número ingresado SenoX
// Formato de un digito entero y cuatro decimales.
// Ejemplo: Si SenoX = 4589, entonces se forma la cadena ASCIIZ
// SenoASCIIZ[] = {'0', '.', '4', '5', '8', '9', 0}
div10=10000;
for(i=1; i<=5; i++){
SenoASCIIZ[i] = SenoX/div10 + '0';
SenoX %= div10;
div10 /= 10;
}
SenoASCIIZ[i] = 0;
SenoASCIIZ[0] = SenoASCIIZ[1];
SenoASCIIZ[1] = '.';

// Transmitimos la cadena formada


UART_TransmiteCadena(MSG_RESULTADO);
UART_TransmiteCadena(SenoASCIIZ);
UART_SiguienteLinea();
}
}

/****************************************************************************************/
/***** F I N D E L P R O G R A M A *****/
/****************************************************************************************/

Captura de pantalla:
PROBLEMA 04:
Se tiene conectado al módulo EK-TM4C123GXL una computadora personal en la que se está ejecutando un programa
Terminal Serial (PuTTY).
Se quiere desarrollar un programa para el microcontrolador que al recibir un carácter numérico (entre ‘0’ y ‘9’) transmita
una cadena de caracteres que representen dicho número en palabras o dicho número en notación romana. Para cambiar
de modo (romano o palabras) se presiona el pulsador SW2, cuando se está en modo romano el led RGB del módulo
debe estar en rojo y cuando se está en modo palabras el led debe estar en azul.
Los parámetros de comunicación deben ser 9600, 8, N, 1 y la frecuencia del reloj del sistema es de 16MHz.

SOLUCIÓN

Diagrama de flujo

a.- Programa principal

INICIO

InicializaPuertosES()

InicializaUART()

modo modoRomanos

ledColor(ROJO)

NO NO
¿Se presionó SW2? ¿Hay datoRx?

SÍ SÍ

NO
¿ 0' datoRx 9?
modo cambiaModo(modo)

numero datoRx – 0

txNumTxt(numero, modo)
b.- Funciones

flancoBajada, antNivel ← sondeaPulsador(NumPul, antNivel ) hayDatoRx, datoRx ← sondeaRx( )

INICIO INICIO

actNivel pulsador NumPul hayDatoRx F

flancoBajada F
NO
¿Hay dato recibido?

actNivel = LOW y NO SÍ
antNivel = HIGH
Leer datoRx del Pto Serial

flancoBajada V
hayDatoRx V

antNivel actNivel
FIN

FIN

/****************************************************************************************/
/***** TivaES_SondeaPulsador() *****/
/****************************************************************************************/
/***** Revisa si se ha producido el evento de presionar el pulsador conectado al *****/
/***** pin especificado en la entrada de la función. Si se ha presionado devuelve *****/
/***** verdadero (TRUE) caso contrario devuelve falso (FALSE). Solo devuelve TRUE *****/
/***** si es que el pulsador está presionado y la vez anterior que se llamó a esta *****/
/***** función el pulsador no estaba presionado. No hay lazo de espera. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** pulsadorMsk: Máscara del pulsador a analizar. *****/
/***** Puede ser SW1 (0x10) o SW2(0x01). *****/
/***** *antNivelPtr: Dirección de memoria que almacena el anterior nivel lógico *****/
/***** del pin a analizar. *****/
/***** SALIDA: TRUE: Se ha presionado el pulsador. *****/
/***** FALSE: No se ha presionado el pulsador. *****/
/****************************************************************************************/
uint8_t TivaES_SondeaPulsador(uint8_t pulsadorMsk, uint8_t *antNivelPtr){
uint8_t flancoBajadaFlag, actNivel;

actNivel = TivaES_LeePulsador(pulsadorMsk);
flancoBajadaFlag = FALSE;
// Si el antiguo nivel fue HIGH y el nivel actual es LOW
// entonces hay flanco de bajada
if((*antNivelPtr == HIGH)&&(actNivel == LOW)){
flancoBajadaFlag = TRUE;
retardoRebote();
}
*antNivelPtr = actNivel;
return flancoBajadaFlag;
}
Código del programa:

/****************************************************************************************/
/****************************************************************************************/
/***** PONTIFICIA UNIVERSIDAD CATÓLICA DEL PERÚ *****/
/***** FACULTAD DE CIENCIAS E INGENIERÍA *****/
/***** SISTEMAS DIGITALES *****/
/****************************************************************************************/
/***** Tema: Comunicación Serial UART *****/
/***** Proyecto: UART_P04_SondeoDatoRxPulsador *****/
/****************************************************************************************/
/***** Microcontrolador: TM4C123GH6PM *****/
/***** EvalBoard: Tiva C Series TM4C123G LaunchPad *****/
/***** Autor: Rolando Sánchez Ponce *****/
/***** Fecha: Octubre 2017 *****/
/***** Última revisión: Mayo 2019 *****/
/****************************************************************************************/
/***** Enunciado: *****/
/***** Se recibe por el puerto serial un caracter numérico (entre '0' y '9'), des- *****/
/***** pues se transmite una cadena de caracteres con el nombre del número on una *****/
/***** cadena con el número en romanos. Se cambia el modo de visualización al pre- *****/
/***** sionar el pulsador SW2. EL led RGB en rojo indica que se está en modo romano *****/
/***** y en azul ndica que se esta en modo nombre. *****/
/***** Módulo: UART0. Parámetros de comunicación: 9600, 8, N, 1 *****/
/***** Frecuencia de reloj del sistema 16MHz *****/
/****************************************************************************************/
/****************************************************************************************/
#include <stdint.h>
#include "tm4c123gh6pm.h"
#include "TivaES.h"
#include "UART.h"

#define modoRomano 0
#define modoPalabras 1

/****************************************************************************************/
/***** P R O T O T I P O S D E F U N C I O N E S *****/
/****************************************************************************************/
uint8_t cambiaModo(uint8_t modoAnterior);
void transmiteNumTxt(uint8_t carNum, uint8_t modo);
void aRomanos(uint8_t cadRomASCIIZ[], uint8_t num);

/****************************************************************************************/
/***** T A B L A S Y M E N S A J E S *****/
/****************************************************************************************/
const uint8_t MSG_INICIO[] = "PROGRAMA QUE CONVIERTE UN NUMERO A ROMANOS O A PALABRAS:\n\r"
"--------------------------------------------------------
\n\r\0";
const uint8_t TextoNumero[10][8] = {"CERO", "UNO", "DOS", "TRES", "CUATRO", "CINCO",
"SEIS", "SIETE", "OCHO", "NUEVE"};

/****************************************************************************************/
/***** P R O G R A M A P R I N C I P A L *****/
/****************************************************************************************/
int main(void){
uint8_t datoRx, numero, antSW2, modoTrabajo;

TivaES_Inicializa();
UART_Inicializa();
antSW2 = TivaES_LeePulsador(SW2);
modoTrabajo = modoRomano;
TivaES_LedColor(ROJO);
UART_TransmiteCadena(MSG_INICIO);
while(1){
// Si se presiona el pulsador SW2
if(TivaES_SondeaPulsador(SW2, &antSW2)){
modoTrabajo = cambiaModo(modoTrabajo);
}
// Si hay dato recibido en el puerto serial
if(UART_SondeaRx(&datoRx)){
if(('0'<=datoRx) && (datoRx<='9')){
numero = datoRx - '0';
transmiteNumTxt(numero, modoTrabajo);
}
}
}
}

/****************************************************************************************/
/***** cambiaModo() *****/
/****************************************************************************************/
/***** Cambia el modo de trabajo de Modo Romanos a Modo Palabras o viceversa. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** modoAnterior: Modo de trabajo a cambiar. *****/
/***** SALIDA: Modo de trabajo actualizado. *****/
/****************************************************************************************/
uint8_t cambiaModo(uint8_t modoAnterior){
uint8_t modoNuevo;
if(modoAnterior == modoRomano){
modoNuevo = modoPalabras;
TivaES_LedColor(AZUL);
}
else if(modoAnterior == modoPalabras){
modoNuevo = modoRomano;
TivaES_LedColor(ROJO);
}
return modoNuevo;
}

/****************************************************************************************/
/***** transmiteNumTxt() *****/
/****************************************************************************************/
/***** Dado un número transmite por el puerto serial su representación en romanos o *****/
/***** en palabras. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** numero: Número a analizar. *****/
/***** modo: modoRomanos: Transmite número en romanos. *****/
/***** modoPalabras: Transmite número en palabras. *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void transmiteNumTxt(uint8_t numero, uint8_t modo){
uint8_t cadNumeroRomano[5];
UART_TransmiteDato(numero+'0');
UART_TransmiteDato(':');
if(modo == modoRomano){
aRomanos(cadNumeroRomano, numero);
UART_TransmiteCadena(cadNumeroRomano);
UART_SiguienteLinea();
}
else if(modo == modoPalabras){
UART_TransmiteCadena(TextoNumero[numero]);
UART_SiguienteLinea();
}
}
/****************************************************************************************/
/***** aRomanos() *****/
/****************************************************************************************/
/***** Dado un número entre 0 y 9 forma una cadena ASCIIZ con la representación de *****/
/***** dicho número en romanos. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** cadRomASCIIZ[]: Dirección de inicio de la cadena donde se almacenará la *****/
/***** representación en romanos. *****/
/***** numero: número a convertir en romanos. *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void aRomanos(uint8_t cadRomASCIIZ[], uint8_t num){
uint8_t i;
switch(num){
case 0:
case 1:
case 2:
case 3: for(i=0; i<num; i++){
cadRomASCIIZ[i] = 'I';
}
cadRomASCIIZ[i] = 0;
break;
case 4: cadRomASCIIZ[0] = 'I';
cadRomASCIIZ[1] = 'V';
cadRomASCIIZ[2] = 0;
break;
case 5:
case 6:
case 7:
case 8: cadRomASCIIZ[0] = 'V';
for(i=1; i<num-4; i++){
cadRomASCIIZ[i] = 'I';
}
cadRomASCIIZ[i] = 0;
break;
case 9: cadRomASCIIZ[0] = 'I';
cadRomASCIIZ[1] = 'X';
cadRomASCIIZ[2] = 0;
}
}

Captura de pantalla:
PROBLEMAS PROPUESTOS

PROBLEMA 01:
Desarrollar la función
void TxNumero(uint8_t numero, uint8_t base)
La función transmite por el puerto serial los caracteres necesarios para mostrar el número en base 2, 10 o 16.
Entrada: numero: Número a mostrar en la pantalla del terminal
base: Base en la que se muestra el número, puede ser 2, 10 o 16.
Salida: Ninguna.

Ejemplo: TxNumero(84, 10); // Se muestra en pantalla 084


TxNumero(84, 2); // Se muestra en pantalla 01010100b
TxNumero(84, 16); // Se muestra en pantalla 54H

PROBLEMA 02:
Desarrollar la función
uint8_t RxNumeroBin(void)
La función espera recibir ocho caracteres ‘0’ o ‘1’. Para cada uno de estos caracteres hace eco. Si se reciben otros
caracteres estos son ignorados. Al recibir el octavo carácter válido finaliza la función devolviendo el número formado
por los caracteres recibidos.
Entrada: Ninguna
Salida: Número ingresado por el usuario.

Ejemplo: Se invoca a la función: numero = RxNumero( );


El usuario ingresa por teclado: 0y1c0018714r0g1
Se muestra en pantalla: 01001101
Devuelve: 77

PROBLEMA 03:
Haciendo uso de las dos funciones anteriores desarrollar un programa que muestre en la pantalla del terminal el siguiente
menú:

1.- Ingresar numero (base 2)


2.- Mostrar numero (base 10)
3.- Mostrar numero (base 2)
4.- Mostrar numero (base 16)

Si el usuario ingresa ‘1’ debe solicitarse un número utilizando la función del Problema 01 y se vuelve a mostrar el menú.
Si el usuario ingresa ‘2’, ‘3’ o ‘4’ se debe mostrar en pantalla el último número ingresado en la base que corresponda y
luego mostrar el menú, si aún no se ha ingresado ningún número no se hace nada.

EJEMPLO:

1.- Ingresar numero (base 2)


2.- Mostrar numero (base 10)
3.- Mostrar numero (base 2)
4.- Mostrar numero (base 16)
<1>
Ingrese un numero: 01010100

1.- Ingresar numero (base 2)


2.- Mostrar numero (base 10)
3.- Mostrar numero (base 2)
4.- Mostrar numero (base 16)
<2>
Numero: 084

1.- Ingresar numero (base 2)


2.- Mostrar numero (base 10)
3.- Mostrar numero (base 2)
4.- Mostrar numero (base 16)
<3>
Numero: 01010100b

1.- Ingresar numero (base 2)


2.- Mostrar numero (base 10)
3.- Mostrar numero (base 2)
4.- Mostrar numero (base 16)
<4>
Numero: 54H

1.- Ingresar numero (base 2)


2.- Mostrar numero (base 10)
3.- Mostrar numero (base 2)
4.- Mostrar numero (base 16)
<1>
Ingrese un numero: 10001111

1.- Ingresar numero (base 2)


2.- Mostrar numero (base 10)
3.- Mostrar numero (base 2)
4.- Mostrar numero (base 16)
<4>
Numero: 8FH

1.- Ingresar numero (base 10)


2.- Mostrar numero (base 10)
3.- Mostrar numero (base 2)
4.- Mostrar numero (base 16)

PROBLEMA 04:

Parte A.
Desarrollar la función
void IngresaFraseOculta(uint8_ t CadFrase[], uint8_t CadAsteriscos[])
La función recibe por el puerto serial una cadena ASCIIZ, termina la recepción al recibir el carácter ENTER. Por cada
carácter recibido se debe hacer un eco. Una vez recibida la cadena esta se muestra en la pantalla del terminal serial
durante, aproximadamente, tres segundos, luego debe verse cada carácter reemplazado por ‘*’ a excepción del espacio.
Entrada: Dirección de inicio de la cadena donde se almacenará la frase ingresada.
Dirección de inicio de la cadena donde se almacenará la cadena de asteriscos y espacios
Salida: Ninguna.

Parte A.
Desarrolle el siguiente juego para dos usuarios:
Inicialmente se solicita al usuario ingresar una frase oculta, el led RGB debe estar en azul que indica que se solicita el
ingreso de una frase. La frase ingresada se muestra en el terminal como una cadena de asteriscos.

Luego el usuario 2 tiene que adivinar la frase letra por letra, cada vez que acierte se debe reemplazar en la frase oculta
los asteriscos por la letra ingresada y el led debe emitir un parpadeo verde. Si la letra ingresada no pertenece a la frase
oculta el led debe emitir un parpadeo rojo.
Si el usuario 2 supera el número de errores permitidos debe mostrarse el mensaje “PERDISTE” y terminó el juego.
Si el usuario 2 acierta la frase debe transmitirse el mensaje “SUPERASTE EL NIVEL X” (X=1, 2, 3, etc). Se vuelve a
solicitar al usuario 1 ingresar una nueva frase.

El número de errores permitidos inicialmente es de 8, y va disminuyendo de 1 en 1 hasta 0. Si el usuario 2 adivina la


frase con cero errores permitidos debe mostrarse el mensaje “GANASTE” y terminó el juego.

Una vez terminado el juego se espera que se presione y suelte el pulsador SW2 para reiniciarlo.
PROBLEMA 05:

Se tiene conectada a la tarjeta de evaluación EK-TM4C123GXL una computadora personal por el puerto serial donde
se ejecuta el programa PuTTY, desarrollar un programa para el microcontrolador TM4C123GH6PM que cumpla con
los siguientes requerimientos:

El microcontrolador espera que el usuario ingrese una frase por el puerto serial (la frase termina al recibir el código
ASCII de la tecla ENTER), el microcontrolador debe retransmitir la frase donde las letras iniciales y finales de cada
palabra estén en mayúsculas y el resto en minúsculas, otros caracteres no se deben ver afectados. Luego se vuelve a
esperar otra cadena.

Ejemplo de cómo se vería en la pantalla del PuTTY:

Hola mUndO 2016 <ENTER>


HolA MundO 2016

PROBLEMA 06:

Desarrollar un programa que solicite al usuario ingresar una frase por el teclado (al ingresar la frase debe haber eco por
cada carácter) y luego transmita dicha frase con los caracteres en mayúsculas y minúsculas alternadamente.
Ejemplo:

Ingrese frase:
Pontificia Universidad Catolica del Peru<ENTER>
PoNtIfIcIA UnIvErSiDaD CaToLiCa DeL PeRu
Ingrese frase:

Para la solución del problema necesariamente debe desarrollar y usar la siguiente función:

void CadenaMayMin(unsigned char cadena[])


Convierte una cadena de caracteres ASCIIZ a una donde los caracteres están en mayúsculas y
minúsculas de manera alternada. El primer carácter de la cadena, así como el primer carácter después
de un espacio se convierte siempre a mayúscula.
Entrada: Dirección de inicio de la cadena a convertir
Salida: Ninguna

Ejemplo
Esta función debe convertir la cadena:
“laboRAtorio de sISTeMas digiTales”
En
“LaBoRaToRiO De SiStEmAs DiGiTaLeS”

PROBLEMA 07:
Desarrollar la función
void ConfiguraUART0(uint32_t VelTx, uint8_t NumBitsDatos, uint8_t Paridad, uint8_t NumBitsParada)
La función configura el UART0 del microcontrolador con los parámetros de comunicación de la entrada. Considere una
frecuencia de reloj del sistema de 16MHz.
Entrada: VelTx: Velocidad de transmisión a la que debe configurarse el UART0.
NumBitsDatos: Cantidad de bits de datos, puede ser 5, 6, 7, u 8.
Paridad: Tipo de paridad. Puede ser N (0 sin paridad), O (1 paridad impar), o E (2 paridad par)
NumBitsParada: Cantidad de bits de parada, puede ser 1 o 2.
Salida: Ninguna.

Ejemplo: ConfiguraUART0(9600, 8, N, 1); // Configura el UART0 a 9600, 8, N, 1


ConfiguraUART0(15200, 7, E, 2); // Configura el UART0 a 15200, 7, E, 2
BIBLIOTECA UART

Archivo UART.h

/****************************************************************************************/
/****************************************************************************************/
/***** PONTIFICIA UNIVERSIDAD CATÓLICA DEL PERÚ *****/
/***** FACULTAD DE CIENCIAS E INGENIERÍA *****/
/***** SISTEMAS DIGITALES *****/
/****************************************************************************************/
/***** Archivo: UART.h *****/
/***** Microcontrolador: TM4C123GH6PM *****/
/***** Módulo(s) uC: UART0 *****/
/***** EvalBoard: Tiva C Series TM4C123G LaunchPad *****/
/***** Autor: Rolando Sánchez Ponce *****/
/***** Fecha: Octubre 2017 *****/
/***** Última revisión: Mayo 2019 *****/
/****************************************************************************************/
/***** Funciones para comunicación serial asíncrona mediante el UART0. *****/
/****************************************************************************************/
/***** Conexiones: *****/
/***** U0Rx - PA0 *****/
/***** U0Tx - PA1 *****/
/****************************************************************************************/
/****************************************************************************************/
#ifndef _UART_H_
#define _UART_H_

/****************************************************************************************/
/***** C O N S T A N T E S *****/
/****************************************************************************************/

/***** CONSTANTES BOOLEANAS *****/


#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif

/***** CONSTANTES PARA CARACTERES ASCII *****/


#define LF 10 // Nueva línea
#define FF 12 // Nueva página
#define CR 13 // Retorno de carro

/****************************************************************************************/
/***** P R O T O T I P O S D E F U N C I O N E S *****/
/****************************************************************************************/

/****************************************************************************************/
/***** UART_Inicializa() *****/
/****************************************************************************************/
/***** Configura el UART0 con los siguientes parámetros de comunicación serial: *****/
/***** 9600bps, 8 bits de datos, sin paridad, 1 bit de parada. *****/
/***** Para una frecuencia de reloj del sistema de 16MHz. *****/
/****************************************************************************************/
/***** ENTRADAS: Ninguna *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void UART_Inicializa(void);
/****************************************************************************************/
/***** UART_EsperaDato() *****/
/****************************************************************************************/
/***** Lee un dato recibido por el puerto serial, para esto espera que haya un dato *****/
/***** en el buffer de recepción del UART0 para leerlo. *****/
/****************************************************************************************/
/***** ENTRADAS: Ninguna *****/
/***** SALIDA: Dato recibido por el UART0 *****/
/****************************************************************************************/
uint8_t UART_EsperaDato(void);

/****************************************************************************************/
/***** UART_SondeaRx() *****/
/****************************************************************************************/
/***** Revisa si hay algún dato recibido en el buffer de recepción del UART0. *****/
/***** Devuelve TRUE si hay dato y FALSE si no hay dato recibido, además si hubiera *****/
/***** lo lee. No hay lazo de espera. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** *datoRxPtr: Dirección de memoria donde se almacenará el dato *****/
/***** recibido si lo hubiera. *****/
/***** SALIDA: TRUE: Hay dato recibido y leido. *****/
/***** FALSE: No hay dato recibido. *****/
/****************************************************************************************/
uint8_t UART_SondeaRx(uint8_t *datoRxPtr);

/****************************************************************************************/
/***** UART_TransmiteDato() *****/
/****************************************************************************************/
/***** Escribe un byte en el buffer de transmisión del UART0 para ser transmitido *****/
/***** por el puerto serial. Si el buffer estuviera lleno espera hasta que se pueda *****/
/***** escribir. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** datoTx: Dato a transmitir por el puerto serial *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void UART_TransmiteDato(uint8_t datoTx);

/****************************************************************************************/
/***** UART_SiguienteLinea() *****/
/****************************************************************************************/
/***** Transmite los caracteres necesarios para posicionar el cursor de la pantalla *****/
/***** del terminal al inicio de la siguiente línea. *****/
/****************************************************************************************/
/***** ENTRADAS: Ninguna *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void UART_SiguienteLinea(void);

/****************************************************************************************/
/***** UART_EsperaCadena() *****/
/****************************************************************************************/
/***** Recibe por el puerto serial una cadena de caracteres ASCII y la almacena en *****/
/***** un arreglo. El usuario ingresa ENTER para finalizar y debe ingresar por lo *****/
/***** menos un caracter antes del ENTER. La función inserta 0 al final de la cade- *****/
/***** na para que sea ASCIIZ. La función hace un eco por cada caracter recibido y *****/
/***** posiciona el cursor al inicio de la siguiente línea al salir. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** cadenaASCIIZ[]: Dirección de inicio de la cadena ASCIIZ a recibir. *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void UART_EsperaCadena(uint8_t cadenaASCIIZ[]);
/****************************************************************************************/
/***** UART_TransmiteCadena() *****/
/****************************************************************************************/
/***** Transmite por el puerto serial una cadena ASCIIZ. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** cadenaASCIIZ[]: Dirección de inicio de la cadena ASCIIZ a transmitir. *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void UART_TransmiteCadena(const uint8_t cadenaASCIIZ[]);

/****************************************************************************************/
/***** UART_EsperaNumeroB10() *****/
/****************************************************************************************/
/***** Recibe por el puerto serial una cadena de caracteres ASCII que representa *****/
/***** un número en base 10. El usuario ingresa ENTER para finalizar y debe ingre- *****/
/***** sar por lo menos un digito antes del ENTER. *****/
/***** La función hace un eco por cada caracter recibido y posiciona el cursor al *****/
/***** inicio de la siguiente línea al salir. *****/
/****************************************************************************************/
/***** ENTRADAS: Ninguna. *****/
/***** SALIDA: Número ingresado por el usuario. *****/
/***** Rango [0, 4294967295] *****/
/****************************************************************************************/
uint32_t UART_EsperaNumeroB10(void);

/****************************************************************************************/
/***** UART_TransmiteNumeroB10() *****/
/****************************************************************************************/
/***** Transmite por el puerto serial los caracteres que representan un número en *****/
/***** base 10. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** numero: Número a transmitirse en caracteres ASCII. *****/
/***** Rango [0, 4294967295] *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void UART_TransmiteNumeroB10(uint32_t numero);

#endif

/****************************************************************************************/
/***** F I N D E L A R C H I V O *****/
/****************************************************************************************/
Archivo UART.c

/****************************************************************************************/
/****************************************************************************************/
/***** PONTIFICIA UNIVERSIDAD CATÓLICA DEL PERÚ *****/
/***** FACULTAD DE CIENCIAS E INGENIERÍA *****/
/***** SISTEMAS DIGITALES *****/
/****************************************************************************************/
/***** Archivo: UART.c *****/
/***** Microcontrolador: TM4C123GH6PM *****/
/***** Módulo(s) uC: UART0 *****/
/***** EvalBoard: Tiva C Series TM4C123G LaunchPad *****/
/***** Autor: Rolando Sánchez Ponce *****/
/***** Fecha: Octubre 2017 *****/
/***** Última revisión: Mayo 2019 *****/
/****************************************************************************************/
/***** Funciones para comunicación serial asíncrona mediante el UART0. *****/
/****************************************************************************************/
/***** Conexiones: *****/
/***** U0Rx - PA0 *****/
/***** U0Tx - PA1 *****/
/****************************************************************************************/
/****************************************************************************************/
#include <stdint.h>
#include "tm4c123gh6pm.h"
#include "UART.h"

/****************************************************************************************/
/***** F U N C I O N E S P Ú B L I C A S *****/
/****************************************************************************************/

/****************************************************************************************/
/***** UART_Inicializa() *****/
/****************************************************************************************/
/***** Configura el UART0 con los siguientes parámetros de comunicación serial: *****/
/***** 9600bps, 8 bits de datos, sin paridad, 1 bit de parada. *****/
/***** Para una frecuencia de reloj del sistema de 16MHz. *****/
/****************************************************************************************/
/***** ENTRADAS: Ninguna *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void UART_Inicializa(void){
// Activamos el reloj para el UART0
SYSCTL_RCGCUART_R |= SYSCTL_RCGCUART_R0;
while(!(SYSCTL_PRUART_R & SYSCTL_PRUART_R0));
// Inhabilitamos el UART0
UART0_CTL_R &= ~UART_CTL_UARTEN;
// Velocidad 9600bps (Fsysclk = 16MHz)
UART0_IBRD_R = (UART0_IBRD_R & 0xFFFF0000) | 104;
UART0_FBRD_R = (UART0_FBRD_R & 0xFFFFFFC0) | 11;
// 8, N, 1, FIFOs habilitados
UART0_LCRH_R = (UART0_LCRH_R & 0xFFFFFF00) | 0x70;
// Habilitamos el UART0, recepción y transmisión
UART0_CTL_R |= (UART_CTL_RXE | UART_CTL_TXE | UART_CTL_UARTEN);
// Activamos la señal de reloj para GPIOA
SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R0;
while(!(SYSCTL_PRGPIO_R & SYSCTL_PRGPIO_R0));
// Activamos funciones alternas para PA0 y PA1
GPIO_PORTA_AFSEL_R |= 0x03;
// Conectamos UART0 a PA0 y PA1
GPIO_PORTA_PCTL_R = (GPIO_PORTA_PCTL_R&0xFFFFFF00)|0x00000011;
// Desactivamos funciones analógicas en PA0 y PA1
GPIO_PORTA_AMSEL_R &= ~(0x03);
// Activamos funciones digitales en PA0 y PA1
GPIO_PORTA_DEN_R |= 0x03;
}

/****************************************************************************************/
/***** UART_EsperaDato() *****/
/****************************************************************************************/
/***** Lee un dato recibido por el puerto serial, para esto espera que haya un dato *****/
/***** en el buffer de recepción del UART0 para leerlo. *****/
/****************************************************************************************/
/***** ENTRADAS: Ninguna *****/
/***** SALIDA: Dato recibido por el UART0 *****/
/****************************************************************************************/
uint8_t UART_EsperaDato(void){
uint8_t datoRx;
while(UART0_FR_R & UART_FR_RXFE);
datoRx = (uint8_t)UART0_DR_R;
return datoRx;
}

/****************************************************************************************/
/***** UART_SondeaRx() *****/
/****************************************************************************************/
/***** Revisa si hay algún dato recibido en el buffer de recepción del UART0. *****/
/***** Devuelve TRUE si hay dato y FALSE si no hay dato recibido, además si hubiera *****/
/***** lo lee. No hay lazo de espera. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** *datoRxPtr: Dirección de memoria donde se almacenará el dato *****/
/***** recibido si lo hubiera. *****/
/***** SALIDA: TRUE: Hay dato recibido y leido. *****/
/***** FALSE: No hay dato recibido. *****/
/****************************************************************************************/
uint8_t UART_SondeaRx(uint8_t *datoRxPtr){
uint8_t hayDatoRxFlag;
hayDatoRxFlag = FALSE;
if(!(UART0_FR_R & UART_FR_RXFE)){
*datoRxPtr = (uint8_t)UART0_DR_R;
hayDatoRxFlag = TRUE;
}
return hayDatoRxFlag;
}

/****************************************************************************************/
/***** UART_TransmiteDato() *****/
/****************************************************************************************/
/***** Escribe un byte en el buffer de transmisión del UART0 para ser transmitido *****/
/***** por el puerto serial. Si el buffer estuviera lleno espera hasta que se pueda *****/
/***** escribir. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** datoTx: Dato a transmitir por el puerto serial *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void UART_TransmiteDato(uint8_t datoTx){
while(UART0_FR_R & UART_FR_TXFF);
UART0_DR_R = (UART0_DR_R & 0xFFFFFF00) | datoTx;
}

/****************************************************************************************/
/***** UART_SiguienteLinea() *****/
/****************************************************************************************/
/***** Transmite los caracteres necesarios para posicionar el cursor de la pantalla *****/
/***** del terminal al inicio de la siguiente línea. *****/
/****************************************************************************************/
/***** ENTRADAS: Ninguna *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void UART_SiguienteLinea(void){
// Transmitimos nueva línea (LF)
UART_TransmiteDato(LF);
// Transmitimos retorno de carro (CR)
UART_TransmiteDato(CR);
}

/****************************************************************************************/
/***** UART_EsperaCadena() *****/
/****************************************************************************************/
/***** Recibe por el puerto serial una cadena de caracteres ASCII y la almacena en *****/
/***** un arreglo. El usuario ingresa ENTER para finalizar y debe ingresar por lo *****/
/***** menos un caracter antes del ENTER. La función inserta 0 al final de la cade- *****/
/***** na para que sea ASCIIZ. La función hace un eco por cada caracter recibido y *****/
/***** posiciona el cursor al inicio de la siguiente línea al salir. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** cadenaASCIIZ[]: Dirección de inicio de la cadena ASCIIZ a recibir. *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void UART_EsperaCadena(uint8_t cadenaASCIIZ[]){
uint8_t datoRx;
uint8_t hay1CaracterFlag = FALSE;
uint8_t finFlag = FALSE;
uint8_t i = 0;

do{
// Esperamos recibir un dato por el puerto serial.
datoRx = UART_EsperaDato();
// Si dato recibido es diferente de ENTER.
if(datoRx != CR){
if(!hay1CaracterFlag) hay1CaracterFlag = TRUE;
UART_TransmiteDato(datoRx);
cadenaASCIIZ[i++] = datoRx;
}
// Si dato recibido es ENTER.
else if(hay1CaracterFlag){
cadenaASCIIZ[i] = 0;
UART_SiguienteLinea();
finFlag = TRUE;
}
}while(!finFlag);
}

/****************************************************************************************/
/***** UART_TransmiteCadena() *****/
/****************************************************************************************/
/***** Transmite por el puerto serial una cadena ASCIIZ. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** cadenaASCIIZ[]: Dirección de inicio de la cadena ASCIIZ a transmitir. *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void UART_TransmiteCadena(const uint8_t cadenaASCIIZ[]){
uint8_t i;
for(i=0; cadenaASCIIZ[i]; i++){
UART_TransmiteDato(cadenaASCIIZ[i]);
}
}

/****************************************************************************************/
/***** UART_EsperaNumeroB10() *****/
/****************************************************************************************/
/***** Recibe por el puerto serial una cadena de caracteres ASCII que representa *****/
/***** un número en base 10. El usuario ingresa ENTER para finalizar y debe ingre- *****/
/***** sar por lo menos un digito antes del ENTER. *****/
/***** La función hace un eco por cada caracter recibido y posiciona el cursor al *****/
/***** inicio de la siguiente línea al salir. *****/
/****************************************************************************************/
/***** ENTRADAS: Ninguna. *****/
/***** SALIDA: Número ingresado por el usuario. *****/
/***** Rango [0, 4294967295] *****/
/****************************************************************************************/
uint32_t UART_EsperaNumeroB10(void){
uint8_t datoRx;
uint32_t numero = 0;
uint8_t hay1DigitoFlag = FALSE;
uint8_t finFlag = FALSE;

do{
// Esperamos recibir un dato por el puerto serial.
datoRx = UART_EsperaDato();
// Si dato recibido es diferente de ENTER.
if(datoRx != CR){
// Si dato recibido es un caracter numérico
if(('0'<=datoRx)&&(datoRx<='9')){
if(!hay1DigitoFlag) hay1DigitoFlag = TRUE;
UART_TransmiteDato(datoRx);
numero = 10*numero + datoRx-'0';
}
}
// Si dato recibido es ENTER.
else if(hay1DigitoFlag){
UART_SiguienteLinea();
finFlag = TRUE;
}
}while(!finFlag);

return numero;
}

/****************************************************************************************/
/***** UART_TransmiteNumeroB10() *****/
/****************************************************************************************/
/***** Transmite por el puerto serial los caracteres que representan un número en *****/
/***** base 10. *****/
/****************************************************************************************/
/***** ENTRADAS: *****/
/***** numero: Número a transmitirse en caracteres ASCII. *****/
/***** Rango [0, 4294967295] *****/
/***** SALIDA: Ninguna *****/
/****************************************************************************************/
void UART_TransmiteNumeroB10(uint32_t numero){
uint32_t divisor = 1000000000;
uint8_t hayDigSigFlag = FALSE;
uint8_t i, digito;

// Repetimos 10 veces: máxima cantidad de dígitos que puede tener número.


for(i=0; i<10; i++){
// Hallamos digito y actualizamos numero y divisor.
digito = numero / divisor;
numero = numero % divisor;
divisor = divisor / 10;
// Si aún no llegamos al dígito más significativo de numero.
if(!hayDigSigFlag){
// Si digito es diferente de 0
if(digito != 0){
hayDigSigFlag = TRUE;
UART_TransmiteDato(digito + '0');
}
// Si digito es 0 y es la última iteración
else if(i==9){
UART_TransmiteDato(digito + '0');
}
}
// Si ya hemos llegado al dígito más significativo.
else{
UART_TransmiteDato(digito + '0');
}
}
}

/****************************************************************************************/
/***** F I N D E L A R C H I V O *****/
/****************************************************************************************/

Rolando Sánchez Ponce


Mayo 2019

También podría gustarte