Hola amigos
Me tome el tiempo de estudiar la hoja de datos y el esquema de ustedes un poco. Asumo que el PIC se comporta y funciona tal y cual todos los controladores funcionan. El PIC16F84A es simpático, pero, perdónenme en decirlo, no lo están usando de forma que tengan el beneficio de sus capacidades.
La razón es que no usan un del os pines RB4:7 que tienen la función de “interrupt-on-change” en combinación con el timer TMR0 para decodificar la señal del receptor. Aquí en el foro el amigo puso los gráficos que demuestran de forma visual muy evidente la forma de los impulsos que aparecen a las salidas del receptor cada 20 ms y cuya longitud define la posición del control en el transmisor.
Ahora de forma escrito como me imagino que deberían hacer el programa para beneficiarse de las interesantes capacidades del controlador:
Entrada:
El impulso cada 20 ms del receptor y cuja longitud define de cómo deben ser encendidos y apagados los LEDs conectado a uno de los pines que NO sean los RB4:7
Salidas:
RB1 y RB2: Los LEDs están conectados entre estos pines y 5V. De allí resulta que si pones un “1” en el registro correspondiente al pin el Pin también tendrá 5V y por lo tanto el LED está apagado. Pones un “0” y el pin esta encendido. Yo recomendaría el uso del portal A! Ver páginas15 y 16 para los detalles del portal A y 17 y 18 para los detalles del portal B
Recursos a utilizar en el controlador:
La función de “interrupt-on-change” de los pines RB4:7
El timer 0 (TMR0)
Iniciación:
Dependiendo de si el impulso de tu radio control es de 5V o de 0V y que entre impulso e impulso la señal tiene la otra tensión, definimos la tensión inicial sin impulso.
Los Pines RB1 y RB2 los definimos como salidas, activamos la resistencia que los jala a 5V y escribimos un “1” al registro correspondiente (ver página 7). De ese modo en descanso y ese estado lo definimos durante la iniciación nos aseguramos que los 2 pines de salida tenga la tensión (5V) que deseamos y que solo cambiarán a “0V” cuando escribamos un “0” a los registros correspondientes a esos 2 pines (Bit1 y Bit2) del registro 06h.
Ahora iniciamos el timer, ver instrucciones en hoja de datos y definimos el timer0 para que cuente de “0” hacia arriba cuando le demos la señal de arrancar y le damos el valor de “0” inicial(creo que es el registro “o2h”)
Asumamos que la señal del receptor normalmente es de “0V” y que el impulso hace que la tensión salte a “5V”.
Iniciamos la función de “interrupt-on-change” para los pines RB4:7, pero aún sin activar el interrupt. Activar el interrupt significa que el controlador saltara en la ejecución de su programa a la rutina de servicio de ese interrupt, apenas cambie la tensión en el pin al que conectamos la señal del receptor, uno de los pines RB4 a RB7.
Ahora tenemos que escribir la rutina de servicio para el interrupt-on-change”.
El valor de una variable que refleja la tensión del pin RBx la iniciamos con el valor “0”, esta inicialización ocurre fuera de la rutina de servicio y es parte de la inicialización.
El controlador saltara a ejecutar esta rutina en el momento que el impulso (la señal) del receptor llegue a la entrada del PIN RBx.
Este Pin al que conectamos la señal del receptor es iniciado como entrada y la resistencia interna no es activada pues solo existe para conectar a “5V” y no a “0V”. Externamente conectaría el pin con una resistencia de 10k con tierra. Así aseguro que esta entrada solo saltara de “0V” a “5V” porque la señal del receptor así lo indica.
El controlador recién podrá saltar a esta rutina cuando en el programa principal activamos el interrupt. Si el controlador llega a esta rutina podemos asumir que esto ocurre por primera vez dentro de un lapso de tiempo de máximo 20ms después de activar el interrupt!
Que hace esta rutina de servicio.
1. Verifica que no estamos midiendo un impulso. Para esto miro si el valor de la variable “longitud señal” tiene el valor “0” o no!
2. 1. Si esto es correcto, inicia el timer que empieza a contar de “0” hacia arriba y le asigna el valor de “0” a la variable “longitud señal”. Así en el caso alternativo sabe que si la variable “longitud señal” no es “0” que está midiendo un impulso.
3. 2. Si ya está midiendo un impulso lee el valor actual del contador y lo asigna a la variable “longitud señal”. Para el contador, lo vuelve a iniciar a “0”.
4. Fin de rutina de servicio
El jueguito es el siguiente:
Antes de que llegue el primer impulso de la señal del receptor la línea tiene el valor del “0”, equivale “0V”. Activamos el “interrupt-on-change”. Cuando llega el impulso la tensión en el pin de entrada salta de “0V” a “5V” y el “interrupt-on-change” hace que la ejecución del programa en el controlador salte a la rutina de servicio correspondiente.
En la rutina de servicio lo primero que hacemos es leer el valor del contador “timer” y asignarlo a una variable. Esta variable tiene el valor inicial de “0”, lo mismo que el contador (TMR0). Siendo esto la primera acción nos aseguramos tener el valor del contador más próximo al evento del cambio de tensión de la señal no se pierda.
Ahora verificamos si el valor es “0” o no!
Si es “0” significa que empezamos a contar, y por lo tanto la segunda acción es arrancar el contador.
La función de “interrupt-on-change” se controla a través de los Bits “0”, “3” y “7” del registro INTCON, ver página 10.
Bit “7” es el interruptor principal que permite o no que interrupt tengan un reacción del controlador.
Bit”3” es el interruptor que activa o desactiva el “interrupt-on-change”.
Bit “0” es la indicación si un interrupt ha ocurrido o no.
Esto significa que la rutina de servicio tiene que resetear (anular) el valor del los bits para que el controlador este preparado a volver a saltar a esta rutina de servicio cuando la señal acabe y la tensión en el pin de entrada vuelve de “5V” a “0V”.
Ahora abandonamos la rutina.
Cuando el “interrupt-on-change” vuelve a hacer que el controlador salte a la rutina de servicio porque la señal del receptor acabo y la tensión volvió a “0V”, cuando leemos el valor del contador este tendrá un valor que no será de “0” y por lo tanto asignado el valor que leemos del contador a la variable “longitud señal” hará que la rutina de servicio salte a sus funciones después de terminar la señal. Pero lo que hace es lo mismo que antes, resetea los valores a “0”, pero adicionalmente para el contador y lo vuelve a inicial a “0”. Después terminamos la rutina de servicio.
Es muy importante durante la programación asegurar que la rutina de servicio sea lo más corto posible. Esto es porque durante el tiempo que estamos en esa rutina el controlador no puede saltar a una rutina de servicio en el caso que alguno de los otros interrupt posibles tenga lugar. Por eso yo lo considero buena practica desactivar el servicio de un interrupt durante este tiempo. Apenas abandonamos la rutina de servicio volvemos a reactivar los interrupt (Bits “7” y/o “3”!
Devuelta en nuestro programa principal tenemos en la variable “longitud señal un valor numérico.
Ahora podemos usar ese valor numérico que es equivalente a la longitud de la señal del receptor para hacer que el controlador haga las funciones que nosotros deseamos a razón de la posición de los controles correspondientes del transmisor. En este caso escribir “0” o “1” al bit del registro “06h” que corresponde al pin al que hemos conectado los LEDs.
De esta forma es imposible que razones no deseadas causen fluctuaciones de la luz de los LEDs. La única forma como un LED se enciende o apaga es que el programa escriba un “0” o un “1”!
Ojalá se entienda lo que escribo aunque ya es sumamente específico y requiere entender como implementar el programa.
Otra cosa que vale la pena resaltar en este ejemplo es la posibilidad de administrar con este controlador hasta 4 canales del receptor al mismo tiempo.
El interrupt, el salto a la rutina de servicio del “interrupt-on-change” ocurre si en cualquiera de los 4 pines RB4, RB5, RB6 y RB7 la tensión cambia su valor. El valor de la tensión de cada pin, “0” o “1” se puede leer en el programa en el registro “06h”.
Existen 2 tipos de receptores en dependencia de cómo proveen la señal. El uno, y ese es el que vino con mi radio control F14 Navy, empieza poniendo canal 1, después canal 2 hasta llegar a canal 8.
El otro tipo saca todas las señales al mismo tiempo.
En ambos casos es posible medir la longitud de los impulsos de 4 canales al tiempo.
La razón es que el interrupt “interrupt-on-change” es activado y resulta en que el controlador salta a la rutina de servicio correspondiente si cualquier de los pines RB4, RB5, RB6 o RB7 muestra un cambio de la tensión. Cuál de los pines vio el cambio se registra y se graba en el registro “06h”. Esto puede ser uno de ellos, 2, 3 o todos. El Bit correspondiente mostrara un “1” o un “0” según sea. El único cambio mayor en nuestra rutina de servicio consiste en leer y en como leer los valores de los Bits. Si las señales ocurren como en el receptor de mi F14 Navy, entonces el único cambio es definir cuál de los 4 pines cambio de valor y asignar el digito al canal correspondiente. Si uso un controlador como el mega168 o mega88 puedo medir las señales de hasta 8 canales.
Si las señales todas empiezan en el mismo momento y terminan en diferentes tiempos, entonces hay que dejar el contador contando hasta haber medido el último de los canales.
Puede parecer que este sistema no es exacto, pero sí lo es, pues aumentando la frecuencia con la que el contador cuenta aumenta la resolución. El controlador es tan rápido que el error es mínimo y puede ser ignorado.
El otro aspecto es que el contador en el pic16F84a es de solo 8 Bit. Eso significa que después de 256 pasos el valor vuelve a ser “0”. Realmente este contador es muy corto y uno de 16 bit o 64000 pasos es más adecuado. Pero hay que saber que existe un interrupt que es activado cada vez que el contador vuelve a tomar el valor de “0”. La rutina de servicio para este contador puede ser muy , pero muy breve, pues todo lo que haría es incrementar el valor de una variable. Cada 256 pasos esta variable aumentaría por “1” y así es posible contar sin pérdida de precisión lapsos de tiempo de cualquier longitud. Pero repito, cada 256 pasos es demasiado breve, pero factible.