# Manejo de un servomotor con PIC 16F887



## Emanuelbolmaro (Dic 10, 2010)

Hola! Soy nuevo en esto, busque informacion sobre el tema sin demasiado exito. Tengo problemas para manejar un servomotor con el modulo CCP2 del microcontrolador (PIC 16F887). Voy a utilizar un cristal de 20MHz. El lenguaje que debo utilizar es Assembler. Hasta ahora configure e inicie el modulo de la siguiente forma:

          BANKSEL       TRISA
          MOVLW         b´X1XXXXXX´ ; CONF. ENTRADA PIN MOD. CCP2
          MOVWF         TRISC
          MOVLW         0 x XX ; 1° DUDA: QUE VALOR PONER?
          MOVWF         PR2
          MOVLW         b´--XX1111´ 
          MOVWF         CCP2CON ; ELIJO MODO PWM
          BANKSEL        PIR1
          BCF              PIR1,1
          BSF              T2CON,1 ; 2° DUDA: QUE Ps USAR? COMO LO DETERMINO?
          BSF              T2CON,2 ; INICIO TEMPORIZADOR
AQUI
          BTFSS           PIR2,TMR2IF
          GOTO            AQUI; DESB. TIMER
          MOVLW         b´XXXXXX0X´
          MOVWF         TRISC


Lei en el foro que los servomotores funcionan a 50 Hz. 

Utilizando la ecuación:

periodoPWM=(PR2+1) x 4Tosc x Ps TMR2

y sabiendo que la frecuencia es igual a:

Frec= 1 / periodoPWM

Es imposible lograr 50 Hz, como manejo el servomotor?

Tampoco se como mover (en asm) el servomotor.

Desde ya muchas gracias!

Saludos!


----------



## Pablet (Dic 13, 2010)

hola!!! yo hace poco hice un pequeño proyecto dond emanejaba un servo, pero tuve que reducir la frecuencia de oscilacion bastante, o otra opción es hacer el pwm con temporizadores. De todas formas los pics de ahora pueden sintetizar diferentes frecuencias de reloj a partir de una sola, lee el datasheet  que ahi te viene los registros que tienes que modificar para bajar la frecuencia de oscilación hasta 1MHz o incluso 32KHz.

Un saludo


----------



## Emanuelbolmaro (Dic 14, 2010)

Hola Pablet! 

Ya lei la hoja de datos y sigo con mis dudas... Voy a volver a repasar el Datasheet para ver si puedo encontrar algo! 

Muchas gracias!!!

Un abrazo!


----------



## ByAxel (Dic 14, 2010)

Que tal:
Revisa un poco de teoría en http://picmania.garcia-cuervo.net/picc_servos_x_8.php.
Con un poco de búsqueda en el foro puedes encontrar cosas... el tema de pwm se a tocado varias veces.
Control de un servomotor con PIC16F84 ASM

saludos


----------



## BKVOT001 (May 19, 2011)

El alcance que puedo darte es que te sera imposible maniobrar bien tu servomotor si utilizas
el modulo PWM del pic16f877, puesto que para que tu servo funcione bien debe tener un periodo
como minimo de 10 ms, y con el moludo PWM del pic solo puedes tener un periodo como
maximo de 4.096 ms (PR2=11111111) max valor.

Lo que sucede cuando tienes un periodo de 4.096 ms, es que si bien tu servo busca la posicion correcta de acuerdo al duty cycle, lo que obtendras seran vibraciones aun cuando el servo haya
alcanzado la posicion deseada. Lo que te recomiendo es que hagas tu propio PWM, osea setea un bit por un tiempo determinado, puede ser entre (1 a 2 ms, estos tiempos son de acuedo al servo que tengas, algunos varian) y limpias el mismo bit por 8 o 9 ms, recuerda que la suma de los tiempos en prendido y apagado de tu bit deben sumar como minimo 10 ms.

aqui te paso un programa mio hecho en assembler, espero te sirva, pues a mi me funciono.

list    p=16f877
    __CONFIG _BODEN_OFF & _WDT_OFF & _PWRTE_ON & _LVP_OFF & _XT_OSC
