# Control de un servomotor con PIC16F84 ASM



## jorger53 (May 4, 2009)

Bueno les comento que hice este pequeño programa en ASM, como verán es muy sencillo y es mediante Timer (servos Hitec), haber si a alguien le sirve y segundo para ver si me resuelven los mas entendidos unas dudas.

Si alguien me puede comentar alguna forma de hacer lo mismo pero para dos servomotores al mismo tiempo, se 
lo agradecería, ya que se me vienen formas un poco complicadas a la cabeza. Mi otra duda es si es posible controlar un servomotor con los modulos CCP que tienen algunos PIC, yo estuve leyendo y por ahí decían que no se puede porque no tienen tanta resolución y la verdad es que al menos yo no pude hacerlo.


```
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC

	LIST 			P=16F84A
	INCLUDE		<P16F84A.INC>

	#DEFINE	CHECAR	PORTA,2
	CBLOCK	0x0C
Contador1
Contador2
Contador3
	ENDC
	
	ORG 0

ORALE
	bsf			STATUS,RP0
	movlw		b'00011111'
	movwf		TRISA
	clrf			TRISB
	bcf			STATUS,RP0
	CLRF		PORTB

INICIO
	btfss	CHECAR
	goto	ADELANTE

ATRAS
	movlw	b'11111111'
	movwf	PORTB
	call		timer_900
	clrf		PORTB
timer_19.1ms
	movlw 	d'191'
	movwf	Contador1
Pedir_19.1ms
	decfsz	Contador1,F
	goto	llamar
	goto 	INICIO
llamar
	call		timer_100
	goto	Pedir_19.1ms

ADELANTE
	movlw	b'11111111'
	movwf	PORTB
timer_2.1ms
	movlw 	d'21'
	movwf	Contador2
Pedir_2.1ms
	decfsz	Contador2,F
	goto	llamar2
	goto 	timer_17.9ms
llamar2
	call		timer_100
	goto	Pedir_2.1ms

timer_17.9ms
	clrf		PORTB
	movlw 	d'179'
	movwf	Contador3
Pedir_17.9ms
	decfsz	Contador3,F
	goto	llamar3
	goto 	INICIO
llamar3
	call		timer_100
	goto	Pedir_17.9ms

carga_900	EQU	-d'225'
timer_900
	bsf		STATUS,RP0
	movlw	b'00000001'
	movwf	OPTION_REG
	bcf		STATUS,RP0
	movlw	carga_900
	movwf	TMR0
	bcf		INTCON,T0IF
rebasamiento1
	btfss		INTCON,T0IF
	goto	rebasamiento1
	return

carga_100	EQU	-d'50'
timer_100
	bsf		STATUS,RP0
	movlw	b'00000000'
	movwf	OPTION_REG
	bcf		STATUS,RP0
	movlw	carga_100
	movwf	TMR0
	bcf		INTCON,T0IF
rebasamiento2
	btfss	INTCON,T0IF
	goto	rebasamiento2
	return
	
	END
```

Saludos.


----------



## karl (May 26, 2009)

ok, tu programa funciona.

En cuanto al control de varios motores, yo usaria la interrupción del timer, cada que se interrumpe el timer descuenta una unidad a los registros de los motores, y cuando llegan al valor de 0 permanecen así hasta que se "resetee" un registro grande que sirve como base de tiempo, el timer (TMR 0 en el 16f627/8 compatibles en pines con tu 16f84), puede preescalarse y modificar su valor hasta que tengas el tiempo minimo de pulso de tus servos (algo asi como el dead band width entre dos por ejemplo), de tal forma que puedas prender y apagar las lineas de control con pulsos codificados.


----------



## jorger53 (Ago 7, 2009)

Bueno amigos, hace tiempo pregunté como controlar multiples servos con éste pic, pues el caso es que hace un rato que lo conseguí en ASM, utilizando por supuesto el TMR0 y las interrupciones, aquí les publico el codigo fuente, por si a alguien le sirve, si observan bie hay partes que son especificas para mi aplicación, el programa debe de funcionar bien para varios servomotores, pero yo solo lo usé para dos, un servo puede moverse a una direccion y el otro al contrario al mismo tiempo.


