TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Xa2 en 21 de Julio de 2004, 03:14:00

Título: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 21 de Julio de 2004, 03:14:00
Buenas gente, haber si podeis ayudarme!!
Deseo generar un duty cycle dependiendo de la velocidad que queremos que gire, es decir, se introduce la velocidad en r.p.m. y se transmite via serie, entonces el PIC generara un PWM dependiendo de esta velocidad, la regla de tres es la siguiente
(velocidad*100)/3900.0=el resultado es el duty cycle que queremos; luego logicamente nos daria una velocidad, que muy dificilmente coincidiria con la deseada, entonces habria que sacar el error y multiplicarlo por una constante y enviar de nuevo otro duty, en funcion del error y la constante (en resumen un lazo Proporcional)!!!
Pero mi primera duda  es la primera, la segunda ya se intentaria solucionr mas adelante!!
 Aqui os mando lo que he hecho, pero no funciona correctamente!!!
Creo que es por alguna definicion de variables, pero si mem pudierais ayudar mejor!!

codigo:

#include <16f873.h>
#device adc=10
#include <stdlib.h>

#fuses XT, NOPROTECT, NOWDT, NOPUT, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8)
#zero_ram

int opcion;
int i;
int16 duty;
int16 pulsos;
int16 interrupcion;
int16 velocidad;
int16 recibido;
int  reset;
float dato;
//float const resolucion=5.0/1024.0;
int16 value;
char string[10];
//float corriente;
//float sumacorriente;
//float corrientemedia;
int habilitacion;
//int convertidor;
int32 tiempoReal;
int32 Tiempo;

#int_RTCC   //se determina la funcion de la interrupcion

