Si además quieres enviarnos un Artículo para el Blog y redes sociales, pulsa el siguiente botón:
Buenas tardes, estoy intentando programar un PIC16f876A (en una SkyPic) para controlar varios servos con timers. De momento el control de servos va bien, excepto cuando en el bulce principal meto senos o cosenos para calcular las posiciones. Va haciendolo bien pero a veces los servos dan saltos y luego continuan.
He pensado que igual el timer interrumpe la rutina del seno y el valor de la variable no está "listo". He probado asignando el seno a una variable temporal y despues asignandola a la variable de posicion del servo, pero esto solo empeora el problema.
La cuestion es que no es un problema nuevo. Me suelen pasar estas cosas cuando uso los timers.
Ya no se muy bien que hacer y seguramente no es algo nuevo, pero no encuentro mucho en los foros. Podría tener que ver con la prioridad del timer, o a lo mejor hay algo que es de cajon y que me estoy saltando.. no lo se.
Otra cosa que pasa es cuando mando texto por el puerto serie con printf, el texto suele salir corrupto en parte (cuando uso timers). Por eso pienso que puede ser tema de prioridades.
Pego mi código por si a alguien se le ocurre qué puede estar pasando. Muchisimas gracias de antemano!!#include <16f876a.h>
#include <math.h>
#fuses NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=20000000)
#use standard_io(b)
#use rs232(baud=19200,xmit=PIN_C6,rcv=PIN_C7)
int Keypress=0;
int servoswitch=0;
float angl=0;
long int tservo0=1900;
long int tservo1=1900;
long int temp0=1900;
long int temp1=1900;
#int_rda
void rda_isr() {
Keypress=0x00;
if(kbhit()){
Keypress=getc();
}
}
#int_TIMER1
void TIMER(){
switch(servoswitch)
{
case 0: //Pulso primer servo
{
set_TIMER1(65535-tservo0);
output_bit(PIN_B0,1);
servoswitch++;
break;
}
case 1: //Pulso segundo servo
{
set_TIMER1(65535-tservo1);
output_bit(PIN_B0,0);
output_bit(PIN_B1,1);
servoswitch++;
break;
}
case 2: //Rellenar hasta 20ms
{
set_TIMER1(15535+tservo1+tservo0);
output_bit(PIN_B1,0);
servoswitch=0;
break;
}
}
}
void main() {
setup_timer_1(T1_INTERNAL | T1_DIV_BY_2);
enable_interrupts(int_rda);
enable_interrupts(global);
enable_interrupts(INT_TIMER1);
set_TIMER1(0);
do {
// Control teclado
if(Keypress!=0x00){
printf("%Lu %Lun",tservo0,tservo1);
switch(Keypress)
{
case 49:
{
tservo0=1900;
tservo1=1900;
break;
}
case 50:
{
tservo0=5800;
tservo1=5800;
break;
}
}
Keypress=0x00;
}
if (angl>6.28)
{
angl=0;
}
angl+=0.005;
tservo0=2000*sin(angl)+3800;
tservo1=2000*cos(angl)+3800;
}
while (TRUE);
}
Duda secundaria: Alguien sabe si existe un equivalente a math.h (aunque sea parcial) que acepte variables en coma fija (en vez de float)??.
Me suena a que el programa no tiene tiempo de hacer los calculos.
Las funciones trigonometricas como senos y cosenos son muy costosas. Ademas el hecho de que los servos den "saltos" cuadra con que no se actualice la posicion con la frecuencia esperada.
Prueba a cambiar el seno y el coseno por valores constantes. Si eso funciona lo que puedes hacer es usar una tabla de referencias.
Te construyes una funcion seno que lo que haga es buscar el valor en una tabla y devolver el resultado correspondiente al angulo mas cercano al que le has pasado, o interpolar entre el anterior y el siguiente.
Esto es muchisimo mas rapido que calcular seno y coseno y la perdida de precision apenas se va a notar, todo depende de lo grande que hagas la tabla. Incluso podrias usar la eeprom del pic para almacenar las tablas (no estoy seguro de esto porque no se a que velocidad se puede leer de la eeprom)