Autor Tema: Varios problemitas con la programación en C  (Leído 3055 veces)

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

Desconectado Chaly29

  • Moderador Global
  • DsPIC33
  • *****
  • Mensajes: 4315
Varios problemitas con la programación en C
« en: 17 de Junio de 2015, 22:52:06 »
Hola a todos, el colega arielmdq tiene unos problemitas con la programación en C.

Primeramente había problemas de hardware que ya los solucionamos y ahora esta complicado con el software, el programa en C y yo no estoy capacitado para darle una mano.

En este POST yo le pasé unos cálculos matemáticos para implementar el programa que necesita, el ya lo a intentado y se le presentaron los problemas que indica en este POST, porlo tanto a quien pueda darle una ayudita, se le estará muy agradecido.

Un saludo.

Atte. CARLOS.

La teoría es cuando se sabe todo y nada funciona. La práctica es cuando todo funciona y nadie sabe por qué.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8136
Re: Varios problemitas con la programación en C
« Respuesta #1 en: 18 de Junio de 2015, 03:11:45 »
Bueno, mirando solo y unicamente la parte de programacion sin mirar exactamente que debe hacer el programa me encuentro con los siguientes problemas:

1- Demasiadas escrituras a la EEPROM, va a hacer que se destruya en un ratito.
2- El float en XC8 es de 24bits por default, se puede agrandar a 32bits pero veo que el nombre que dice tu funcion es de 16bits.
3- La implementacion de "menu" esta mal, por que eso se ejecuta MUY rapidamente, lo cual guardar valores en la EEPROM va a ser muy rapido y tal ves es una sola presionada se grabe 30 veces. Y tal ves tengas que presionar 2 botones juntos.

De todas formas si queres usar la EEPROM, primero hacelo funcionar desde la RAM.
Y Como primer programa tambien deberias de hacer unicamente la funcion que te interesa,  luego hacer el menu aparte y finalmente juntarlo todo.


Desconectado juaperser1

  • Colaborador
  • DsPIC30
  • *****
  • Mensajes: 2901
Re: Varios problemitas con la programación en C
« Respuesta #2 en: 18 de Junio de 2015, 05:53:50 »
Bueno, pues como dice killer hay demasiadas escrituras de memoria, a parte eso lleva a muchos delay, uno por cada escritura o lectura, y eso nunca es bueno para llevar una base de tiempo como un pwm, si eso lo juntamos con que es CCS podemos tener bastantes funcionamientos extraños,.

En cuanto al tamaño de las variables que dice killer, no lo he mirado pero killer creo que no se ha dado cuenta de que es CCS y no xc8.
 
Lo primero que yo haría seria simular que el menú funcione correctamente. En cuanto a que no ves las variables. A cuales te refieres? En el CCS ? Hace ya muchísimo que no uso CCS pero hay se podía simular o ver variables?