```
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC

	LIST		P=16F84A
	INCLUDE 	<P16F84A.INC>
	
	ERRORLEVEL	1;-302	;EVITAR ERRORES DE CAMBIO DE BANCO

	#DEFINE	SERVO1 	PORTB,6
	#DEFINE	SERVO2	PORTB,7

	CBLOCK	0x0C
YEAH
FASE
Guardar_W
Guardar_STATUS
SERVOS
	ENDC
	
	ORG 	0x000
	goto	ORALE
	ORG	0x004
	goto	Interrupcion

ORALE
	bsf			STATUS,RP0
	movlw		b'00011111'			;TRISA como entrada
	movwf		TRISA
	clrf			TRISB				;TRISB como salida
	bcf			STATUS,RP0
	bcf			STATUS,RP1
	clrf			PORTB  
	movlw		b'10100000'
	movwf		INTCON   			;Habilitar interrupciones generales
	clrf			PORTB
	clrf			FASE
INICIO
	movf	FASE,f			;Revisa en que fase del programa se encuentra
	bz		SIGUE			;si no es en la fase 0 se hace un bucle infinito
	btfss	PORTB,0		;Salta si es uno, interruptor pala abajo
	goto	VAMOS
	bsf		PORTB,3
	bcf		PORTB,4
VAMOS
	movf	PORTA,0		;-------------------------------------------------------
	xorlw	b'00001111'
	andlw	b'00001100'
	xorlw	d'12'
	bz		subir
	movf	PORTA,1 
	xorlw	b'00001111'
	andlw	b'00000011'	
	xorlw	d'3'
	bz		bajar
	goto	INICIO

subir
	bsf		PORTB,2
	bcf		PORTB,3
esperar
	btfss	PORTB,0		;Salta si es uno
	goto	esperar
	call 		parar
	goto	INICIO
	
bajar
	bcf		PORTB,2
	bsf		PORTB,3
	btfss	PORTB,1		;Salta si es uno, interruptor pala abajo
	goto	bajar
	goto	activar.brocha
	
	
activar.brocha
	bcf		PORTB,2
	bsf		PORTB,3
	bcf		PORTB,4
	goto	INICIO

parar
	bcf		PORTB,2
	bcf		PORTB,3
	return

SIGUE						;-----------------------------------------------------------------------------
	movf	PORTA,0		;El contenido del puerto A se pasa a W
	xorlw	b'00001111'		;Invertimos el valor de las entradas ya que el receptor de control remoto trabajo en bajo
	andlw	b'00001111'		;Se enmascara el valor obtenido
	call 		tablaVERDAD	;Se llama a la tabla para obtener el tiempo de cada servo
	movwf	SERVOS		;
	bsf		SERVO1
	bsf		SERVO2

timer_900
	bsf		STATUS,RP0	;Se cambia al banco 1
	movlw	b'00000001'		;Se modifica el preescaler
	movwf	OPTION_REG	;a 1:4 del TMR0
	bcf		STATUS,RP0	;Se regresa al banco 0
	bcf		STATUS,RP1
	movlw	d'40'			;Se carga 31 en TMR0
	movwf	TMR0			;para obtener un tiempo de 900us aprox.
	bcf		INTCON,T0IF	;Reseteamos el bit de desbordamiento del timer
	movlw	b'00000001'		;El programa pasa a la fase 1
	movwf	FASE
	goto	INICIO


Interrupcion
	bcf		INTCON,T0IE		;Deshabilitamos interrupciones
	movwf	Guardar_W
	swapf	STATUS,W
	movwf	Guardar_STATUS

Distribuidor

	movf	FASE,W	;La interrupcion revisa en que fase del programa está
	xorlw	0x01
	bz		FASE1
	movf	FASE,W
	xorlw	0x02
	bz		FASE2
	movf	FASE,W
	xorlw	0x03
	bz		FASE3
	movf	FASE,W
	xorlw	0x04
	bz		FASE4

FASE1
	movlw	0x02
	movwf	FASE
	movf	SERVOS,0		;Primero se revisa el servo1
	andlw	b'00111000'		;Enmascaramos para revisar solo el servo1
	xorlw	b'00010000'		;Se invierte W para saber si hay un 1 en el bit que indica 
	bz		servo1.limpiar	;que el servo1 requiere un tiempo de 900us
	goto	continua1

servo1.limpiar
	bcf		SERVO1

continua1
	movf	SERVOS,0		;Primero se revisa el servo1
	andlw	b'00000111'		;Enmascaramos para revisar solo el servo1
	xorlw	b'00000010'		;Se invierte W para saber si hay un 1 en el bit que indica 
	bz		servo2.limpiar1	;que el servo1 requiere un tiempo de 900us
	goto	continua2

servo2.limpiar1
	bcf		SERVO2
	
continua2
	bsf		STATUS,RP0	;Configuramos todo para detenernos en 1.5ms
	movlw	   b'00000001'		;Seleccionamos preescaler de 1:4 para  TMR0
	movwf	      OPTION_REG
	bcf		STATUS,RP0
	bcf		STATUS,RP1
	movlw	d'106'			;Con 106 en TMR0 obtenemos 600us que es lo que restamos
	movwf	TMR0			;para lograr los1.5ms deseados
	goto	salir


FASE2
	movlw	0x03
	movwf	FASE
	movf	SERVOS,0		;Primero se revisa el servo1
	andlw	b'00111000'		;Enmascaramos para revisar solo el servo1
	xorlw	b'00001000'		;Se invierte W para saber si hay un 1 en el bit que indica 
	bz		servo1.limpiar2	;que el servo1 requiere un tiempo de 1500us
	goto	continuacion

servo1.limpiar2
	bcf		SERVO1

continuacion
	movf	SERVOS,0		;Primero se revisa el servo1
	andlw	b'00000111'		;Enmascaramos para revisar solo el servo1
	xorlw	b'00000001'		;Se invierte W para saber si hay un 1 en el bit que indica 
	bz		servo2.limpia2	;que el servo1 requiere un tiempo de 1500us
	goto	continuar

servo2.limpia2
	bcf		SERVO2
	
continuar
	bsf		STATUS,RP0	;Configuramos todo para detenernos en 2.1ms
	movlw	b'00000001'		;Seleccionamos preescaler de 1:4 para TMR0
	movwf	OPTION_REG
	bcf		STATUS,RP0
	bcf		STATUS,RP1
	movlw	d'108'			;Con 106 en TMR0 obtenemos 600us que es lo que restamos
	movwf	TMR0			;para lograr los 2.1ms deseados
	goto	salir

FASE3
	movlw	0x04
	movwf	FASE
	movf	SERVOS,0		;Primero se revisa el servo1
	andlw	b'00111000'		;Enmascaramos para revisar solo el servo1
	xorlw	b'00100000'		;Se invierte W para saber si hay un 1 en el bit                 que indica 
	bz		servo1.limpiar3	;
	goto	continue

servo1.limpiar3
	bcf		SERVO1

continue
	movf	SERVOS,0		;Primero se revisa el servo1
	andlw	b'00000111'		;Enmascaramos para revisar solo el servo1
	xorlw	b'00000100'		;Se invierte W para saber si hay un 1 en el bit que indica 
	bz		servo2.limpia3	;
	goto	continueNOW

servo2.limpia3
	bcf		SERVO2
	
continueNOW
	bsf		STATUS,RP0	;Configuramos todo para detenernos en 20ms para obtener un periodo
	movlw	b'00000111'		;Seleccionamos preescaler de 1:256 para TMR0
	movwf	OPTION_REG
	bcf		STATUS,RP0
	bcf		STATUS,RP1
	movlw	d'190'				;Con 190 en TMR0 obtenemos 17,900us que es lo que restamos
	movwf	TMR0			;para lograr los 20ms deseados
	goto	salir

FASE4
	clrf		FASE;			;Se ha conseguido un periodo por lo que regresamos a la fase1
	
salir
	bcf		INTCON,T0IF			;Se limpia el flag de desbordamiento de TMR0
	swapf	Guardar_STATUS, W
	movwf	STATUS	
	swapf	Guardar_W, f
	swapf	Guardar_W, w
	bsf		INTCON,T0IE			;Se reactiva interrupcion por TMR0
	retfie

tablaVERDAD
		addwf PCL,F				
 TABLA	retlw	b'00001001'		
		retlw 	b'00100100'			
	retlw	b'00010010'			         
		retlw	b'00001001'			;0011 
		retlw	b'00010100'			;
		retlw	b'00010001'			;
		retlw	b'00001100'			;0110 
		retlw	b'00001001'			;0111
		retlw	b'00010010'			;1000 
		retlw 	b'10100001'			;1001 
		retlw	b'00001010'			;1010 
		retlw	b'00001001'			;1011
		retlw	b'00001001'			;1100
		retlw	b'00001001'			;1101
		retlw	b'00001001'			;1110
		retlw	b'00001001'			;1111

	END
```