RTCC_isr()
{

    if(habilitacion==1)
    {

         tiempoReal++;   //se suma a una variable que computa el tiempo transcurrido

         pulsos=get_timer1();    //se obtiene el valor del contador timer1
         interrupcion++;   //se suma en uno el flag de interrupcion
         if(interrupcion==100)   //cuando se llega a 100, es decir, 1 segundo, 100*10ms=1000ms=1seg; se introduce en la funcion
         {
            velocidad=pulsos*15;   //sacamos la velocidad con una regla de tres
            printf("%lu r.p.m.
",velocidad);  //tambien puerto serie

            /* ************ convertidor analógico *****************
            for(i=0;i<10;i++)
            {
            set_adc_channel( 0 );       //el canal 0, entrada AN0
            delay_us(160);                //delay 1us
            value = read_adc();
            dato = value*resolucion;
            corriente=dato;   //una R=0,005 -->  V=IR; I=V/R; corriente=dato/R=dato/0.005=corriente

                 sumacorriente=sumacorriente+corriente;
                 corrientemedia=sumacorriente/10.0;
            }
            printf("%1.3f A
",corrientemedia);*/
            printf("%lu duty",duty);
            Tiempo=tiempoReal*0.01;
            printf("%lu segundos", Tiempo);
            //corrientemedia=0;
            //sumacorriente=0;

            interrupcion=0;  //se inicializa de nuevo el flag de interrupcion para que vuelva a contar 100 interrupciones
            set_timer1(0);   //se inicializa tambien el contador
            set_rtcc(178);   //se introduce de nuevo el valor del temporizador de interrupcion
         }
         else
         {
            set_rtcc(178);
            set_timer1(pulsos);
         }
    }

}








main()
{
   //set_tris_b(0x00);     //si se habilita no se puede sacar el PWM 1
   enable_interrupts(GLOBAL); //se habilitan interrupcion general
   enable_interrupts(INT_RTCC);  //habilita int. del timer0
   setup_timer_0 ( RTCC_INTERNAL | RTCC_DIV_128);  //se configura el timer0 como temporizador y una báscula de 128
   set_rtcc(178); //10ms -> 10000us -> 10000/128=78 -> 255-78=177 se le inserta el tiempo a contar, se suma uno
   duty = 0;   //se inicializa el duty en cero
   setup_ccp1(CCP_PWM); //Se habilita el pwm 1
   setup_timer_2(T2_DIV_BY_16, 99, 1); //Se establece el valor de la frecuencia de 620Hz(1,6 ms el periodo) para el PWM
   set_pwm1_duty(duty); //se manda el duty al PWM
   //setup_adc_ports( ALL_ANALOG ); //todo el puerto analogico
   //setup_adc( ADC_CLOCK_INTERNAL ); //convertidor con clock interno



   setup_timer_1(T1_EXTERNAL | T1_DIV_BY_1); //se configura el timer1 como contador, de pulsos externos y de báscula 1
   set_timer1(0); //se inicializa el contador en cero

   interrupcion=0;   //se inicializan los flags
   habilitacion=0;
   //convertidor=0;
   tiempoReal=0;
   Tiempo=0;

   while(true)
   {
   //el programa principal que estaria haciendo, esperando a la interrupcion del timer0

               //while(!kbhit());


               gets(string); //Guarda el Duty (0-255) en la variable string aunque solo necesitamos hasta 100
                              //y espera un RETURN (Ctrl 13)
               opcion=atoi(string); //Usa la función ATOI para pasarlo a entero
         switch (opcion) {

            case 3:  //recibido duty cycle

                  while(true)
                  {
                     gets(string);
                     recibido=atol(string);
                     if(recibido==200 || recibido==201);

                        reset_cpu();

                     else
                        duty=recibido;
                        set_pwm1_duty(duty); //El caracter ascii recibido pasado a entero
                                    //establecido como ciclo de trabajo
                        habilitacion=1;   //flag pata habilitar el contaje de los pulsos de velocidad del optoacoplador

                  }
                  break;

            case 4:  //recibido velocidad

                  while(true)
                     {
                     gets(string);
                     recibido=atol(string);
                     if(recibido==200 || recibido==201)

                        reset_cpu();


                     else

                        duty=(recibido*100.0)/3900.0;
                        set_pwm1_duty(duty);
                        habilitacion=1;

                     }
                  break;   }



   }

}


PD: en el codigo estoy intentando tambien tener la opcion de poder controlar con la velocidad o con el duty cycle; por eso la sentencia CASE!! Dpendiendo de lo que le llegue por el puerto serie (un 3 o un 4)!!
Muchas gracias y saludos!!!
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 21 de Julio de 2004, 03:39:00
Buenas de nuevo!!
Acabo de solucionar el problema, ya puedo controlar mediante el duty cycle y la velocidad si lo deseo, dependiendo de lo que me llegue por el puerto serie!!

Ahora solo me falta realizar el lazo cerrado Proporcional, si alguien podria ayudarme, es uqe no tengo ni idea de como se podria realizar.
Este lazo solo se podria realizar en el control mediante velocidad, no en el control mediante duty!!
Entonces yo solo se que tengo sacar el error, es decir, la diferencia entre la velocidad medida y la deseada, y luego ese error multiplicarlo por una constante ygenerar otro duty, y asi ir acercandonos al velocidad deseada!!
Eso enteoria, pero como se podria hacer programando??? Como se calcularia la konstante, por la cual hay que multiplicar???
Gracias y saludos, os pongo el nuevo codigo:


#include <16f873.h>
#device adc=10
#include <stdlib.h>

#fuses XT, NOPROTECT, NOWDT, NOPUT, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8)
#zero_ram

int opcion;
int i;
int duty;
int16 pulsos;
int16 interrupcion;
int16 velocidad;
int16 recibido;
int  reset;
float dato;
int16 value;
char string[10];
int habilitacion;
int32 tiempoReal;
int32 Tiempo;

#int_RTCC   //se determina la funcion de la interrupcion

RTCC_isr()
{

    if(habilitacion==1)
    {

         tiempoReal++;   //se suma a una variable que computa el tiempo transcurrido

         pulsos=get_timer1();    //se obtiene el valor del contador timer1
         interrupcion++;   //se suma en uno el flag de interrupcion
         if(interrupcion==100)   //cuando se llega a 100, es decir, 1 segundo, 100*10ms=1000ms=1seg; se introduce en la funcion
         {
            velocidad=pulsos*15;   //sacamos la velocidad con una regla de tres
            printf("%lu     ",velocidad);  //tambien puerto serie

         
            printf("%u     ",duty);  //imprimo el duty para saber cual nos ha generado
            Tiempo=tiempoReal*0.01; //calculo el tiempo en segundos trnascurrido
            printf("%lu     ", Tiempo); //imprimo el tiempo
            interrupcion=0;  //se inicializa de nuevo el flag de interrupcion para que vuelva a contar 100 interrupciones
            set_timer1(0);   //se inicializa tambien el contador
            set_rtcc(178);   //se introduce de nuevo el valor del temporizador de interrupcion
         }
         else
         {
            set_rtcc(178);
            set_timer1(pulsos);
         }
    }

}








main()
{
   enable_interrupts(GLOBAL); //se habilitan interrupcion general
   enable_interrupts(INT_RTCC);  //habilita int. del timer0
   setup_timer_0 ( RTCC_INTERNAL | RTCC_DIV_128);  //se configura el timer0 como temporizador y una báscula de 128
   set_rtcc(178); //10ms -> 10000us -> 10000/128=78 -> 255-78=177 se le inserta el tiempo a contar, se suma uno
   duty = 0;   //se inicializa el duty en cero
   setup_ccp1(CCP_PWM); //Se habilita el pwm 1
   setup_timer_2(T2_DIV_BY_16, 99, 1); //Se establece el valor de la frecuencia de 620Hz(1,6 ms el periodo) para el PWM
   set_pwm1_duty(duty); //se manda el duty al PWM



   setup_timer_1(T1_EXTERNAL | T1_DIV_BY_1); //se configura el timer1 como contador, de pulsos externos y de báscula 1
   set_timer1(0); //se inicializa el contador en cero

   interrupcion=0;   //se inicializan los flags
   habilitacion=0;
   tiempoReal=0;
   Tiempo=0;

   while(true)
   {
   //el programa principal que estaria haciendo, esperando a la interrupcion del timer0

               //while(!kbhit());


               gets(string); //Guarda el Duty (0-255) en la variable string aunque solo necesitamos hasta 100
                              //y espera un RETURN (Ctrl 13)
               opcion=atoi(string); //Usa la función ATOI para pasarlo a entero
               
         switch (opcion) {    //case para entrar en un ocdigo u otro

            case 3:  //recibido duty cycle se controla mediante duty cycle con un rango

                  while(true)
                  {
                     gets(string);  //recibo la cadena
                     recibido=atol(string);  //la convierto la cadena a entero
                     if(recibido==150 || recibido==151)  //si se envia cualquiera de estos dos numeros se resetea el PIC, reset por software
                        {
                           reset_cpu();
                        }
                     else     //si no se ha recibido reset o desconexion, se prosigue a realizar el duty
                        {
                           duty=recibido;  
                           set_pwm1_duty(duty); //El caracter ascii recibido pasado a entero
                                       //establecido como ciclo de trabajo
                           habilitacion=1;   //flag pata habilitar el contaje de los pulsos de velocidad del optoacoplador
                        }
                  }
                  break;

            case 4:  //recibido velocidad se controla mediante velocidad con un rango

                  while(true)
                     {
                     gets(string);
                     recibido=atol(string);
                     if(recibido==150 || recibido==151)
                        {
                           reset_cpu();
                        }
                     else     //si no se ha recibido el reset o desconexion se prosigue a ejecutar el duty
                        {
                           duty=(recibido*100.0)/3900.0;
                           set_pwm1_duty(duty);
                           habilitacion=1;
                        }
                     }
                  break;   }        //fin del "CASE"



   }

}
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: nordestenica en 21 de Julio de 2004, 04:55:00
Xa2 me as dejado estoy intentando acer algo parecido a esto e me e passado meses e nada de nada e de repente aparece un genio e en dos dias lo consigue

que dezirte bueno que eres un genio e perguntarte si puedo usar parte de tu codigo para mi bichito que estoy construiendo ace 4 meses e no me salia ni por nada
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 21 de Julio de 2004, 05:50:00
Gracias asi da gusto!!
Claro que puedes utilizarlo parte, pero hay que cambiar 150 y 151 por 5000 y 5001, ya que si introduces una velocidad de 150 o 151 el PIC se resetea!!!
Saludos!!
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: pocher en 21 de Julio de 2004, 12:14:00
Te felicito Xa2, con la información que te dimos y con lo que tu has añadido te ha quedado un proyecto chulo.

Ahora a ver como solucionas lo de los decimales en el Duty de la velocidad ... estoy seguro que lo conseguirás.

Un saludo
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 21 de Julio de 2004, 12:41:00
Gracias Pocher!!!
Todo un cumplido viniendo de ti, muchas gracias!!!
No tengo el problema del duty, mi problema es otro, es el lazo proporcional!!!
Que no se que calculos hay que hacer ni nada!!
Haber si podeis ayudarme o mandarme alguna informacion buena!!
Gracias y saludos!!!
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: pocher en 21 de Julio de 2004, 12:48:00
Sí creo que sí que son los decimales. Mira un ejemplo:

Si mandas una v=60 r.p.m. ---> CCPR1L (Duty)=(60·100)/3900=1,5 entonces como la variable duty es entera toma 1 y claro ya no irá a 60 r.p.m. irá a menos

Si mandas una v=180 r.p.m. ---> CCPR1L (Duty)=(180·100)/3900=4,6 entonces como la variable duty es entera toma 4 y claro ya no irá a 180 r.p.m. irá a menos

PD. ¿Elegiste 4 radios en el disco, no?
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 21 de Julio de 2004, 15:02:00
Si elegi 4 radios en el disco!!
Pero si tengo decimales, no puedo mandar flotantes para el PWM, solo enteros, entonces como se mandaria con decimales??
De todas formas luego vendria el lazo cerrado de velocidad proporcional y se corregiria el error o diferencia de velocidades deseadas y obenidas!!
No se contestame que te parece, o que harias tu!!!
Gracias de nuevo, no se que haria sin ti, jejej y luego dicen que soy un genio, pero si aqui el unico genio eres tù!!!
Saludos
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: pocher en 22 de Julio de 2004, 00:32:00
Entre todos vamos haciendo camino ...

No te prometo nada, si puedo miraré lo del control P.

Un saludo
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: pocher en 22 de Julio de 2004, 06:56:00
Oye si tienes el "chiringuito" montado podrías comprobar y decirme que velocidades devuelve si le envias por ejemplo 60 r.p.m., 120 r.p.m., 180 r.p.m. y 3900 r.p.m.
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 22 de Julio de 2004, 07:07:00
Pues ahora mismo no, porque esoty haciendo la placa y estoy teniendo unos problemillas, pero te puedo decir que la minima velocidad es de 700 r.p.m., ya que cuando introduces menos el motor no gira, no le llega suficiente intensidad!!
Si te sirve de ayuda!!
Cuando termine de monatr, te dejo el resto de datosQ!Q
Saludos^Pocher !!!
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 22 de Julio de 2004, 07:23:00
Ya esta, a 3900 r.p.m. me dan 3600 r.p.m. alrededor, siempre por esos valores!!
Las demas velocidades no me da!!
Tu me diras!!
Saludos
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: pocher en 22 de Julio de 2004, 12:05:00
Pués sí que se va de mucho y eso que para 3900 r.p.m. no hay decimales (sale un duty justo igual a 100).

¿Porqué en esta medida se va de tanto? Prueba a conectar el motor directamente a alimentación (es de 5V, 12V, ... ¿?) a ver si saca las 3900 r.p.m. (velocidad máxima especificada en el motor), ya me dirás cuanto sale ahora.
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 22 de Julio de 2004, 14:00:00
Nosotros lo alimentamos a 13,2 V; pero te voy a decir porque cuando pongo 3900 r.p.m. deseadas salen 3600; es porque en el programa hago una regla de tres, y he supuesto que al 100 de duty la velocidad es de 3900, cuando es alrededor de 3600; por eso sale la diferencia, si se pone en el programa entre 3700 donde pone entre 3900; al desear 3700 r.p.m. nos saldria unas 3680 o siempre por esos valores.
Por eso nos sucede ese error!!
Creo que es por eso, si te vale la respuesta??
Saludos!!!
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 22 de Julio de 2004, 14:05:00
Joder se me ha olvidado decirte que en el motor tenemos una resistencia shunt de 1 ohmio; entonces hay una caida de tension de como maximo de 120 mV; esta medido, por lo que al motor le llegan 13,1 V mas o menos; te lo digo para que lo sepas aunque no creo que influya en la diferencia de velocidad real y velocidad del motor deseada!!
Yo creo que es por lo que te he dicho antes!!
Seguire probando cambiando la regla de tres que te he dicho, y te dare los resultados!
Saludos!!!

Título: RE: Control motor introduciendo la velocidad!!
Publicado por: pocher en 23 de Julio de 2004, 00:03:00
Claro, claro en el programa tienes que cambiar el 3900 por la velocidad máxima real medida, si no lo estarías engañando.
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 23 de Julio de 2004, 03:08:00
Una vez solucionado esto, haber si me pdeis ayudar con el problema del control proporcional, que estoy desesperado!!!
Haber si me facilitais por lo menos informacion para que la trabaje yo; o algo asi, no os pido el codigop hecho, solo posible ayuda para ir haciendo algo.
Saludos y espero que podais, pero si no tranquilos eh???
Gracias!!!
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 23 de Julio de 2004, 03:57:00
Ahhhh!!!!
Pocher te tengo que decir que la variacion de la velocidad del motor medida, respecto del duty introducido no es lineal, es exponencial!!!

Te pongo los datos para que los veas mejor



Duty            Velocidad medida
19       Nada
20       135
21         300
22        480
23        645
25        945
30        1605
35        2100
40        2460
45        2730
50        3000
55        3030
60        3270
65        3300
70        3330
75        3375
80        3420
85        3450
90        3465
95        3570
100      3690-3700


Creo que la gran variacion que hay a pequeños dutys es por la resistencia shunt, ya que se hace mas influyente al llegar menos tension al motor, por lo que la caida de la R es mas apreciable y daterminante!!!
Saca tus conclusiones!!!
Saludo!!!!
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: pocher en 23 de Julio de 2004, 04:50:00
Tienes por ahí la tabla de velocidades (teórica --- medida) poniendo en el programa el 3700?
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: pocher en 23 de Julio de 2004, 10:24:00
Intenté hacerlo con una banda proporcional y porcentajes pero desistí.

Mira lo que he pensado:

Imaginemos que mandamos VRS232=3000r.p.m. el programa aplica la fórmula y le sale un determinado Duty, este Duty es aplicado al motor que a su vez mediante el opto envia pulsos. El programa calcula la nueva velocidad y le sale 3450r.p.m. (según tu tabla) por lo tanto hemos de reducir el Duty para que vaya más despacio.

El nuevo Duty sería el inicial menos el Duty resultante de la resta de las 2 velocidades, dando lugar a la siguiente fórmula: Duty corregido=((2·VRS232 - Vpulsos)·100)/3700

Aplica este Duty al motor, que te recalcule la velocidad y que la envie al hiperterminal, a ver si ahora salen bastante más iguales. Creo que sí.

Un saludo
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 23 de Julio de 2004, 11:38:00
Has pensado lo mismo que yo, pero kon una variante!!
Como tiene que ser un control proporcional ahi que multiplicar por una constante!!!
introducimos velocidad deseada; entonces el error, sera la velocidad deseada menos velocidad medida:

error=abs(recibido-velocidad);

se multiplica por una constante;

errorKP=error*KP;

y se genera el duty correspondiente a ese valor!! Si p.e. introducimos 2000rpm --> error = 2000 --> errorKP=2000*0.8; tomamos KP=0.8 p.e.! errorKP=1600 generamos duty -->43; y esto se lo restamos al duty inicial, que en este caso es 0

errorKP=error*KP;
duty=abs(duty-(errorKP*100.0)/3700.0);
set_pwm1_duty(duty);

Entonces medimos la velocidad obtenida 2600 mas o menos!!
Ahora el error es de 600
entonces errorKP=600*0.8= 480
calculamos duty de este que es 480*100/3700=12
se lo restamos al anterior
43 - 12 =31 y medimos la velocidad que es 1600;
error 400 por debajo; errorKP=400*0.8 =320; generamos duty que es 320 *100/3700 =8; entonces ahora viene el problema habria uqe sumarselo al anterior; que seria 31+8=39 y mediriamos la velocidad que es 2300; error 300 por encima, mismas operaciones de antes; errorKP=240; duty generado -->6, se lo restamos al anterior
39-6=33 y nos daria una velocidad de 1800, error 200; errorKP=160; duty generado 4; se lo sumamos al anterior
33+4=37, y medimos la velocidad de 2150; error 150; errorKP=120; duty generado 3, se lo restamnos al anterior; 37-3=34; velcocidad medida 2000, al final hemos conseguido que se nos acerque bastante, esto es el control proporcional!!
Todo esto en muy poco tiempo claro; un segundo o dos!!
Que te parece, creo que deberia ser asi; pero el problema esta en hacer el codigo dentro de mi programa!!
Si no entiendes algo dime!!
Un saludo
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: pocher en 24 de Julio de 2004, 01:07:00
Se entiende perfectamente.

Es lo mismo que yo había pensado sin fórmulas de control P, con las diferencias:

- Yo he supuesto una Kp=1

- Como en la tabla de velocidades la Vpulsos medida es siempre mayor que la VRS232 teórica no he tenido en cuenta el otro intervalo (el que hay que sumar Dutys) ... pero tienes razón el desarrollo completo es teniendo en cuenta los 2 intervalos.

La programación a simple vista no parece que vaya a ser complicada. Mira a ver que te parece:

Velocidad teórica enviada vía RS232 = VRS232

Velocidad medida a partir de los pulsos = Vpulsos

Si VRS232 - Vpulsos > 0 ---> Sumar Duty al anterior

Si VRS232 - Vpulsos < 0 ---> Restar Duty al anterior

Si VRS232 - Vpulsos = 0 ---> Fin
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 24 de Julio de 2004, 02:22:00
Haber que te parece esto!!! Te `pomgo el codigo completo:




*****************************************************
#include <16f873.h>
#device adc=10
#include <stdlib.h>

#fuses XT, NOPROTECT, NOWDT, NOPUT, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8)
#zero_ram

float KP;
float errorKP;
int opcion, lazofinalizado;
int velocidadmedida;
int duty, dutygenerado, dutycorregido;
int16 error;
int16 pulsos;
int16 interrupcion;
int16 velocidad;
int16 recibido;
float dato;
char string[8];
int habilitacionVelo, habilitacionDuty;
int32 tiempoReal;
int32 Tiempo;

lazo_proporcional(){


      if(recibido - velocidad > 0)
      {
         error=recibido-velocidad;
         errorKP=error*KP;
         dutygenerado=(errorKP*100.0)/3700.0;
         dutycorregido=duty+dutygenerado;
         set_pwm1_duty(dutycorregido);
         duty=dutycorregido;
         dutycorregido=0;

      }

      if(recibido - velocidad < 0)
      {
         error=velocidad-recibido;
         errorKP=error*KP;
         dutygenerado=(errorKP*100.0)/3700.0;
         dutycorregido=abs(duty-dutygenerado);
         set_pwm1_duty(dutycorregido);
         duty=dutycorregido;
         dutycorregido=0;
      }
     
      if(recibido - velocidad == 0)
      {
     
         lazofinalizado=1;
         
      }

}



Contr_Velocidad(){
        habilitacionDuty=0;
        gets(string);
        recibido=atol(string);
        if(recibido==5000 || recibido==5001)
        {
            reset_cpu();
        }
        else
        {
            if(recibido>=800 && recibido<=3700)
            {
               habilitacionVelo=1;
            }
            else
            {
            set_pwm1_duty(duty);
            }

        }
}



Contr_duty_cycle(){

        habilitacionVelo=0;
        gets(string);  //recibo la cadena
        recibido=atol(string);  //la convierto la cadena a entero
        if(recibido==5000 || recibido==5001)  //si se envia cualquiera de estos dos numeros se resetea el PIC, reset por software
        {
            reset_cpu();
        }

        else
        {
            if(recibido>=20 && recibido<=100)
            {
                duty=recibido;
                set_pwm1_duty(duty); //El caracter ascii recibido pasado a entero
                                  //establecido como ciclo de trabajo
                habilitacionDuty=1;   //flag pata habilitar el contaje de los pulsos de velocidad del optoacoplador
            }
            else     //si no se ha recibido reset o desconexion, se prosigue a realizar el duty
            {
               set_pwm1_duty(duty);
            }
        }
}




#int_RTCC   //se determina la funcion de la interrupcion

RTCC_isr()
{

    if(habilitacionVelo==1 || habilitacionDuty==1)
    {

         if(habilitacionVelo==1 && velocidadmedida==1 && lazofinalizado==0)
         {
            lazo_proporcional();
         }

         tiempoReal++;   //se suma a una variable que computa el tiempo transcurrido

         pulsos=get_timer1();    //se obtiene el valor del contador timer1
         interrupcion++;   //se suma en uno el flag de interrupcion
         if(interrupcion==100)   //cuando se llega a 100, es decir, 1 segundo, 100*10ms=1000ms=1seg; se introduce en la funcion
         {
            velocidad=pulsos*15;   //sacamos la velocidad con una regla de tres
            velocidadmedida=1;
              printf("%lu     ",velocidad);  //tambien puerto serie
            printf("%u      ",duty);  //imprimo el duty para saber cual nos ha generado
            Tiempo=tiempoReal*0.01; //calculo el tiempo en segundos transcurridos
            printf("%lu     ", Tiempo); //imprimo el tiempo



            interrupcion=0;  //se inicializa de nuevo el flag de interrupcion para que vuelva a contar 100 interrupciones
            set_timer1(0);   //se inicializa tambien el contador
            set_rtcc(178);   //se introduce de nuevo el valor del temporizador de interrupcion
         }
         else
         {
            set_rtcc(178);
            set_timer1(pulsos);
         }
    }

}


main()
{
   enable_interrupts(GLOBAL); //se habilitan interrupcion general
   enable_interrupts(INT_RTCC);  //habilita int. del timer0
   setup_timer_0 ( RTCC_INTERNAL | RTCC_DIV_128);  //se configura el timer0 como temporizador y una báscula de 128
   set_rtcc(178); //10ms -> 10000us -> 10000/128=78 -> 255-78=177 se le inserta el tiempo a contar, se suma uno
   duty = 0;   //se inicializa el duty en cero
   setup_ccp1(CCP_PWM); //Se habilita el pwm 1
   setup_timer_2(T2_DIV_BY_16, 99, 1); //Se establece el valor de la frecuencia de 620Hz(1,6 ms el periodo) para el PWM
   set_pwm1_duty(duty); //se manda el duty al PWM
   setup_timer_1(T1_EXTERNAL | T1_DIV_BY_1); //se configura el timer1 como contador, de pulsos externos y de báscula 1
   set_timer1(0); //se inicializa el contador en cero


   interrupcion=0;   //se inicializan los flags
   habilitacionVelo=0, habilitacionDuty=0;
   tiempoReal=0;
   Tiempo=0;
   dutygenerado=0;
   dutycorregido=0;
   error=0;
   errorKP=0;
   velocidadmedida=0;
   lazofinalizado=0;



/******************************************* Constante KP************************************************/



   KP=1;  //la constante del control proporcional



/********************************************************************************************************/




   while(true)
   {
   //el programa principal que estaria haciendo, esperando a la interrupcion del timer0

               gets(string); //Guarda el Duty (0-255) en la variable string aunque solo necesitamos hasta 100
                              //y espera un RETURN (Ctrl 13)
               opcion=atoi(string); //Usa la función ATOI para pasarlo a entero

         switch (opcion) {    //case para entrar en un codigo u otro

            case 1:  //recibido duty cycle se controla mediante duty cycle con un rango

                  while(true)
                  {
                     Contr_duty_cycle();
                  }
                  break;

            case 2:  //recibido velocidad se controla mediante velocidad con un rango

                  while(true)
                  {
                     Contr_Velocidad();
                  }
                  break;   }        //fin del "CASE"
   }

}
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: pocher en 26 de Julio de 2004, 03:22:00
Te lo he estado mirando y corrigiendo. Espero no haberme equivocado con los razonamientos.

- El emisor tendrá que estar enterado de estos rangos:

20<=dutys<=100  ;  800<=v<=3700 con un mensajito enviado desde el PIC

- En la función Contr_duty_cycle() sustituir el else por un else if(recibido>=20 && recibido<=100) y eliminar el último else (creo que no sirve para nada)

- El comentario gets(string); //Guarda el Duty (0-255) en la variable string aunque solo necesitamos hasta 100 yo lo corregiría puesto que no se espera un Duty si no un 1 o un 2.

- Idem para el comentario del case1 puesto que todavía no se ha recibido el duty.

- Si nada má conectar la alimentación al PIC eliges el case2 (velocidad), el if(habilitacionVelo==1 && velocidadmedida==1 && lazofinalizado==0) no lo va a ver ya que velocidadmedida=0 con lo cual no te entrará en el lazo proporcional. Claro si antes has hecho el case1 entonces sí  que te entrará ya que ahora velocidadmedida=1.

- Poner dutycorregido=0 en el lazoproporcional() creo que no es necesario, funcionará igual.

- Antes de meterte en el lazoproporcional() tienes que calcular el duty por primera vez (duty=(recibido*100.0)/3700.0 de lo contrario se meterá con duty=0. Este cálculo mételo en la función Contr_Velocidad()

- El  if(recibido - velocidad == 0) convendría quitarlo por si hay alguna desviación de la velocidad que se autocorrija a sí mismo.

Xa2 piensa en todos estos razonamientos y ya me dirás que te parecen.

Un saludo

   
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 26 de Julio de 2004, 06:08:00
Aqui te dejo el codigo, durante este fin de semana ya habia hecho cambios que me has puesto aqui, de todas formas gracias; he hecho mas cambios, aunque no todos los que me has puesto porque sino no funciona correctamente; es decir, como se desea!!
Gracias de nuevo por tu interes y ayuda!!!!

Haber si se puede pulir aun mas!!


*****************************************************
#include <16f873.h>
#device adc=10
#include <stdlib.h>

#fuses XT, NOPROTECT, NOWDT, NOPUT, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8)
#zero_ram

float KP;
float errorKP;
int opcion;
int duty, dutygenerado, dutycorregido;
int16 error;
int16 pulsos;
int16 interrupcion;
int16 velocidad;
int16 recibido;
float dato;
char string[8];
int habilitacionVelo, habilitacionDuty, FueraRango;
int32 tiempoReal;
int32 Tiempo;

lazo_proporcional(){

      if(recibido > velocidad)
      {
            error=recibido-velocidad;
            errorKP=error*KP;
            dutygenerado=(errorKP*100.0)/3700.0;
            dutycorregido=duty+dutygenerado;
            if(dutycorregido>100)
            {
               set_pwm1_duty(100);
               duty=100;
               dutygenerado=0;
            }

            if(dutycorregido<20)
            {
               set_pwm1_duty(20);
               duty=20;
               dutygenerado=0;
            }
            if(dutycorregido<=100 && dutycorregido>=20)
            {
               set_pwm1_duty(dutycorregido);
               duty=dutycorregido;
               dutycorregido=0;
               dutygenerado=0;
            }
            dutycorregido=0;

      }

      if(recibido < velocidad)
      {
            error=velocidad-recibido;
            errorKP=error*KP;
            dutygenerado=(errorKP*100.0)/3700.0;
            dutycorregido=abs(duty-dutygenerado);
            if(dutycorregido>100)
            {
               set_pwm1_duty(100);
               duty=100;
               dutygenerado=0;
            }

            if(dutycorregido<20)
            {
               set_pwm1_duty(20);
               duty=20;
               dutygenerado=0;
            }
            if(dutycorregido<=100 && dutycorregido>=20)
            {
               set_pwm1_duty(dutycorregido);
               duty=dutycorregido;
               dutygenerado=0;
            }
            dutycorregido=0;
      }

}



Contr_Velocidad(){
        habilitacionDuty=0;
        gets(string);
        recibido=atol(string);
        if(recibido==5000 || recibido==5001)
        {
            reset_cpu();
        }
        else
        {
            if(recibido>=800 && recibido<=3700)
            {
               habilitacionVelo=1;
               FueraRango=0;
            }
            else
            {
               printf("Rango 800-3700 r.p.m.";
               FueraRango=1;
            }
        }
}



Contr_duty_cycle(){

        habilitacionVelo=0;
        gets(string);  //recibo la cadena
        recibido=atol(string);  //la convierto la cadena a entero
        if(recibido==5000 || recibido==5001)  //si se envia cualquiera de estos dos numeros se resetea el PIC, reset por software
        {
            reset_cpu();
        }

        else
        {

            if(recibido>=20 && recibido<=100)
            {
               duty=recibido;
               set_pwm1_duty(duty); //El caracter ascii recibido pasado a entero
                                     //establecido como ciclo de trabajo
               habilitacionDuty=1;   //flag pata habilitar el contaje de los pulsos de velocidad del optoacoplador
            }

            else
            {
               printf("Rango 20-100 duty cycle";

            }
        }
}




#int_RTCC   //se determina la funcion de la interrupcion

RTCC_isr()
{

    if(habilitacionVelo==1 || habilitacionDuty==1)
    {



         tiempoReal++;   //se suma a una variable que computa el tiempo transcurrido

         pulsos=get_timer1();    //se obtiene el valor del contador timer1
         interrupcion++;   //se suma en uno el flag de interrupcion
         if(interrupcion==100)   //cuando se llega a 100, es decir, 1 segundo, 100*10ms=1000ms=1seg; se introduce en la funcion
         {
            velocidad=pulsos*15;   //sacamos la velocidad con una regla de tres

            if(habilitacionVelo==1 && FueraRango==0)
            {
               lazo_proporcional();
            }

              printf("%lu     ",velocidad);  //tambien puerto serie
            printf("%u      ",duty);  //imprimo el duty para saber cual nos ha generado
            Tiempo=tiempoReal*0.01; //calculo el tiempo en segundos trnascurrido
            printf("%lu     ", Tiempo); //imprimo el tiempo



            interrupcion=0;  //se inicializa de nuevo el flag de interrupcion para que vuelva a contar 100 interrupciones
            set_timer1(0);   //se inicializa tambien el contador
            set_rtcc(178);   //se introduce de nuevo el valor del temporizador de interrupcion
         }

         else
         {
            set_rtcc(178);
            set_timer1(pulsos);
         }
    }

}


main()
{
   enable_interrupts(GLOBAL); //se habilitan interrupcion general
   enable_interrupts(INT_RTCC);  //habilita int. del timer0
   setup_timer_0 ( RTCC_INTERNAL | RTCC_DIV_128);  //se configura el timer0 como temporizador y una báscula de 128
   set_rtcc(178); //10ms -> 10000us -> 10000/128=78 -> 255-78=177 se le inserta el tiempo a contar, se suma uno
   duty = 0;   //se inicializa el duty en cero
   setup_ccp1(CCP_PWM); //Se habilita el pwm 1
   setup_timer_2(T2_DIV_BY_16, 99, 1); //Se establece el valor de la frecuencia de 620Hz(1,6 ms el periodo) para el PWM
   set_pwm1_duty(duty); //se manda el duty al PWM
   setup_timer_1(T1_EXTERNAL | T1_DIV_BY_1); //se configura el timer1 como contador, de pulsos externos y de báscula 1
   set_timer1(0); //se inicializa el contador en cero


   interrupcion=0;   //se inicializan los flags
   habilitacionVelo=0, habilitacionDuty=0;
   tiempoReal=0;
   Tiempo=0;
   dutygenerado=0;
   dutycorregido=0;
   error=0;
   errorKP=0;
   FueraRango=0;





/******************************************* Constante KP************************************************/



   KP=1;  //la constante del control proporcional



/********************************************************************************************************/




   while(true)
   {
   //el programa principal que estaria haciendo, esperando a la interrupcion del timer0

               gets(string);
               opcion=atoi(string); //Usa la función ATOI para pasarlo a entero

         switch (opcion) {    //case para entrar en un codigo u otro

            case 1:  //recibido duty cycle se controla mediante duty cycle con un rango

                  while(true)
                  {
                     Contr_duty_cycle();
                  }
                  break;

            case 2:  //recibido velocidad se controla mediante velocidad con un rango

                  while(true)
                  {
                     Contr_Velocidad();
                  }
                  break;

            default:

                  reset_cpu();
                          }        //fin del "CASE"
   }

}
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: pocher en 26 de Julio de 2004, 14:04:00
Uf me duelen las pestañas de mirarlo y remirarlo.

Bien, ahora está bastante mejor, aunque creo que seguirá sin funcionarte bien por una de las cosillas que te comentaba anteriormente:

- Antes de meterte en el lazoproporcional() tienes que calcular el duty por primera vez (duty=(recibido*100.0)/3700.0 de lo contrario se meterá con duty=0. y entonces el primer dutygenerado será el de la resta.

Otra cosa que me ha llevado de cabeza: ¡¡¡Para que la función abs() funcione bien las variables de dentro tienen que ser signed!!!



Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 27 de Julio de 2004, 03:45:00
Ya lo siento Pocher, pero muchas gracias!!
En cuanto a lo d meter priemro el duty antes de entrar al lazo proporcional, no lo hago porque el primer duty que deseo que se haga es el de la resta, ya que es un control cerrado proporcional!!!
Entonces se resta la velocidad medida menos la velocidad deseada, y la resta sera la que genere el priemr duty!!!Luego ya sera el error entre medidas y deseadas!!
En cuanto al Abs() me lo hace bien, aunque seria bueno cambiarlo por si acaso, no lo hago porque igual hay que cambiar msa cosas de programacion, y asi no me da ningun tipo de problema!!
Gracias de nuevo Pocher y saludos!!
Lo he probado y funciona a las mil maravillas!!!
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: pocher en 27 de Julio de 2004, 06:28:00
Perdona si soy pesado pero creo que cuando la resta sea negativa la función abs() no va a ir bien. Yo lo comprobé.

Lo único que tienes que cambiar: int duty, dutygenerado, dutycorregido por signed int duty, dutygenerado, dutycorregido.

Un saludo.
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: pocher en 28 de Julio de 2004, 11:52:00
Uf ya sé porque la función abs() "te funciona bien" sin tener declaradas como signed las variables que hay dentro de ella ... simplemente no está funcionando. Es decir si no declaras las variables que hay dentro de ella como signed no opera.

Traduciendo, si la quitas no va a pasar nada.

Prueba y cuentas.
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: Xa2 en 28 de Julio de 2004, 13:46:00
Gracias Pocher!!!
Entonces dices que con declarar las variables como signed vale??
Entonces dejo la funcion abs() y declaro las variables como signed, no??
Haciendo esto funcionaria bien, no??
Gracias de nuevo por las molestias y un saludo!!
Título: RE: Control motor introduciendo la velocidad!!
Publicado por: pocher en 29 de Julio de 2004, 00:29:00
No mejor que eso, quítala y deja tan solo la resta, si mis cálculos no fallan esa resta nunca va a dar resultado negativo.

Prueba y cuentas.
Título: Re: Control motor introduciendo la velocidad!!
Publicado por: PIC-A-SHU en 06 de Junio de 2006, 14:55:32
 :-/ :-/ :-/ holaaaa.....soy nuevo en el foro y quiero aprender con uds. ya q soy nuevo en el tema de pic..........me gustaria probar ese programilla q han realizado....se q debe haber costado mucho su realizacion pero quiero hacerlo.......esta funcionando correctamente???.........me pueden ayudar a atilizarlo o explicarme como funciona......ya les agradeceria q me dejaran compartir sus ideas.....adios.- :-/ :-/ :-/