Para poder usar los módulos hardware CCP con el Servo no se puede usar con fosc=4MHz,
ya que así el Tmáx=(255+1)·4·1/4MHz·16=4096us [ T=(PR2+1)·4·Tosc·TMR2preesc ], con
lo que la fmín=1/Tmáx=1/4096us=244,14Hz y esta frecuencia no nos sirve ya que los
servos funcionan entre 50Hz y 100Hz. La solución es modificar la fosc.
1er PROGRAMA:
Usaremos una fosc=200KHz, con ella y cargando el PR2 con 249 y con TMR2preesc=4
conseguimos: T=(249+1)·4·1/200KHz·4=20ms con lo que la F=1/T=1/20ms=50Hz
#include <16F877.h>
#fuses XT, NOPROTECT, NOPUT, NOWDT, NOBROWNOUT, NOLVP, NOCPD, WRT
#use delay(Clock=200000) //fosc=200KHz (para que no salgan decimales en CCPR1L)
#include <lcd.c>
#use fast_io(A)
#use fast_io(B)
#byte port_a = 5
#byte port_b = 6
void main(void)
{
int8 w;
long CCPR1L_DER,CCPR1L_CEN,CCPR1L_IZQ; //Usaremos los 2 bits de CCPCON1<5:4>
//Si usaramos int en la fórmula de CCPR1L
//aparecería un 4, que no nos sirve, ya que
//dá lugar a decimales
set_tris_a(0b11111111);
set_tris_b(0b00000000);
setup_ccp1(CCP_PWM);
setup_ccp2(CCP_PWM);
setup_timer_2(T2_DIV_BY_4,249,1); //T=(PR2+1)·4·Tosc·TMR2preesc
//PR2=(T/(4·Tosc·TMR2preesc))-1=
//=(20ms/(4·(1/200KHz)·4))-1=249
lcd_init();
lcd_gotoxy(1,1);
printf(lcd_putc,"S1c");
lcd_gotoxy(5,1);
printf(lcd_putc,"S2c");
CCPR1L_DER=100;
CCPR1L_CEN=75;
CCPR1L_IZQ=50;
set_pwm1_duty(CCPR1L_CEN); // Inicialmente Servos al centro
set_pwm2_duty(CCPR1L_CEN);
while (1)
{
if (w!=port_a)
{
w=port_a;
switch(port_a)
{
//------------------------------------- SERVO 1 ------------------------------------
case 1:
lcd_gotoxy(1,1);
printf(lcd_putc,"S1d");
set_pwm1_duty(CCPR1L_DER); // Derecha (2ms)
break;
case 2:
lcd_gotoxy(1,1);
printf(lcd_putc,"S1c"); // Centro (1,5ms)
set_pwm1_duty(CCPR1L_CEN);
break;
case 4:
lcd_gotoxy(1,1);
printf(lcd_putc,"S1i"); // Izquierda (1ms)
set_pwm1_duty(CCPR1L_IZQ);
break;
//------------------------------------- SERVO 2 ------------------------------------
case 9:
lcd_gotoxy(5,1);
printf(lcd_putc,"S2d"); // Derecha (2ms)
set_pwm2_duty(CCPR1L_DER);
break;
case 10:
lcd_gotoxy(5,1);
printf(lcd_putc,"S2c"); // Centro (1,5ms)
set_pwm2_duty(CCPR1L_CEN);
break;
case 12:
lcd_gotoxy(5,1);
printf(lcd_putc,"S2i"); // Izquierda (1ms)
set_pwm2_duty(CCPR1L_IZQ);
break;
}
}
}
}
//Calculos:
// T=(PR2+1)·4·Tosc·TMR2preesc ---> PR2=
// Duty=(CCPR1L:CCPCON1<5:4>)·Tosc·TMR2preesc --> CCPR1L:CCPCON1<5:4>=Duty/(Tosc·TRM2preesc)
// T=(249+1)·4·1/200KHz·4=20ms con lo que la F=1/T=1/20ms=50Hz
// CCPR1L:CCPCON1<5:4>=1,5ms/(1/200KHz)·4=75 Servos al centro
// CCPR1L:CCPCON1<5:4>=1ms/(1/200KHz)·4=50 Izquierda
// CCPR1L:CCPCON1<5:4>=2ms/(1/200KHz)·4=100 Derecha
2º PROGRAMA:
Usaremos una fosc=1MHz a partir del oscilador interno de un PIC16F88, con ella y
cargando el PR2 con 255 y con TMR2preesc=16 conseguimos: T=(255+1)·4·1/1MHz·16=16,38ms
con lo que la F=1/T=1/16,38ms=61,05Hz
#include <16F88.h>
#fuses NOPROTECT, NOPUT, NOWDT, NOBROWNOUT, NOLVP, NOCPD, WRT, INTRC_IO, NOMCLR
//NOMCLR para que lea un 0 en el pin RA5 y no tenga que cambiar el valor de los case
//Si se quisiera enviar el pwm por RB3 añadiriamos el fuse ccpb3, por omisión, pwm por RB0
#use fast_io(A)
#byte port_a = 5
void main(void)
{
int8 w;
long CCPR1L_DER,CCPR1L_CEN,CCPR1L_IZQ; //Usaremos los 2 bits de CCPCON1<5:4>
//Si usaramos int en lugar de long,
//en la fórmula de CCPR1L aparecería un 4
set_tris_a(0b11111111);
set_tris_b(0x00);
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_16,255,1); //T=(PR2+1)·4·Tosc·TMR2preesc
//PR2=(T/(4·Tosc·TMR2preesc))-1=
//=(16,384ms/(4·(1/1MHz)·16))-1=255
setup_oscillator(OSC_1MHZ);
// Duty=(CCPR1L:CCPCON1<5:4>)·Tosc·TMR2preesc
// CCPR1L:CCPCON1<5:4>=Duty/(Tosc·TRM2preesc)
CCPR1L_DER=125; //CCPR1L:CCPCON1<5:4>=2ms/(1/1MHz)·16=125 Derecha
CCPR1L_CEN=94; //CCPR1L:CCPCON1<5:4>=1,5ms/(1/1MHz)·16=93,75=94 Servo al centro
CCPR1L_IZQ=62; //CCPR1L:CCPCON1<5:4>=1ms/(1/1MHz)·16=62,5=62 Izquierda
set_pwm1_duty(CCPR1L_CEN); // Inicialmente Servo al centro
while (1)
{
if (w!=port_a)
{
w=port_a;
switch(port_a)
{
case 1:
set_pwm1_duty(CCPR1L_DER); // Derecha (2ms)
break;
case 2:
set_pwm1_duty(CCPR1L_CEN); // Centro (1,5ms)
break;
case 4:
set_pwm1_duty(CCPR1L_IZQ); // Izquierda (1ms)
break;
}
}
}
}
Estos programas no han sido provados físicamente, tan solo por PROTEUS.
Os adjunto más abajo los ficheros .c, .hex y .dsn para que los podais simular.
Un saludo