include  <p16f877.inc>

org   0x00

El alcance que puedo darte es que te sera imposible maniobrar bien tu servomotor si utilizas
el modulo PWM del pic16f877, puesto que para que tu servo funcione bien debe tener un periodo
como minimo de 10 ms, y con el moludo PWM del pic solo puedes tener un periodo como
maximo de 4.096 ms (PR2=11111111) max valor.

Lo que sucede cuando tienes un periodo de 4.096 ms, es que si bien tu servo busca la posicion correcta de acuerdo al duty cycle, lo que obtendras seran vibraciones aun cuando el servo haya
alcanzado la posicion deseada. Lo que te recomiendo es que hagas tu propio PWM, osea setea un bit por un tiempo determinado, puede ser entre (1 a 2 ms, estos tiempos son de acuedo al servo que tengas, algunos varian) y limpias el mismo bit por 8 o 9 ms, recuerda que la suma de los tiempos en prendido y apagado de tu bit deben sumar como minimo 10 ms.

aqui te paso un programa mio hecho en assembler, espero te sirva, pues a mi me funciono.

list    p=16f877
    __CONFIG _BODEN_OFF & _WDT_OFF & _PWRTE_ON & _LVP_OFF & _XT_OSC
include  <p16f877.inc>

PDel0          equ        0x20
PDel1          equ        0x21          ;declaracion de variables empleadas en PicDel

org   0x00

                 bcf         status,7   ;me mantiene entre los banco 0 y 1
                 bcf         status,6  
                 bsf         status,5   ;banco 1
                 movlw     b'11111110'
                 movwf    trisc         ;configuro al bit 0 del puerto c como salida
                 bcf         status,5   ;banco 0

;*****rutina de PWM*****

rutpwm       bsf         portc,0      ;seteo el bit 0 del puerto c
                 call         retardo      ;llamo a la subrutina de retardo, dura 1 ms
                 bcf         portc,0      ;limpio el bit 0 del puerto c
                 call         retardo      ;llamo a la subrutina de retardo, dura 1 ms
                   .
                   .
                   .
                ;llamar 9 veces a la subrutina "retardo" despues de limpiar el bit 0 del puerto c
                   .
                goto        rutpwm

la rutina de "retardo" te recomiendo que la obtengas por medio del programa PicDel, es pequeño y puedes descargarlo gratis y facilmente de google, aqui te paso el link http://www.ziddu.com/download/5654504/PICDEL.EXE.html/eng    es facil de utilizar y los retardos que obtienes son precisos, no te olvides de declarar las variables que te manda. no olvides de colocar END depues del RETURN de la subrutina retardo. el programa empleado es el
MPLAB.IDE v7.20, la señal de control de tu servo la conectas al pin 0 del puerto c del pic.

Espero mi aporte te haya sido de ayuda. Saludos


----------



## reypic (Feb 1, 2014)

Hola buenas noches, recientemente he estado aprendiendo a programar PIC´s en ensamblador, tengo un problema en un programa que hice para controlar un servo, el hardware consta solo de un pulsador de entrada y la salida con el PWM conectada al servo, al presionar el botón la posición del servo debe de incrementarse desde su posición cero hasta sus 180° y si se sigue presionando va de regreso de 180° hasta su posición cero. 
Hasta el momento tengo el siguiente programa, lo he simulado en MPLAB y por lo que puedo ver ya funciona como debería, al simular en proteus no funciona del todo bien, pues me aparecen pequeños pulsos cuando presiono el pulsador, ahora cuando lo arme en físico no funciona nada bien solo mueve el servo desde cero a 90° y se estanca en esa posición. 

El tiempo de la señal es de 20ms, para el servo tiempo en alto: 600us ---> 0°, 1500us ---> 90°, 2400us--->180° 

También cabe destacar que es la primera vez que trabajo con un servomotor y no se si sea de importancia pero los retardos los hice con picloops.

Disculpen si no lo hice de una forma más sencilla o con otras instrucciones, pero como dije anteriormente apenas estoy aprendiendo ensamblador y realicé el programa con lo poco que he aprendido.

