En esta entrada entenderemos como podemos controlar un Servomotor con PIC usando el compilador CCS C Compiler. Vamos a emplear un PIC 16F887, pero puedes usarlo también con un PIC 16F877A, 18F4550 o cualquier otro microcontrolador que tu desees usar. Los códigos aqui son adpatables a cualquier PIC.
Antes que nada, si todavia no has visto todo el curso gratuito de microcontroladores PIC desde cero usando lenguaje C, te invito a que le des un vistazo y te vuelvas un experto: 👉 CURSO DE PIC GRATIS
Y que te suscribas al canal de YouTube para seguir aprendiendo más sobre microcontroladores:
🤔 ¿Que es un Servomotor?
Un servomotor es básicamente un motor con su propio controlador interno, esto quiere decir que su giro va a ser proporcional a un comando de entrada, en lugar de estar girando continuamente como un motor convencional.
Como conectar un Servomotor
Un servomotor se compone de tres cables que son GND, Power (5v) y Control.
La siguiente ilustración muestra como conectar un servomotor:
La conexión del servomotor ya nos da una idea de como va a trabajar este componente electromecánico.
Como funciona el Servomotor
Para que el servomotor funcione, deben enviarse una secuencia de pulsos (PWM) por el cable de control, de esa forma el servomotor verifica su posición actual y actúa para ir hacia la posición deseada.
Para poder entender bien el concepto del funcionamiento de un servomotor, debemos dejar claro que este no se comporta como un motor cualquiera, como ya lo mencionamos antes, o sea que no va a girar libremente simplemente energizandolo, si no que por el contrario al ser un motor que tiene su propio controlador (PID) interno, el trabaja por referencias, y esta referencia es en Grados, lo que quiere decir que yo debo informarle si deseo que se vaya para 0°, o para 25°, 48°,100°, 180°, etc.
Entonces el cable de Control, es usado especificamente para eso, para informarle al motor a cual ángulo yo deseo que él se vaya.
Pero ¿Como le envío los ángulos al motor por medio de una secuencia de pulsos (PWM Servomotor)?
🎳 Control de Giro de un Servomotor 180 con PIC
El servomotor procesará la señal de pulso (PWM) y dependiendo del ancho del pulso, él sabrá cual es el angulo que estamos pidiéndole.
Generalmente un Servomotor procesa un pulso con un periodo de 20ms y valiendonos del datasheet del servomotor podremos saber cuanto es el ancho de pulso que necesitamos colocarle a la señal pwm para que el servomotor recorra la distancia deseada.
Un pulso de 1.5 ms, por ejemplo, va hacer con que el motor se detenga en la posición de 90 grados. Si el pulso es menor que 1.5 ms, hará que el motor se detenga lo mas cerca posible de los 0° y si el pulso tiene una anchura mayor que 1.5 ms, el eje del servomotor girará lo mas cerca posible a 180 grados, tal y como lo podemos apreciar en la siguiente figura:
Nota que cada periodo, (cuando el pulso se vuelve positivo) ocurre a cada 20ms.
Teniendo un poco más claro el funcionamiento del servomotor, procederemos a controlar servos con PIC y el compilador CCS C.
Para este proyecto, vamos a usar el siguiente servomotor:
- el servomotor MG996R de (120 grados, torque de 10Kg) Datasheet
Pero puede ser empleado cualquier otro servomotor como el MG995, SG90, etc.
Servomotor via PWM con PIC -modulo CCP
Como podemos apreciar en los datasheet de los servomotores, la frecuencia de un servomotor típicamente es de 50Hz.
Una de las formas de controlar un servomotor es configurando el PWM del PIC usando el modulo CCP, para usar el control de servomotor con pic 16F887 vamos a tener que configurar el PWM a esa frecuencia.
Oscilador Interno con PIC CCS
Como es una baja frecuencia vamos a tener que configurar el oscilador interno del PIC, para eso simplemente basta con configurar el #FUSE y usar la función de configuración del oscilador interno del PIC CCS
#fuses INTRC_IO #use delay(clock=500000) void main() { setup_oscillator(OSC_500KHZ|OSC_INTRC); //Cristal interno de 500KHz }
El oscilador interno del PIC 16F887 al igual que el PIC16F877A o el 18F4550 puede ser configurado con frecuencias desde 8MHz hasta 32KHz, para eso solo basta configurar en la directiva de la función setup_oscillator como:
- OSC_8MHZ
- OSC_4MHZ
- OSC_2MHZ
- OSC_1MHZ
- OSC_500KHZ
- OSC_250KHZ
- OSC_125KHZ
- OSC_32KHZ
Para otros microcontroladores PIC, debes ver en el datasheet si soporta estas mismas frecuencias, simplemente abres el datasheet y buscas por el registro “OSCCON”
Configuración del PWM para el servomotor
Vamos a obtener los 50Hz con el PWM, para eso vamos a configurar el oscilador interno a 500Khz y hacer los calculos del PWM que fueron explicados detalladamente en la entrada PWM con PIC CCSC.
El periodo (Inverso de la frecuencia) f=50Hz.
T_{PWM}=\dfrac{1}{50Hz}=0.02s
T_{Osc}=\dfrac{1}{500000Hz}=2\mu s
Desbordamiento del TIMER 2 (PR2) con preescaler de 16 y poscaler de 1:
T_{PWM}=(PR2+1)\cdot 4 \cdot(Preescaler) \cdot T_{Osc} \cdot Postcaler
PR2 =\dfrac{T_{PWM}}{4(Preescaler)T_{Osc}} - 1
PR2 =\dfrac{0.02}{4*16*0.000002} - 1=155
El valor de carga del Timer2 es PR2=155
El Timer 2 quedaría así:
setup_timer_2(T2_DIV_BY_16,155,1);
Ahora solo nos falta determinar el valor de resolución para saber cuanto es lo máximo que podremos variar el ancho de pulso, aplicando la formula de resolución tenemos:
n=\dfrac{log\left (\dfrac{500000}{50*16} \right )}{log(2)}=9.28
Así, el máximo ancho de pulso lo voy a obtener colocando la variable valor:
valor=2^{9.28}=625
Con esto sabemos que si colocamos 625 en el duty cicle, vamos a tener el PWM completamente en alto. Ahora bién como nosotros solo queremos inyectar máximo 2ms para hacer que el motor vaya a 180° y mínimo 1 ms para que el motor vaya a 0°, nuestro duty cilce haciendo una regla de tres simple sabiendo que 625 equivalen a 20ms, va a estar en el rango aproximado de
30\leq Duty\ Cicle\leq 63
Sin embargo cada Servomotor es fabricado de forma diferente y la configuración interna del controlador puede variar, asi que en la práctica se debe verificar si dichos valores de frecuencia realmente llevan el servomotor de 0°a 180°.
Por ejemplo, en mi caso para conseguir este barrido completo debo aumentar los limites del ancho del PWM en:
20\leq Duty\ Cicle\leq 80
Servomotor PIC C Compiler usando interrupción por TIMER
En este caso podremos controlar un mayor número de servomotores con un pic 16F877A, 18F4550, 16F84A, 16F887 o cualquier otro PIC configurando para que la interrupción por TIMER, salte a cada 20ms, por lo tanto aquí podremos utilizar normalmente nuestro cristal de cuarzo.
Vamos a realizar los calculos para que nuestro Timer 0, Recordemos que ya habíamos visto una entrada con las configuraciones del Timer 0 (Timer 0 con PIC C Compiler).
Sabemos que el servomotor necesita unos pulsos cada 20ms, sin embargo este valor no es totalmente extricto, como en este proyecto vamos a trabajar con un cristal de 4Mhz, vamos a configurar nuestro Timer 0 para que se desborde aproximadamente cada 16.38ms
Para eso vamos a tomar un preescaler de 64, y sabiendo que el Timer 0 se desborda cuando llega a la carga de 256 pues vamos a conseguir el tiempo que queríamos:
DesbordeT=CargaTimer\cdot preescaler\cdot \dfrac{4}{F.Oscilador}=256\cdot 64\cdot \dfrac{4}{4000000}=0.01638s=16.38ms
Perfecto! con esto el PIC saltará a la interrupción del Timer 0 cada 16.38ms cuando cuente de 0 a 256. ¿Pero como vamos a mandar los pulsos de 1ms y 2ms? Pues hacemos una regla de 3 simple.
Valor mínimo:
x=\dfrac{256\cdot 1ms}{16.38ms }=15.62\approx 16
Valor máximo:
x=\dfrac{256\cdot 2ms}{16.38ms }=31.25\approx 32
Ahora dentro de la rutina de interrupción, modificaremos la carga del Timer 0 y colocaremos en alto o en bajo la salida del PIC donde esté conectado el servomotor.
Por ejemplo, si queremos el servomotor en 180° (2ms) sabemos que:
- Pregunto si la salida está en alto o bajo
- Si esta en alto, cargo el timer0 con 32 y pongo la salida en bajo, de esa forma al timer0 solo tendra que contar desde 32 hasta 256, es decir 224 para volverse a desbordar.
- Si esta en bajo, cargo el timer0 con (255-32) y pongo la salida en alto, de esa forma al timer0 solo tendra que contar desde 223 hasta 256, es decir 32 para volverse a desbordar.
La ventaja de usar el timer 0 es que podremos usar el control de varios servomotores con nuestro PIC
Ejemplo de Control de Servomotor con PIC
Vamos a implementar el siguiente circuito con nuestro PIC, donde vamos a controlar 2 servomotores de 180° con 3 pulsadores. Los pulsadores tienen la siguiente función:
- incrementa los angulos del motor
- decrementa los angulos del motor
- selecciona el motor a controlar
El código será implementado de las dos formas:
- Controlando los Servomotores con PWM (Oscilador Interno)
- Controlando los Servomotores con Timer 0 (Cristal de 4MHz)
El siguiente esquema muestra como realizar el control del servo via pwm en el proteus, que será el mismo esquema para el control de servomotores en proteus via timer 0.
Es importante que verifiques el voltaje de alimentación de tu servomotor, ya que puedes tener un servomotor de 5v o un servomotor de 12v.
Asegurate de tener una buena fuente de voltaje si el servomotor va a manejar alguna carga.
Descargar Código
A continuación te dejo el código para que lo descargues junto con los archivos del Proteus 8.
Recuerda compartir este contenido en tus redes sociales para ayudar a más personas con este tema y permitir que este sitio web siga aportando más contenido de calidad.
Descarga de Archivos
>> Codigos Servomotor con PIC C Compiler <<
Servomotor PWM: CCP con PIC C Compiler
// ServoMotor Usando PWM con modulo CCP (Oscilador Interno a 500KHz) // Por: Sergio Andres Castaño // https://controlautomaticoeducacion.com/ //___________________________________________________________________________ #include <16f887.h> //#include <18f4550.h> #device ADC=10 #FUSES NOWDT //No Watch Dog Timer #FUSES NOBROWNOUT //No brownout reset #FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O #use delay(internal=500000) #byte porta=5 //Dirección de los puertos para PIC 18F //#byte porta = 0xf80 // Identificador para el puerto A. #define plus porta,0 #define minus porta,1 #define change porta,2 int16 ang1,ang2; int i,servo=1; void main() { //20 y 80 int lmin=30,lmax=65; //Configura el PWM a 500Khz setup_timer_2(t2_div_by_16,155,1); //Configuracion de Timer 2 para establecer frec. PWM a 1kHz setup_ccp1(ccp_pwm); //Configurar modulo CCP1 en modo PWM setup_ccp2(ccp_pwm); set_tris_a(0x07); //Define los angulos con el valor mínimo ang1=lmin; ang2=lmin; while(1) { //Pregunta si se desea controlar el otro servo if(bit_test(change)){ delay_ms(200); //Anti-Rebote while(bit_test(change)) //Espera hasta dejar de presionar el botón {} //Si servo es 1 pongalo en 2, si es 2 pongalo 1 servo= (servo==1) ? 2 : 1; } //Pregunta por el botón de angulo positivo if(bit_test(plus)){ delay_ms(200); if(servo==1) ang1++; //Aumenta el angulo en el servo 1 else ang2++; //Aumenta el angulo en el servo 2 } //Pregunta por el botón de angulo negativo if(bit_test(minus)){ delay_ms(200); if(servo==1) ang1--; //Decrementa el angulo en el servo 1 else ang2--; //Decrementa el angulo en el servo 2 } //Valida que los angulos estén en el PWM de lmin hasta lmax ang1= (ang1<lmin) ? lmin : ang1; ang1= (ang1>lmax) ? lmax : ang1; ang2= (ang2<lmin) ? lmin : ang2; ang2= (ang2>lmax) ? lmax : ang2; //Configura el PWM set_pwm1_duty((int16)ang1); set_pwm2_duty((int16)ang2); } }
Servomotor usando TIMER 0 con PIC C Compiler
// ServoMotor Usando Timer 0 // Por: Sergio Andres Castaño Giraldo // https://controlautomaticoeducacion.com/ //___________________________________________________________________________ #include <16F887.h> //#include <18F4550.h> #device ADC=8 #fuses XT,NOPROTECT,NOWDT,NOBROWNOUT,PUT,NOLVP #use delay(clock=4000000) //Dirección de los puertos para PIC 16F #byte porta=5 #byte portc=7 //Dirección de los puertos para PIC 18F //#byte porta = 0xf80 // Identificador para el puerto A. //#byte portc = 0xf82 // Identificador para el puerto C. #define plus porta,0 #define minus porta,1 #define change porta,2 #define servo2 portc,1 #define servo1 portc,2 unsigned char ang1,ang2,cont=1; int i,servo=1; //Rutina de interrupción por RTCC (TIMER) #INT_RTCC void pulse() { switch(servo){ case 1: if(bit_test(servo1)) //La salida del servo 1 está en alto? { set_rtcc(ang1); bit_clear(servo1); } else { set_rtcc(255-ang1); bit_set(servo1); } break; case 2: if(bit_test(servo2)) //La salida del servo 1 está en alto? { set_rtcc(ang2); bit_clear(servo2); } else { set_rtcc(255-ang2); bit_set(servo2); } break; } } void main() { //6 y 36 int lmin=14,lmax=32; //Limites max y min en 100us set_tris_a(0x07); //Define RA0, RA1, RA2 como entradas set_tris_c(0); //Define puerto C como salida portc=0; //SET_RTCC(246); //Cargo valor inicial del timer para ejecutarse cada 100us setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64|RTCC_8_bit); //Configura interrupcion del timer ENABLE_INTERRUPTS(INT_RTCC); //Activa interrupcion del timer ENABLE_INTERRUPTS(GLOBAL); //Activa las interrupciones globales ang1=lmin; ang2=lmin; while(TRUE) { //Pregunta si se desea controlar el otro servo if(bit_test(change)){ delay_ms(200); //Anti-Rebote while(bit_test(change)) //Espera hasta dejar de presionar el botón {} //Si servo es 1 pongalo en 2, si es 2 pongalo 1 servo= (servo==1) ? 2 : 1; } //Pregunta por el botón de angulo positivo if(bit_test(plus)){ delay_ms(200); if(servo==1) ang1++; //Aumenta el angulo en el servo 1 else ang2++; //Aumenta el angulo en el servo 2 } //Pregunta por el botón de angulo negativo if(bit_test(minus)){ delay_ms(200); if(servo==1) ang1--; //Decrementa el angulo en el servo 1 else ang2--; //Decrementa el angulo en el servo 2 } //Valida que los angulos estén en el PWM de lmin hasta lmax ang1= (ang1<lmin) ? lmin : ang1; ang1= (ang1>lmax) ? lmax : ang1; ang2= (ang2<lmin) ? lmin : ang2; ang2= (ang2>lmax) ? lmax : ang2; } }
Eso es todo por la entrada del dia de hoy, espero les haya gustado y hayan aprendido algo nuevo. Si te ha servido el contenido de esta entrada, de los videos y los códigos de implementación y deseas apoyar mi trabajo invitandome a un café super barato, puedes hacerlo en el siguiente link:
👉 Invitar a Sergio a un Café ☕️
Que esten muy bien, nos vemos en la siguiente entrada.
Mi nombre es Sergio Andres Castaño Giraldo, y en este sitio web voy a compartir una de las cosas que mas me gusta en la vida y es sobre la Ingeniería de Control y Automatización. El sitio web estará en constante crecimiento, voy a ir publicando material sobre el asunto desde temas básicos hasta temas un poco más complejos. Suscríbete al sitio web, dale me gusta a la página en Facebook y únete al canal de youtube. Espero de corazón que la información que comparto en este sitio, te pueda ser de utilidad. Y nuevamente te doy las gracias y la bienvenida a control automático educación.