Epale!
He estado trabajando con servos y me han ayudado mucho los trabajos de Redpic... y no tengo nada en contra de hacerlo así, pero me surgió una idea... y me gustaría que vieran qué les parece...
Con la lógica de Redpic, usamos las interrupciones de RTCC para contar los 20ms que es el período de trabajo del servo...
Y para fijar el ancho del pulso, el el valor del timer y lo compara, así:
#
valTIMER0 = get_TIMER0();
#
if(valTIMER0>tSERVO1){
#
flagSERVO1=0;
#
output_low(PIN_SERVO1);
#
}
Me puse a hacer varios experimentos... y según lo que han comentado otros, no es a mí no mas que me pasa... resulta que a veces hay un pequeño movimiento indeseado en el servo, pequeño, pero lo hay... me puse a pensar... será que el tiempo en alto es crítico y al evaluar el valor del timer con el "if" la cosa no resulta tan exacta?
Y me vino una idea... ¿Qué tal si uso la interrupción por RTCC para contar ese tiempo?
Aquí les dejo un grafiquito como los de Redpic para mostrar lo que estoy diciendo:

De esta forma, la lógica de programación cambia un poquito:
1- Inicialmente pongo el pin que está conectado al cable "control" del servo (lo llamaré salida de ahora en adelante, por flojera) en 1, y el timer se carga con el valor correspondiente al ancho del pulso (aquí hay que tomar en cuenta el oscilador y bla, bla, bla... si... ya ustedes saben el resto del cuento)...
2- Cuando ocurre la primera interrupción, quiere decir que pasó el tiempo que yo quiero que esté el pulso en alto. Entonces pongo la salida a 0 y pongo a 1 una bandera que indica que ya terminó de contarse el "tiempo en alto".
3- Hay que hacer un cálculo sencillísimo: dividir el tiempo en ticks que el timer debería contar para hacer 20ms (con un cristal de 20M y la pre-escala de 1:64 esto es 1563) entre la precarga que le estamos colocando al timer. ¿Para qué? Pues claro, para saber la cantidad de interrupciones que deben ocurrir hasta el siguiente ciclo ¿sencillo verdad? Sí, si, ya sé... no siempre van a ser exactamente los 20ms lindos y bellos... pero ¿qué se va a hacer? Nada es perfecto jajaja... bueno esa no es la respuesta técnica... lo cierto es que según estuve investigando y por los experimentos que hice...puedo ratificar que el tiempo entre pulso y pulso no es tan crítico en los servos... entre 15ms y 30ms funciona para la mayoría... con esta lógica siempre estará entre 19ms y 21ms... ¿es un error pasable no creen?
4- Finalmente, mientras la bandera flag_pulso está en cero (la salida todavía está en 1) no hago nada... esto asegura que tenga un pulso seguro y firme siempre... cuando la bandera cambia a 1 entonces hago los cálculos por si deseo cambiar el ancho de pulso, en este ejemplo lo que tengo que hacer es usar el CAD para leer el valor de un potenciómetro y luego adecuar ese valor al que debe cargarse al timer para que cuente el ancho de pulso adecuado.
5- No hay más que decir... como dice el conejo Box:
esto es todo amigos!!Bien aquí les dejo el código... a mí me funciona perfectamente... pero POR FAVOR, todos, y especialmente ustedes, amigos sabios del ccs en este foro, me dicen sus opiniones!!

La configuración del circuito, como se darán cuenta en el código es:
PIC16F876 (barato y fácil de conseguir jejeje)
Cristal 20MHz
Potenciómetro conectado a Canal 0 (RA0) [puede ser otro dispositivo apropiado, como algún sensor; yo lo hice inicialmente con un potenciómetro sólo de prueba]
Control del Servo conectado a RC4
Servo HS-300.
Paz y bien para todos!
Nos leemos en el foro!