Espero que alguien pueda ayudarme y gracias de antemano.


```
INCLUDE <P16F887.INC>
 LIST P=16F887
 __CONFIG _CONFIG1 , _INTRC_OSC_NOCLKOUT & _WDT_OFF & _MCLRE_OFF & _PWRTE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF
 CBLOCK  0X21
		CA,CB,CA1,CB1,CA2,CB2,SENTIDO,INDICE
		ENDC
			ORG 0X00
			CLRF SENTIDO
			CLRF INDICE
			BANKSEL TRISA
			MOVLW 0XF0
			MOVWF TRISD
			MOVLW 0X0F	
			MOVWF TRISB
			BANKSEL PORTD
			MOVLW 0X00
			MOVWF PORTD
			;MOVWF PORTB

MAIN		BSF PORTD,0
			MOVF CA1,W
			MOVWF CA
			MOVF CB1,W
			MOVWF CB
			CALL DELAY
			BCF PORTD,0
			MOVF CB2,W
			MOVWF CB
			MOVF CA2,W
			MOVWF CA
			CALL DELAY
			GOTO MAIN

DELAY		NOP
LOOP		BTFSC PORTD,7
			GOTO SIGUE
			DECFSZ CA
			GOTO LOOP
			DECFSZ CB
			GOTO LOOP
			RETURN



SIGUE 		MOVLW 0X09
			SUBWF INDICE,W
			BTFSS STATUS,Z
			GOTO SIGUE2
			MOVLW 0X01
			MOVWF SENTIDO
SIGUE2		MOVLW 0X00
			SUBWF SENTIDO,W
			BTFSS STATUS,Z  
			GOTO SIGUE3
			INCF INDICE
			GOTO SIGUE4
SIGUE3		;MOVLW 0X01
			;DECF INDICE
			MOVLW 0X00
			SUBWF INDICE,W
			BTFSS STATUS,Z
			GOTO DECRM   ;DECF INDICE
			CLRF SENTIDO
			RETURN
						
DECRM		DECF INDICE		

SIGUE4		CALL T1
			MOVWF CB1
			CALL T2
			MOVWF CA1
			CALL T3
			MOVWF CB2
			CALL T4
			MOVWF CA2
			RETURN
			
T1			MOVF INDICE,W
			ADDWF PCL
			RETLW D'2'
			RETLW D'3'
			RETLW D'3'
			RETLW D'4'
			RETLW D'4'
			RETLW D'5'
			RETLW D'5'
			RETLW D'6'
			RETLW D'6'
			RETLW D'7'

T2			MOVF INDICE,W
			ADDWF PCL
			RETLW D'141'
			RETLW D'17'
			RETLW D'151'
			RETLW D'27'
			RETLW D'161'
			RETLW D'37'
			RETLW D'171'
			RETLW D'47'
			RETLW D'181'
			RETLW D'57'

T3			MOVF INDICE,W
			ADDWF PCL
			RETLW D'51'
			RETLW D'50'
			RETLW D'50'
			RETLW D'49'
			RETLW D'49'
			RETLW D'48'
			RETLW D'48'
			RETLW D'47'
			RETLW D'47'
			RETLW D'46'

T4			MOVF INDICE,W
			ADDWF PCL
			RETLW D'98'
			RETLW D'221'
			RETLW D'87'
			RETLW D'211'
			RETLW D'77'
			RETLW D'201'
			RETLW D'68'
			RETLW D'191'
			RETLW D'57'
			RETLW D'181'
			END
```


----------



## BrunoARG (Feb 4, 2014)

Hola. Perdón si me equivoco, pero no es poco 50Hz para un motor? Una frecuencia más alta, como de 300Hz te iría bien, así el movimiento sería más fluido.

Con un pulso largo es poco preciso mover un motor; si cambia la temperatura o algo, se puede mover más o menos. Te recomiendo usar PWM a un duty alto al principio, y uno bajo al final, así el motor se mueve más despacio al final, y cuando frena casi no tiene inercia. Resulta en mejor precisión.

Respecto a ASM no sé nada, en eso no te puedo ayudar. Saludos.


----------

