Diseño de Sistemas Basados en Microprocesadores Experiencia con Motores paso a paso Rubén Tauroni Gil ITIS 2008-2009 Universidad de Las Palmas de Gran Canaria Índice Objetivos .............................................................................................................................3 Parte Teórica........................................................................................................................4 Desarrollo de la práctica .......................................................................................................7 Flujo del programa............................................................................................................7 Apartado 1) ......................................................................................................................8 Apartado 2) ......................................................................................................................9 Apartado 3) ....................................................................................................................10 Apartado 4) ....................................................................................................................11 Apartado 5) ....................................................................................................................12 Apartado 6) ....................................................................................................................14 Problemas y mejoras ..........................................................................................................16 Conclusión .........................................................................................................................16 Código del programa ..........................................................................................................17 Bibliografía.........................................................................................................................24 2 Objetivos El objetivo de esta práctica es que el alumno se desenvuelva aún más con la programación en ensamblador en un PIC16F84 en una práctica ideada por el propio alumno, o ideada por el profesor si el alumno no se le ocurre nada. Vamos a trabajar con un motor paso a paso de un reproductor de CDs. La práctica se puede dividir en aparatos: 1º Sobre el motor paso a paso, debemos investigar y averiguar la secuencia que mueve a dicho motor, así como intentar llegar a la velocidad máxima del mismo. 2º Se programará el timer interno, para aprovecharlo y poder calcular 1 segundo. 3º Aprovechando el timer, lo usaremos para que cada segundo, mostraremos más adelante algo por la pantalla. 4º Cada x segundo hacemos el siguiente paso de la secuencia del motor. Aumentando la velocidad de manera progresiva. 5º Adaptando un fotodiodo al motor paso a paso en su circuito adaptado para ello, captaremos cada vuelta del motor, enviando una señal por el puerto RB0 produciendo una interrupción y contabilizar dicha vuelta. 6º Por último, mostraremos por la pantalla de la Placa PicSchool, el mensaje “Vuelta/Seg XX” donde XX irá las vueltas por segundos que actualmente se está dando. Para la realización de la práctica necesitaremos una serie de materiales para el desarrollo de la actividad. Placa PicSchool Ordenador y software de grabación Microcontrolador PIC16F84 Fuente de alimentación Cables para las conexiones Resistencias Fotodiodo Motor paso a paso 3 Parte Teórica Placa PicSchool Es un laboratorio de carácter didáctico y una evolución lógica de los populares conocidos entrenadores Micro’PIC Trainer y PIC’Laboratory. Permite trabajar con los dispositivos PIC más representativos de las familias 12F, 16F y 18F, pudiéndose desarrollar aplicaciones tanto a nivel de software como de hardware. Dispone de un amplio y representativo número de periféricos muy utilizados en las aplicaciones reales y un módulo board para el montaje sin soldadura que permite implementar el hardware necesario en un determinado proyecto. PIC16F84 El microcontrolador PIC16F84 es un microcontrolador de 8 bits. Dispone de 18 pines y un repertorio de instrucciones RISC. Su estructura interna consta de: Memoria Flash de programa (1K x 14). Memoria EEPROM de datos (64 x 8). Memoria RAM (68 registros x 8). Banco de registros de propósito general (STATUS, OPTION, INTCON, PC) Un temporizador/contador (timer de 8 bits). Un divisor de frecuencia. Varios puertos de entrada-salida (13 pines en dos puertos, 5 pines el puerto A y 8 pines el puerto B). Manejo de interrupciones (de 4 fuentes). Perro guardián (watchdog). Bajo consumo. Frecuencia de reloj externa máxima 10MHz. (Hasta 20MHz en nuevas versiones). La frecuencia de reloj interna es un cuarto de la externa, lo que significa que con un reloj de 20Mhz, el reloj interno sería de 5Mhz y as__ pues se ejecutan 5 Millones de Instrucciones por Segundo (5 MIPS). Pipe-line de 2 etapas, 1 para búsqueda de instrucción y otra para la ejecución de la instrucción (los saltos ocupan un ciclo más). Repertorio de instrucciones reducido (RISC), con tan solo 30 instrucciones distintas. 4 tipos distintos de instrucciones, orientadas a byte, orientadas a bit, operación entre registros, de salto. 4 Cabe destacar la organización de la memoria dividida en tres bloques, RAM, con registros de propósito general y propósito especial, EEPROM, grabable dinámicamente desde el programa y FLASH, memoria de programa. Tenemos un vector de reset indicando la dirección de comienzo del programa (Reset Vector: 0000h) y un vector de interrupciones con una única entrada de interrupción (Interrupt vector 0004h), tras la cual hemos de identificar cual de las líneas la ha generado. La memoria de datos (RAM), está organizada en bancos, en nuestro PIC, se organiza en 2 bancos (vease figura a la izquierda) admitiendo cada uno de ellos hasta 128 bytes. Para movernos entre los bancos el bit RP0 del registro general STATUS, el cual, cuando está a 0, estamos en el banco 0 y cuando está a 1, estamos en el banco 1. Vease en el dibujo como algunos registros son comunes a ambos bancos, ocurriendo lo mismo a partir de la dirección 0Ch de la memoria. MOTOR PASO A PASO Básicamente estos motores están constituidos normalmente por un rotor sobre el que van aplicados distintos imanes permanentes y por un cierto número de bobinas excitadoras bobinadas en su estator. Las bobinas son parte del estator y el rotor es un imán permanente. Toda la conmutación (o excitación de las bobinas) deber ser externamente manejada por un controlador. Existen dos tipos de motores paso a paso de imán permanente: Cuestiones básicas Los motores paso a paso se pueden ver como motores eléctricos sin escobillas. Es típico que todos los bobinados del motor sean parte del estator, y el rotor puede ser un imán permanente o, en el caso de los motores de reluctancia variable (que luego describiremos mejor), un cilindro sólido con un mecanizado en forma de 5 dientes (similar a un engranaje), construido con un material magnéticamente "blando" (como el hierro dulce). La conmutación se debe manejar de manera externa con un controlador electrónico y, típicamente, los motores y sus controladores se diseñan de manera que el motor se pueda mantener en una posición fija y también para que se lo pueda hacer girar en un sentido y en el otro. La mayoría de los motores paso a paso conocidos se pueden hacer avanzar a frecuencias de audio, lo que les permite girar muy velozmente. Con un controlador apropiado, se los puede hacer arrancar y detenerse en un instante en posiciones controladas. Comportamiento propio de los motores paso a paso: Los motores paso a paso tienen un comportamiento del to do diferente al de los motores de corriente continua. En primer lugar, no giran libremente por sí mismos. Los motores paso a paso, como lo indica su nombre, avanzan girando por pequeños pasos. También difieren de los motores de CC en la relación entre velo cidad y torque (un parámetro que también es llamado "par motor" y "par de giro"). Los motores de CC no son buenos para of recer un buen torque a baja velocidad sin la ayuda de un mecanismo de reducción. Los motores paso a paso, en cambio, trabajan de manera opuesta: su mayor capacidad de torque se produce a baja velocidad. Los motores paso a paso tienen una característica adicional: el torque de detención (que se puede ver mencionado también como "par de detención", e incluso par/torque "de mantenimiento"), que no existe en los motores de CC. El torque de detención hace que un motor paso a paso se mantenga firmemente en su posición cuando no está girando. Esta característica es muy útil cuando el motor deja de moverse y, mientras está detenido, la fuerza de c arga permanece aplicada a su eje. Se elimina así la necesidad de un mecanismo de freno. Si bien es cierto que los motores paso a paso funcionan controlados por un pulso de avance, el control de un motor paso a paso no se realiza aplicando en directo este pulso eléctrico que lo hace avanzar. Estos motores tienen varios bobinados que, para producir el avance de ese paso, deben ser alimentados en una adecuada secuencia. Si se invierte el orden de esta secuencia, se logra que el motor gire en sentido opuesto. Si los pulsos de alimentación no se proveen en el orden correcto, el motor no se moverá apropiadamente. Puede ser que zumbe y no se mueva, o puede ser que gire, pero de una manera tosca e irregular. Esto signif ica que hacer girar un motor paso a paso no es tan simple como hacerlo con un motor de corriente continua, al que se le entrega una corriente y listo. Se requiere un circuito de control, que será el responsable de convertir las señales de avance de un paso y sentido de giro en la necesaria secuencia de energización de los bobinados. 6 Desarrollo de la práctica Explicaremos cada uno de los apartados en que subdividimos la práctica y explicaremos tanto su uso como su desarrollo, pero antes mostraremos un pequeño flujo del programa tal y como está estructurado el código. Flujo del programa Hay que recordar que cuando se produce la interrupción, vamos a tratarla y al retornar volvemos justo por donde iba el flujo del programa. 7 Apartado 1) 1º Sobre el motor paso a paso, debemos investigar y averiguar la secuencia que mueve a dicho motor, así como intentar llegar a la velocidad máxima del mismo. En primer lugar hemos tenido que calcular cuales son los valores hexadecimales para el movimiento del motor paso a paso. Al investigar cómo se realiza este movimiento averiguamos que existen distintas manera, secuencia normal, secuencia del tipo wave drive y secuencia de medio paso. Al probarlas descubrimos que la que mejor funciona es la secuencia de medio paso, pero vemos que no funciona con la exactitud con l a que realmente querríamos. Para ello creamos una tabla, en la cual irá dicha secuencia. Para probar con otro motor, tan solo deben cambiar dicha secuencia. Tabla ; Tabla para el movimiento del motor movlw HIGH Tabla movwf PCLATH movfw CUENTA_TABLA addwf PCL,W BTFSC STATUS, C incf PCLATH,F movfw CUENTA_TABLA addwf PCL,F retlw 08h ;1000 retlw 0Ch ;1100 retlw 04h ;0100 retlw 06h ;0110 retlw 02h ;0010 retlw 0Ah ;1010 Por ensayo y error fuimos buscando hasta encontrar cual era la velocidad máxima, siendo entre 70 y 80 RPM. Empezamos desde una velocidad lenta, hasta ir aumentando poco a poco hasta llegar a la velocidad máxima y manteniéndola constante. 8 Apartado 2) 2º Se programará el timer interno, para aprovecharlo y poder calcular 1 segundo. bsf STATUS,RP0 ; banco 1 bcf OPTION_REG,3 ; activo preescaler TMR0 bcf OPTION_REG,5 ; activo cuenta interna ; Ahora lo tengo a 1:16 bsf OPTION_REG,0 ; Rango del prescaler TMR0 Rate 1:4 bsf OPTION_REG,1 ; Rango del prescaler TMR0 Rate 1:4 bcf OPTION_REG,2 ; Rango del prescaler TMR0 Rate 1:4 clrf TRISB bcf STATUS,RP0 Con esto el timer se incrementará de uno en uno cada 16 instrucciones, hasta llegar a 256, tras la cual este se reseteará y producirá una excepción. Un segundo equivale a 1 millón de instrucciones, por lo que tenemos: 255 x 16 = 4080 instrucciones por cada interrupción 1000000 4080 =245 veces Pasando 245 a hexadecimal tenemos que cada segundo se producirá tras F5 interrupciones del timer. 9 Apartado 3) 3º Tendremos un programa Principal el cual comprobará indefinidamente si hemos de hacer un cambio al siguiente paso del motor, o bien mostrar por pantalla. Aprovechando el timer, lo usaremos para que cada segundo, mostremos más adelante algo por la pantalla. Una vez calculado cuando se producirá un segundo podemos pasar a organizar nuestro programa. Estaremos continuamente comprobando si hemos llegado a la velocidad terminal, si es así tendremos que cambiar al Siguiente_Paso, en caso contrari o, también debemos comprobar si ha transcurrido ya un segungo, si es así debemos mostrar_vueltas por la pantalla y sino pues volvemos a Principal y seguir comprobando. Durante todo esto surgirán interrupciones, que se acudirán a ellas recordando por donde va el flujo del programa. Principal movfw velocidadTer movwf velocidadAux movfw velocidad subwf velocidadAux,W ; si velocidad = velocidadTer paso siguiente BTFSS STATUS, Z goto Prin2 goto Siguiente_Paso Prin2 ; Vamos al siguiente paso movfw tiempo sublw 0F5h ; si tiempo=n mostrar vueltas BTFSS STATUS,Z goto Principal goto Mos_Vuel ; goto Mostrar_Vueltas 10 Apartado 4) 4º Cada x segundo hacemos el siguiente paso de la secuencia del motor. Para cambiar la secuencia del motor, buscamos en la tabla el código del paso siguiente, una vez buscado dicho paso, lo mandamos por el puerto B realizándose. Debemos resetear velocidad, para empezar con el siguiente paso, todo esto controlando que no nos salgamos de la tabla Siguiente_Paso call Tabla ; Buscamos en la tabla el paso siguiente movwf PORTB ; Hacemos el siguiente paso clrf velocidad ; Reseteamos la velocidad incf CUENTA_TABLA,1 ; Incrementamos para siguiente paso movfw CUENTA_TABLA sublw 06h ; Si es 6 volvemos al inicio de la tabla BTFSS STATUS, Z goto Principal clrf CUENTA_TABLA clrf velocidad ; Reseteamos la velocidad goto Principal 11 Apartado 5) 5º Adaptando un fotodiodo al motor paso a paso en su circuito adaptado para ello, captaremos cada vuelta del motor, enviando una señal por el puerto RB0 produciendo una interrupción y contabilizar dicha vuelta. Aprovecharemos este apartado para mostrar y explicar el código de las interrupciones, que nuestro caso tenemos dos tipos, interrupción por RB0 e interrupción por timer. Al producirse una interrupción primero hemos de salvar los registros de STATUS y el valor de W para no perder ningún valor cuando se produce la interrupción, eso se hace en “PUSH”. Hemos de comprobar de donde proviene la interrupción comprobando e l bit 0 del puerto B, si este está a 0, la interrupción la produjo el timer, en caso contrario la produjo RB0, esto se hace en “ISR”. En “TIMER” tan solo incrementamos en 1, velocidad y tiempo, que son variables auxiliares que una vez llegado a un valor, se resetean y obligan a cambiar algo. Tiempo hace que cada vez que llegue al valor F5 se vaya a la subrutina que muestra por pantalla y Velocidad que cada vez que llegue a una velocidad terminal, el tiempo de cambio al siguiente paso sea mas rápida y así aumente la velocidad del motor. Cada vez que llegamos a “LED” es que se produjo una vuelta en el motor, la contabilizamos y deshabilitamos la interrupción. Por último en “POP”, recuperamos los valores de STATUS y W “deshabilitamos” la interrupción por Timer y continuamos por donde iba la ejecución del programa. Interrupciones GLOBAL Interrupciones PUSH MOVWF W_TEMP ; Copia W en W_TEMP SWAPF STATUS, W ; Swap status y deja resultado en W MOVWF STATUS_TEMP ; Salva STATUS EN STATUS_TEMP register ISR BTFSS INTCON,1 ; Testeamos el bit 0 de PORTB goto TIMER ; Si es 0 interrupción por TMR0 goto LED ; si es 1 interrupción por RB0 POP SWAPF STATUS_TEMP, W; Recupera STATUS en W 12 MOVWF STATUS ; Mueve W a STATUS SWAPF W_TEMP, F ; Recupera W SWAPF W_TEMP, W ; bcf INTCON,2 ; desabilito causa-interrupcion retfie ; Retornamos bcf PORTB,7 ; (Bit que muestra parpadeo/seg) incf tiempo,1 ; incrementamos tiempo incf velocidad,1 ; incrementamos velocidad TIMER goto POP LED ; Cada vez que llegamos aquí contamos 1 vuelta ; Cuando mostramos vueltas_seg hay que resetearla incf vueltas_seg,1 bcf INTCON,1 ; desabilito interrupción por RB0 goto POP ;Fin de rutinas de interrupciones end 13 Apartado 6) 6º Por último, mostraremos por la pantalla de la Placa PicSchool, el mensaje “Vuelta/Seg XX” donde XX irá las vueltas por segundos que actualmente se está dando. Al inicio de la ejecución del programa mostramos el mensaje por la pantalla. Para ello debemos incluir la librería de la pantalla LCD y declarar sus funciones: include "lcd.inc" ;Librería pantalla LCD EXTERN DISPLAY_CONF, BORRA_Y_HOME, LCD_DATO, LCD_REG, LCD_INI Codigo que muestra el mensaje “Vueltas/Seg XX” usando las funciones ya desarrolladas. call LCD_INI ;Inicializa display call DISPLAY_CONF movlw 'V' call LCD_DATO movlw 'u' call LCD_DATO movlw 'e' call LCD_DATO movlw 'l' call LCD_DATO movlw 't' call LCD_DATO movlw 'a' call LCD_DATO movlw 's' call LCD_DATO movlw '/' call LCD_DATO movlw 's' call LCD_DATO movlw 'e' call LCD_DATO movlw 'g' call LCD_DATO movlw 0C0h call LCD_REG movlw 'X' call LCD_DATO movlw 'X' call LCD_DATO bcf PORTA,2 ;Desactivamos la pantalla 14 Para mostrar el valor de Vueltas_Seg, debemos pasar dicho valor que está en hexadecimal y pasarlo a código ascci. Mostrarmos dos números por la pantalla por lo que para el digito más significativo nos quedamos con los 4 bits del segundo byte de vueltas_seg lo rotamos 4 posciones a la derecha y le sumamos 30h y obtenemos el número en ascci, y para el otro número repetimos el proceso pero sin desplazamiento: Mos_Vuel ; Aquí llegamos una vez por segundo movlw 0C0h call LCD_REG movfw vueltas_seg andlw 0F0h movwf ascii bcf STATUS,C rrf ascii rrf ascii rrf ascii rrf ascii movfw ascii addlw 30h call LCD_DATO bcf PORTA,2 movfw vueltas_seg andlw 0Fh addlw 30h call LCD_DATO bcf PORTA,2 clrf vueltas_seg 15 Problemas y mejoras El mayor problema ha sido que no conseguimos el perfecto control del motor paso a paso, como realmente se debería haber conseguido. Tampoco se logró una velocidad asombrosa. Se hizo la prueba con otro motor paso a paso, pero era un poco más complejo, al no poderlo acoplar directamente a la placa, para este caso tuvimos que alimentar el motor paso a paso desde una fuente de alimentación, pero la velocidad fue muy parecida que en el otro caso. Mejoras que se lo podría añadir a la práctica sería añadirle otras funcionalidades al control del motor paso a paso controladas o bien con el teclado de la placa o bien mediante pulsadores o conmutadores, como por ejemplo: Cambiar de sentido al motor. Aumentar la velocidad. Disminuir la velocidad. Detenerlo Conclusión Una vez terminado el trabajo vemos que el uso de los microcontroladores pic16f84 para la realización y control de tareas sencillas con una serie de entradas y salidas es ideal puesto que su repertorio de instrucciones permite una programación sin demasiada dificultad. Lo más interesante que me resulta es aplicar los conocimientos de programación en algo tangible hecho por nosotros, con resultados interesantes. Además esta práctica ha servido a aprender a usar aún más los microcontroladores, así como conocer el funcionamiento de los motores paso a paso. 16 Código del programa Fichero “pr1”: List p=16F84A ;Tipo de procesador include "P16F84A.INC" ;Definiciones de registros internos include "lcd.inc" ;Libreria pantalla LCD LIST ; P16F84.INC Standard Header File, Version 2.00 Microchip Technology, Inc. EXTERN velocidad, tiempo, vueltas_seg EXTERN Interrupciones EXTERN DISPLAY_CONF, BORRA_Y_HOME, LCD_DATO,LCD_REG, LCD_INI Cero EQU 00h ; Inicialzar UDATA statusR RES 1 ; Registro temporal de estado PORTB_TEMP RES 1; Salvamos PORTB(Interrupcion) CUENTA_TABLA RES 1; lleva la cuenta de la tabla v RES 1; variable fija, si velocidad = v -> Siguiente_Paso n RES 1; variable fija, si tiempo = n -> Mostrar_Vueltas velocidadTer RES 1; velocidad terminal cambiante velocidadAux RES 1; ascii RES 1; 0x00 ;Vector de Reset BOOT CODE goto Inicio INTERRUPCION CODE 0x04 goto Interrupciones 17 PPAL CODE ;Interrupciones Tabla ; Tabla para el movimiento del motor movlw HIGH Tabla movwf PCLATH movfw CUENTA_TABLA addwf PCL,W BTFSC STATUS,C incf PCLATH,F movfw CUENTA_TABLA addwf PCL,F retlw 08h ;1000 retlw 0Ch ;1100 retlw 04h ;0100 retlw 06h ;0110 retlw 02h ;0010 retlw 0Ah ;1010 Inicio bsf STATUS,RP0 ; banco 1 bcf OPTION_REG,3 ; activo preescaler TMR0 bcf OPTION_REG,5 ; activo cuenta interna ; Ahora lo tengo a 1:16 bsf OPTION_REG,0 ; Rango del prescaler TMR0 Rate 1:4 bsf OPTION_REG,1 ; Rango del prescaler TMR0 Rate 1:4 bcf OPTION_REG,2 ; Rango del prescaler TMR0 Rate 1:4 clrf TRISB bcf STATUS,RP0 call LCD_INI;Inicializa display call DISPLAY_CONF movlw 'V' 18 call LCD_DATO movlw 'u' call LCD_DATO movlw 'e' call LCD_DATO movlw 'l' call LCD_DATO movlw 't' call LCD_DATO movlw 'a' call LCD_DATO movlw 's' call LCD_DATO movlw '/' call LCD_DATO movlw 's' call LCD_DATO movlw 'e' call LCD_DATO movlw 'g' call LCD_DATO movlw 0C0h call LCD_REG movlw 'X' call LCD_DATO movlw 'X' call LCD_DATO bcf PORTA,2 movlw Cero movwf PORTB clrf TMR0 movlw 0h ; inicialiamos tiempo y velocidad 19 movwf tiempo movwf velocidad movlw 060h ; inicialiamos velocidad terminal movwf velocidadTer movlw 01h; movwf CUENTA_TABLA bcf INTCON,1 ; RB0 did not ocurr bcf INTCON,2 ; TMR0 did not overflow bsf INTCON,4 ; Activo interrupción por RB0 bsf INTCON,5 ; Activo interrupción por TMR0 bsf INTCON,7 ; Activo interrupción blobal Principal movfw velocidadTer movwf velocidadAux movfw velocidad subwf velocidadAux,W ; si velocidad=velocidadTer paso siguiente BTFSS STATUS,Z goto Prin2 goto Siguiente_Paso ; Vamos al siguiente paso Prin2 movfw tiempo sublw 0F5h ; si tiempo=n mostrar vueltas BTFSS STATUS,Z goto Principal goto Mos_Vuel ; goto Mostrar_Vueltas Siguiente_Paso call Tabla movwf PORTB clrf velocidad ; Buscamos en la tabla el paso siguiente ; Hacemos el siguiente paso ; Reseteamos la velocidad incf CUENTA_TABLA,1 ; Incrementamos para siguiente paso 20 movfw CUENTA_TABLA sublw 06h ; Si es 6 volvemos al inicio de la tabla BTFSS STATUS, Z goto Principal clrf CUENTA_TABLA clrf velocidad ; Reseteamos la velocidad goto Principal Mos_Vuel ;Aquí llegamos una vez por segundo movlw 0C0h call LCD_REG movfw vueltas_seg andlw 0F0h movwf ascii bcf STATUS,C rrf ascii rrf ascii rrf ascii rrf ascii movfw ascii addlw 30h call LCD_DATO bcf PORTA,2 movfw vueltas_seg andlw 0Fh addlw 30h call LCD_DATO bcf PORTA,2 clrf vueltas_seg bsf PORTB,7 ; mostramos parpadeo/seg clrf tiempo ; Reseteamos el tiempo movfw velocidadTer ; Hacemos que la velocidad sea constante 21 sublw 04h ; en su momento de máxima velocidad BTFSS STATUS, Z goto Decre goto Principal Decre decf velocidadTer,F ; Sino es velocidad máxima, decrementamos goto Principal; Stop nop nop end Fichero “interup_code.asm”: List p=16F84 ;Tipo de procesador include "P16F84.INC" ;Definiciones de registros internos LIST ; P16F84.INC Standard Header File, Version 2.00 Microchip Technology, Inc. UDATA W_TEMP RES 1 ; Registro temporal para interrupciones STATUS_TEMP RES 1; Salvamos STATUS(Interrupcion) velocidad RES 1; contador para cambiar secuncia del motor tiempo RES 1; contador del timer vueltas_seg RES 1; contador de vueltas GLOBAL velocidad, tiempo, vueltas_seg CODE 22 Interrupciones GLOBAL Interrupciones PUSH MOVWF W_TEMP ; Copia W en W_TEMP SWAPF STATUS, W ; Swap status y deja resultado en W MOVWF STATUS_TEMP ; Salva STATUS EN STATUS_TEMP register ISR BTFSS INTCON,1 ; Testeamos el bit 0 de PORTB goto TIMER ; Si es 0 interrupción por TMR0 goto LED ; si es 1 interrupción por RB0 POP SWAPF STATUS_TEMP, W; Recupera STATUS en W MOVWF STATUS ; Mueve W a STATUS SWAPF W_TEMP, F ; Recupera W SWAPF W_TEMP, W ; bcf INTCON,2 ; desabilito causa-interrupcion retfie ; Retornamos bcf PORTB,7 ; (Bit que muestra parpadeo/seg) incf tiempo,1 ; incrementamos tiempo incf velocidad,1 ; incrementamos velocidad TIMER goto POP LED ; Cada vez que llegamos aquí contamos 1 vuelta ; Cuando mostramos vueltas_seg hay que resetearla incf vueltas_seg,1 bcf INTCON,1 ; desabilito interrupción por RB0 goto POP ;Fin de rutinas de interrupciones End 23 Bibliografía http://www.todorobot.com.ar/informacion/tutorial%20stepper/stepper-tutorial.htm http://www.todorobot.com.ar/informacion/tutorial%20stepper/stepper-tutorial.htm http://es.wikipedia.org/wiki/Motor_paso_a_paso 24