Autor Tema: formula para DualRate valor0=rango1+(read_adc()/1022)*(8000-(2*rango1));  (Leído 5707 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado japifer_22

  • PIC18
  • ****
  • Mensajes: 405
edito:
Citar
por favor lean el post de mas abajo en el cual pongo la imagen de mi circuito en cuestion, que es de un emisor a contrl remoto, que estoy implementando.

hola, bueno me encuentro aqui esta vez por el siguente motivo.

resulta que estoy trabajando con el ADC del pic 16f877a en CCS C, y el rango de trabajo del ADC tengo que meterlo en una formula, la cual es (int16 valor0;) valor0=rango1+(read_adc()/1022)*(8000-(2*rango1));
 ó
valor0=rango1+read_adc()*((8000/1022)-((2/1022)*rango1)); que es la misma pero menos abreviada, bueno en esta formula estoy teniendo problemas, ya que no me da los rangos que nesesito que recorra, esto es con respecto al valor del ADC que me arroge.

los que hace esta formula es que si rango1 esta en 0, y solo varia el ADC (recordando que el adc trabaja con un rango de 0 a 1022, osea para una entrada de 0 a 5v), el resultado tendria que variar entre el intervalo de 0 a 8000, pero a medida que cambio el valor de rango1, el resultado cambia su rango de trabajo, achicando este mismo.

por otra parte el resultado de esta formula (valor0) lo guardo en un strings, para luego leer este strings en el timer1.

« Última modificación: 27 de Junio de 2010, 14:33:54 por japifer_22 »

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: no me funciona bien esta formula=rango1+(read_adc()/1022)*(8000-(2*rango1));
« Respuesta #1 en: 26 de Junio de 2010, 15:35:40 »
Hola.

El problema es que el compilador va a intentar simplificar al máximo el tipo de operaciones según el tipo de variables involucradas.

Por ejemplo, en el caso de read_adc() / 1022, ambas variables son interpretadas como unsigned int16 por el compilador, por lo que su división también será entera. El resultado de eso será siempre 0, excepto en el caso de que read_adc() valga 1023, pero eso es por un error de rango cometido por vos.
Estas necesitando lo que se llama casting. Sirve para indicarle al compilador que transforme una variable en otro tipo antes de ser sometida a una operacion o funcion.

valor0= rango1 + (float)read_adc() / 1023.0 * (8000 - 2 * rango1);

Suerte.
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado bmb

  • PIC18
  • ****
  • Mensajes: 423
Re: no me funciona bien esta formula=rango1+(read_adc()/1022)*(8000-(2*rango1));
« Respuesta #2 en: 26 de Junio de 2010, 16:44:57 »
Hola japifer_22, tal como te explica BrunoF, debes aplicar lo que llaman casting (o conversión de tipos) a las variables; asumiendo que estás usando la directiva #device adc=10, la forma de escalar un valor adc de 10 bits dentro de un valor de 8000 sería más o menos:

Código: [Seleccionar]
#include <16F877A.h>
#device adc=10
.
.
.
.
void main()
{
   int16 valor0;
   .
   .
   set_adc_channel(1);   // canal adc a leer
   delay_us(10);
   valor0 = ((float)read_adc() / 1023.0) * 8000.0;
   .
   .

Como verás, los valores de la expresión son ahora todos valores flotantes excepto valor0 que tomará el valor entero del resultado de la expresión.  Lo que no me queda muy claro es de donde sale rango1 y que hace que cambie su valor.

Un saludo.
« Última modificación: 26 de Junio de 2010, 16:49:37 por bmb »

Desconectado japifer_22

  • PIC18
  • ****
  • Mensajes: 405
Re: no me funciona bien esta formula=rango1+(read_adc()/1022)*(8000-(2*rango1));
« Respuesta #3 en: 26 de Junio de 2010, 19:33:28 »
hola gracias por las respuestas.
primero BrunoF, se que el rango es de 0 a 1024, pero le puse 1022 para probar algo nadamas.  :oops:

ahora estoy teniendo el siguiente problemas de compilacion, ya que me sale este mensaje y no me deja compilar:



por que saldra este mensaje ????

Desconectado juanpavz

  • PIC12
  • **
  • Mensajes: 77
Re: no me funciona bien esta formula=rango1+(read_adc()/1022)*(8000-(2*rango1));
« Respuesta #4 en: 26 de Junio de 2010, 19:39:55 »
Cuando quieres programar en lenguaje C en micros de la serie 16 a menudo faltan recursos. Puedes probar optimizando tu codigo (quitando instrucciones redundantes, si es que existen). Pero lo mas conveniente es mudar a la serie 18.
Hazlo o no lo hagas... Pero no lo intentes

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: no me funciona bien esta formula=rango1+(read_adc()/1022)*(8000-(2*rango1));
« Respuesta #5 en: 26 de Junio de 2010, 19:47:26 »
Una posible solución a ese problema es separar el programa en distintas funciones y a su vez quizá sea necesario usar "#separate".

Eso fuerza al compilador al "meter" el código que sigue a "separate" en otra página.

Algo así...
Código: C
  1. void funcion1 (void)
  2. {
  3. ............
  4. ...........
  5. ...........
  6. }
  7.  
  8. unsigned char funcion2(int)
  9. {
  10. ...............
  11. ...............
  12. .................
  13. ..................
  14. }
  15.  
  16. #separate
  17.  
  18. void main(void)
  19. {
  20. ..............
  21. ..............
  22. ...............
  23. ..................
  24. }

Busca en la ayuda de CCS

PD: perdón, si es que estás usando dicho compilador
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado japifer_22

  • PIC18
  • ****
  • Mensajes: 405
Re: no me funciona bien esta formula=rango1+(read_adc()/1022)*(8000-(2*rango1));
« Respuesta #6 en: 26 de Junio de 2010, 21:14:47 »
hola, bueno miren les comento lo que  estoy asiendo hace algún tiempo. es un control remoto para un proyecto en mente, y bueno así que  he obstado por hacerme yo mismo el control, y bueno funciona bien todo, pero ahora me faltaba hacerle el DualRate, esto por cada canal y por software.
el control que estoy asiendo es de 7 canales, el cual 4 de ellos son netamente análogos, y los tres restante son análogos/digital, esto dependiendo de lo que se quiera. en resumen se puede obtener 7 canales 100% análogos ó 4 análogos y tres digital. esto cuenta con una pantalla LCD de 20x4, en conjunto con un menú.
en esta pantalla se muestra el estado de la batería, esto como pantalla principal, y en el menú, da la opción de poder elegir si es que se quiere cambiar de giro el ó los servo o no, esto por cada canal del control  (se accede al menú principal presionando al mismo tiempo los botones de D1 y D2, y se puede mover dentro de él con los botones D3 Y D4 respectivamente). También se tiene la opción de poder poner los canales análogos/digital, esto solo para los canales 5, 6 y 7 del control (una vez que se escoja la opción del menú que se quiera, se presiona el botón de D1), para poder moverse entre estos canales se presiona los botones D3 y D4, y para cambiar la configuración que,  para este caso es A/D  ó D/A, se presiona los botones de D1 y D2, y una vez modificado lo necesario se presiona el botón de D5.
ahora para poder guardar las modificaciones que se han hecho en el programa, se presiona los botones D1 y D3 al mismo tiempo. para que al apagar el control, nuestras modificaciones queden guardadas y listas para usar en nuestro próximo encendido del control.
por último y es este el problema que pregunte, y es sobre el DualRate, la formula que he puesto en mi primer post de este hilo es para hacer el rango de trabajo del servo, que para mi caso es de 3500 a 11500, pero como de 3500 a 11500 hay 8000, solo vario el rango de este último, ósea solo vario ó acorto el rango que va de 0 a 8000, que es lo que se mueve mi servo ( de 0.7 a 2.3ms).
ahora bien la formula que puse mas arriba traía 2 variables (rango1+(read_adc()/1022)*(8000-(2*rango1))), la primera es la proveniente de la lectura del ADC, y que es read_adc, donde esta trabaja de 0 a 1024, esto solo dependiendo del  estado del potenciómetro, de X canal. la segunda variable es para trabajar el DualRate y es la rango1, donde esta es la que modificamos nosotros, para acortar el rango del trabajo del servo, el valor máximo que puede tomar esta variable es de 4000, y es para dejar  el servo al centro y sin que se pueda mover. pero en esto estoy teniendo problema, ya que pongo esta fórmula en el programa y me da el siguiente error.

esta formula la quiero poner en la parte donde hago todas las lecturas de los canales análogos.
además le he dejado una función que es la rangos_de_trabajos, para poder ir modificando la variable rango1, rango2, rangoN......
en fin, les dejo mejor el programa para que lo vean y me digan que puedo simplificar o modificar para mejo. además les dejo la simulación en proteus.

el codigo es este:
Código: [Seleccionar]
#define Salida_emisor PIN_C0

void menu_principal(void);
void menu_de_control(void);
void conversion(void);
void escribir_eeprom(void);
void rangos_de_trabajos(void);

const int16  Ticks4Window  = 12500;  // PWM Window for servo = 2.5 ms x 8 = 20 ms
const int16  Ticks4Minimum =  3500;  // PWM High for Minimum Position = 0.7 ms 
const int16  Ticks4Center  =  7500;  // PWM High for Center  Position = 1.5 ms 
const int16  Ticks4Maximum = 11500;  // PWM High for Maximum Position = 2.3 ms 

static int16 Servo_PWM[8];
static int8  control_Servo=0;
static int1  flag_Phase;
static int16 TicksDeInterrupcion=53036;

int1 a=0,b=0,c=0,d=0,e=0,f=0,g=0,k=0,m=0,n=0;//control de menu y control
int j=0,p=0,q=0;
int rec_eprom=0,recorrido_eeprom=0;

#int_timer1
void timer1_isr(void){

   if(flag_Phase==0){
   switch(control_Servo){
      case 0: output_high(Salida_emisor);break;
      case 1: output_high(Salida_emisor);break;
      case 2: output_high(Salida_emisor);break;
      case 3: output_high(Salida_emisor);break;
      case 4: output_high(Salida_emisor);break;
      case 5: output_high(Salida_emisor);break;
      case 6: output_high(Salida_emisor);break;
      case 7: output_high(Salida_emisor);break;
   }
      TicksDeInterrupcion = 65535 - Servo_PWM[control_Servo];
      set_timer1(TicksDeInterrupcion);
   }
   if(flag_Phase==1){
   switch(control_Servo){   
      case 0: output_low(Salida_emisor);break;
      case 1: output_low(Salida_emisor);break;
      case 2: output_low(Salida_emisor);break;
      case 3: output_low(Salida_emisor);break;
      case 4: output_low(Salida_emisor);break;
      case 5: output_low(Salida_emisor);break;
      case 6: output_low(Salida_emisor);break;
      case 7: output_low(Salida_emisor);break;
   }
      TicksDeInterrupcion = 65535 - Ticks4Window + Servo_PWM[control_Servo];
      set_timer1(TicksDeInterrupcion);
      if(++control_Servo>7) control_Servo=0;
   }
   ++flag_Phase;
}

void main(void) {
   
   int8 i;
   int16 Valor0,Valor1,Valor2,Valor3,Valor4,Valor5,Valor6,Valor7;       // para 10 bits
   float resolucion= 5.0/1022.0;      // Conversión con 10 bits de la entrada analoga
  lcd_init();                             //inicializa lcd

   /////////////////////////////////////////// INICIALIZACIONES PERTINENTES A LA APLICACION                                     

   set_tris_a(0b00111111);
   set_tris_c(0b11111110);
   set_tris_d(0b11111111);   
   set_tris_e(0b00000111);
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
   set_timer1(TicksDeInterrupcion);
   enable_interrupts(int_timer1);
   enable_interrupts(global);   
   
  //////////////// Configuramos entradas analogicas:///////////////////////////
   setup_adc_ports(ALL_ANALOG);//configuracion de pines como entradas analogas
   setup_adc(ADC_CLOCK_INTERNAL);

  /////////////// configuracion de lectura eeprom interna del pic//////////////
a=read_EEPROM(rec_eprom);
rec_eprom++;
b=read_EEPROM(rec_eprom);
rec_eprom++;
c=read_EEPROM(rec_eprom);
rec_eprom++;
d=read_EEPROM(rec_eprom);
rec_eprom++;
e=read_EEPROM(rec_eprom);
rec_eprom++;
f=read_EEPROM(rec_eprom);
rec_eprom++;
g=read_EEPROM(rec_eprom);
rec_eprom++;
k=read_EEPROM(rec_eprom);
rec_eprom++;
m=read_EEPROM(rec_eprom);
rec_eprom++;
n=read_EEPROM(rec_eprom); 
  ////////////////////////////////////////////////////////////////////////////
  do{
/////////////////// Tomamos las medidas de las señales analogas/////////////////
// ejemplo de aplicacion:
//valor=1022*(5/1022)*1600 --->1022 es el rango de medicion 0 -> 0V y 1022 ->5V
//valor=8000 --->1600 es para llegar al rango de 8000 que lo nesesitamos para completar
//.... el rango de 11500, equivalente a 2.3ms. recorrido maximo del servo
////////////////////////////////////////////////////////////////////////////////
///    rango1+read_adc()*((8000/1022)-((2/1022)*rango1));
///    rango1+(read_adc()/1022)*(8000-(2*rango1));

  set_adc_channel(0);              //toma el valor de medicion de la entrada analoga de 0 a 1022 (0 a 5V)
  Valor0=read_adc()*resolucion*1600;
   set_adc_channel(1);              //toma el valor de medicion de la entrada analoga de 0 a 1022 (0 a 5V)
  Valor1=read_adc()*resolucion*1600;//almacena el valor de medicion y lo paso a rango de 0 a 5V, y 1600 para rango de PWM   
   set_adc_channel(2);              //toma el valor de medicion de la entrada analoga de 0 a 1022 (0 a 5V)
  Valor2=read_adc()*resolucion*1600;//almacena el valor de medicion y lo paso a rango de 0 a 5V, y 1600 para rango de PWM   
   set_adc_channel(3);              //toma el valor de medicion de la entrada analoga de 0 a 1022 (0 a 5V)
  Valor3=read_adc()*resolucion*1600;//almacena el valor de medicion y lo paso a rango de 0 a 5V, y 1600 para rango de PWM 
   set_adc_channel(4);              //toma el valor de medicion de la entrada analoga de 0 a 1022 (0 a 5V)
  Valor4=read_adc()*resolucion*1600;//almacena el valor de medicion y lo paso a rango de 0 a 5V, y 1600 para rango de PWM
   set_adc_channel(5);              //toma el valor de medicion de la entrada analoga de 0 a 1022 (0 a 5V)
  Valor5=read_adc()*resolucion*1600;//almacena el valor de medicion y lo paso a rango de 0 a 5V, y 1600 para rango de PWM
   set_adc_channel(6);              //toma el valor de medicion de la entrada analoga de 0 a 1022 (0 a 5V)
  Valor6=read_adc()*resolucion*1600;//almacena el valor de medicion y lo paso a rango de 0 a 5V, y 1600 para rango de PWM
   set_adc_channel(7);              //toma el valor de medicion de la entrada analoga de 0 a 1022 (0 a 5V)
  Valor7=read_adc();//almacena el valor de medicion y lo paso a rango de 0 a 5V, y 1600 para rango de PWM

///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
//                    MANEJO DE MENSAJES POR LA PANTALLA LCD 20x4
///////////////////////////////////////////////////////////////////////////////
lcd_gotoxy(1,4);                          // visualiza en la cuarta fila el voltaje de la bateria
printf(lcd_putc,"   Bat: %4.2f[Vol]",(float)Valor7*(5.0/1022));//muestra el voltaje de la bateria

lcd_gotoxy(1,1);                          // visualiza en la primera fila el numero de canales del emisor
lcd_putc("      1234567       ");  // muestra los canales del emisor para interactuar con el menu
lcd_gotoxy(1,2);                          // visualiza en la segunda fila que estamos en el programa principal               
lcd_putc(" PANTALLA PRINCIPAL ");  // muestra por pantalla que estamos en la pantalla principal
lcd_gotoxy(1,3);                          // borra en la tercera fila lo que este escrito
lcd_putc("                    ");  // borra lo que este escrito en esta linea del LCD
///////////////////////////////////////////////////////////////////////////////

///////////ALMASENA LOS DATOS DE LA SEÑAL EMITIDA EN EL STRING SERVO_PWM///////
//esta parte del programa recorre cada una de las pulsos que conforman la trama de la señal
//guardando su valor en cada una de las posiciones del string servo_PWM, probenientes
//de los botones o palancas de control (entradas analogas o digitales)
//
//la configuracion de las entradas analogas es como sigue:
//servo_PWM=(valor*resolucion*1600)+3500
//donde valor son los datos que toma mi señal analoga de 0 a 1022, y resolucion
//es el paso de mi señal analoga a rango de 0 a 5V (resolucion=5/1022).
//los 1600 es una constante que multiplica el resultado de valor por resolucion
//para dejarlo en el rango de 0 a 8000, donde este rango se utilisa para mover
//los servos, mas la suma de la otra contante de 3500 que es lo minimo que se puede
//tener para mover a la minima posicion el servo a 0.7ms, que es equivalente a
//3500 ticks y para el maximo equivale a 11500 ticks que es una señal de 2.3ms.
// ejemplo de la aplicacion:
//suponiendo que valor sea igual a 1022 (equivale a una entra da de 5V)
//servo_PWM=(1022*(5/1022)*1600)+3500
//servo_PWM=(5*1600)+3500
//servo_PWM=8000+3500
//servo_PWM=11500 que equivalen a los ticks maximo de movilidad del servo a 2.3ms
//
//ahora para el caso que valor sea igual a 0 (equivale a una entrada de 0V)
//servo_PWM=(0*(5/1022)*1600)+3500
//servo_PWM=3500 que equivalen a los ticks minimo de movilidad del servo a 0.7ms
//
//por ultimo en el caso de servo_PWM=11500-valor, lo que hace es dar buelta la señal
//osea ahora el maximo de tick va a ser el minimo y el minimo ahora va a ser el maximo
///////////////////////////////////////////////////////////////////////////////

for(i=0;i<8;i++){                           //RECORRE CADA UNA DE LAS POSICIONES DEL STRING SERVO_PWM....
                                            //...GUARDA LOS DATOS DE LAS POCISIONES DE LOS BOTONES Y PALANCAS
switch(i){                                  //RECORRE CADA UNA DE LAS POSICIONES DEL STRING Y GUARDA LOS VALORES..
case 0:                                     //TRABAJA EN EL CANAL 1 DEL EMISOR (RECORDAD QUE ES DE 3500 A 11500 ticks)
       if(a==0){                            //SELECCIONA EL SENTIDO DE GIRO DEL SERVO
       Servo_PWM[0]=valor0+3500;            //GUARDA EN MI STRING EL VALOR ANALOGO DEL CHANEL 1 Y HACE LA CONVERSION DE
       }                                    //...LA ENTRADA ANALOGA AL MOVIMIENTO DEL SERVO (0.7 A 2.3ms)
       else if(a==1){                       //CAMBIA DE GIRO DEL SERVO
       Servo_PWM[0]=11500-valor0;           //GUARDA EN MI STRING EL VALOR ANALOGO DEL CHANEL 1 Y HACE LA CONVERSION DE
       }                                    //...LA ENTRADA ANALOGA AL MOVIMIENTO DEL SERVO (0.7 A 2.3ms)
break;                                      //SALTA DEL CHANEL 1 AL CHANEL 2
case 1:                                     //TRABAJA EN EL CANAL 2 DEL EMISOR (RECORDAD QUE ES DE 3500 A 11500 ticks)
       if(b==0){                            //SELECCIONA EL SENTIDO DE GIRO DEL SERVO
       Servo_PWM[1]=valor1+3500;            //GUARDA EN MI STRING EL VALOR ANALOGO DEL CHANEL 2 Y HACE LA CONVERSION DE
       }                                    //...LA ENTRADA ANALOGA AL MOVIMIENTO DEL SERVO (0.7 A 2.3ms)
       else if(b==1){                       //CAMBIA DE GIRO DEL SERVO
       Servo_PWM[1]=11500-valor1;           //GUARDA EN MI STRING EL VALOR ANALOGO DEL CHANEL 2 Y HACE LA CONVERSION DE
       }                                    //...LA ENTRADA ANALOGA AL MOVIMIENTO DEL SERVO (0.7 A 2.3ms)
break;                                      //SALTA DEL CHANEL 2 AL CHANEL 3
case 2:                                     //TRABAJA EN EL CANAL 3 DEL EMISOR (RECORDAD QUE ES DE 3500 A 11500 ticks)
      if(c==0){                             //SELECCIONA EL SENTIDO DE GIRO DEL SERVO
      Servo_PWM[2]=valor2+3500;             //GUARDA EN MI STRING EL VALOR ANALOGO DEL CHANEL 3 Y HACE LA CONVERSION DE
      }                                     //...LA ENTRADA ANALOGA AL MOVIMIENTO DEL SERVO (0.7 A 2.3ms)
      else if(c==1){                        //CAMBIA DE GIRO DEL SERVO
      Servo_PWM[2]=11500-valor2;            //GUARDA EN MI STRING EL VALOR ANALOGO DEL CHANEL 3 Y HACE LA CONVERSION DE
      }
break;                                      //SALTA DEL CHANEL 3 AL CHANEL 4
case 3:                                     //TRABAJA EN EL CANAL 4 DEL EMISOR (RECORDAD QUE ES DE 3500 A 11500 ticks)
       if(d==0){                            //SELECCIONA EL SENTIDO DE GIRO DEL SERVO
       Servo_PWM[3]=valor3+3500;            //GUARDA EN MI STRING EL VALOR ANALOGO DEL CHANEL 4 Y HACE LA CONVERSION DE
       }                                    //...LA ENTRADA ANALOGA AL MOVIMIENTO DEL SERVO (0.7 A 2.3ms)
       else if(d==1){                       //CAMBIA DE GIRO DEL SERVO
       Servo_PWM[3]=11500-valor3;           //GUARDA EN MI STRING EL VALOR ANALOGO DEL CHANEL 4 Y HACE LA CONVERSION DE
       }
break;                                      //SALTA DEL CHANEL 4 AL CHANEL 5
case 4:                                     //TRABAJA EN EL CANAL 5 DEL EMISOR (RECORDAD QUE ES DE 3500 A 11500 ticks)
       if(k==0){                            //TRABAJA CHANEL DE FORMA DIGITAL...                           
       if(input(PIN_C1) && input(PIN_C2)){  //MANTIENE EN LA POSICION CENTRAL AL SERVO
       Servo_PWM[4]=Ticks4Center;           // GUARDA LOS TICKS 7500 EN MI STRING PARA PONER EL CHANEL AL CENTRO
       }
       if(e==0){                            //SELECCIONA EL SENTIDO DE GIRO DEL SERVO
       if(!input(PIN_C1)){                  //AL MANTERNER PULSADO ESTE BOTON EL SERVO VA A SU POSICION MAXIMA
       Servo_PWM[4]=Ticks4Maximum;          //GUARDA EN MI STRING LA POSICION MAXIMA DEL SERVO, 11500 TICKS-->2.3ms
       }
       else if(!input(PIN_C2)){             //AL MANTERNER PULSADO ESTE BOTON EL SERVO VA A SU POSICION MINIMA
       Servo_PWM[4]=Ticks4Minimum;          //GUARDA EN MI STRING LA POSICION MINIMA DEL SERVO, 3500 TICKS-->0.7ms
       }}
       else if(e==1){                       //CAMBIA DE GIRO DEL SERVO
       if(!input(PIN_C2)){
       Servo_PWM[4]=Ticks4Maximum;
       }
       else if(!input(PIN_C1)){
       Servo_PWM[4]=Ticks4Minimum;
       }}}                                  //TERMINO DE TRABAJO DE FORMA DIGUITAL
       else if(k==1){                       //TRABAJA EL CHANEL DE FORMA ANALOGA
              if(e==0){                     //SELECCIONA EL SENTIDO DE GIRO DEL SERVO
       Servo_PWM[4]=valor4+3500;            //GUARDA EN MI STRING EL VALOR ANALOGO DEL CHANEL 5 Y HACE LA CONVERSION DE
       }                                    //..DE VOLTAJE A TICKS 0v-->0 TICKS 0.7ms Y 5v-->11500 TICKS 2.3ms
       else if(e==1){                       //CAMBIA DE GIRO DEL SERVO
       Servo_PWM[4]=11500-valor4;
       }}                                   //TERMINO DEL CHANEL DE FORMA ANALOGA
break;                                      //SALTA DEL CHANEL 5 AL CHANEL 6
case 5:                                     //TRABAJA EN EL CANAL 6 DEL EMISOR (RECORDAD QUE ES DE 3500 A 11500 ticks)
       if(m==0){
       if(input(PIN_C3) && input(PIN_C4)){
       Servo_PWM[5]=Ticks4Center;
       }
       if(f==0){                            //SELECCIONA EL SENTIDO DE GIRO DEL SERVO
       if(!input(PIN_C3)){
              Servo_PWM[5]=Ticks4Maximum;
       }
       else if(!input(PIN_C4)){
              Servo_PWM[5]=Ticks4Minimum;
       }}
       if(f==1){                            //CAMBIA DE GIRO DEL SERVO
       if(!input(PIN_C4)){
              Servo_PWM[5]=Ticks4Maximum;
       }
       else if(!input(PIN_C3)){
              Servo_PWM[5]=Ticks4Minimum;
       }}}
       else if(m==1){
              if(f==0){                     //SELECCIONA EL SENTIDO DE GIRO DEL SERVO
       Servo_PWM[5]=valor5+3500;
       }
       else if(f==1){                       //CAMBIA DE GIRO DEL SERVO
       Servo_PWM[5]=11500-valor5;
       }}       
break;                                      //SALTA DEL CHANEL 6 AL CHANEL 7
case 6:                                     //TRABAJA EN EL CANAL 7 DEL EMISOR (RECORDAD QUE ES DE 3500 A 11500 ticks)
       if(n==0){
       if(input(PIN_C5) && input(PIN_C6)){
       Servo_PWM[6]=Ticks4Center;
       }
       if(g==0){                            //SELECCIONA EL SENTIDO DE GIRO DEL SERVO
       if(!input(PIN_C5)){
       Servo_PWM[6]=Ticks4Maximum;
       }
       else if(!input(PIN_C6)){
       Servo_PWM[6]=Ticks4Minimum;
       }}
       if(g==1){                            //CAMBIA DE GIRO DEL SERVO
       if(!input(PIN_C6)){
       Servo_PWM[6]=Ticks4Maximum;
       }
       else if(!input(PIN_C5)){
       Servo_PWM[6]=Ticks4Minimum;
       }}}
       else if(n==1){
              if(g==0){                     //SELECCIONA EL SENTIDO DE GIRO DEL SERVO
       Servo_PWM[6]=valor6+3500;
       }
       else if(g==1){                       //CAMBIA DE GIRO DEL SERVO
       Servo_PWM[6]=11500-valor6;
       }}       
break;                                      //SALTA DEL CHANEL 7 AL CHANEL 8
case 7:                                     //TRABAJA EN EL CANAL 8 DEL EMISOR (RECORDAD QUE ES DE 3500 A 11500 ticks)
       Servo_PWM[7]=2000;                   //SEÑAL PARA SINCRONISAR CON RECEPTOR       
break;
}}

if(!input(PIN_D1) && !input(PIN_D2)){       //accede a mi menu principal, al presionar los botones de D1 y D2
do{}while(!input(PIN_D1) && !input(PIN_D2));//.....al mismo tiempo.
menu_principal();
}
if(!input(PIN_D1) && !input(PIN_D3)){       //guarda la configuracion de la radio,al presionar....
do{}while(!input(PIN_D1) && !input(PIN_D3));//..... los botones de D1 y D3 al mismo tiempo.
recorrido_eeprom=0;
escribir_eeprom();
}

   } while (TRUE);
}   

///////////////////////////////////////////////////////////////////////////////
//                          MENU PRINCIPAL
///////////////////////////////////////////////////////////////////////////////

void menu_principal(void){

lcd_gotoxy(1,2);
lcd_putc("   MENU PRINCIPAL   ");

do{
if(!input(PIN_D3)){
         do{                           //SI -> eliminar...           
         }while(!input(PIN_D3));            //...rebotes del boton
p++;
if(p==3){p=0;}
}
else if(!input(PIN_D4)){
         do{                           //SI -> eliminar...           
         }while(!input(PIN_D4));            //...rebotes del boton
p--;
if(p==-1){p=2;}
}
switch (p){
           case 0:
                  lcd_gotoxy(1,3);
                  lcd_putc("~ INVERCION DE GIRO ");
                  if(!input(PIN_D1)){
                  do{                           //SI -> eliminar...           
                  }while(!input(PIN_D1));            //...rebotes del boton
                  menu_de_control();
                  }
                  if(!input(PIN_D5)){p=5;}
                  break;
           case 1:
                  lcd_gotoxy(1,3);
                  lcd_putc("~ CHANEL A/D o D/A  ");
                  if(!input(PIN_D1)){
                  do{                           //SI -> eliminar...           
                  }while(!input(PIN_D1));            //...rebotes del boton
                  conversion();
                  }
                  if(!input(PIN_D5)){p=5;}
                  break;
           case 2:
                  lcd_gotoxy(1,3);
                  lcd_putc("~ RANGOS DE TRABAJO ");
                  if(!input(PIN_D1)){
                  do{                           //SI -> eliminar...           
                  }while(!input(PIN_D1));            //...rebotes del boton
                  rangos_de_trabajos();           //llama a la funcion para modificar los rangos
                  }                                //de trabajo de los servos
                  if(!input(PIN_D5)){p=5;}
                  break;
                 
}
}while(p<4);
p=0;
}

///////////////////////////////////////////////////////////////////////////////
// MENU DE CAMBIO DE GIRO DE LOS SERVOS EN MI PROGRAMA PRINCIPAL
///////////////////////////////////////////////////////////////////////////////

Void menu_de_control(void){

do{
if(!input(PIN_D3)){
         do{                           //SI -> eliminar...           
         }while(!input(PIN_D3));            //...rebotes del boton
j++;
if(j==7){j=0;}
lcd_gotoxy(1,2);
lcd_putc("Rever               ");
lcd_gotoxy(1,3);
lcd_putc("Ch                  ");
}

if(!input(PIN_D4)){
         do{                           //SI -> eliminar...           
         }while(!input(PIN_D4));            //...rebotes del boton
j--;
if(j==-1){j=6;}
lcd_gotoxy(1,2);
lcd_putc("Rever               ");
lcd_gotoxy(1,3);
lcd_putc("Ch                  ");
}

switch(j){
case 0:
       lcd_gotoxy(1,2);
       lcd_putc("Rever |             ");
       if(!input(PIN_D1) && j==0){
                                  a=0;
                                  lcd_gotoxy(1,3);
                                  lcd_putc("Ch directo          ");
                                 }
       else if(!input(PIN_D2) && j==0){
                                       a=1;
                                       lcd_gotoxy(1,3);
                                       lcd_putc("Ch inverso          ");
                                       }   
       if(!input(PIN_D5)){j=9;}                                       
break;
case 1:
      lcd_gotoxy(1,2);
      lcd_putc("Rever  |            ");
      if(!input(PIN_D1) && j==1){
                                 b=0;
                                 lcd_gotoxy(1,3);
                                 lcd_putc("Ch directo          ");
                                 }
      else if(!input(PIN_D2) && j==1){
                                      b=1;
                                      lcd_gotoxy(1,3);
                                      lcd_putc("Ch inverso          ");
                                      }
       if(!input(PIN_D5)){j=9;}                                     
break;
case 2:
      lcd_gotoxy(1,2);
      lcd_putc("Rever   |           ");
      if(!input(PIN_D1)){
                         lcd_gotoxy(1,3);
                         lcd_putc("Ch directo          ");
                         c=0;
                         }
      else if(!input(PIN_D2)){
                              lcd_gotoxy(1,3);
                              lcd_putc("Ch inverso          ");
                              c=1;
                              }
       if(!input(PIN_D5)){j=9;}                             
break;
case 3:
       lcd_gotoxy(1,2);
       lcd_putc("Rever    |          ");
       if(!input(PIN_D1)){
                          lcd_gotoxy(1,3);
                          lcd_putc("Ch directo          ");
                          d=0;
                          }
       else if(!input(PIN_D2)){
                               lcd_gotoxy(1,3);
                               lcd_putc("Ch inverso          ");
                               d=1;
                              }
       if(!input(PIN_D5)){j=9;}                             
break;
case 4:
       lcd_gotoxy(1,2);
       lcd_putc("Rever     |         ");
       if(!input(PIN_D1)){
                          lcd_gotoxy(1,3);
                          lcd_putc("Ch directo          ");
                          e=0;
                          }
       else if(!input(PIN_D2)){
                               lcd_gotoxy(1,3);
                               lcd_putc("Ch inverso          ");
                               e=1;
                              }
       if(!input(PIN_D5)){j=9;}                             
break;
case 5:
       lcd_gotoxy(1,2);
       lcd_putc("Rever      |        ");
       if(!input(PIN_D1)){
                          lcd_gotoxy(1,3);
                          lcd_putc("Ch directo          ");
                          f=0;
                          }
       else if(!input(PIN_D2)){
                               lcd_gotoxy(1,3);
                               lcd_putc("Ch inverso          ");
                               f=1;
                              }
       if(!input(PIN_D5)){j=9;}                             
break;
case 6:
       lcd_gotoxy(1,2);
       lcd_putc("Rever       |       ");
       if(!input(PIN_D1)){
                          lcd_gotoxy(1,3);
                          lcd_putc("Ch directo          ");
                          g=0;
                          }
       else if(!input(PIN_D2)){
                               lcd_gotoxy(1,3);
                               lcd_putc("Ch inverso          ");
                               g=1;
                              }
       if(!input(PIN_D5)){j=9;}                             
break;
}
}while(j<8);
j=0;}

///////////////////////////////////////////////////////////////////////////////
// MENU DE CONVERCION DE SEÑAL ANALOGO/DIGITAL Ó DIGITAL/ANALOGO
///////////////////////////////////////////////////////////////////////////////

void conversion(void){

do{
if(!input(PIN_D3)){
         do{                           //SI -> eliminar...           
         }while(!input(PIN_D3));            //...rebotes del boton
q++;
lcd_gotoxy(1,3);
lcd_putc("CHANEL              ");
if(q==3){q=0;}
}
else if(!input(PIN_D4)){
         do{                           //SI -> eliminar...           
         }while(!input(PIN_D4));            //...rebotes del boton
q--;
lcd_gotoxy(1,3);
lcd_putc("CHANEL              ");
if(q==-1){q=0;}
}
switch (q){
           case 0:
                  lcd_gotoxy(1,2);
                  lcd_putc("Convers   |         ");
                  if(!input(PIN_D1)){
                  k=0;
                  lcd_gotoxy(1,3);
                  lcd_putc("CHANEL D/A          ");                 
                  }
                  else if(!input(PIN_D2)){
                  k=1;
                  lcd_gotoxy(1,3);
                  lcd_putc("CHANEL A/D          ");                 
                  }
                  if(!input(PIN_D5)){q=5;}
                  break;
           case 1:
                  lcd_gotoxy(1,2);
                  lcd_putc("Convers    |        ");
                  if(!input(PIN_D1)){
                  m=0;
                  lcd_gotoxy(1,3);
                  lcd_putc("CHANEL D/A          ");
                  }
                  else if(!input(PIN_D2)){
                  m=1;
                  lcd_gotoxy(1,3);
                  lcd_putc("CHANEL A/D          "); 
                  }
                  if(!input(PIN_D5)){q=5;}
                  break;
           case 2:
                  lcd_gotoxy(1,2);
                  lcd_putc("Convers     |       ");
                  if(!input(PIN_D1)){
                  n=0;
                  lcd_gotoxy(1,3);
                  lcd_putc("CHANEL D/A          ");
                  }
                  else if(!input(PIN_D2)){
                  n=1;
                  lcd_gotoxy(1,3);
                  lcd_putc("CHANEL A/D          "); 
                  }
                  if(!input(PIN_D5)){q=5;}
                  break;
}
}while(q<4);
q=0;
}
void escribir_eeprom(void){

write_eeprom(recorrido_eeprom,a);
recorrido_eeprom++;
write_eeprom(recorrido_eeprom,b);
recorrido_eeprom++;
write_eeprom(recorrido_eeprom,c);
recorrido_eeprom++;
write_eeprom(recorrido_eeprom,d);
recorrido_eeprom++;
write_eeprom(recorrido_eeprom,e);
recorrido_eeprom++;
write_eeprom(recorrido_eeprom,f);
recorrido_eeprom++;
write_eeprom(recorrido_eeprom,g);
recorrido_eeprom++;
write_eeprom(recorrido_eeprom,k);
recorrido_eeprom++;
write_eeprom(recorrido_eeprom,m);
recorrido_eeprom++;
write_eeprom(recorrido_eeprom,n);

                  lcd_gotoxy(1,3);
                  lcd_putc("~ GUARDANDO PROGRAMA");
                  delay_ms(1000);
                  lcd_gotoxy(1,3);
                  lcd_putc("~ LISTO.....        ");
                  delay_ms(1000);                 
}


void rangos_de_trabajos(void){

}

la pantalla de proteus es la que sigue:




Desconectado bmb

  • PIC18
  • ****
  • Mensajes: 423
Re: formula para DualRate valor0=rango1+(read_adc()/1022)*(8000-(2*rango1));
« Respuesta #7 en: 27 de Junio de 2010, 15:21:07 »
Holajapifer_22, revisando por ahora la parte de conversión de datos análoga, tienes en tu código:

 
Código: [Seleccionar]
 
int16 Valor0,Valor1,Valor2,Valor3,Valor4,Valor5,Valor6,Valor7;       // para 10 bits
   float resolucion= 5.0/1022.0;      // Conversión con 10 bits de la entrada analoga
   .
   .
   static int16 Servo_PWM[8];
   .
   .
   Valor0=read_adc()*resolucion*1600;
   set_adc_channel(1);              //toma el valor de medicion de la entrada analoga de 0 a 1022 (0 a 5V)
   .
   .

Aquí estás almacenando en una variable 'Valor0' que es de tipo int16, un resultado que es de tipo float, ya que la variable 'resolución' es de tipo float y la expresión:
Código: [Seleccionar]
read_adc()*resolucion*1600da como resultado un número flotante, perdiendo asi precisión;  luego estás trasladando esta imprecisión al manejo de los servos:

Código: [Seleccionar]
case 0:                                           //TRABAJA EN EL CANAL 1 DEL EMISOR (RECORDAD QUE ES DE 3500 A 11500 ticks)
       if(a==0){                                         //SELECCIONA EL SENTIDO DE GIRO DEL SERVO
       Servo_PWM[0]=valor0+3500;            //GUARDA EN MI STRING EL VALOR ANALOGO DEL CHANEL 1 Y HACE LA CONVERSION DE
       }                                                     //...LA ENTRADA ANALOGA AL MOVIMIENTO DEL SERVO (0.7 A 2.3ms
       .
       .)

Sin embargo, no veo por que involucras el valor de tipo flotante de la variable 'resolucion', que es el valor del voltaje que está ingresando por el pin análogo para obtener el valor PWM del servo, cuando para este valor solo necesitas un número entero escalado de acuerdo al valor de 10 bits de la entrada.

Un saludo.
« Última modificación: 27 de Junio de 2010, 15:24:41 por bmb »

Desconectado japifer_22

  • PIC18
  • ****
  • Mensajes: 405
Re: formula para DualRate valor0=rango1+(read_adc()/1022)*(8000-(2*rango1));
« Respuesta #8 en: 27 de Junio de 2010, 16:28:24 »
hola bmb, tienes toda la rason, no me avia dado cuenta de este error.
alguna sugerencia al respecto?  :lol:

de todas formas le voy a echar un vistazo ahora mismo al codigo para ver que puedo hacre al respecto :oops:

Desconectado bmb

  • PIC18
  • ****
  • Mensajes: 423
Re: formula para DualRate valor0=rango1+(read_adc()/1022)*(8000-(2*rango1));
« Respuesta #9 en: 27 de Junio de 2010, 23:31:32 »
Hola, te cuento que yo nunca he trabajado con servos, pero me entró la curiosidad y estoy consultando aquí en el foro y en otros sitios y ahora estoy haciendo un programa sencillo para manejar un Futaba que tengo aqui a la mano y con un potenciómetro por AN0.  Apenas lo tenga lo subo para ver si te sirve de ayuda.

Un saludo.

Desconectado japifer_22

  • PIC18
  • ****
  • Mensajes: 405
Re: formula para DualRate valor0=rango1+(read_adc()/1022)*(8000-(2*rango1));
« Respuesta #10 en: 28 de Junio de 2010, 22:20:40 »
hola,  comento que estado viendo todo este dia el tema, y me di cuenta que haga lo que haga me dice el compilador que mi programa es demasiado largo, lo que tu mensionas lo arregle con floor () de todas formas para dejar todo el valor en int16.

bmb:
Citar
Aquí estás almacenando en una variable 'Valor0' que es de tipo int16, un resultado que es de tipo float, ya que la variable 'resolución' es de tipo float y la expresión:
Código:

read_adc()*resolucion*1600

da como resultado un número flotante, perdiendo asi precisión;  luego estás trasladando esta imprecisión al manejo de los servos:

pero en fin me he dado cuenta que a llegado la hora de emigrar de familia, y a la vez, dar un paso mas en mi aprendisaje con los pic, es por esto que voy a tener que sltar al pic de la serie C18, para asi poder terminar este proyecto.

de todas formas si tiene alguna sugerencia al respeto, no dejen de decirme por favor OK ??

saludos!

a y de todas formas voy ha aqui mismo ir preguntando las dudas que tengas con este nuevo pic  :mrgreen:

Desconectado bmb

  • PIC18
  • ****
  • Mensajes: 423
Re: formula para DualRate valor0=rango1+(read_adc()/1022)*(8000-(2*rango1));
« Respuesta #11 en: 30 de Junio de 2010, 11:08:30 »
Hola japifer_22, lo de migrar de familia a los PIC18 está muy bien.  Como te comenté antes, estoy haciendo en los ratos libres un programa sencillo para manejar un servo y casualmente lo estoy haciendo con un PIC18.  Mi principal fuente de consulta, aparte de muchas otras,  ha sido la página de Redpic, de donde no solo he tomado muchas ideas, sino que también me ha quedado bastante claro el funcionamiento de los servos rc.  Inicialmente hice cambios del programa de don Diego para funcionar con un potenciómetro por una entrada análoga y lo simulé en Proteus.  Me gustaría preguntarte si aparte de simular tu proyecto en Proteus, lo has montado fisicamente en una protoboard; te lo pregunto porque comencé simulando en Proteus y todo funciona a la perfección.  Otra historia muy diferente es cuando lo monté en la protoboard...  Ahora estoy tratando de solucionar algunos problemas de inestabilidad del servo y si logro que me funcione bien, subo el programa para si te sirve de ayuda. 

Un saludo!

Desconectado bmb

  • PIC18
  • ****
  • Mensajes: 423
Re: formula para DualRate valor0=rango1+(read_adc()/1022)*(8000-(2*rango1));
« Respuesta #12 en: 30 de Junio de 2010, 17:00:16 »
Hola japifer_22, como lo prometido es deuda, aqui te dejo un programita sencillo para manejar un servo rc.  Como sugerencia te diría que comiences a montar tu circuito para hacerle pruebas y que si tienes un osciloscopio a la mano, te va a ser de mucha ayuda.  Como te digo el programa es muy simple, es para un solo servo aunque se puede facilmente modificar para más servos.  El programa está comentado, pero si tienes alguna duda con mucho gusto te la puedo aclarar.

Un saludo!