----------



## DJ DRACO (Nov 15, 2009)

Bueno gente, recién empiezo en el tema microcontroladores, y mi primer programita funciono bien de primera...
...el problema es que quiero hacer un 2do o 3er programita donde debo manejar 2 servomotores con un PIC16F84A y la verdad es que no sé como se hace para generar el PWM con las instrucciones en assembler.

si alguien tira una soguita la agarro con todo gusto.

saludos.


----------



## shadow_x (Abr 26, 2010)

Saludos; necesito un poco de ayuda en algo; quiero controlar 6 servomotores (4 hitec 311, 1 VS05, y 1 VS11); estoy usando el pic18f4585 y para programar estoy usando MPLAB C18.

Hay 8 posisciones para los 6 servos; las oredenes de la posicion llegaran por usart.

Intente por algo simple en pic16f84A:

    Usando la Interrupcion por PuertoB <3:0>  cambiaba el valor de la posicion de cada servo con un registro entre 0 y 180 y usando eso para subrutinas de 10us (10us+600ms=1º). y actualizo la posicion cada 50ms (por desborde de tmr0).

  Pase la misma logica al pic18 pero no me resulto.


----------



## lammont69 (Nov 9, 2011)

hola amigos, hice uno, aunque de manera arcaica para controlar 6 servos. Al activarse un switche, realiza una rutina, y cuando el primer servo que esta en el puerto b del 16f877 se debe desactivar el switche para que la rutina funcione. el programa es muy basico aunque largo. con puros bsf y bcf. por eso que el tiempo en bajo no es muy exacto. saludos.


