Professional Documents
Culture Documents
MÓDULO 3:
Puerto serie (SCI)
Introducción al lenguaje C (II)
2
Programación
de periféricos
Comunicaciones serie
3
Comunicación serie VS paralela
SERIE
● Los bits se transmiten en
serie, uno detrás de otro
● Sólo se necesita 1 hilo
● Más lento
PARALELO
● Más rápido
4
Comunicación serie síncrona VS asíncrona
ASÍNCRONA
● Cada sistema tiene su
propio reloj local.
● Sincronización mediante
SÍNCRONA
● Una señal de Reloj común
● El MAESTRO genera el
reloj
● Dos hilos
● Velocidades mayores
5
Full-duplex VS Half-duplex
FULL-DUPLEX
● Comunicación
bidireccional simultánea
● Dos canales de datos (TX,
RX)
● Dos hilos
HALF-DUPLEX
● Comunicación
bidireccional multiplexada
en el tiempo
● Un único canal (DATA)
● Primero en un sentido,
6
La USART del PIC
● USART = Universal Synchronous Asynchronous Receiver Transmitter
● Otro nombre equivalente: SCI. Serial Communication Interface
● Modos de funcionamiento:
7
Norma RS-232 (I)
8
Norma RS-232 (II)
DB9 macho
9
Comunicación entre el PIC y el PC
11
Registros del SCI en el PIC (II)
12
Ejemplo: Configuración del SCI
sci-conf.c
Configuración a 9600 baudios, 8N1
#include <pic16f876a.h>
#define LED RB1 Cada vez que se recibe un carácter
se cambia el estado del led
void main(void)
{ Configurar LED
volatile unsigned char c;
Configurar a 9600 baudios
TRISB1=0;
BRGH=1; SPBRG=129; Comunicaciones asíncronas
SYNC=0;
SPEN=1; Activar pines del puerto serie
CREN=1;
Habilitar el recepctor
TXEN=1;
Habilitar el transmisor
while(1) {
while (RCIF==0); Esperar a que se reciba un byte
c=RCREG; Leer byte recibido para que el flag
LED^=1; RCIF se ponga a cero (volatile!)
}
Cambiar el led de estado
}
13
Ejemplo: Configuración del SCI (II)
Configuración
14
Ejemplo: Configuración del SCI (III)
sci-conf2.c
#include <pic16f876a.h>
#define LED RB1
void main(void)
Configurar puerto serie
{
volatile unsigned char c;
TRISB1=0;
sci_conf();
while(1) {
while (RCIF==0);
c=RCREG;
LED^=1;
}
15
}
Ejemplo: Envío-recepción de bytes
sci-eco.c
el valor 0
sci-cad2.c
#include <pic16f876a.h>
void sci_conf() {...}
unsigned char sci_read() {...} Funciones de los ejemplos anteriores
void sci_write() {...}
void sci_cad() {...}
void main(void)
Cadena que contiene caracteres
{ especiales
unsigned char cad[]="hola\b\b\b\b";
sci_conf();
TRISB=0; Enviar la cadena
while(1) { Esperar a que llegue un carácter
sci_cad(cad); y sacarlo por los leds, para
PORTB=sci_read(); mostrar que hay actividad
}
}
20
La instrucción switch
21
La instrucción switch: Ejemplo (I)
sci-menu.c (parte 1)
void menu(void)
{
Carácter \n al final de cada
sci_cad("Menu\n"); cadena: Salto de línea
sci_cad("\n");
sci_cad("1. Cambiar el estado del led\n");
sci_cad("2. Poner todo el puerto B a 1\n");
Si se prueba desde el
sci_cad("3. Reset del puerto B\n");
hyperterminal de windows
sci_cad("4. Sacar este menu otra vez\n");
posiblemente haya que añadir \r
sci_cad("Opcion? ");
al final, para que se vea
} correctamente
22
sci-menu.c (parte 2) La instrucción switch: Ejemplo (II)
void main(void)
{
unsigned char c;
TRISB=0; Sacar el menú
sci_conf();
menu();
Esperar la opción del usuario
while(1) {
c=sci_read(); Según el carácter recibido....
switch(c) {
case '1': Si es la opción 1...
LED^=1; Cambiar el led de estado
break;
case '2': Si es la opción 2...
PORTB=0xFF; Todos los pines del puerto B a '1'
break;
case '3': Si es la opción 3...
PORTB=0x00;
break; Todos los pines del puerto B a '0'
case '4':
Si es la opción 4...
menu();
break; Sacar el menú
}
} 23
}
Probando el programa sci-menu.c
● Arrancar el terminal. Pulsar reset. Aparecerá el menú:
24
Ejercicio:
●Hacer un programa que envíe una cadena (por ejemplo “Hola como
estas...”) por el puerto serie, pero carácter a carácter.
25
Errores en la recepción
● Acciones a tomar:
● El software de bajo nivel no puede hacer nada
● Hay que notificarlo al software de nivel superior para:
● Que se descarte el dato
● Que se solicite retransmisión (PROTOCOLO)
● Este error se puede ignorar si se están empleando tramas que
llevan incorporado un CRC para la detección de errores.
26
Errores en la recepción (II)
● Error de overflow
●Se produce cuando el buffer de recepción (2 bytes) se llena y el
software del PIC no ha realizado lecturas.
●Esto ocurre si el software no lee los datos recibidos con la
suficiente frecuencia
● El efecto es que se pierden datos.
● Se activa el flag OERR.
● Acciones a tomar:
● Para desactivar OERR, hay que poner CREN=0 y luego CREN=1.
Con esto se activa el recptor y se pueden seguir recibiendo datos
●Igual que en el caso anterior, se puede notificar al nivel superior
para solicitar retransmisión de datos (PROTOCOLO).
● Se puede ignorar si se están empleando tramas que llevan
incorporado un CRC para la detección de errores, o bien se están 27
usando timeouts.
Ejemplo de overflow
sci-error.c Funciones de los
ejemplos anteriores
#include <pic16f876a.h>
#define LED RB1 Enviar cadena al PC
void sci_conf() {...}
unsigned char sci_read() {...} Pausa. Simulamos que el PIC
void sci_write() {...} está haciendo operaciones
void sci_cad() {...}
void pausa() {...} Leer un dato por el puerto serie
Solución:
●Usar while comprobando al menos dos condiciones: el valor que
queremos y la condición de error o un timeout, de manera que nunca
pueda entrar en bucle infinito
● Usar interrupciones.
29
Solución para el bloqueo del programa sci-error.c
El programa ahora no se
cuelga
30
Operadores booleanos y condicionales
En C:
Verdadero significa que se devuelve un número positivo distinto de 0
Falso significa que se devuelve 0
31
Interrupciones
32
Interrupción de carácter recibido: Pruebas
sci-int-rx.c
34
sci-contador-eco.c Interrupción de carácter recibido (II)
#include <pic16f876a.h>
unsigned char c;
#include <pic16f876a.h>
Programa “hola mundo” para probar las
unsigned char i=0; interrupciones del puerto serie. Se envia la
unsigned char cad[]={'h','o','l','a',0}; cadena “hola” mediante interrupciones
void sci_conf() {...} Rutina de atención a la interrupción.
void isr() interrupt 0 Cada vez que el PIC está listo para enviar
{ un carácter se ejecuta esta rutina
if (cad[i]!=0) {
TXREG=cad[i];
i++;
}
}
void main(void)
{
unsigned char cont=0;
TRISB=0;
Activar interrupciones
sci_conf();
TXIE=1;
PEIE=1; El bucle principal no hace nada
GIE=1;
while(1);
}
36
Interrupción de carácter transmitido
37
Interrupción de carácter transmitido (II)
sci-contadores.c
#include <pic16f876a.h>
unsigned char i=0;
Formas de hacerlo:
39
Reutilización de código: Código en fichero .h (I)
VENTAJAS:
● Método sencillo y rápido. Válido para hacer pruebas rápidas
● No hay que cambiar ningún parámetro de compilación
INCONVENIENTES:
●Método “cutre”. Los fichero .h no se usan para incluir código, sino
para almacenar macros, deficiones y los prototipos de las funciones.
●Cada vez que se compila nuestro programa, también se compilarán
estas funciones, aunque no se hayan modificado. Si es un proyecto
grande se pierde tiempo de compilación innecesariamente
40
Reutilización de código: Código en fichero .h (II)
sci.h
#include <pic16f876a.h> void sci_cad(unsigned char *cad)
{
void sci_conf() unsigned char i=0;
{
BRGH=1; SPBRG=129; while (cad[i]!=0) {
SYNC=0; SPEN=1; sci_write(cad[i]);
CREN=1; TXEN=1; i++;
} }
}
unsigned char sci_read()
{
unsigned char car;
while (RCIF==0 && OERR==0);
●Todas las funciones del SCI las
car = RCREG; agrupamos en el fichero sci.h
if (OERR==1) {
CREN=0;
CREN=1;
}
return car;
}
void sci_write(unsigned char dato)
{
while (TXIF==0);
TXREG=dato;
} 41
Reutilización de código: Código en fichero .h (III)
#include
<pic16f876a.h> Programa “clásico” del Eco, pero usando las
#include "sci.h" funciones definidas en sci.h. El programa es
ahora mucho más corto y fácil de entender.
void main(void)
{
unsigned char c;
TRISB=0; Compilación:
sci_conf();
sdcc -Wl-ainhx8m -mpic14 -p16f876a -o sci-test sci-test.c
while(1) {
c=sci_read(); Exactamente igual que los ejemplos vistos
PORTB=c; hasta ahora
sci_write(c);
}
}
42
Reutilización de código: Módulos (I)
Programa Módulo
Mi_programa.c
Mi_modulo.c Mi_modulo.h
Código Prototipos
+ Mi_programa.hex
Enlazado
43
Módulo libsci para el manejo del SCI (I)
libsci.c
#include <pic16f876a.h> void sci_cad(unsigned char *cad)
{
void sci_conf() unsigned char i=0;
{
BRGH=1; SPBRG=129; while (cad[i]!=0) {
SYNC=0; SPEN=1; sci_write(cad[i]);
CREN=1; TXEN=1; i++;
} }
}
unsigned char sci_read()
{
unsigned char car;
while (RCIF==0 && OERR==0); libsci.h
car = RCREG;
if (OERR==1) { void sci_conf();
CREN=0; unsigned char sci_read();
CREN=1; void sci_write(unsigned char dato);
} void sci_cad(unsigned char *cad);
return car;
}
void sci_write(unsigned char dato)
{ Prototipos
while (TXIF==0);
TXREG=dato;
} 44
Módulo libsci para el manejo del SCI (II): Ejemplo
Compilación:
modulo1.o
modulo2.o + libreria.lib
modulo3.o
Programa Libreria
modulo1
Mi_programa.c modulo2
modulo3
+ Mi_programa.hex
Enlazado
46
Librerías (II). Ejemplo: libsci.lib
47
Ejemplo de PIC + PC: Monitorización del Skybot (I)
Sensores de infrarrojos
Sensores de contacto
Sensor de luz
Control de los motores
PC
Comunicación serie
Robot Skybot 49
Ejercicio final de puerto serie:
50
PIC 16F87X