#include <16F88.h>
#device adc=8
#FUSES NOWDT,INTRC_IO,MCLR,PUT,NOBROWNOUT,NOCPD,NOLVP,NOIESO,NODEBUG
//--- Constantes ---
#define SERVO_1 PIN_A0 //linea de control por PWM para el servo
#define ADC_SERVO 1 //canal adc que se usa para el potenciometro
//------------------
#use delay(clock=4000000)
#use standard_io(a)
#use standard_io(b)
//--- Variables ---
int1 flag5RTCC = TRUE; //indica si se completaron 5 RTCC
int1 flag50mS = FALSE; //indica si ocurrio interrupcion de timer1
int1 flagPulso_Alto = FALSE; //indica si esta el pulso en alto
int8 Posicion_Servo = 93; //donde se posiciona el servo segun la lectura del adc
int8 ContRTCC = 0; //contador de RTCC
//-----------------
//--- Funciones ---
void Calcular_Posicion(void);
//-----------------
#int_TIMER0
void TIMER0_isr(void){ //timer que cuenta 20mS
//Timer de 8 bits --> 256 = 1 RTCC
//Pescaler de 1:16
//1 tick cada 16 uS = 0.016mS
//1 RTCC cada 4.0mS (256 - 6 Ticks)
//5 RTCC = 20mS
ContRTCC = ContRTCC + 1;
set_TIMER0(6);
if(ContRTCC == 5){
flag5RTCC = TRUE;
ContRTCC=0;
}
}
#int_TIMER1
void TIMER1_isr(void) { //timer que cuenta 50mS
//Timer de 16 bits --> 65536 = 1 RTCC
//Pescaler de 1:1
//1 tick cada 1 uS
//1 RTCC cada 50mS (65536 - 15536 Ticks)
set_TIMER1(15535);
flag50mS = TRUE;
}
void main(void) {
int8 ValTMR0;
setup_adc_ports(sAN1|VSS_VDD);
setup_adc(ADC_CLOCK_INTERNAL);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
setup_oscillator(OSC_4MHZ|OSC_INTRC);
set_adc_channel(ADC_SERVO);
do {
//>-----------------------Movimiento del servo--------------------------------->
//--- Calcula posicion servo segun lectura adc ---
if(flag50mS == TRUE){
Calcular_Posicion();
flag50mS = FALSE;
}
//------------------------------------------------
//--- Dispara pulso PWM cuando se completan 5 RTCC ---
if(flag5RTCC == TRUE){
flag5RTCC = FALSE;
output_high(SERVO_1);
flagPulso_Alto = TRUE;
}
//----------------------------------------------------
//--- Baja pulso PWM cuando corresponda ---
valTMR0 = get_TIMER0() - 6;
if((flagPulso_Alto == TRUE) && (valTMR0 > Posicion_Servo)){ //baja el pulso en el tiempo correspondiente a Posicion
output_low(SERVO_1);
flagPulso_Alto = FALSE;
}
//-----------------------------------------
//<----------------------------------------------------------------------------<
} while(true);
}
void Calcular_Posicion(void){
int16 ValorADC;
ValorADC = read_adc();
Posicion_Servo = 31 + (int16)((int16)(ValorADC * 124) / 255);
}Posicion_Servo = 31 + (int16)((int16)(ValorADC * 124) / 255);esto en concreto no esta comentado, pero es una operacion aritmetica que dado el valor del ADC me devuelve la posicion en que se debe colocar el servo, expresada en ticks de reloj
entendi hasta lo de poner el pulso en alto, pero no entendi lo de poner otro timer en modo compare para bajar el pulso... tal vez sea que nunca use un timer de ese modo
////////////////////////////////////////////////////////////////////////////////////
//
// Moviendo 8 servos con un solo timer
//
//
// Propósito: Mover hasta 8 servos eficientemente
//
// Conectar 8 servos al PORT_B
//
////////////////////////////////////////////////////////////////////////////////////
#include <16f876.h>
#fuses HS,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP,NOCPD,NODEBUG,NOWRT
#ORG 0x1F00,0x1FFF {} //Para 8k Pic 16F876/7 (necesario para bootloader)
#use delay(clock=20000000) //Cambiar segun el cristal utilizado
////////////////////////////////////////////////////////////////////////////////////
//
// Defines y Constantes
//
////////////////////////////////////////////////////////////////////////////////////
float const uSxTick = 0.2; // Microsegundos por Tick de TMR1 a 20 Mhz
#define VAL_TIMER1 53000 // 65536-53000=12536 * 0,0002 = 2,5 milisegundos
////////////////////////////////////////////////////////////////////////////////////
//
// Variables Globales
//
////////////////////////////////////////////////////////////////////////////////////
int8 servo=0; // Numero de servo
int1 flag_timer1=FALSE;
////////////////////////////////////////////////////////////////////////////////////
//
// Interrupción por desbordamiento del timer1
//
////////////////////////////////////////////////////////////////////////////////////
#int_timer1
void handle_timer1_int() // Se activa cada 2,5 ms
{
flag_timer1=TRUE;
set_timer1(VAL_TIMER1); // 65536-53000=12536*0,0002 = 2,5 ms
}
////////////////////////////////////////////////////////////////////////////////////
//
// Interrupción timer1 modo compare
//
////////////////////////////////////////////////////////////////////////////////////
#int_ccp2
void handle_ccp2_int()
{
bit_clear(*6,servo); // igual que output_low(PIN_Bx); -> *6=PORTB -> Pone a 0 el bit indicado en servo
}
////////////////////////////////////////////////////////////////////////////////////
//
// PROGRAMA PRINCIPAL
//
////////////////////////////////////////////////////////////////////////////////////
void main()
{
////////////////////////////////////////// INICIALIZACIONES GENERALES
delay_ms(333); // Espero a que todo se estabilice e ...
disable_interrupts(global); // Inicializo el Micro y ...
disable_interrupts(int_timer1); // deshabilitando todo lo no necesario ...
disable_interrupts(int_rda);
disable_interrupts(int_ext);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_ccp2(CCP_COMPARE_INT); // Configura CCP2 en modo COMPARE
set_timer1(VAL_TIMER1); // 65536-53000=12536*0,0002 = 2,5 ms
// Habilito las interrupciones necesarias
enable_interrupts(int_timer1); //Int timer 1
enable_interrupts(int_ccp2); // Habilito la interrpción INT_CCP2
enable_interrupts(global); //Habilita interrupciones
do
{
if(flag_timer1==TRUE) // Cuando se activa la int_timer1 -> cada 2,5 ms
{
servo++;
if (servo>=9) servo=1;
bit_set(*6,servo); // igual que output_high(PIN_Bx); -> *6=PORTB -> Pone a 1 el bit indicado en servo
CCP_2 = VAL_TIMER + pos_servo(servo); // Calculo posicion servo correspondiente
// La funcion pos_servo() debeis implementarla vosotros
flag_timer1=FALSE;
}
}
while (TRUE);
}
mi mujer ya ha nombrado la palabra "divorcio" y "trastos" varias veces en varias frases. :?
Tengo que dejarlo por hoy :mrgreen:
uff... llevo un rato leyendome los post de redpic de como medir y generar pulsos, pero no consigo comprender como funciona el modulo CCP... mi duda es CUAL ES LA DIFERENCIA ENTRE EL CCP Y INT_EXT? porque ambos se activan a la entrada de un pulso, incluso se pueden configurar para que se activen a la subida o la bajada... el ccp en modo capture es lo mismo que la int_ext? para que sirve exactamente el modo compare?
gracias! y espero que compenses a tu mujer por tener tanta paciencia :D
ya consegui hacer funcionar el servo con el CCP!!! :-/
el problema era que estaba declarando el pin de salida como #bit, y luego no hacia un tris...
ahora esta solucionado. dejo el codigo que funciona sin problemasCódigo: C
#include <16F88.h> #device adc=8 #FUSES NOWDT,INTRC_IO,MCLR,PUT,NOBROWNOUT,NOCPD,NOLVP,NOIESO,NODEBUG #use delay(clock=4000000) //--- Constantes --- #bit SERVO = 0x06.1 //Pin B0 control del servo #define ADC 0 //canal adc que se usa para el potenciometro //------------------ //--- Variables --- int1 flagLeerADC = FALSE; //indica cuando leer adc //----------------- //--- Funciones --- void Calcular_Posicion(void); //----------------- #int_TIMER1 void TIMER1_isr(void) { //timer que cuenta 20mS //Timer de 16 bits --> 65536 = 1 RTCC //Osc 4Mhz --> 1 instruccion cada 1uS //Pescaler de 1:1 --> 1 tick cada 1 uS //Overflow cada 20mS (65536 - 45536 Ticks) set_TIMER1(45535); SERVO = 1; //sube el pulso del servo } #int_CCP1 void CCP1_isr(void){ SERVO = 0; //baja el pulso del servo flagLeerADC = TRUE; //manda a leer el adc } void main(void) { setup_adc_ports(sAN0|VSS_VDD); setup_adc(ADC_CLOCK_INTERNAL); setup_spi(FALSE); setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); setup_timer_2(T2_DISABLED,0,1); setup_comparator(NC_NC_NC_NC); setup_ccp1(CCP_COMPARE_INT); setup_vref(FALSE); enable_interrupts(INT_TIMER1); enable_interrupts(INT_CCP1); enable_interrupts(GLOBAL); setup_oscillator(OSC_4MHZ|OSC_INTRC); set_adc_channel(ADC); set_timer1(45535); set_tris_b(0); CCP_1 = 47535; do { if(flagLeerADC == TRUE){ flagLeerADC = FALSE; Calcular_Posicion(); } } while(true); } void Calcular_Posicion(void){ int8 ValorADC; ValorADC = read_adc(); CCP_1 = 46035 + (ValorADC * 7.8125); //carga CCP1 con un valor entre 500 y 2500 (mas los 45535 de donde comienza a contar el timer, a menos que haya algun calculo que se desborde :( }
espero que a alguien le sea util... para mi lo es :mrgreen:
salu2