----------



## daniel28 (Oct 5, 2012)

bueno estoy intentando mover 2 servomotores con un pic 16f84a en mplab para que giren continuamente .... les explico mi proyecto es que si el sensor no esta activado uno de los motores gire 360 grados indefinidamente hasta que el sensor se prenda y ya se activen los dos motores y siga los objetos ... esto es lo que llevo pero hasta el momento no me ha funcionado espero sus consejos


```
LISTP=16F84A
PCL               EQU    0X02
STATUS       EQU    0X03
PORTA     EQU    0X05
TRISA     EQU    0X85
PORTB     EQU    0X06
TRISB     EQU    0X86
RETARDO1      EQU 0X10
RETARDO2    EQU 0X11
    
    ORG    00
    BSF STATUS,5
          MOVLW  B'11111111'
          MOVWF TRISA
          MOVLW B'00000000'
          MOVWF TRISB
          BCF STATUS,5

UNO    movlw    b'00000001'
    movwf    PORTB
    CALL RETARDO
    CLRF PORTB
    CALL RETARDO
    movlw    b'00000001'
    movwf    PORTB
    CALL    RETARDO
    CLRF    PORTB
    CALL     RETARDO
    btfss    PORTA,0
    GOTO    UNO
PATI movlw    b'00000011'
    movwf    PORTB
    CALL RETARDOdos
    CLRF PORTB
    CALL RETARDOdos
    movlw    b'00000011'
    movwf    PORTB
    CALL    RETARDOdos
    CLRF    PORTB
    CALL     RETARDOdos
    btfss   PORTA,1
    GOTO UNO        
    GOTO PATI    
        
RETARDO MOVLW .200
    MOVWF    RETARDO1
DOS    DECFSZ    RETARDO1
    GOTO        DOS
    RETURN
    
            
RETARDOdos MOVLW .200
    MOVWF    RETARDO1
    tres    DECFSZ    RETARDO1
    GOTO        tres
    RETURN
    END
```


----------