//////////////////////////////////////////////////
// Lee el canal 0 del pic y modifica //
// PWM para control de servo //
//////////////////////////////////////////////////
//Definiciones generales previas:
//PIC16F876
//Cristal de 20MHz
//Pin donde está conectado la línea de control del servo
//El programa está hecho para un servo, pero esta lógica
//puede ampliarse de forma sencilla para abarcar más servos.
#include <16f876.h>
#device PIC16F876 ADC=10
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
#use delay(CLOCK=20000000)
#define servo_1 PIN_C4
int canal_adc=0; //para elegir qué servo mover (elige el potenciómetro a leer)
int ancho_pulso=0; //el valor que se va a cargar en el timer0 y que representa el ancho del pulso
int n=0; //la cantidad de veces que se
int flags=0;
int i=0;
int16 j=0;
int16 valor=0;
#bit flag_pulso = flags.0
const int tmr_pulso_minimo = 39;
const int tmr_pulso_medio = 117;
const int tmr_pulso_maximo = 195;
const int16 periodo = 1563;
void conf_conversion (int canal) //Función que configura el CAD del pic y fija canal a leer.
{
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(RA0_RA1_RA3_ANALOG);
set_adc_channel(canal);
delay_us(20);
}
int16 conversion() //Esta función es la conversión en sí misma, devuelve
{ //el valor de 10 bits correspondiente a la lectura del canal analógico.
int16 value=0;
value=read_adc();
return(value);
}
void ajusta_pwm () //Esta función fija los parámetros para el siguiente pulso de la PWM.
{
float escala=0;
valor=conversion(); //Lee el valor analógico del dispositivo conectado al pic (ej: potenciómetro).
escala=1024/(tmr_pulso_maximo-tmr_pulso_minimo);//Escala para convertir a un valor que se cargará a timer0
ancho_pulso=(int)(valor/escala); //y es proporcional al ancho de pulso deseado.
ancho_pulso=256-tmr_pulso_minimo-ancho_pulso; //El valor se carga en el timer.
n=(int)(periodo/ancho_pulso); //Calcula la cantidad de interrupciones necesarias
//para completar un período de PWM (aprox. 20ms)
}
#INT_RTCC //Función de interrupción por sobreflujo en timer0.
RTCC_isr ()
{
if(i==1) //La ocurrencia de la primera interrupción indica al pic
{ //que ha transcurrido el tiempo del ancho de pulso deseado,
output_low(servo_1); //de manera que la señal debe fijarse a cero (fin del pulso).
flag_pulso=1; //y fijo a 1 una bandera que indica que el pulso ya terminó (flag_pulso).
}
if(i==n) //Si ha interrumpido la cantidad de veces necesarias
{ //para completar un período:
i=0; // -Aclaro el contador.
output_high(SERVO_1); // -La señal a 1 (comienza próxima ciclo, comienza nuevo pulso).
flag_pulso=0; // -Aclaro bandera (flag_pulso) que indica que el pulso no ha terminado.
}
i++; //Cuenta cada vez que ocurre interrupción por sobreflujo en timer 0.
set_rtcc(ancho_pulso); //Y vuelvo a cargar el valor deseado al timer, que es proporcional al ancho de pulso.
}
main()
{
int canal_an=0; //Indica qué canal del CAD voy a leer.
setup_counters(RTCC_INTERNAL,RTCC_DIV_64);//Configura el timer0 (RTCC), aquí uso pre-escala de 1:64
enable_interrupts(INT_RTCC); //Habilita interrupción por sobreflujo en timer0
enable_interrupts(GLOBAL); //Habilita interrupciones globales
conf_conversion(canal_an); //Llama a la función para configurar el CAD
ajusta_pwm(); //Llama a función para preparar primer ciclo de PWM
i=n; //inicializa i en n, de manera que
RTCC_isr(); //cuando entre en esta función coloque la señal a 1 (inicia pulso).
while(TRUE) //Un ciclo infinito.
{
if(flag_pulso==1)ajusta_pwm(); //Si ya pasó el pulso, ajusta PWM (de este modo el pic no hará nada
} //durante el tiempo que dure el pulso, el cual es crítico
} //en lo que respecta a controlar el servo.