
PIC , Robots y automatismos
Primer programa: encender, apagar el led auxiliar (rojo) de la CMUcam4
16.07.2013 02:04
Bueno, en este capítulo vamos a ver como mandar comandos a la CMUcam4 desde un PIC y veremos como responde la cámara. Comenzaremos por lo más sencillo, encender y apagar el led auxiliar que tiene la CMU, es el de color rojo.
La CMUcam4 tiene dos leds, Power LED y Auxiliary LED. El primero, verde, se enciende al dar alimentación a la cámara y el segundo, rojo, lo utiliza la cámara para indicarnos que está trabajando en algún proceso, por ejemplo cuando se le solicita que mande una imagen. También lo podemos manejar, enviándole comandos desde un PC o desde nuestro PIC.
En concreto, el AUX LED, lo podemos apagar, encender o hacerle parpadear con un rango de frecuencias que van desde -1 hasta 10,000,000 ambos inclusive.
Según el documento CMUcam4-Command-List-102[1], si mandamos "L0\r ", a la CMU, apagaremos el LED y si la mandamos “L1 0\r” , encenderemos el LED.
Cada vez que mandamos un comando a la cámara, este debe ir seguido de un retorno de carro, en nuestro caso lo haremos mandando los caracteres \r .
Para hacer esta práctica, he incluido un teclado 3x4 y un display de dos líneas por 16 caracteres cada una, conectados ambos al puerto B del PIC. De esta forma podremos mandar distintos comandos y ver la progresión del programa.
La alimentación de la cámara puede ser distinta a la alimentación del PIC, pero la conexión GND de la cámara y del PIC debe ser la misma.
Ahora solamente falta desarrollar el programa para poder apagar y encender el LED AUXILIAR.
Este programa lo primero que hace es mandar un comando de RESET a la cámara, de esta forma nos aseguramos que tenemos comunicación.
Al salir del RESET, la cámara lo primero que manda es :
1º ACK retorno de carro
2º retorno de carro
3º CMUcam4 V1.02 retorno de carro
4º ":"
Mostraremos el mensaje "CMUcam4 V1.02" en el LCD y seguidamente colocaremos en el LCD un menú de opciones
1 LED ON
2 LED OFF
En este punto el programa queda a la espera de que se pulse una tecla, está claro, si pulsamos 2 apagamos el LED y si pulsamos 1 encendemos el LED. Veremos el correspondiente ACK que manda la cámara tras recibir un comando válido.
Es recomendable consultar el diagrama del flujo de datos de la CMU que viene en el documento
"CMUcam4-Command-List-102[1].PDF" del fabricante.
Antes de seguir, tengo que hacer una aclaración importante. En el apartado CMUcam4\MAX232 escribí:
“Cuando conectemos la CMUcam4 a un microcontrolador, siempre y cuando este funcione con niveles TTL, no será necesario el MAX232, se pueden conectar directamente los pines de la cámara a los pines de nuestro microcontrolador.”
Pues esto debería ser así, pero en mi caso no. Me explico:
En un principio conecté la línea TX y RX de la CMU a las líneas RX y TX del PIC, directamente, al ser dos puertos con supuestos niveles TTL. Para mi asombro, la cosa no iba bien. Mi programa en el PIC, lo primero que hace es mandar un RESET a la CMU, y la CMU debería contestar con un
ACK retorno de carro
retorno de carro
CMUcam4 V1.02 retorno de carro
":"
Pero no había manera, el PIC mandaba el RESET, la CMU se reseteaba, pues veía como se apagaba y encendía el led auxiliar rojo, pero, tras esto el PIC no recibía los mensajes de respuesta y se quedaba colgado.
Este comportamiento me ha traído de cabeza durante unos cuantos días. He repasado mil veces el programa, las conexiones del PIC y de la CMU, he hecho pruebas para comprobar que la CMU si me comunicaba con el PC a través del MAX232 y con el hyperterminal, etc, etc.
Por fin, conseguí un osciloscopio y lo conecté a las líneas TX y RX, para ver las señales de las transmisiones del PIC y de la CMU. Observando que cuando el PIC transmite lo hace con niveles de 0 y +5 voltios y aparecen ruidos en la línea RX. Y cuando la CMU transmite lo hace con niveles de 0 y +3.12 voltios y aparecen ruidos en la línea RX.
El canal azul es la transmisión del PIC, y el canal rojo es la transmisión de la CMU. Cuando el PIC transmite, se producen ruidos en el canal rojo que es el TX de la CMU o el RX del PIC.
Esto me hizo sospechar o bien el PIC se bloquea, pues mientras transmite recibe ruidos por la línea RX o no se entera pues la CMU no llega a los niveles necesarios de voltaje para los pines del PIC.
Por lo que se me ocurrió utilizar el MAX232 para igualar los niveles de tensión, tanto del PIC como de la CMU.
El MAX232 tiene dos canales por los que puedes mandar niveles TTL y los convierte a niveles RS232 y puedes mandar niveles RS232 y los convierte a TTL.
Si puenteamos los pines de la zona RS 232, tendremos que, mandamos TTL, lo convierte a RS232, a través del puente los reenvía como RS232 y vuelve a mandar la señal como TTL, pero estabilizada por el MAX232.
Si hacemos esto tendremos la siguiente secuencia para el PIC y la CMU.
PIC TX TTL 0, + 5 ---> RS232 ---> RS232 ---> CMU RX TTL 0, + 5 V
CMU TX TTL 0, +3,12 ---> RS232 ---> RS232 ---> PIC RX TTL 0 , + 5 V
Tal vez se me entienda mejor con un esquema.
Conectando de Nuevo el osciloscopio, comprobé como los niveles de transmisión para el PIC y la CMU esta vez eran iguales a 0 y + 5V .
Como se puede ver los ruidos se han atenuado bastante en el canal rojo.
Ahora el programa funciona correctamente. El esquema que he utilizado para este ejemplo es:
(Para ver mejor el esquema selecciona VER\ZOOM en la barra de herramientas del navegador.)
PROGRAMA
Compilar el siguiente programa, para cargarlo en el PIC.
Está escrito en CCS, funcionando bajo el IDE de MPLAB.
//PIC TRABAJANDO CON GRISTAL A 20000000HZ
//RS232 TRABAJANDO A 19200 BAUDIOS
//Todos los retados de este programa, son para darnos tiempo a leer
//los mensajes, del PIC y de la CMU..
#include <16f877A.h> //NUESTRO PIC
#use delay (clock=20000000) //Cristal a 20Mhz
#fuses HS,NOWDT,NOPROTECT,NOLVP
//Parámetros para la conexión serie rs232 con la CMU
#use rs232(UART1, baud=19200, xmit=pin_c6, rcv=pin_c7, bits=8, parity=N,stop=1)
//damos nombre a las posiciones de memoria
#BYTE tris_a = 0x85
#BYTE tris_b = 0x86
#BYTE tris_c = 0x87
#BYTE tris_d = 0x88
#BYTE tris_e = 0x89
#BYTE port_a = 0x05
#BYTE port_b = 0x06
#BYTE port_c = 0x07
#BYTE port_d = 0x08
#BYTE port_e = 0x09
//SUBRUTINAS
//**************************************************+
//**************************************************+
void ledon() //Función para encende el led de la CMUcam4
{
char mensajeACK[5]; //Para recibir la respuesta ACK ó NCK
char dospuntos; //Para recibir el carácter dos puntos ":"
lcd_gotoxy(1,1); //Primera línea del LCD
lcd_putc("\fENCIENDE LED"); //Texto para el LCD
printf("l1 0\r"); //Comando para la CMU + retorno de carro.
gets(mensajeACK); //Espera la respuesta de la CMU.
dospuntos=getchar();
//después del mensaje ACK, la CMU manda ":", no los ponemos en el LCD
//Estos ":" indican CMU en estado idle = esperando comando
printf (lcd_putc"\f %s\n", mensajeACK); //Borra LCD
//y Pone respuesta de la CMU
delay_ms(1000); //espera 1 segundo
}
//++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++
void ledoff()
{
char mensajeACK[5];
char dospuntos;
lcd_gotoxy(1,1); //Primera línea del LCD
lcd_putc("\fAPAGA LED"); //Texto para el LCD
printf("l0\r"); //Comando para la CMUcam4 + retorno de carro
gets(mensajeACK); //Espera respuesta de la CMU
dospuntos=getchar();
lcd_gotoxy(1,1); // primera línea del LCD
printf (lcd_putc"\f %s\n", mensajeACK); //Respuesta de CMU
delay_ms(1000); //espera 1 segundo
}
//*************************************************
//*************************************************
//*************************************************
void main(void)
{
char tecla; //variable para guardar la tecla pulsada
char mensaje1[15];
char mensaje2[15];
char mensaje3[15];
char dospuntos;
//Debemos tener en cuenta las siguientes líneas del
//archivo kbd.c, según al puerto al que conectemos el teclado.....
// Un-comment the following define to use port B
// #define use_portb_kbd TRUE
kbd_init(); //inicializa el teclado, teclado 3 x 4 teclas
//Debemos tener en cuenta las siguientes líneas del
//archivo lcd.c, según al puerto que conectemos el display.....
// Un-comment the following define to use port B
//#define use_portb_lcd TRUE
lcd_init(); //inicializa el display LCD
port_b_pullups(TRUE); //Conecta las resistencias PULL-UP
//del puerto B, para evitar conflictos entre el teclado y el LCD,
//pues están conectados al mismo puerto aparte yo suelo
//colocar resistencias de 330 ohmios en el teclado.
//MENSAJE INICIAL...........
lcd_putc("\fCMU PROGRAMA V1");
lcd_gotoxy(1,2); //nos colocamos en la segunda línea
lcd_putc("VERSION 1"); //mensaje para la segunda línea
delay_ms(3000); //retardo de 3 segundos
lcd_putc("\f"); //borra el LCD
lcd_putc("\RESET CMU"); //lo escribimos en el LCD
delay_ms(1000); //retardo de 1 segundo
//para comprobar que estamos conectados,
//mandamos un reset a la CMU
printf("RS\r"); //COMANDO PARA CMU, reset de la CMU
//"\r" = retorno de carro, la cámara espera un retorno de
//carro después de cada comando
//LA CMU SE RESETEA Y CONTESTA…
//ACK retorno carro
//retorno carro
//CMUcam4 V1.02 retorno carro)
//:
gets(mensaje1); //guardamos ACK retorno de carro
gets(mensaje2); //guardamos retorno de carro
gets(mensaje3); //guardamos CMUcam4 v1.02 retorno de carro
dospuntos=getchar(); //dos puntos que indican CMU
//en estado idle = esperando comando
lcd_gotoxy(1,1);
lcd_putc("\fMENSAJE1");
lcd_gotoxy(1,2); //Segunda línea del LCD
printf (lcd_putc" %s\n", mensaje1); //En el LCD lo que
//ha contestado la CMU en mensaje1
delay_ms(2000); //retardo de 2 segundos...
//lo mismo para el resto de mensajes...
lcd_gotoxy(1,1);
lcd_putc("\fMENSAJE2");
lcd_gotoxy(1,2);
printf (lcd_putc" %s\n", mensaje2);
delay_ms(2000);
lcd_gotoxy(1,1);
lcd_putc("\fMENSAJE3");
lcd_gotoxy(1,2);
printf (lcd_putc" %s\n", mensaje3); //Veremos "CMUcam4 v1.02"
delay_ms(4000);
do //bucle infinito
{
lcd_putc("\f1 LED ON"); //Opción 1
lcd_gotoxy(1,2); //Segunda línea del LCD
lcd_putc("2 LED OFF"); //Opción 2
//bucle espera la pulsación de una tecla, teclado 3x4
do
{
tecla = kbd_getc(); //Obtenemos la tecla pulsada
}
while(tecla==0); //si no se pulsan teclas sigue esperando
//SEGÚN LA TECLA PULSADA
switch (tecla)
{
case '1': //si pulsamos tecla 1...
ledon(); //encendemos el led
break;
case '2': //si pulsamos tecla 2...
ledoff(); //apagamos el led
break;
}
}
while (true);
}
Una vez compilado este programa, conseguiremos nuestro archivo "*.HEX", el cual cargaremos en el PIC. Yo utilizo un programador JDM casero, el cual me funciona muy bien. Hay mucha información en Internet para que puedas fabricarte el tuyo.
Si todo ha salido bien, veremos como se resetea la CMU, los mensajes que responde tras el reset y después pulsando 2 apagaremos el LED AUX y pulsando 1 lo encenderemos, 2 apagar, 1 encender, 2 apagar, 1 encender... FASCINANTE.
—————