Comunicación RS232
Prueba de conexión serie entre un PIC y una PC
Circuito convertidor serie-paralelo para el port serie de la PC
por Eduardo J. Carletti
Presento aquí la prueba de laboratorio de un circuito realizado
específicamente para experimentar, de manera básica, con la comunicación entre un microcontrolador
PIC 16F628A
y el puerto serie de una PC (estándar RS-232). El circuito tiene, además del microcontrolador, un integrado
convertidor de niveles RS232 a TTL que es reemplazo del conocido MAX232,
pero cuesta más barato en el mercado argentino. Se trata del
HIN232CP de
Intersil.
Integrado HIN232CP: Los circuitos con letra T son "Transmitters", que trasladan nivel TTL/CMOS en su
entrada a nivel RS232 en su salida. Los circuitos con letra R son "Receivers", que
trasladan señales RS232 en su entrada (que pueden ser de hasta +30/-30 V) a nivel
TTL/CMOS en su salida.
|
Aquí voy a hacer una pequeña disgresión sobre por qué utilizo el
PIC 16F628A en esta ocasión y en gran parte de los proyectos que encaro y encararé,
excepto cuando las prestaciones de este microcontrolador no sean suficientes para la
función requerida.
La razón principal es que es pata a pata compatible con el más antiguo pero ya clásico
PIC 16F84A. Y es compatible en sus programas, con la única salvedad de que la memoria
RAM se encuenta en otra dirección. Transformar un programa hecho para el PIC 16F84A para
utilizarlo en este microcontrolador es una cosa de segundos. Y hay miles de ejemplos en
Internet y en libros y revistas para el 16F84A, porque hace años que se diseña sobre él,
como procesador básico.
Distribución de patas (con sus funciones) del PIC 16F628A. |
El PIC 16F84A puede estar muy bien como elección para
comenzar, pero la única razón que va quedando para hacerlo es que la mayoría de los
ejemplos de programa y de circuito que se encuentran por allí están realizados sobre él.
En base a lo dicho en el párrafo anterior, entonces el PIC 16F628A es igual de elegible,
ya que es un reemplazo prácticamente directo de nuestro famoso microcontrolador "de
batalla". ¿Pero por qué cambiar, si ambos están disponibles en el mercado? Por una razón
muy simple: el PIC 16F628A tiene más memoria de programa (el doble), más RAM, más EEPROM,
más modos de uso, más timers, y más prestaciones, incluyendo la que aprovechamos en este
diseño, el puerto serie implementado por hardware... y el PIC 16F628A, por lo menos en
Argentina, cuesta menos... ¿Por qué no cambiar, entonces?
COMPARACIÓN
| 16F84A | 16F628A
|
Memoria programa | 1K | 2K
|
Memoria datos | 68 bytes | 224 bytes
|
EEPROM | 64 bytes | 128 bytes
|
Timers | 1 | 3
|
PWM | - | 1
|
Reg. comparación/captura | - | sí
|
Comparadores | - | 2
|
Referencias de voltaje | - | 1
|
Oscilador interno reloj | - | 37 KHz / 4 MHz
|
Patas usables E/S | 13 | 16
|
Programación a bajo voltaje | - | sí
|
Ahora volvamos al circuito de esta prueba
El microcontrolador se comunica utilizando su puerto serie.
He programado este puerto a una velocidad de 9600 baudios, un formato de dato de 8 bits, sin paridad,
un bit de parada, y sin ningún control de flujo. El programa en el microcontrolador
se inicia enviando un mensaje a la PC que dice Hola amigo. Luego la rutina principal de este
pequeño programa espera a recibir un caracter, lo devuelve como
eco hacia la PC, y luego lo exhibe a través de sus puertos, donde tenemos conectados
LEDs indicadores. Esto nos permite comprobar la recepción de los caracteres ASCII desde
la PC, cuyo código veremos sobre los LEDs. También hace que nuestro circuito cumpla la
función de transformar la salida serie de la PC en una salida de 8 bits en paralelo.
A continuación se puede observar los circuitos que he utilizado:
Circuito del interfaz de comunicación RS232 entre un PIC y una PC
Módulo adaptador USB - TTL
Algún lector observador habrá notado que no se utiliza el Puerto A
completo (1 byte) para manejar los LEDs que exhiben el caracter que se ha recibido desde la PC.
Los bits 4 y 5 del
Puerto A no se utilizan, y a cambio los LEDs que corresponden a estos bits se
conectan al Puerto B. ¿Por qué complicarse así? ¿No es mejor escribir un byte
completo en un puerto, sin tener que manejar dos bits por separado en otro puerto,
que para peor tiene dos bits afectados a la comunicación serie?
Paciencia, todo tiene su explicación: Tal como se ha configurado el microcontrolador, el Puerto A tiene, efectivamente, ocho
bits de ancho, pero por características de circuito no se pueden utilizar los ocho
como salida. El bit 5 solamente se puede utilizar como entrada, y el bit 4 tiene un
circuito de salida de drenaje abierto, es decir, cuando está en alto no entrega corriente,
de manera que no encendería el LED con el circuito que estamos utilizando. Antes que
ponerme a hacer algunos malabarismos con el circuito, preferí solucionar esto por
programa y "sacar" los dos bits faltantes a través del Puerto B, bits 4 y 5. El "costo"
de esta solución son tres o cuatro líneas de programa, nada más.
Montaje del circuito de conexión serie entre un PIC 16F628A y una PC
Detalle de montaje del circuito de conexión serie
Programa
;*******************************************************************
; INTERFAZ SERIE RS232 - ECO Y DISPLAY EN LEDS
; CONVERTIDOR SERIE RS232 - PARALELO 8 BITS
;*******************************************************************
LIST P=16F628, R=DEC ; Usar el PIC16F628 y sistema decimal
#include "P16F628A.INC" ; Incluye datos de PIC16F628A
CONFIG _CP_OFF & _WDT_OFF & _LVP_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF
;*******************************************************************
; CONFIGURACION
;*******************************************************************
; El PIC es configurado para usar todas las entradas y salidas
; posibles = 16. Por eso no se usa el oscilador con cristal externo,
; lo que deja libres las patas 15 y 16 para usar como bits de puerto.
; Se define el clock interno a 4 MHz. No se usa el master reset
; (pata 4), que queda convertida en el Puerto A, bit 5 (entrada).
;*******************************************************************
; VARIABLES
;*******************************************************************
contador EQU 0x28 ; variable
dato_serie EQU 0x29 ; dato serie desde la PC
;*******************************************************************
ORG 0x000 ; El programa empieza en 0x000
;*******************************************************************
; Inhibe comparadores
;*******************************************************************
movlw 7
movwf CMCON ; CMCON=7 inhibir los comparadores
;*******************************************************************
; Inicializar Puertos
;*******************************************************************
movlw b'00000000' ; valor inicial portA
movwf PORTA
movlw b'00000000' ; valor inicial portB
movwf PORTB
bsf STATUS,RP0 ; Pág 1 RAM
movlw b'00000000'
movwf TRISA ; salidas (para mostrar el dato en LEDS)
; de estas salidas, no usaremos
; PORTA 4, que tiene salida open drain, y
; PORTA 5, que sólo puede ser entrada
movlw b'11001011' ; RB0 entrada
; RB1 (RX) = entrada
; RB2 (TX) = salida
; RB3 = entrada
; RB2 = salida del bit 4 del dato a LEDS
; RB5 = salida del bit 5 del dato a LEDS
; RB6 y RB7 = entradas
movwf TRISB
;*******************************************************************
; BAUD RATE para la comunicación RS232
; y otras definiciones para USART
;*******************************************************************
; Baud Rate = 9600, Sin Paridad, 1 Bit parada
;
movlw 0x19 ; 0x19=9600 bps (0x0C=19200 bps)
movwf SPBRG
movlw b'00100100' ;
movwf TXSTA ; habilita la transmisión Async
bcf STATUS,RP0 ; RAM PAGE 0
movlw b'10010000' ; habilita de recepción Async
movwf RCSTA
;*******************************************************************
; TIEMPO DE ESTABILIZACION
;*******************************************************************
clrf contador
estab decfsz contador,F
goto estab
movf RCREG,W
movf RCREG,W
movf RCREG,W ; vacía el buffer de recepción
call Bienvenida ; envía mensaje de bienvenida
;*******************************************************************
; LAZO PRINCIPAL
;*******************************************************************
loop
clrw
btfss PIR1,RCIF ; (5) se fija si hay dato RS232
goto loop ; no, no llegó
call recibeRS232 ; sí, hay
movwf dato_serie ; guarda dato (para uso de cualquier rutina)
call enviaRS232 ; envía el eco a la PC
call muestra ; muestra el caracter recibido en LEDS
goto loop
;*******************************************************************
; RECIBE CARACTER SERIE - RS232 - DESDE LA PC
;*******************************************************************
recibeRS232
movf RCREG,W ; guarda dato recibido en acumulador
return
;*******************************************************************
; ENVIA CARACTER SERIE - RS232 - A LA PC Y ESPERA A QUE HAYA SALIDO
;*******************************************************************
enviaRS232
movwf TXREG ; envío el dato en acunulador w
bsf STATUS,RP0 ; Pág 1 RAM
Espere btfss TXSTA,TRMT ; transmision completa si es alto
goto Espere
bcf STATUS,RP0 ; Pág 0 RAM
return
;*******************************************************************
; MUESTRA DATO
;*******************************************************************
muestra
movf dato_serie,w ; recupera el dato guardado
movwf PORTA ; exhibe el dato en LEDS en PORTA
btfss dato_serie,4 ; pero, como el PORTA tiene el bit 4 que es
bcf PORTB,4 ; open drain, nos conviene poner
btfsc dato_serie,4 ; el bit 4 del dato en otra salida;
bsf PORTB,4 ; lo hacemos en el bit 4 del PORTB.
btfss dato_serie,5 ; y , como el PORTA tiene el bit 5 que es
bcf PORTB,5 ; sólo usable como entrada, tenemos que poner
btfsc dato_serie,5 ; el bit 5 del dato en alguna salida;
bsf PORTB,5 ; lo hacemos en el bit 5 del PORTB.
return
;*******************************************************************
; MENSAJES
;*******************************************************************
Bienvenida
; los primeros caracteres 0x00 son
; para estabilización del circuito
movlw 0x00
call enviaRS232
movlw 0x00
call enviaRS232
movlw 0x00
call enviaRS232
movlw 0x00
call enviaRS232
movlw 0x00
call enviaRS232
call msgCR
movlw 'H'
call enviaRS232
movlw 'o'
call enviaRS232
movlw 'l'
call enviaRS232
movlw 'a'
call enviaRS232
movlw ' '
call enviaRS232
movlw 'a'
call enviaRS232
movlw 'm'
call enviaRS232
movlw 'i'
call enviaRS232
movlw 'g'
call enviaRS232
movlw 'o'
call enviaRS232
msgCR
movlw 0x0D
call enviaRS232
movlw 0x0A
goto enviaRS232
END
|
Bajar el programa en formato ASM (puede usar el botón derecho de su mouse)
Bajar el programa en formato HEX (puede usar el botón derecho de su mouse)
Por las dudas, el archivo incluido P16f628a.inc (puede usar el botón derecho de su mouse)
Programa a utilizar en la PC
Para establecer la comunicación serie desde la PC, se debe utilizar un
programa de Terminal. Sugerimos uno simple que puede bajar desde AQUÍ (en este caso se llama PARALLAX SERIAL TERMINAL (PST.exe, no necesita instalación),
o cualquier otra aplicación de terminal serie básica que usted desee. Cópielo en una carpeta o en su escritorio y cree un ícono de acceso directo
en su escritorio o donde usted desee.
Programa PARALLAX SERIAL TERMINAL (PST.exe)
Los valores que se utilizan en esta comunicación son:
- Bits por segundo = 9600
- Bits de datos = 8
- Paridad = Ninguna
- Bits de parada = 1
- Control de flujo = Ninguno
Con PST.exe sólo deberá definir los Bits por segundo (además de conectarse al puerto COM, ver el Breve Manual de uso.
A partir de Windows 7 y 8 el programa HyperTerminal no está disponible. Utilice un programa de terminal como el que sugerimos arriba
Uso del programa "HyperTerminal" para la comunicación desde la PC
Para establecer la comunicación serie desde la PC, se debe utilizar el
programa HyperTerminal que viene con el sistema operativo Windows, o cualquier otra
aplicación de terminal básica que usted desee.
Aquí se puede ver una explicación de Microsoft sobre cómo utilizar el programa HyperTerminal.
En la configuración de la conexión, usted debe indicar que se va a
conectar "Directo a COM", indicando cuál es el puerto COM de la PC que va a utilizar en
esta comunicación (generalmente es el COM1... pero cada PC es un mundo aparte).
Esto se define en la sección "Configurar".
- Bits por segundo = 9600
- Bits de datos = 8
- Paridad = Ninguna
- Bits de parada = 1
- Control de flujo = Ninguno
Ver las imágenes. (A la izquierda, las propiedades de la conexión
nombrada por mí como "robots", a la derecha, la pantallita "Configurar" del puerto
elegido en esta conexión, el COM1).
|
Algunas cosas que observé
- El uso de los bits de puerto adicionales del PIC 16F628A luego de convertir por configuración las líneas para el cristal del oscilador de reloj y la de Master Clear en bits del Puerto A me causó, al principio, algunos problemas. En concreto, el de los bits 4 y 5 del Puerto A, tema ya explicado arriba. Esto demuestra que se debe leer bien la hoja de datos y nunca dar nada por sobreentendido. La conclusión es que si se utiliza el puerto serie interno del PIC 16F628A (que ocupa dos bits en el Puerto B) no hay disponible, lamentablemente, un puerto completo para manejar un byte entero de salida. No sé si es muy importante, pero en la programación se hace un poco más engorroso "sacar" un byte entero.
- Por lo dicho en el punto anterior, si se desea utilizar de algún modo un byte de salida en paralelo que no sea para exhibirlo en LEDs, se debe implementar un pulso de aviso (strobe) que anuncie que el dato es válido, ya que este byte de salida se actualiza por partes.
- El programa es básico y no tiene ninguna comprobación de confirmaciones en el protocolo de comunicación, así que si se envían datos a mucha velocidad desde la PC se pueden perder datos e incluso puede quedar "colgado" el PIC, situación que a mí no se me ha presentado... pero puede pasar.
- Según todas las teorías, usando esta configuración en la que se genera internamente un pulso de reloj de 4 MHZ sin cristal, podría haber algún problema de corrimiento de la frecuencia del reloj y, por ende, de la velocidad de transferencia del puerto serie del PIC (baudios). Sin embargo, no he notado dificultades de comunicación.
- No es difícil implementar esta comunicación por interrupción, tarea que encararé en una próxima prueba. No quise hacerlo aquí para no complicar un ejemplo que, a mi entender, debe ser básico.
|