Desgraciadamente estoy de exámenes y no puedo, ponerme ha arreglarte personalmente el programa lo siento :(

Un saludo.
Visita mi canal para aprender sobre electrónica y programación:

https://www.youtube.com/channel/UCxOYHcAMLCVEtZEvGgPQ6Vw

Desconectado arielmdq

  • PIC16
  • ***
  • Mensajes: 166
Re: Varios problemitas con la programación en C
« Respuesta #3 en: 18 de Junio de 2015, 08:11:17 »
Hola gente !!! muchas gracias por responder .Cuando leo sus respuestas me confunde un poco la parte en que dicen que se va a romper la eeprom.En la eeprom solo guardo 3 parametros que es a la hora de calibrar el instrumento y despues no se vuelve a tocar , o al menos esa es la idea y despues los uso para hacer los calculos .Pero tal vez este mal escrito el programa, tal como lo ven ustedes y sí ,este grabando continuamente pero eso no es lo que quiero.Me gustaria si alguno me puede sacar de esa duda por favor les estare agradecido.Saludos !!!!!
El tiempo es una ilusión ,solo existe el presente................

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8136
Re: Varios problemitas con la programación en C
« Respuesta #4 en: 18 de Junio de 2015, 13:57:04 »
Citar
En cuanto al tamaño de las variables que dice killer, no lo he mirado pero killer creo que no se ha dado cuenta de que es CCS y no xc8.

Si me confundi, de todas formas son de 24 bits igual.

Hola gente !!! muchas gracias por responder .Cuando leo sus respuestas me confunde un poco la parte en que dicen que se va a romper la eeprom.En la eeprom solo guardo 3 parametros que es a la hora de calibrar el instrumento y despues no se vuelve a tocar , o al menos esa es la idea y despues los uso para hacer los calculos .Pero tal vez este mal escrito el programa, tal como lo ven ustedes y sí ,este grabando continuamente pero eso no es lo que quiero.Me gustaria si alguno me puede sacar de esa duda por favor les estare agradecido.Saludos !!!!!

Lo dije por que la EEPROM tiene un numero limitado de escrituras y todo depende de cuanto las ibas a estar actualizando, como estaba el programa iba a ser seguro que cada ves que presionaras se guardara varias veces.
Pero para "evitar" por ahora la complicacion de guardar y leer la EEPROM podrias haberlo hecho en RAM, luego si lo haces en como queres.
El manual de CCS aporta un codigo de como escribir y leer un float(24bytes):

Código: C
  1. WRITE_FLOAT_EXT_EEPROM( long int n, float data) {
  2. int i;
  3. for (i = 0; i < 4 ; i++)
  4. write_ ext_ eeprom(i + n, *(((int 8 *)&data + i) ) ;
  5. }
  6.  
  7. float READ_FLOAT_EXT_EEPROM( long int n) {
  8. int i;
  9. float data;
  10. for (i = 0; i < 4; i++)
  11. *(((int 8 *)&data) + i) = read_ ext_ eeprom(i + n);
  12. return(data);
  13. }
(n tiene que ser multiplo de 4 para los floats ( 4bytes ) )

Lo raro que le ADC da un valor de 10bits como maximo y no tiene sentido que lo castees a float, como lo estas haciendo. si guardaras solo el valor del ADC entonces serian 16bits, pero bueno te dejo la funcion por igual

Con respecto al menu no soy de hacerlo de esa forma... Si es cosiderado un "menu" pero aca te dejo una parte del codigo:

Código: C
  1.                 if (input(pin_b4)==0)                                                   //switch que habilita la configuracion de parametros
  2.                 {                                                                        
  3.                         if (input(pin_b1)==1)                                           //switch que habilita para establecer
  4.                         {                                                               // el limite izquierdo ( toper)  
  5.                                 delay_ms(20);                                           // Antirebote
  6.                                 while(input(pin_b1));                                   // Espero hasta que suelte
  7.                                 write_int16_eeprom(0x120,(float) cursor);               // escribe en la memoria
  8.                                 delay_ms(15);                                           // el valor de toper
  9.                                 toper=read_int16_eeprom(0x120);          
  10.                         }
  11.  
  12.                         if (input(pin_b2)==1)                                           //switch que habilita para establecer
  13.                         {                                                               // el limite derecho ( topbr)
  14.                                 delay_ms(20);                                           // Antirebote
  15.                                 while(input(pin_b1));                                   // Espero hasta que suelte
  16.                                 write_int16_eeprom(0x122,(float) cursor);               // escribe en la memoria
  17.                                 delay_ms(15);                                           // el valor de topbr
  18.                                 topbr=read_int16_eeprom(0x122);
  19.                         }
  20.                         if (input(pin_b3)==1)                                           //switch que habilita para establecer
  21.                         {                                                               // el valor central  ( cero )
  22.                                 delay_ms(20);                                           // Antirebote
  23.                                 while(input(pin_b1));                                   // Espero hasta que suelte
  24.                                 write_int16_eeprom(0x126,(float) cursor);               // escribe en la memoria
  25.                                 delay_ms(15);                                           // el valor central (cero)
  26.                                 cero= read_int16_eeprom(0x126);
  27.                                 delay_ms(15);
  28.                         }
  29.                 }

La diferencia aca radica en que tenes que presionar y soltar el boton para que haga lo que debe el programa, esto para evitar que si lo tenes presionado siga entrando. Esta es una solucion simple, tambien esta la otra que es guardar el valor del puerto y hasta que no cambie no entrar de nuevo ahi.

Problemas que puede traer la solucion que dije arriba? Si tu PWM esta realizado por software va a dejar de funcionar mientras RB4 sea igual a 0, pero ese problema ya lo tenias antes.

Por otro lado te presento una nueva... alternativa solo para que lo penses si conviene o tal ves no.. en ves de guardar lo que da el ADC, si guardas directamente el valor de duty (16bits entero) ?, esto evitaria que tengas que volver a hacer TODAS las operaciones cuando arranque, y con una lectura de la EEPROM apenas arranca el programa, este arrancaria con el duty que dejo cuando se apago a diferencia como esta ahora el programa.
« Última modificación: 18 de Junio de 2015, 14:17:04 por KILLERJC »

Desconectado arielmdq

  • PIC16
  • ***
  • Mensajes: 166
Re: Varios problemitas con la programación en C
« Respuesta #5 en: 18 de Junio de 2015, 17:21:26 »
Wow cuantas cosas por aprender!!! .Muchas gracias killerjc !!! muy bueno todo lo que me explicas.Pero claaaaro ahora te entiendo lo del rebote al grabar en la eeprom  ,si con cada pulsacion se grabarian un monton de veces ja ja .Leí los 2 mensajes que pusiste y bueno creo entender ,pero a la vez se me siembran algunas dudas:
La idea de escribir en la eeprom ,es para que cuando se apague el instrumento no se pierdan esos parametros que guardo,segun tenia entendido en la RAM se me borrarian no es asi ?.

De todos modos para evitar confuciones me gustaria explicar como funciona esto : un vez que  instalo el instrumento necesito  calibrarlo ,como hago:pongo el switch en modo configuracion, muevo el timon todo para una banda por ejemplo a la derecha ( estribor ) grabo ese parametro ,lo muevo a la otra banda izquierda (babor)grabo el otro limite , lo llevo al centro  y grabo el cero o centro, muevo el switch a modo de uso y listo el programa se encargaria de hacer el resto (por lo visto no como estaba  el mio ja ja ).
Se supone que una vez que grabo estos 3 parametros, no los vuelvo a tocar nunca mas ,o hasta que para una reparacion, se desarme el sistema y se tenga que volver a calibrar .
Otra cosa que hace el programa y que no lo subi aca para simplificarlo un poco, es que cuando llega a los limites babor y estribor accionan unos reles que hacen que si el timon esta en modo electrico, cortan unas solenoides que lo frenan para no forzarlo. Bien sigo con las dudas:
                    El tema de las variables, en el programa original yo estaba usando int16 en todas ya que mi adc es de 10 bits y manejaba numeros de 0 a 1023 pero el programa era demasiado rustico ,(aclaro soy muy principiante y autodidacta programando) entonces  chaly me planteo lo de las cuentas y como vi que tenian coma ,pase todo a float pero aca empece con el problema ,que ahora veo que me mostras la forma correcta  de guardar un float en la eeprom,asi que al parecer ahi tenia un problema.
                   Ahora, se puede hacer con int16 ?
                  Como haria las cuentas con coma ?
                  Se pueden mezclar tipos distintas de variables en una cuenta ?
                  Si se me llenara la eeprom como la vacío ?
Aclaracion :No es problema que deje de funcionar el pwm cuando estoy configurando ya que en ese momento no necesito ver el instrumento, pero si leer el adc.
                Lo del menu ,supongo que intenta serlo ja ja ja :D .Aunque solo visualizo mediante 2 leds uno me muestra cuando esta en modo configuracion y otro cuando pulso el boton que graba en la eeprom , pero si me podes enseñar otra forma de hacerlo bienvenido sea .
Killerjc ,te agradezco un monton que te hallas interesado en el tema ,la verdad que cada vez que pregunto algo en el foro aprendo muchas cosas ,esta buenisimo!!!.Asi que voy a empezar a probar todo lo que me decis ,aunque me frena un poco el tema de las variables ,saber cual me conviene usar ? Bueno manos a la obra !!!! Mil gracias !!! Saudos !!!!

Hago otra aclaracion : en el while seria pin_bo  no  b1
                           
Código: C
  1. if (input(pin_b3)==1)                                            
  2.                         {                                                              
  3.                                 delay_ms(20);
  4.                                 while(input(pin_b1));           //Aca seria while(input(pin_b0));                                                                                                                                                                                              
  5.                                 write_int16_eeprom(0x126,(float) cursor);      
  6.                                 delay_ms(15);                                          
  7.                                 cero= read_int16_eeprom(0x126);
  8.                                 delay_ms(15);
« Última modificación: 18 de Junio de 2015, 17:34:13 por arielmdq »
El tiempo es una ilusión ,solo existe el presente................

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8136
Re: Varios problemitas con la programación en C
« Respuesta #6 en: 18 de Junio de 2015, 18:00:47 »
Bueno ahora que lo explicaste veo mejor que queres hacer.

Si el ADC es de 16 bits, y deberias guardarlo con 16 bits, y no llevarlo a float, cuando haces las operaciones recien ahi lo pones en float.

Otra cosa.. Yo pense que los limites eran fijos  y querias guardar por ejemplo el valor del duty. Ahora viendo tu explicacion. Observo un error.

Chaly dio las formulas como si fuera lineal desde el extremo izquierdo al extremo derecho, dejando el centro que se acomode solo con la formula.
Ahora si vos me decis que queres grabar los valores: "MAXIMO", "MINIMO" y "CENTRO".

Eso quiere decir que Entre centro y maximo vas a tener que multiplicarlo por un valor y minimo y centro por otro. Ya que centro muy rara ves te va a quedar JUSTO en la mitad de Minimo y maximo. Ahora si solo tomas esos 2 extremos ya no hay tantos problemas.
Ya que el centro se calcularia como (Maximo - Minimo)/2

Respondo las dudas ahora

Citar
Ahora, se puede hacer con int16 ?

Si se puede hacer. Hay cosas nomas que interesan que sean "float" es decir con decimales, por ejemplo lo que pasas como parametro en set_pwm_duty() es un entero, lo cual no interesa que tengan comas. C normalmente agranda el tamaño de las vriables para trabajar con las mismas. Poer hay veces que tenes que "castearlas" ( de cast en ingles ).

Suponete esto:

int ADCResultado = 1000, valor;

valor = ADCResultado * 1.6486 - 450.68

Asi como esta C va a convertir el resultado de la operacion ( ADCResultado*1.6486 ) en float , por que uno de los operandos tiene coma, luego sumas y vas a encontrarte que tiene coma tambien y lo va a seguir tratando como un float.
Luego cuando intenta guardar ese resultado en valor se encuentra que valor es un int, entonces transforma ese float a un int y lo guarda., Ahora si haces pasos intermedio si vas a tener que guardarlo como float

Con lo cual tu resultado del ADC, tu resultado de la operacion es decir el duty pueden ser enteros. Que es necesario que sea float? El resultado de hacer 1023 / (max-min) , pero eso no es necesario guardarlo.

Citar
Si se me llenara la eeprom como la vacío ?
No se te va a llenar ya que estas escribiendo siempre sobre la misma posicion, pero la idea es tocar lo menos posible la EEPROM


Citar
Hago otra aclaracion : en el while seria pin_bo  no  b1

Si ... se me fue en el copy paste de todos xD... en realidad lo que esta dentro del while es lo mismo que el if, asi:

Código: C
  1. if (input(pin_b3)==1)                                            
  2.                         {                                                              
  3.                                 delay_ms(20);
  4.                                 while(input(pin_b3));                          //Espero que suelte


Desconectado pablomanieri

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 639
Re: Varios problemitas con la programación en C
« Respuesta #7 en: 18 de Junio de 2015, 18:20:30 »
...Ahora si solo tomas esos 2 extremos ya no hay tantos problemas.
Ya que el centro se calcularia como (Maximo - Minimo)/2
...

El centro en realidad sería (Maximo+Minimo)/2

Saludos

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8136
Re: Varios problemitas con la programación en C
« Respuesta #8 en: 18 de Junio de 2015, 18:27:55 »
Perdon por el doble post,, pero espero que este codig te funcione:

Código: C
  1. #include <16f876a.h>
  2. #device adc =10
  3. #use delay (clock=8M)
  4. #fuses XT,NOWDT,NOPROTECT,NOLVP
  5. #include <internal_eeprom.c>
  6. #use fast_io(B)
  7. #use fast_io(c)
  8. #use fast_io(a)
  9.  
  10. //******declaracion de variables******************************
  11.  
  12. int16 cursor,toper,topbr,cero,ciclo_util;
  13. float c;
  14.  
  15. //***********************************************************
  16. void main()
  17. {
  18.         set_tris_c(0b00000000);
  19.         output_c(0b00000000);
  20.         set_tris_b(0b11111111);
  21.         output_b(0b00000000);
  22. //****************ADC**************************
  23.         setup_adc_ports(AN0);//* entrada analogica*//
  24.         setup_adc (ADC_CLOCK_INTERNAL);
  25.         setup_COUNTERS(RTCC_internal.rtcc_div_8);
  26.  
  27. // *************PWM**************************************
  28.  
  29.         setup_ccp1(CCP_PWM);
  30.         setup_timer_2(T2_DIV_BY_16,255, 1);
  31.         set_pwm1_duty(ciclo_util);
  32.    
  33. //**************Recupero Valores************************  
  34. //Aqui sis se reinicio tomo los valores , los calculo para lo que esta guardado en el EEPROM
  35.  
  36.  
  37.         toper=read_int16_eeprom(0x120);
  38.         delay_ms(15);                  
  39.    
  40.         topbr=read_int16_eeprom(0x122);
  41.         delay_ms(15);
  42.  
  43.         cero=(toper+topbr)/2;
  44.         c = (float)1023/(topbr - toper);
  45.    
  46.         WHILE (1)
  47.         {
  48.    
  49.                 set_adc_channel (0);
  50.                 delay_us (20);
  51.                 cursor = read_adc ();
  52.      
  53.  //*********************************************
  54.  // Programacion
  55.  //*********************************************
  56.  
  57.                 if (input(pin_b4)==0)                                                   //switch que habilita la configuracion de parametros
  58.                 {                                                                        
  59.                         if (input(pin_b1)==1)                                           //switch que habilita para establecer
  60.                         {                                                               // el limite izquierdo ( toper)  
  61.                                 delay_ms(20);                                           // Antirebote
  62.                                 while(input(pin_b1));                                   // Espero hasta que suelte
  63.                                 if(cursor!=toper)
  64.                                 {
  65.                                         write_int16_eeprom(0x120, cursor);              // escribe en la memoria
  66.                                         toper = cursor;
  67.                                         cero = (toper+topbr)/2;                         // Calculo nuevamente centro con el nuevo valor
  68.                                         c = (float)1023/(topbr - toper);                        // 1023 /(limite izq - limite derecho)
  69.                                 }
  70.                         }
  71.  
  72.                         if (input(pin_b2)==1)                                           //switch que habilita para establecer
  73.                         {                                                               // el limite derecho ( topbr)
  74.                                 delay_ms(20);                                           // Antirebote
  75.                                 while(input(pin_b2));                                   // Espero hasta que suelte
  76.                                 if(cursor!=topbr)
  77.                                 {
  78.                                         write_int16_eeprom(0x122, cursor);              // escribe en la memoria
  79.                                         topbr = cursor;
  80.                                         cero = (toper+topbr)/2;                         // Calculo nuevamente centro con el nuevo valor
  81.                                         c = (float)1023/(topbr - toper);                        // 1023 /(limite izq - limite derecho)
  82.                                 }
  83.                         }
  84.                 }
  85.    
  86.  
  87.   //********************************************
  88.   // Funcionamiento normal
  89.   //********************************************
  90.  
  91.                 if (input(pin_b4)==1)//switch que habilita el funcionamiemto
  92.                 {
  93.  
  94.                         if(cursor<topbr){cursor=topbr;}                                 // Fijo los limites de la entrada
  95.                         if(cursor>toper){cursor=toper;}
  96.  
  97.                         if(cursor>cero)                                                 // Caso que Cursor sea mayor a cero
  98.                         {
  99.                                 a = ((cursor-cero)*c)+cero;
  100.                         }
  101.                         else
  102.                         {
  103.                                 a = ((cero-cursor)*c)-cero;
  104.                         }
  105.                         if(a!=ciclo_util)                                               // Luego de los calculos, es necesario volver a cargar el duty ?
  106.                         {
  107.                                 set_pwm1_duty(a);
  108.                                 ciclo_util=a;
  109.                         }
  110.                 }
  111.         }  
  112. }

Cambios realizados:

- Cuando arranca el micro en la parte de configuracion ahi recupero los valores de la EEPROM y calculo los valroes necesarios, ya que estos tengo que calcularlos una sola ves.
- Elimine muchas funciones que hacian mas voluptuoso el programa, asi ademas condense las formulas para ocupar la menor cantidad e variables.
- Quite la programacion del "centro" por las razones que explique anteriormente, si aun asi deseas hacerlo con el centro, hay que cambiar el programa para que calcule las 2 distintas pendientes.
- Solamente se vuelven a calcular y guardar los valores SI es que cambiaron de los valores ay predefinidos, sino no vale la pena volverlos a calcular, esto es capricho mio, una para guardar lo menos posible en la EEPROM y la otra para ahorrar tiempo.
- Agregue los limites a cursor, si es menor o mayor de los valores esperados se fijan esos valores, ahi puede activarse algo si deseas.
- Por ultimo si no cambia el ciclo_util entonces que no actualize el PWM, esto en si no es preocupantes, en ciclo_util mantengo el valor viejo, y "a" es el valor nuevo.

Una cosa que no agregue es cuando "cursor" es igual a "cero", que lo podria haber realizado con unos else if. Y hubiera quedado de esta forma:

Código: C++
  1.                         if(cursor>cero)                                                 // Caso que Cursor sea mayor a cero
  2.                         {
  3.                                 a = ((cursor-cero)*c)+cero;
  4.                         }
  5.                         else if (cursor<cero)
  6.                         {
  7.                                 a = ((cero-cursor)*c)-cero;
  8.                         }
  9.                         else
  10.                         {
  11.                                 a=512;
  12.                         }

PD: Gracias por la correccion pablomanieri
« Última modificación: 18 de Junio de 2015, 19:04:27 por KILLERJC »

Desconectado arielmdq

  • PIC16
  • ***
  • Mensajes: 166
Re: Varios problemitas con la programación en C
« Respuesta #9 en: 18 de Junio de 2015, 18:33:56 »
Pero Si necesito grabar el centro .El centro en los timones nunca esta a la mitad exacta de los dos extremos puede diferir un poquito  
lo que no me quedo claro es como primero tengo el adc en un int16 y despues lo paso a float para hacer las cuentas .Lo declaro global como int16 y despues local como float ? como seria ?
Ahora te entendi lo que me explicas del while para grabar en la eepron ,de esta manera no nesecito boton solo con colocar el switch y cuando lo cambio de posicion se grabaria .Antes yo lo hacia colocando un switch de bajo a alto para entrar en la configuracion de ese parametro y luego con un boton lo gravaba. Gracias !!!!


A disculpa recien veo que subiste un codigo , lo leo y despues te cuento muchas gracias !!!!
El tiempo es una ilusión ,solo existe el presente................

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8136
Re: Varios problemitas con la programación en C
« Respuesta #10 en: 18 de Junio de 2015, 18:53:09 »
Tenes que entender esto de C:

Entero * Entero => resultado en entero => asigno resultado al lugar destino.

float c;
int16 a=5,b=2;

c = a / b;

entero / entero => entero => luego asigno ese entero al float
5/2 => 2 => 2.0

eso por que son variables, ahora si yo le digo al compilador que los trate como float

c = (float)a/b

entero(casteado a float) / entero => resultado en float => asigno a c
5(como float)/2 => 2.5 => c=2.5

Si fueran constantes podrias hacer:

c = 5.0/2

al tener una coma se lo toma como flotante.
Ahora un ejemplo un poco mas concreto a lo tuyo

a = ((cursor-cero)*c)+cero;

entero - entero = entero  (cursor-cero)

entero * flotante = flotante (resultado anterior por c )

flotante + entero = flotante ( toda la ecuacion)

flotante asignado al entero, le quita lo de la coma.


-------------------------------


Cambiando de tema, si me decis que el centro no se encuentra en el medio, entonces para un lado o para el otro va a tener disitnta "pendiente" la funcion, lo que hizo Chaly matematicamente hablando es encontrar una pendiente a una recta en el que entra valores (topbr a centro) y sale con valor 0 a mitad del duty. (y= cx +z <= funcion de una recta)

Ahora si vos cambias el valor centro por uno mas chico por ejemplo, esa funcion, va a tener que crecer mas rapido la señal, por lo cual "c" tiene que se mas grande del lado izquierdo, pero en el lado derecho va a tener que tomar otro valor, un valor mas chico. Asi que ahora tenes que tener un "c" para cada lado. Una funcion distinta para cada lado. Espero hacerme entender.
« Última modificación: 18 de Junio de 2015, 19:08:05 por KILLERJC »

Desconectado arielmdq

  • PIC16
  • ***
  • Mensajes: 166
Re: Varios problemitas con la programación en C
« Respuesta #11 en: 18 de Junio de 2015, 19:49:30 »
Disculpa la demora para responder,justo cuando esto se esta poniendo bueno ..... ,pero tengo un bebe de 4 meses y me toco bañarlo  :) ,Ahora y leyendo rapido para tratar de responder ,sos un capo como me explicaste todo , muchas gracias!!! creo que voy  entendiendo esto de las variables  . Estaba revisando el programa mio y tenes razon estaba usando la misma constante (c) para ambos lados y tendria que ser una para cada lado, por que es asi , depende como este armada la parte mecanica del timon puede que una banda sea mas amplia para un lado que para el otro. De todos modos probe el codigo que me pasaste pero no funciona , lo simule en proteus pero cuando tengo el pote en el centro no me marca 2,5 volt y cuando esta en los extremos no llega ni a 0v  ni a 5v  .Pero bueno voy a revisar todo de nuevo mas tranquilo a ver que me surge
El tiempo es una ilusión ,solo existe el presente................

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8136
Re: Varios problemitas con la programación en C
« Respuesta #12 en: 18 de Junio de 2015, 20:22:27 »
Puede que le erre en algo, estoy haciendolo en el bloc de notas, no lo estoy simulando ni nada por el estilo. Luego sigo agregando mas cosas. Para que tengas en cuenta, y tal ves le ponga un poco de matematica.. Asi que espero que logres entenderme.

Desconectado arielmdq

  • PIC16
  • ***
  • Mensajes: 166
Re: Varios problemitas con la programación en C
« Respuesta #13 en: 18 de Junio de 2015, 20:47:43 »
Si si muchas gracias , creo que te voy entendiendo bien ,pero tranqui cuando puedas .
                                                                                                                      Saludos !!!!
El tiempo es una ilusión ,solo existe el presente................

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8136
Re: Varios problemitas con la programación en C
« Respuesta #14 en: 18 de Junio de 2015, 23:02:45 »
Bueno no se en que esta fallando mi codigo, ya lo voy a tener que simular y ver realmente que es.


Por ahora continuo..

Calculando los valores correctos
Como dije estamos tratando de crear una recta que pasa por 2 puntos bien definidos. Una recta para la izquierda y otra para la derecha del centro. Esta ecuacion de la recta va a transformar nuestra entrada ( x  o cursor ) en un valor de salida (y o duty)
Entonces primero debemos encontrarla, para esto tu programa debe de calcular esa recta.

Entonces buscamos un poco de informacion https://es.wikipedia.org/wiki/Recta
Y encontramos que la ecuacion de nuestra recta que pasa por los puntos (x1,y1) y (x2,y2) esta dado por la ecuacion:



Para dar un ejemplo voy a usar los valores que dio Chaly en el post que te explico,
Sabemos que cuando sea minimo ( es decir cursor=x=205 , nos tiene que dar como resultado 0 ) , o es lo mismo que decir (205,0) x1=205 e y1=0
Por otra parte sabemos que cuando llegue a su maximo 818, tiene que llegar a 1023 es decir (818,1023) o x2=818 e y2=1023.

Si reemplazamos esos valores nos va a dar una formula asi:

1.6688 * X - 342.11  

( yo me ayude con una pagina )
https://www.wolframalpha.com/input/?i=line+through+%28205%2C0%29+and+%28818%2C1023%29

Es decir si yo tengo una X con un valor de 205 a 818 de ahi sale 0 a 1023 , la mitad en caso que sea igual para ambos lados (205+818)/2 = 516
Con ese valor y la perdida de algunos valores luego de la coma me da como salida 519 casi casi cerca de la mitad. Si tomara exactamente todos los digitos daria 511.5 exacto ( es decir 1023/2 )

Ahora como dije si movemos el centro y queremos que en todo el recorrido ya sea izquierda o derecha vaya variando de forma lineal, necesitamos de 2 rectas.
Una del minimo al centro, y la otra del centro al maximo. Yo agregue que solo cuando pasa por el centro ya me de el valor 511

Es decir los puntos serian:

una de (min,0) a (centro,511)
Y otra de (centro,511) a (max,1023)
si es igual a centro(511) se obtiene 511 directamente de las rectas, pero para evitar que posible falta de precision no llegue al valor de 511 como salida, hago que cuando cursor sea igual a centro, salga un 511. (511.5 seria lo exacto pero no admite coma el duty)

reemplazando los valores en la ecuacion de la recta tenemos:

Yizq = 511 / (centro-min) X -  ((511*min) / (centro-min))

Yder = 512 / (max-centro) X + 511 -  ((512*min) / (max-centro))

Finalmente tenemos las 2 formulas, el calculo es complejo asi que mientras menos se haga mejor, por que lleva mucho tiempo.

Segun el valor de cursor, si esta por debajo de centro se va a usar Yizq (salida de 0-510), si esta por encima se va a usar Yder(salida de 512 a 1023), si es igual a centro entonces es igual a 511

Vamos a hacer unos ejemplos.....

min = 100
max = 1000
centro = 400

2 lineas de
(100,0) a (399,510)           =>     y=510/299x - 51000/299     , https://www.wolframalpha.com/input/?i=line+through+%28100%2C0%29+and+%28399%2C510%29
(401,512) a (1000,1023)    =>     y=511/599x + 101777/599  , https://www.wolframalpha.com/input/?i=line+through+%28401%2C512%29+and+%281000%2C1023%29
1 punto:
(400,511)

Y una grafica de las 2 rectas
http://m.wolframalpha.com/input/?i=plot+%28510%2F299%29*x+-+51000%2F299%2C+%28511%2F599%29*x+%2B+101777%2F599%2C+x%3D0+to+1000&x=0&y=0

Se puede ver como una comienza en x=100 y equivale a Y=0 a medida que aumenta se cruzan en aproximadamente 400 que es el centro y de ahi en adelante se usa la otra linea, que cuando llega a 1000 es 1023.

Ecuacion de la recta:
Y = Ax + B

Fijate en las formulas que A y B son numeros. Esos numeros los vas a tener que calcular cada ves que modifiques los valores de derecha,izquierda y centro.

Toma de datos del ADC

Con una sola toma de datos del ADC es mas que suficiente, pero es muy comun que siempre esten variando los ultimos bits, entonces para eliminar esto recurrimos a un promedio, usamos un multiplo de 2^n para que sea mas simple para el micro

for(i=0;i<8;i++)
{
  cursor += read_adc ();
}

cursor/=8;

Es decir sumo 8 resultados y luego lo divido por 8, con 8 siendo el maximo de 1023 es de 8184 (8*1023) asi que no va a superar los 16bits de mi variable.

Por ultimo y mas importante EL USUARIO!!!

Si ese que mete la pata en los mejores momentos y hacen que el programa funcione mal, por su ineptitud o descuido. Entonces hay que tomar ciertos "cuidados", siempre desconfia del usuario, incluso aunque seas vos mismo.
Por ejemplo teniendo estos valores:

min = 200
max = 800

y alguien le cambia el centro a el valor 100.. No hay nada que lo evite.
Otra cosa, imaginate ahora que le ponga un valor de 201. Tambien otro comportamiento "no previsto".

Entonces te tenes que asegurar de algunas cosas.. Dejar un espacio minimo entre min y max, asi no se juntan demasiado, tambien definir un espacio minimo entre min-centro y centro-max. Y que se cumpla que min < centro < max
Esto evitaria todas esas clases de problemas, si alguno mete la manito, o un dia te levantaste mal y presionaste sin querer algo por lo menos no va a andar tan mal.

PD: tal ves me fui un poco en la matematica pero es para que entiendas de donde calcular los valores de la formula. Que luego queres implementar en tu programa.
« Última modificación: 19 de Junio de 2015, 14:51:17 por KILLERJC »


 

anything