M-Turret (Diseño de Sistemas basados en Microprocesadores) Christopher Orihuela Sosa David M. Godoy Delgado José Luis Santana Acosta Miércoles, 25 de Junio de 2008 Introducción El presente documento corresponde a la memoria del trabajo realizado por Christopher Orihuela Sosa, David M. Godoy Delgado y José Luis Santana Acosta, alumnos de la asignatura Diseño de Sistemas Basados en Microprocesadores, durante el año académico 2007/2008. El objetivo del proyecto (bautizado con el nombre de M-Turret) es la construcción de un artefacto mecánico capaz de apuntar en determinadas direcciones, en función de los datos que, a través de una pantalla táctil, el usuario le facilite al artefacto. Una vez que el objeto se encuentre apuntando en la dirección correcta, deberá detenerse. Para detectar que el artefacto ha llegado a la posición correcta, los motores que mueven el puntero están conectados a sendos potenciómetros, por lo que podemos adivinar la posición del puntero digitalizando las entradas de dichos potenciómetros. Cuando el usuario pulsa en alguna zona de la pantalla, la M-Turret utilizará sus motores para posicionarse de manera que apunte en la dirección del punto en que ha pulsado el usuario. El movimiento del puntero es diferencial, se moverá más rápido cuanto más lejos esté el puntero de su destino. Podemos así dividir el proyecto en tres partes bien diferenciadas, a saber: Control y lectura de la pantalla táctil Digitalización de las entradas de los potenciómetros Control de los motores Las siguientes secciones explican detalladamente estos tres módulos del proyecto. A grandes rasgos, el módulo de pantalla táctil se encarga de configurar dicho dispositivo y leer las pulsaciones del usuario, el módulo de digitalización realiza la conversión analógico/digital de las entradas de los potenciómetros y el módulo de motores controla el movimiento y velocidad de los mismos. Control de la pantalla táctil El control de la pantalla táctil se realiza por medio de RS232. Para ello empleamos gran parte del código de la práctica de Humberto Luis Barriento González y Mario Castellano Díaz, disponible en http://serdis.dis.ulpgc.es/~itis-dsm/_private/2005-2006/pic-tactil.pdf. La conexión física al PIC se realizó en PORT.B0 que implementa RX y PORT.B2 que implementa TX: #DEFINE #DEFINE #DEFINE #DEFINE MIRX PORTB,0 MITX PORTB,2 CONF_MIRX TRISB,0 CONF_MITX TRISB,2 Utilizamos las siguientes variables para la transmisión RS232: ; VARIABLES ; Inicio_Memoria DATO RET1 RET2 CONT8 SOH EQU 0x0C EQU (Inicio_Memoria+1) ;Dato a Transmitir o Recibido RS232 EQU (Inicio_Memoria+2) ;para retardo de bit RS232 EQU (Inicio_Memoria+3) ;para retardo de bit RS232 EQU (Inicio_Memoria+4) ;Contador de bits en rutinas MIRX y MITX EQU (Inicio_Memoria+5) ;Registro para guardar el byte y comprobar si es carita Y las siguientes para los datos que nos llegan de la pantalla: ; Variables nuevas para recoger los datos del paquete de datos ; Numero_Byte_Datos EQU (Inicio_Memoria+6) ;Un indice dentro del paquete de datos PTactil_X_MSB EQU (Inicio_Memoria+7) ;Most Significant Byte de la X (10 bits) PTactil_X_LSB EQU (Inicio_Memoria+8) ;Least Significant Byte de la X (10 bits) PTactil_Y_MSB EQU (Inicio_Memoria+9) ;Most Significant Byte de la Y (10 bits) PTactil_Y_LSB EQU (Inicio_Memoria+10) ;Least Significant Byte de la Y (10 bits) Nueva_Pulsacion EQU (Inicio_Memoria+11) ;Se pone a 1 si hay pulsacion nueva de la pantalla Pantalla_Tactil_X EQU (Inicio_Memoria+12) ;Coordenada X de la pantalla (en formato 8 bits) Pantalla_Tactil_Y EQU (Inicio_Memoria+13) ;Coordenada Y de la pantalla (en formato 8 bits) STATUS_BAK EQU (Inicio_Memoria+14) ;Coordenada Y de la pantalla (en formato 8 bits) W_BAK EQU (Inicio_Memoria+15) ;Coordenada Y de la pantalla (en formato 8 bits) Configuración inicial de la pantalla Tras configurar RX/TX correspondientemente para entrada y salida, procedemos a configurar la pantalla en modo hexadecimal. En este modo, recibimos un paquete de datos de 9 bytes para cada pulsación: – 1 de cabecera. – 3 de la X (solo se aprovechan los 4 últimos bits, salvo del primero que sólo son 2 bits) – 1 byte de separación – 3 de la Y (solo se aprovechan los 4 últimos bits, salvo del primero que sólo son 2 bits) – 1 byte de terminación En total esto nos da 10 bits para X y 10 para Y, aunque para simplificar los cálculos los reducimos (más adelante en el código) a 8 bits. Los puertos A1 y A4 los utilizamos para indicar la zona de la pulsación de pantalla, a modo de debug: ;configuración inicial de puertos PANTALLA bcf CONF_LIBREA1; configurar el pin del led a salida (DEBUG) bcf CONF_LIBREA4 ; configurar el pin del led a salida (DEBUG) bcf CONF_MITX ;configurar TX a salida bsf CONF_MIRX ;configurar RX a entrada ;configuración inicial de puertos PANTALLA ;Posiciones iniciales de los pines BSF MITX BSF MIRX bcf LIBREA1 ;LED1 bcf LIBREA4 ;LED2 ;Posiciones iniciales de los pines La función FH envía el comando de configuración para modo hexadecimal por RS232 a la pantalla: ;CONFIGURACION DEL CONTROLADOR DE LA PANTALLA EN FORMATO hexadecimal call Espera_Larga CALL FH ;COMANDO PARA ESTABLECER FORMATO HEXADECIMAL call Espera_Larga CALL FH ;REPETIMOS POR SI NO FUNCIONA LA PRIMERA VEZ La recepción de los bytes de la pantalla se hará en la interrupción del pin de RX, cuando reciba un start bit, así que lo configuramos: ;HABILITAMOS LAS INTERRUPCIONES para dar paso al programa principal BSF INTCON,INT0IE ;HABILITA INTERRUPCIÓN INT0 Bcf INTCON, INT0IF ;borrar la flag de "ocurrido int0" BSF INTCON,GIE ;HABILITA INTERRUPCIONES GLOBALMENTE ;Según el manual IPEN está a 0 por defecto (prioridades altas) ;e INT0 es siempre de prioridad alta Recepción de bytes Lo mostrado a continuación es el código de la interrupción. Tras comprobar el motivo de la interrupción (en realidad no podría haber otro), guardamos registros y empezamos a recibir bytes. Para todos los bytes comprobamos el número de byte (número de secuencia en variable Numero_Byte_Datos). Para recibir cada byte llamamos a MIRXDATO y comprobamos que W sea TRUE, que indica recepción correcta. Tras el primer byte comprobamos que sea el de cabecera, y luego tras cada uno de los otros bytes comprobamos que el start bit sea correcto, si no lo fuera iría a Error_de_transmisión que inicializaría los contadores esperando otra pulsación. Si todo va bien, los bytes de las coordenadas estarán en Ptactil_X_MSB, Ptactil_X_LSB, Ptactil_Y_MSB y Ptactil_Y_LSB (10 bits cada uno). ;Código de la interrupción (sólo usamos INT0) INTERRUPCION BTFSS INTCON,INT0IF ;COMPROBACIÓN DE INTERRUPCION INT RETFIE ; movff STATUS, STATUS_BAK ;guardamos status movwf W_BAK ;guardamos W ; movf Numero_Byte_Datos,W btfss STATUS, Z goto Siguiente_Byte_1 CALL MIRXSOH ;Aquí llama para recibir SOH (cabecera) XORLW TRUE ;Esto es una comprobación para saber si el procedimiento a ejecutado btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos goto Salir_Interrupcion Siguiente_Byte_1 movf Numero_Byte_Datos,W xorlw 1 btfss STATUS, Z goto Siguiente_Byte_2 CALL MIRXDATO XORLW TRUE btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos movf DATO,W andlw 0x0f movwf PTactil_X_MSB goto Salir_Interrupcion Siguiente_Byte_2 movf Numero_Byte_Datos,W xorlw 2 btfss STATUS, Z goto Siguiente_Byte_3 CALL MIRXDATO XORLW TRUE btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos rlcf DATO rlcf DATO rlcf DATO rlcf DATO movf DATO,W andlw 0xf0 movwf PTactil_X_LSB goto Salir_Interrupcion Siguiente_Byte_3 movf Numero_Byte_Datos,W xorlw 3 btfss STATUS, Z goto Siguiente_Byte_4 CALL MIRXDATO XORLW TRUE btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos movf DATO,W andlw 0x0f addwf PTactil_X_LSB goto Salir_Interrupcion Siguiente_Byte_4 movf Numero_Byte_Datos,W xorlw 4 btfss STATUS, Z goto Siguiente_Byte_5 CALL MIRXDATO XORLW TRUE btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos goto Salir_Interrupcion Siguiente_Byte_5 movf Numero_Byte_Datos,W xorlw 5 btfss STATUS, Z goto Siguiente_Byte_6 CALL MIRXDATO XORLW TRUE btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos movf DATO,W andlw 0x0f movwf PTactil_Y_MSB goto Salir_Interrupcion Siguiente_Byte_6 movf Numero_Byte_Datos,W xorlw 6 btfss STATUS, Z goto Siguiente_Byte_7 CALL MIRXDATO XORLW TRUE btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos rlcf DATO rlcf DATO rlcf DATO rlcf DATO movf DATO,W andlw 0xf0 movwf PTactil_Y_LSB goto Salir_Interrupcion Siguiente_Byte_7 movf Numero_Byte_Datos,W xorlw 7 btfss STATUS, Z goto Siguiente_Byte_8 CALL MIRXDATO XORLW TRUE btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos movf DATO,W andlw 0x0f addwf PTactil_Y_LSB goto Salir_Interrupcion Siguiente_Byte_8 ; bsf Nueva_Pulsacion, 0 ; marcamos la llegada de nuevos datos ; ; el resto de bytes no nos importa Finalmente convertimos las variables de 10 bits a variables de 8 para manejarlas mejor (Pantalla_Tactil_X y Pantalla_Tactil_Y). Luego indicamos la nueva pulsación en la variable Nueva_Pulsacion. Tras ello, inicializamos contadores de bytes, restauramos W y STATUS y salimos: ;ahora convertimos el formato de 10 bits en 8 bits (los más significativos) movff PTactil_X_LSB, Pantalla_Tactil_X rrncf Pantalla_Tactil_X rrncf Pantalla_Tactil_X bcf Pantalla_Tactil_X,7 bcf Pantalla_Tactil_X,6 btfsc PTactil_X_MSB,1 bsf Pantalla_Tactil_X,7 btfsc PTactil_X_MSB,0 bsf Pantalla_Tactil_X,6 ; movff PTactil_Y_LSB, Pantalla_Tactil_Y rrncf Pantalla_Tactil_Y rrncf Pantalla_Tactil_Y bcf Pantalla_Tactil_Y,7 bcf Pantalla_Tactil_Y,6 btfsc PTactil_Y_MSB,1 bsf Pantalla_Tactil_Y,7 btfsc PTactil_Y_MSB,0 bsf Pantalla_Tactil_Y,6 ;termina la interrupcion normalmente ; Error_Transmision clrf Numero_Byte_Datos ; para que lea otro paquete Salir_Interrupcion movf W_BAK,W ;restauramos W movff STATUS_BAK,STATUS ;restauramos status ; BCF INTCON,INT0IF ;BORRA BANDERA INT RETFIE Rutina de Adquisición de datos Analógicos La adquisición de datos de las entradas analógicas consta de dos partes, una primera etapa de configuración del puerto y una segunda etapa donde activamos la susodicha conversión, pero la mejor forma de comprender cómo realizar la conversión es siguiendo el código. En una primera configuración nos centramos en el registro ADCON1 (A/D CONTROL REGISTER 1), que es el empleado para configurar si las entradas son digitales o analógicas, colocando un 0 en el bit correspondiente a la entrada ANx la configuraremos como analógica y en cambio con un 1 la configuraremos como Digital. movlw b'01111110' ;Seleccionamos la entrada AN0 como analógica movwf ADCON1 El siguiente punto a configurar es el Registro ADCON2, que es el encargado de configurar cómo se llevará a cabo la conversión, formato y tiempo de adquisición. El Bit 7 del registro nos permite seleccionar el formato de la conversión, esto es, si queremos que la lectura esté justificada a la Izquierda (0) o a la Derecha (1). Los Bits del 5 al 3 sirven para seleccionar el tiempo de adquisición que queremos que emplee la conversión según la tabla suministrada por el fabricante. Y por último los Bits del 2 al 0 se emplean para configurar los ciclos de reloj que empleará la conversión. movlw b'00000101' ;Justificación a la Izquierda, 0TAD , Fosc/16 movwf ADCON2 El siguiente registro de configuración es el ADCON0, que es el empleado para realizar el setup del conversor Analógico-Digital, seleccionando los voltajes de referencia, el canal por el que se realizará la conversión y la activación/aviso de la conversión. De esta forma los Bits 7 y 6 son empleados para seleccionar las referencias de voltaje siguiendo la tabla que facilita el fabricante, 11 para poner ambas referencias externamente. Los Bits 4 a 2 son los empleados para seleccionar el canal por el que se realizará la conversión, según la tabla especifica, 000 para seleccionar el canal AN0. El Bit 1 hace referencia al GO/DONE que es el estado de la conversión, de esta forma colocaremos a 1 este bit cuando queramos realizar la conversión y se pondrá a 0 cuando la conversión esté terminada. El Bit 0 se refiere a ADON que se utiliza para activar el modulo de conversión, 1 activo y 0 desactivado. Una vez activado el modulo de conversión hay que realizar una pequeña espera, ya que un condensador interno debe descargarse para que se pueda llevar a cabo la conversión correctamente. movlw b'11000000' ;enable A/D, AN0, mod enable movwf ADCON0 bsf ADCON0,0 ; ACTIVAMOS EL CONVERSOR ;ESPERAMOS EL TIEMPO NECESARIO PARA LA ADQUISICION call delayan Para ahorrarnos problemas durante la conversión desactivamos las interrupciones. Una vez listos para realizar la conversión activamos el bit GO del ADCON0 y esperamos a que se desactive indicando que la conversión ha terminado. BCF bsf INTCON,GIE ;Desactivamos las Interrupciones ADCON0,GO ;Iniciamos la Conversión adloop btfsc ADCON0,DONE ;Esperamos a que se complete la Conversión goto adloop Una vez terminada la conversión sólo nos queda reactivar las interrupciones y mover el dato desde los registros especiales ADRESH y ADRESL a nuestra variable. En este caso sólo empleamos el H ya que hemos seleccionado la justificación a la Izquierda y despreciamos los 2 bits menos significativos de la conversión, ya que da valores que varían en estos bits para el mismo voltaje, y desactivamos el módulo Analógico-Digital. BSF INTCON,GIE ;Reactivamos las Interrupciones movff ADRESH,ANDATA1 ;Movemos el resultado de la conversión bcf ADCON0,0 ;Desactivamos el Modulo AD En caso de querer realizar capturas de varios puertos es recomendable realizar una espera entre configuración y configuración, y seguir los pasos uno a uno, ya que tratamos de realizar una configuración conjunta, la conversión fallaba y arrojaba datos erróneos. Módulo motriz Para controlar el uso de los motores utilizamos un chip L293D, que consta de 4 drivers con señal de habilitación por parejas. A diferencia del L293, el L293D lleva integrados los diodos necesarios para proteger los motores, por lo que podemos conectar tanto el PIC como los motores al L293D “a pelo”. A continuación se muestra un esquema de la organización interna del L293D. Antes de mostrar las conexiones PIC-L293D-Motores, vamos a echar un vistazo al código para ver qué patillas vamos a utilizar. El movimiento de los motores se divide en “pasos lógicos”, es decir, cada cierto tiempo (concretamente después de digitalizar las entradas de los potenciómetros) se ejecuta un paso del motor. Si el paso es 0, el motor se detiene. Si el paso es uno, el motor gira. Un paso termina cuando se ejecuta el paso siguiente. La duración de cada paso es muy pequeña, de manera que la estrategia que utilizamos para controlar la velocidad es modificar la frecuencia de pasos con valor 1. Veamos las patillas que usaremos. El siguiente trozo de código muestra los defines de las patillas utilizadas, los utilizaremos posteriormente en las funciones. Nótese que para cada motor tenemos declarados 2 defines para las direcciones del motor, 1 define para la habilitación de movimiento y 3 defines para configurar las patillas de ese motor. #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE ENABLEH PORTA,7 CONF_ENABLEH TRISA,7 ENABLEV PORTB,3 CONF_ENABLEV TRISB,3 IZQUIERDA PORTB,4 CONF_IZQUIERDA TRISB,4 DERECHA PORTB,5 CONF_DERECHA TRISB,5 ARRIBA PORTB,6 CONF_ARRIBA TRISB,6 ABAJO PORTB,7 CONF_ABAJO TRISB,7 A continuación se muestra la inicialización de los bytes que utilizaremos para controlar la velocidad de los motores. Cada paso del motor invocará una de las 8 funciones de movimiento, y cada una de ellas tiene su propio byte. Fijarse como los bytes FAST* se inicializan a 0xFF (todo unos, todos los pasos son dados) y los SLOW* a 0xEE (el 75% de los pasos son dados). FASTRIGHT FASTLEFT FASTUP FASTDOWN SLOWRIGHT SLOWLEFT SLOWUP SLOWDOWN movlw movwf movwf movwf movwf movwf movlw movwf movwf movwf movwf EQU EQU EQU EQU EQU EQU EQU EQU (Inicio_Memoria+22) (Inicio_Memoria+23) (Inicio_Memoria+24) (Inicio_Memoria+25) (Inicio_Memoria+26) (Inicio_Memoria+27) (Inicio_Memoria+28) (Inicio_Memoria+29) (…) 0xFF HORIZONTAL FASTRIGHT FASTLEFT FASTUP FASTDOWN 0xEE SLOWRIGHT SLOWLEFT SLOWUP SLOWDOWN Para terminar con las inicializaciones, configuramos las patillas que vamos a utilizar en modo salida. bcf bcf bcf bcf bcf bcf CONF_ENABLEH CONF_ENABLEV CONF_IZQUIERDA CONF_DERECHA CONF_ARRIBA CONF_ABAJO Veamos ahora las funciones desarrolladas. Existe un total de 12 funciones relacionadas con el control de los motores, 4 de ellas para (des)habilitación y 8 para movimiento. Las funciones de (des)habilitación de motores simplemente ponen a 1 o a 0 ENABLEH o ENABLEV, que como veremos en breve son las patillas que van conectadas a las entradas ENABLE del L293D. En cuanto a las funciones de movimiento, todas tienen la misma estructura: primero se ponen a 0 las salidas que controlan el movimiento en el eje del motor, luego se testea el bit más significativo del byte asociado a la función (en caso de ser 1 se activa una de las salidas antes desactivadas) para acabar rotando el registro asociado a través del CARRY. inith bsf ENABLEH return initv bsf ENABLEV return stoph bcf ENABLEH return stopv bcf ENABLEV return fleft bcf bcf btfsc bsf bcf rlcf btfsc bsf return IZQUIERDA DERECHA FASTRIGHT, 7 IZQUIERDA STATUS,C FASTRIGHT, 1 STATUS,C FASTRIGHT, 0 fup bcf bcf btfsc bsf bcf rlcf btfsc bsf return ARRIBA ABAJO FASTUP, 7 ARRIBA STATUS,C FASTUP, 1 STATUS,C FASTUP, 0 fright bcf bcf btfsc bsf bcf rlcf btfsc bsf return IZQUIERDA DERECHA FASTLEFT, 7 DERECHA STATUS,C FASTLEFT, 1 STATUS,C FASTLEFT, 0 fdown bcf bcf btfsc bsf bcf rlcf btfsc bsf return ARRIBA ABAJO FASTDOWN, 7 ABAJO STATUS,C FASTDOWN, 1 STATUS,C FASTDOWN, 0 sleft bcf bcf btfsc bsf bcf rlcf btfsc bsf return IZQUIERDA DERECHA SLOWRIGHT, 7 IZQUIERDA STATUS,C SLOWRIGHT, 1 STATUS,C SLOWRIGHT, 0 sup bcf bcf btfsc bsf bcf rlcf btfsc bsf return ARRIBA ABAJO SLOWUP, 7 ARRIBA STATUS,C SLOWUP, 1 STATUS,C SLOWUP, 0 sright bcf bcf btfsc bsf bcf rlcf btfsc bsf return IZQUIERDA DERECHA SLOWLEFT, 7 DERECHA STATUS,C SLOWLEFT, 1 STATUS,C SLOWLEFT, 0 sdown bcf bcf btfsc bsf bcf rlcf btfsc bsf return ARRIBA ABAJO SLOWDOWN, 7 ABAJO STATUS,C SLOWDOWN, 1 STATUS,C SLOWDOWN, 0 Para concluir la explicación sobre el funcionamiento de los motores, se muestra a continuación el esquema de conexión PIC-L293D-Motores. Anexo I: Código list p=18f1320 include <P18F1320.INC> ; MACROS Y DEFINICION DE BITS #DEFINE BANK0 BCF STATUS,RP0 #DEFINE BANK1 BSF STATUS,RP0 ; TRUE EQU 1 FALSE EQU 0 CTRAN EQU 0XFE ; SOH NEGADO (ASCII) ; #DEFINE MIRX PORTB,0 #DEFINE MITX PORTB,2 #DEFINE CONF_MIRX TRISB,0 #DEFINE CONF_MITX TRISB,2 #DEFINE CONF_MIAN0 TRISA,0 #DEFINE CONF_MIAN5 TRISB,1 #DEFINE ENABLEH PORTA,7 #DEFINE CONF_ENABLEH TRISA,7 #DEFINE ENABLEV PORTB,3 #DEFINE CONF_ENABLEV TRISB,3 #DEFINE IZQUIERDA PORTB,4 #DEFINE CONF_IZQUIERDA TRISB,4 #DEFINE DERECHA PORTB,5 #DEFINE CONF_DERECHA TRISB,5 #DEFINE ARRIBA PORTB,6 #DEFINE CONF_ARRIBA TRISB,6 #DEFINE ABAJO PORTB,7 #DEFINE CONF_ABAJO TRISB,7 #DEFINE LIBREA1 PORTA,1 #DEFINE LIBREA4 PORTA,4 #DEFINE LIBREA5 PORTA,5 #DEFINE LIBREA6 PORTA,6 #DEFINE CONF_LIBREA1 TRISA,1 #DEFINE CONF_LIBREA4 TRISA,4 #DEFINE CONF_LIBREA5 TRISA,5 #DEFINE CONF_LIBREA6 TRISA,6 ; ; VARIABLES ; Inicio_Memoria DATO RS232 RET1 RET2 CONT8 rutinas MIRX y MITX SOH EQU 0x0C EQU (Inicio_Memoria+1) ;Dato a Transmitir o Recibido EQU (Inicio_Memoria+2) ;para retardo de bit RS232 EQU (Inicio_Memoria+3) ;para retardo de bit RS232 EQU (Inicio_Memoria+4) ;Contador de bits en EQU (Inicio_Memoria+5) ; registro para guardar el byte y comprobar si es carita ; ; Variables nuevas para recoger los datos del paquete de datos ; Numero_Byte_Datos EQU (Inicio_Memoria+6) ; un indice dentro del paquete de datos PTactil_X_MSB EQU (Inicio_Memoria+7) ; Most Significant Byte de la X (10 bits) PTactil_X_LSB EQU (Inicio_Memoria+8) ; Least Significant Byte de la X (10 bits) PTactil_Y_MSB EQU (Inicio_Memoria+9) ; Most Significant Byte de la Y (10 bits) PTactil_Y_LSB EQU (Inicio_Memoria+10) ; Least Significant Byte de la Y (10 bits) Nueva_Pulsacion EQU (Inicio_Memoria+11) ; Se pone a 1 si hay pulsacion nueva de la pantalla Pantalla_Tactil_X EQU (Inicio_Memoria+12) ; Coordenada X de la pantalla (en formato 8 bits) Pantalla_Tactil_Y EQU (Inicio_Memoria+13) ; Coordenada Y de la pantalla (en formato 8 bits) STATUS_BAK EQU (Inicio_Memoria+14) ; Coordenada Y de la pantalla (en formato 8 bits) W_BAK EQU (Inicio_Memoria+15) ; Coordenada Y de la pantalla (en formato 8 bits) ; ;Variables ADC delayA EQU (Inicio_Memoria+16); delayB EQU (Inicio_Memoria+17); cont3 EQU (Inicio_Memoria+18);temporal para el muestra_adc delayC EQU (Inicio_Memoria+19) ANDATA1 EQU (Inicio_Memoria+20) ANDATA2 EQU (Inicio_Memoria+21) ; FASTRIGHT EQU (Inicio_Memoria+22) FASTLEFT EQU (Inicio_Memoria+23) FASTUP EQU (Inicio_Memoria+24) FASTDOWN EQU (Inicio_Memoria+25) SLOWRIGHT EQU (Inicio_Memoria+26) SLOWLEFT EQU (Inicio_Memoria+27) SLOWUP EQU (Inicio_Memoria+28) SLOWDOWN EQU (Inicio_Memoria+29) HORIZONTAL EQU (Inicio_Memoria+30) VERTICAL EQU (Inicio_Memoria+31) ADC EQU (Inicio_Memoria+32); ; Temp1 EQU (Inicio_Memoria+33); Temp2 EQU (Inicio_Memoria+34); ;============================================================================ ORG 0 GOTO INICIO ORG 0x8 ; interrupcion alta prioridad (solo tenemos INT0) GOTO INTERRUPCION ;Inicio del programa ORG 0x20 GOTO INICIO ; ir a INICIO ; Codigo de la interrupcion (Solo usamos INT0) INTERRUPCION BTFSS INTCON,INT0IF ;COMPROBACIÓN DE INTERRUPCION INT RETFIE ; movff STATUS, STATUS_BAK ;guardamos status movwf W_BAK ;guardamos W ; movf Numero_Byte_Datos,W btfss STATUS, Z goto Siguiente_Byte_1 CALL MIRXSOH ;Aquí llama para recibir SOH (cabecera) XORLW TRUE ;Esto es una comprobación para saber si el procedimiento a ejecutao btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos goto Salir_Interrupcion Siguiente_Byte_1 movf Numero_Byte_Datos,W xorlw 1 btfss STATUS, Z goto Siguiente_Byte_2 CALL MIRXDATO XORLW TRUE btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos movf DATO,W andlw 0x0f movwf PTactil_X_MSB goto Salir_Interrupcion Siguiente_Byte_2 movf Numero_Byte_Datos,W xorlw 2 btfss STATUS, Z goto Siguiente_Byte_3 CALL MIRXDATO XORLW TRUE btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos rlcf DATO rlcf DATO rlcf DATO rlcf DATO movf DATO,W andlw 0xf0 movwf PTactil_X_LSB goto Salir_Interrupcion Siguiente_Byte_3 movf Numero_Byte_Datos,W xorlw 3 btfss STATUS, Z goto Siguiente_Byte_4 CALL MIRXDATO XORLW TRUE btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos movf DATO,W andlw 0x0f addwf PTactil_X_LSB goto Salir_Interrupcion Siguiente_Byte_4 movf Numero_Byte_Datos,W xorlw 4 btfss STATUS, Z goto Siguiente_Byte_5 CALL MIRXDATO XORLW TRUE btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos goto Salir_Interrupcion Siguiente_Byte_5 movf Numero_Byte_Datos,W xorlw 5 btfss STATUS, Z goto Siguiente_Byte_6 CALL MIRXDATO XORLW TRUE btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos movf DATO,W andlw 0x0f movwf PTactil_Y_MSB goto Salir_Interrupcion Siguiente_Byte_6 movf Numero_Byte_Datos,W xorlw 6 btfss STATUS, Z goto Siguiente_Byte_7 CALL MIRXDATO XORLW TRUE btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos rlcf DATO rlcf DATO rlcf DATO rlcf DATO movf DATO,W andlw 0xf0 movwf PTactil_Y_LSB goto Salir_Interrupcion Siguiente_Byte_7 movf Numero_Byte_Datos,W xorlw 7 btfss STATUS, Z goto Siguiente_Byte_8 CALL MIRXDATO XORLW TRUE btfss STATUS, Z goto Error_Transmision incf Numero_Byte_Datos movf DATO,W andlw 0x0f addwf PTactil_Y_LSB goto Salir_Interrupcion Siguiente_Byte_8 ; bsf Nueva_Pulsacion, 0 ; marcamos la llegada de nuevos datos ; ; ; el resto de bytes no nos importa ;ahora convertimos el formato de 10 bits en 8 bits (los mas significativos) movff PTactil_X_LSB, Pantalla_Tactil_X rrncf Pantalla_Tactil_X rrncf Pantalla_Tactil_X bcf Pantalla_Tactil_X,7 bcf Pantalla_Tactil_X,6 btfsc PTactil_X_MSB,1 bsf Pantalla_Tactil_X,7 btfsc PTactil_X_MSB,0 bsf Pantalla_Tactil_X,6 ; movff PTactil_Y_LSB, Pantalla_Tactil_Y rrncf Pantalla_Tactil_Y rrncf Pantalla_Tactil_Y bcf Pantalla_Tactil_Y,7 bcf Pantalla_Tactil_Y,6 btfsc PTactil_Y_MSB,1 bsf Pantalla_Tactil_Y,7 btfsc PTactil_Y_MSB,0 bsf P Pantalla_Tactil_Y,6 ; ;termina la interrupcion normalmente ; Error_Transmision clrf Numero_Byte_Datos ; para que lea otro paquete Salir_Interrupcion ; movf W_BAK,W ;restauramos W movff STATUS_BAK,STATUS ;restauramos status ; BCF INTCON,INT0IF ;BORRA BANDERA INT R RETFIE ;;;;;;;;;;;;;;;;;;; COMIENZO DEL PROGRAMA PRINCIPAL ;;;;;;;;;;;;;;;;;;;;;;;; INICIO ; ; Inicializacion de variables clrf Numero_Byte_Datos clrf Nueva_Pulsacion ; Inicializacion de variables ; ; Configuracion ; movlw b'11101111' movwf OSCCON; velocidad de reloj 4 MHz movlw 0h movwf OSCTUNE; 4mhz exactos ;Configuración de todo el tema de motores clrf PORTA clrf PORTB bcf CONF_ENABLEH bcf CONF_ENABLEV bcf CONF_IZQUIERDA bcf CONF_DERECHA bcf CONF_ARRIBA bcf CONF_ABAJO movlw 0xFF ;Todos los FAST<X> valen 0xAA (motor se mueve el 75% de los "pasos") movwf HORIZONTAL movwf FASTRIGHT movwf FASTLEFT movwf FASTUP movwf FASTDOWN movlw 0xEE ;Todos los SLOW<X> valen 0x88 (motor se mueve el 25% de los "pasos") movwf SLOWRIGHT movwf SLOWLEFT movwf SLOWUP movwf SLOWDOWN ; configuracion inicial de puertos PANTALLA bcf CONF_LIBREA1; configurar el pin del led a salida (DEBUG) bcf CONF_LIBREA4 ; configurar el pin del led a salida (DEBUG) bcf CONF_MITX ;configurar TX a salida bsf CONF_MIRX ;configurar RX a entrada ; configuracion inicial de puertos PANTALLA ; configuracion inicial de puertos Analogico bsf CONF_MIAN0 bsf CONF_MIAN5 ; configuracion inicial de puertos Analogico movlw 0x7F movwf ADCON1 ;en un principio todos los canales AN son puestos a digitales ; bcf INTCON2, INTEDG0 ; int0 en flanco bajada ;;;;;; ;Posiciones iniciales de los pines BSF MITX BSF MIRX bcf LIBREA1;LED1 bcf LIBREA4 ; LED2 ;Posiciones iniciales de los pines ; ;;;;;CONFIGURACION DEL CONTROLADOR DE LA PANTALLA EN FORMATO hexadecimal ; call Espera_Larga CALL FH ; COMANDO PARA ESTABLECER FORMATO HEXADECIMAL call Espera_Larga CALL FH ; REPETIMOS EL COMANDO POR SI NO FUNCIONA LA PRIMERA VEZ ; ;;PRUEBA DEL LED ;DEBUG bsf LIBREA1;LED1 bsf LIBREA4 ; LED2 call Espera_Larga bcf LIBREA1;LED1 bcf LIBREA4 ; LED2 call Espera_Larga ;DEBUG ;;PRUEBA DEL LED ;DEBUG ;;HABILITAMOS LA INTERRUPCIONES para dar paso al programa principal ; BSF INTCON,INT0IE ;HABILITA INTERRUPCIÓN INT0 bcf INTCON, INT0IF ; borrar la flag de "ocurrido int0" BSF INTCON,GIE ;HABILITA INTERRUPCIONES GLOBALMENTE ; segun el manual IPEN esta a 0 por defecto (prioridades altas) ; e INT0 es siempre de prioridad alta ; ; Programa principal ; Bucle_Principal ; DEBUG programa de prueba btfss Nueva_Pulsacion,0 goto Salir_BP clrf Nueva_Pulsacion ;;;; Bucle_Mover_Motor1 bcf LIBREA1;LED1 bcf LIBREA4 ; LED2 btfsc Pantalla_Tactil_X,7 bsf LIBREA1;LED1 btfsc Pantalla_Tactil_X,6 bsf LIBREA4 ; LED2 call movf subwf movff movwf analog ANDATA1,W Pantalla_Tactil_X,W ; ahora W tiene el resultado de PX­AND STATUS,Temp2; T Temp1; lo poenemos en temp1 ; ; segun el manual si el resultado es negativo ni carry ni zero estan puestos ; movff Temp2,STATUS; btfsc STATUS,Z goto Motor_Positivo btfsc STATUS,C goto Motor_Positivo ; ;motor negativo btfss WREG,7 goto rapido_neg btfss WREG,6;s goto rapido_neg btfss WREG,5;s goto rapido_neg ; call inith call sleft goto Salir_Bucle_Mover_Motor1 r rapido_neg call inith c call fleft ;motor negativo goto Salir_Bucle_Mover_Motor1 S ;motor positivo Motor_Positivo M ;zona muerta ;cuando estemos en un ciclo positivo y el valor <16 parar andlw 0xf0 btfss STATUS,Z goto Mover_positivo_Normal call stoph goto Salir_Bucle_Mover_Motor1 ; ; Mover_positivo_Normal ; recuperacion zona muerta movf Temp1,W ; andlw b'11100000' btfsc STATUS,Z goto rapido_pos ; call inith call fright goto Salir_Bucle_Mover_Motor1 r rapido_pos call inith c call sright ; ;motor positivo Salir_Bucle_Mover_Motor1 goto Bucle_Mover_Motor1 B ;;; Salir_BP goto B Bucle_Principal ; ; ;­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ ;­­­retardo doble Ret_2max movlw 8 movwf delayC Ret2max call delay decfsz delayC goto Ret2max return ;­­­­­retardo Ret_max movlw 4 movwf delayC Retmax call delay decfsz delayC goto Ret2max return ;­­­­­­­­retardo mitad Ret_max2 movlw 2 movwf delayC Retmax2 call delay decfsz delayC goto Ret2max return delay movlw 0xFF movwf delayA d loopA movlw 0xFF movwf delayB d loopB decfsz delayB, f goto loopB decfsz delayA, f goto loopA l r return ;­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ ;Delay Routine delayan movlw 0x03 movwf delayA loopAan movlw 0xFF movwf delayB loopBan decfsz delayB, f goto loopBan decfsz delayA, f goto loopAan return ; ; ; ******* Rutinas RS232 ; ; ; ; Rutinas de RS232 ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MIRXDATO ;RECIBE UN BYTE POR MIRX ;W := FALSE SI NO HAY START BIT AL PRINCIPIO ;W := TRUE ; DATO := BYTE RECIBIDO POR MIRX EJECUCION CORRECTA ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BTFSS MIRX GOTO MIRXBYTE RETLW FALSE MIRXBYTE CALL TIME2 MOVLW 8 MOVWF CONT8 BIT CALL TIME RRCF DATO,F BCF DATO,7 BTFSC MIRX BSF DATO,7 DECFSZ CONT8,F GOTO BIT CALL TIME2 RETLW TRUE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MIRXSOH ;RECIBE UN BYTE POR MIRX ;W := FALSE SI NO HAY START BIT AL PRINCIPIO, si no es SOH ;W := TRUE ; SOH := BYTE RECIBIDO POR MIRX EJECUCION CORRECTA ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BTFSS MIRX GOTO MIRXBYTESOH RETLW FALSE MIRXBYTESOH CALL TIME2 MOVLW 8 MOVWF CONT8 BITSOH CALL TIME RRCF SOH,F BCF SOH,7 BTFSC MIRX BSF SOH,7 DECFSZ CONT8,F GOTO BITSOH CALL TIME2 MOVF SOH,0 ;Se mueve el valor de SOH a W BZ SALIRFALSE ; Si es 0, no es SOH ANDLW CTRAN ; Realizamos un And con SOH negado BZ SALIRTRUE ;Si el resultado de la AND fue 0, el caracter era SOH RETLW FALSE ; Si el resultado de la AND no fue 0, el caracter no era SOH SALIRTRUE RETLW TRUE SALIRFALSE RETLW FALSE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MITXDATO ; TRANSMITE EL BYTE GUARDADO EN DATO POR LA LINEA MITX ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MOVLW 8 MOVWF CONT8 BCF MITX BIT2 CALL TIME RRCF DATO,F BTFSS STATUS,C BCF MITX BTFSC STATUS,C BSF MITX DECON DECFSZ CONT8,F GOTO BIT2 CALL TIME BSF MITX CALL TIME RETURN ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TIME2 ;RETARDO DE 52 uS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MOVLW 1 MOVWF RET1 T1 MOVLW .14 MOVWF RET2 T2 DECFSZ RET2,F GOTO T2 DECFSZ RET1,F GOTO T1 NOP RETURN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TIME ;104 uS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MOVLW 1 MOVWF RET1 T3 MOVLW .28 MOVWF RET2 T4 DECFSZ RET2,F GOTO T4 DECFSZ RET1,1 GOTO T3 NOP NOP RETURN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ESPERAW ;tiempo de espera = W*(10*104) uS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MOVWF CONT8 BUCLEW CALL TIME CALL TIME CALL TIME CALL TIME CALL TIME CALL TIME CALL TIME CALL TIME CALL TIME CALL TIME DECF CONT8,1 BZ CONTINUARW GOTO BUCLEW CONTINUARW RETURN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RET_CARRO ;Envía el retorno de carro ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MOVLW d'13' MOVWF DATO CALL MITXDATO MOVLW 0FFh MOVWF CONT8 CALL TIME DECFSZ CONT8,F MOVLW d'10' MOVWF DATO CALL MITXDATO RETURN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; FH ;Envía el comando FH (formato hexadecimal) para la pantalla tactil ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MOVLW 0x01 MOVWF DATO CALL MITXDATO MOVLW "F" MOVWF DATO CALL MITXDATO MOVLW "H" MOVWF DATO CALL MITXDATO CALL RET_CARRO RETURN ; ; Fin rutinas de RS232 ; ; ; Otras rutinas ; Espera_Larga CALL ESPERAW MOVLW 0FFh CALL ESPERAW MOVLW 0FFh CALL ESPERAW MOVLW 0FFh CALL ESPERAW MOVLW 0FFh CALL ESPERAW return ;­­­­­­­­­­­ ; lectura ADC analog movlw b'01111110' movwf ADCON1 ;1º SELECCIONAR CANAL 0 movlw b'00000101'; right justified, 0TAD, FOSC/16 movwf ADCON2 ; configrar adcon2 movlw b'11000000' ;enable A/D, AN0, mod enable movwf ADCON0 bsf ADCON0,0 ; ACTIVAMOS EL CONVERSOR ; ESPERAMOS EL TIEMPO NECESARIO PARA LA ADQUISICION 1000 INSTRUCCIONES call delayan ; tras la espera hacemos 0la conversion BCF INTCON,GIE bsf ADCON0,GO ;go do a/d conversion adloop btfsc ADCON0,DONE goto adloop BSF INTCON,GIE movff ADRESH,ANDATA1 ;get the value in speed bcf ADCON0,0 call delayan ;; call Ret_2max ; ESPERAMOS UN TIEMPO ANTES DE LA SIGUIENTE CONFIGURACION movlw b'01011111' movwf ADCON1 ;1º SELECCIONAR CANAL 5 movlw b'00000101'; right justified, 0TAD, FOSC/16 movwf ADCON2 ; configrar adcon2 movlw b'11010100' ;enable A/D, AN0, mod enable movwf ADCON0 bsf ADCON0,0 ; ACTIVAMOS EL CONVERSOR ; ESPERAMOS EL TIEMPO NECESARIO PARA LA ADQUISICION 1000 INSTRUCCIONES call delayan ; tras la espera hacemos la conversion BCF INTCON,GIE bsf ADCON0,GO ;go do a/d conversion adloop2 btfsc ADCON0,DONE goto adloop2 BSF INTCON,GIE movff ADRESH,ANDATA2 ;get the value in speed bcf ADCON0,0 movlw 0x7F movwf ADCON1 BSF INTCON,GIE return ;INICIO DE FUNCIONES DE MOTORES inith bsf ENABLEH return initv bsf ENABLEV return stoph bcf ENABLEH return stopv bcf ENABLEV return fleft bcf IZQUIERDA bcf DERECHA btfsc FASTRIGHT, 7 bsf IZQUIERDA bcf STATUS,C rlcf FASTRIGHT, 1 btfsc STATUS,C bsf FASTRIGHT, 0 return fright bcf IZQUIERDA bcf DERECHA btfsc FASTLEFT, 7 bsf DERECHA bcf STATUS,C rlcf FASTLEFT, 1 btfsc STATUS,C bsf FASTLEFT, 0 return fup bcf ARRIBA bcf ABAJO btfsc FASTUP, 7 bsf ARRIBA bcf STATUS,C rlcf FASTUP, 1 btfsc STATUS,C bsf FASTUP, 0 return fdown bcf ARRIBA bcf ABAJO btfsc FASTDOWN, 7 bsf ABAJO bcf STATUS,C rlcf FASTDOWN, 1 btfsc STATUS,C bsf FASTDOWN, 0 return sleft bcf IZQUIERDA bcf DERECHA btfsc SLOWRIGHT, 7 bsf IZQUIERDA bcf STATUS,C rlcf SLOWRIGHT, 1 btfsc STATUS,C bsf SLOWRIGHT, 0 return sright bcf IZQUIERDA bcf DERECHA btfsc SLOWLEFT, 7 bsf DERECHA bcf STATUS,C rlcf SLOWLEFT, 1 btfsc STATUS,C bsf SLOWLEFT, 0 return sup bcf ARRIBA bcf ABAJO btfsc SLOWUP, 7 bsf ARRIBA bcf STATUS,C rlcf SLOWUP, 1 btfsc STATUS,C bsf SLOWUP, 0 return sdown bcf ARRIBA bcf ABAJO btfsc SLOWDOWN, 7 bsf ABAJO bcf STATUS,C rlcf SLOWDOWN, 1 btfsc STATUS,C bsf SLOWDOWN, 0 return ;FIN DE FUNCIONES DE MOTORES ;­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ ; ; RUTINAS MOSTRADO DATOS ADC (PARPADEO BITS) ;­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ ;MUESTRA EL CONTENIDO DEL REGISTRO ADC BIT A BIT DE MENOS A MAS SIGNIFICATIVO ;PORTB7 DATO ;PORTB6 RELOJ ;CUANDO EL RELOJ ESTÁ A UNO EL DATO ES VALIDO ;CUANDO EL RELOJ ESTÁ A CERO NO HACER CASO AL DATO ;PRESUPONE EL PORTB EN MODO SALIDA ;DESTRUYE ADC mostrar_ADC ; movff ANDATA1,ADC movlw 3 movwf cont3 ppad1 BSF LIBREA4 ;ENCIENDE RELOJ call Ret_max2 ; RETARDO BCF LIBREA4 ; APAGA RELOJ BCF LIBREA1 ; APAGA data; christopher call Ret_max2 ;RETARDO DECFSZ cont3 goto ppad1 call Ret_2max movlw 8 movwf cont3 siguiente_bit BCF LIBREA4 ; APAGA RELOJ BCF LIBREA1 ; APAGA dato ;chrstopher call Ret_max ;RETARDO BCF LIBREA1 BTFSC ADC,0 BSF LIBREA1 ;coloca el siguiente bit en Dato BSF LIBREA4 ; activa el reloj call Ret_2max ;retardo RRCF ADC DECFSZ cont3 goto siguiente_bit ; termina la transmision, se apagan los leds BCF LIBREA1 BCF LIBREA4 call Ret_max ;­­­­­­­­­­indica fin de transmision movlw 3 movwf cont3 ppad2 BSF LIBREA4 ;ENCIENDE RELOJ call Ret_max2 ; RETARDO BCF LIBREA4 ; APAGA RELOJ call Ret_max2 ;RETARDO DECFSZ cont3 goto ppad2 return ;FIN MUESTRA_ADC­­­­­­­­­­­ ; ; ;=========================================================================== ;­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ ;PROgramacion de configuracion org 0x300000 CONFIG1 data 0xC9FF CONFIG2 data 0x000C CONFIG3 data 0x00FF CONFIG4 data 0xFF80 CONFIG5 data 0xC003 CONFIG6 data 0xE003 CONFIG7 data 0x4003 END