Buscando programas en el pc he encontrado uno de los primeros que hice
para un pic en ensamblador para parte de un robot que nunca
llegó a andar.
Una forma sencilla y barata de controlar un robot o circuito a
distancia es usar un mando infrarrojo, como puede ser el de la
televisión, cadena etc.. de los muchos que hay por casa. Barato
porque sólo necesitaremos un receptor y una resistencia que
conectar al microcontrolador, es decir entre uno y dos euros. Como
receptor he utilizado un TSOP1738, que se encarga de demodular la
señal enviada por el mando y nos la da en una línea en
serie. Tiene 3 patas, dos de alimentación y la salida, en la que
debemos colocar una resistencia de pull-up y conectarla al
microcontrolador. Su montaje es el siguiente:
Circuito TSOP1738
Cada fabricante suele usar sus propios protocolos, por lo que primero
tenemos que saber que es lo que buscamos en esa salida que nos
proporciona el TSOP. Para esto yo he usado un analizador
lógico de pc, que nos permite ver los unos y ceros que
tienen lugar durante un tiempo, su precio está sobre los 150,
200 euros y nos será útil a la hora de trabajar con
microcontroladores para comprobar su correcto funcionamiento. Es
recomendable hacerse con uno que su soft tenga un analizador de
protocolos. El que yo uso de 8 canales lo compre por unos 180 euros (lo
más barato que encontre en su día) .
Analizador lógico.
Para ver los datos que recibimos del mando conectamos un canal del
analizador lógico a la salida del TSOP, y procedemos a
pulsar botones. En este caso se está usando un mando de
JVC y al pulsar un botón nos manda lo siguiente.
Mando JVC
Esa señal es la que sale del mando cuando pulsamos un botón.
Como se puede ver la señal comienza cuando baja la línea, con un pulso de
8.4 ms seguido de uno de 4.2 ms, esto sólo se realiza una vez para
indicar que se ha pulsado el botón y diferenciar de cuando se mantiene
pulsado, la señal se repite cada 50 ms esta vez sin el pulso de inicio
de 8 y 4 ms.
Para diferenciar entre 1 y 0 se mide el
tiempo que pasa entre dos
flancos de bajada, 1 ms corresponde a un 0 y 2.1 ms a un 1, en este
ejemplo se mandan 16 bits (8 de dirección y 8 de dato
según el protocolo de JVC). En este caso tenemos 11000101
(197) y 01111000 (120).
Por cada botón nuestro micro va a recibir dos bytes, el primer
byte es de dirección, dice para que componente del equipo
receptor es el segundo byte que sale del mando, por lo que en el mando
nos encontraremos con unos cuántos botones que mandan el mismo
primer byte. En este caso en el mando sólo había dos
bytes de dirección, es decir todos los botones mandaban uno u
otro.
Una vez que sabemos lo que sale del mando tenemos que capturarlo, interpretarlo y usarlo.
Para capturarlo se puede hacer de varias maneras, usando algún
periférico del micro para protocolos serie, o en mi caso de la
forma larga mediante una interrupción activada por el flanco de
bajada de la línea del TSOP y contando tiempos entre flancos de
bajada. La ventaja de programar en ensamblador es que en todo momento
sabemos lo que está haciendo el microcontrolador y podemos tener
un control del tiempo exacto.
Cada instrucción de nuestro programa en ensamblador del
microcontrolador tarda una cantidad de ciclos de reloj en ejecutarse,
el reloj es el cristal que conectamos externo que puede ser de varios
KHz, MHz, o un oscilador interno propio del microcontrolador del orden
de KHz a MHz.
Por ejemplo si tenemos el siguiente código para pic:
***************************************************
*************************************************** org 0
goto Start
org 5
Start
bsf STATUS,RP0 ; select Register Page 1
bcf TRISC,0 ; make IO Pin C.0 an output
bcf STATUS,RP0 ; back to Register Page 0
MainLoop
bcf PORTC,0 ; turn on LED C0
bsf PORTC,0 ; Turn off LED C0
goto MainLoop ; Do it again...
end
***************************************************
***************************************************
Nuestro programa hace lo que tenemos dentro del Mainloop de forma
repetida, es decir haríamos 3 instrucciones en bucle: "bcf PORTC,0" y "
bsf PORTC,0" instrucciones de 4 ciclos de reloj, y "goto
MainLoop" instrucción de 8 ciclos de reloj. Es decir cada
iteracción del bucle serían 4+4+8 = 16 ciclos de
reloj.
Si colocamos el osciloscopio en el puerto C0 tendremos una señal
cuyo período es función del valor del oscilador. Por
ejemplo si nuestro oscilado funciona a 16 MHz, en el port c tendremos
una señal de 16 MHz/ 16 ciclos de reloj, es decir 1 MHz. Nuestro
bucle de 3 instrucciones se realizaría en 1 microsegundo.
Cristal de 16 MHz
Primero se realiza la instrucción que pone a cero el pin C0,
0.25 uS a cero la salida. Después ponemos el pin del puerto a 1
0.25 uS y luego con este pin a 1 volvemos a la primera
instrucción, esto tarda 0.5 uS, por lo que nos encontramos con
una señal con un duty del 75%.
Si por ejemplo utilizamos el oscilador interno del pic a 4 MHz, tendríamos la siguiente salida:
Oscilador 4 MHz
La frecuencia de la señal es 4 MHz / 16 ciclos de reloj = 250
Khz, es decir el bucle de 3 instrucciones se realizaría en
1/250KHz = 4 microsegundos. Luego la primera instrucción tarda 1
uS, la siguiente otro uS y el goto 2 uS, en todal los 4 uS.
De esta forma podemos calcular lo que tarda en realizarse un trozo de
código de nuestro programa, que usaremos para capturar los unos
y los ceros mandados por el TSOP17.
Nuestro código para capturar la señal salta mediante una
interrupción en RB0, cuando se detecta un flanco de bajada en
este puerto salta nuestra interrupción y pasamos a ejecutar su
código (repito que hay formas más adecuadas de hacerlo),
por lo que tenemos que medir el tiempo que pasa entre flancos de bajada
para saber si nos llega un uno y un cero, y esto lo hacemos
incrementado un contador cada 0.1 ms en un registro del pic, para ello
debemos conocer cuánto tarda en ejecutarse cada
instrucción.
Si entre dos flancos de bajada nuestro contador vale menos de un valor
mínimo o más de uno máximo nos salimos de la
interrupción con una condición de error, ya que
ningún valor de 1 o 0 se corresponde con estos tiempos, estamos
ante un ruido. Si vale más de 0.8 ms estamos ante un 0, y si
vale más de 1.7 ms ante un uno. De esta forma capturamos los 1 y
0 y los almacenamos en dos registros del pic.
Una vez que tenemos un montón de unos y ceros debemos de saber
que hacer con ellos. Si queremos que nuestro circuito realice una
función con cada botón, sólo debemos comparar el
valor de cada registro con un valor en otro registro perteneciente a
ese botón, y ejecutar cierta acción cuando los registros
sean iguales.
En este caso lo que se ha hecho es convertir esos registros en binario
a decimal, y sacar este valor convertido por un LCD para comprobar que
el valor leído es el mismo que el visto en el analizador
lógico, y de esta forma comprobar que nuestro programa funciona.
Sobre el tema del LCD pongo un link en español de ionitron donde
explica bien el tema http://www.x-robotics.com/rutinas.htm#LCD.
Se podía haber sacado en unos y ceros sin convertir a decimal,
pero un valor decimal siempre es más fácil de identificar
que 16 unos y ceros seguidos.
En el analizador lógico teníamos el 197 y el 120 (tecla +
del mando) recibidos por el TSOP1738, se puede ver como esos unos y
ceros son capturados, convertidos a decimal y llevados al LCD.
Foto conjunto.
El circuito del pic es un circuito de pruebas con un 16F877A orientado
hacía robótica, se puede ver un L298 y algunos
componentes más. A la izquierda el receptor de infrarrojos y
abajo el LCD con los valores recibidos por el receptor.
Agrego todo el programa al final, fue uno de los primero que hice en
ensamblador para probar las interrupciones y tiempos del pic, todos los
botones vistos en el analizador lógico se corresponden con los
leídos en el LCD, así que supongo que funciona. De todas
formas para implementar esto lo mejor es usar un periférico del
microcontrolador para tal fin.
Video de funcionamiento. El color azul del led indica que recibe dato.