Autor Tema: Ajustar Velocidad de motor dada las RPM  (Leído 4263 veces)

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

Desconectado artemis

  • PIC10
  • *
  • Mensajes: 34
Ajustar Velocidad de motor dada las RPM
« en: 10 de Agosto de 2020, 23:52:36 »
Hola gente, soy nuevo con esto del PIC y tengo que hacer un proyecto donde se pueda setear las RPM de un motor y la velocidad se ajuste a ese parámetro.
Utilizo el pic 16F876A



Adjunto una captura del proyecto en proteus, la idea es que al pulsar en el botón "incremento" se setee "X" RPM y entonces el motor se tenga que ajustar a eso, yo utilizo un motor encoder donde cuento los pulsos que hace en un segundo y ahí estimo las RPM. Pero ahora me piden que haga eso de que dada las RPM que el motor se ajuste a ese valor y no se como hacerlo, tengo que modificar el duty para eso? o cómo podría ser?

Dejo el código como archivo adjunto

Antes quiero comentar esta parte, acá lo que intento plantear es que dada las RPM que se setean al presionar el botón (200 RPM en este caso), calculo la cantidad de pulsos por segundo que hay que contar para tener esas RPM en el motor.
Código: [Seleccionar]
 
if(INPUT(PIN_A0)==1) //condición de la pulsación de incremento
   {     
         P_RPM=200;
         i=P_RPM/30; //cantidad de pulsos que hay que contar por minuto para poder tener las revoluciones requeridas, como el encoder es de 2 pulsos por vuelta entonces 60/2=30         
         while(contador<i)
         {           
            prueba++;
            set_pwm1_duty(prueba);//no se si está bien plantearlo así
         }
   }

Saludos
 
* interrupcionRB.c
(3.05 kB - descargado 165 veces)
 
* interrupcionRB.c
(3.05 kB - descargado 165 veces)

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Ajustar Velocidad de motor dada las RPM
« Respuesta #1 en: 11 de Agosto de 2020, 05:54:10 »
Hola, entiendo que se trata de un motor de escobillas con encoder incorporado.

  Ahi vas a necesitar 4 funciones principales dentro del bucle del main:

while(1) {

- Lectura de pulsadores para ajustar la velocidad (Vset).
- Lectura del régimen actual (mediante interrupcion).
- Ajuste del dutty cicle del PWM si es necesario.
- Feedback.
}


La lectura de pulsadores ningún problema, if (!p+) rpm++; if(!p-) rpm--  o similar, como lo quieras ajustar y le pones alguna rutina antirrebote.

Para la lectura del régimen de giro actual necesitas usar un timer, y una variable inicializada a cero para almacenar el numero de veces que desborda ese timer. conectas el encoder a un pin que tenga interrupción por cambio de estado.
Cuando se produzca un cambio de estado entras en la interrupción y:
1- Lees el estado actual del pin y te mantienes en espera de que cambie de nuevo.
2- Una vez ha cambiado, pones el timer a cero y vigilas dos cosas:
       2-1: La bandera tmrxxif (que indica que el timer ha desbordado), entonces incrementas el contador y bajas la bandera, nada mas.
       2-2: Control de timeout: ¿Cuanto tiempo máximo esperarás cambio de estado antes de abandonar?, si el motor se detiene el programa quedaría atrapado esperando cambios de estado, si eso no interesa, y no creo que interese, aqui debes esperar lo que creas conveniente. Como tieness un contador de desbordamientos, y sabes el tiempo que tarda el timer en desbordar (depende del oscilador, preescalador, postcalador, etc) sabes con qué valor de contador abandonas.

3- Esperas otros dos cambios de estado. En todos ellos haces lo mismo descrito en 2-1 y 2-2.
- Una vez alcanzado el ultimo cambio de estado:
   - lees el valor del timer.
   - Lees el valor del contador de desbordamientos. Si es un timer de 16 bits desborda a las 65535 + 1 pulsos de conteo. De 8 bits desborda a los 255 + 1 pulso de conteo.

    la operacion para periodo es:
   periodo = numero de desbordamientos * (65535 + 1);
   periodo += valor del timer obtenido al momento del ultimo cambio de estado del pin.

    Todo esto es para UN SOLO DIENTE del encoder. Ahora bien, o repites lo anterior tantas veces como dientes tenga el encoder y vas acumulando las lecturas y aplicar la operación del periodo a todo, o....     Lo haces para un solo diente y el resultado lo multiplicas por el numero de dientes del encoder (No merece la pena, ya puestos.....  mejor medirlo todo), solo tienes que encerrar todo lo anterior (excepto el calculo del periodo) en un while(){} cuya condicion sea while (numero_de_dientes-- > 0) { }


    De una manera u otra, una vez que tienes un periodo, lo conviertes en su tiempo equivalente. Como sabes el tiempo que tarda el timer en incrementarse y en desbordarse por que lo has calculado dependiendo del oscilador, prescaler, postcaler y poco más,  puedes saber cuanto tiempo ha tardado el motor en dar un giro completo.

  Le aplicas la inversa y ya tienes la frecuencia.
  La divides entre 60 y ya tienes las rpm, aunque yo aun lo trabajaría en frecuencia. Las rpm solo para mostrarlas si hace falta.

 
Ya solo queda el bloque de feedback, que consiste en comparar el valor de rpm ajustado (Vset) con el obtenido, si es mayor, bajamos el dutty cicle al pwm, si es menor, subimos el dutty cicle al pwm...  Esto es lo mas facil, pero no es lo mejor.

   Para bordarlo ya mejor implementar un algoritmo PID que no es muy complicado y te dará un redondeo de ajuste y suavidad que quitan el sentido.... :D

  Un saludo.

Desconectado artemis

  • PIC10
  • *
  • Mensajes: 34
Re:Ajustar Velocidad de motor dada las RPM
« Respuesta #2 en: 11 de Agosto de 2020, 18:11:48 »
Hola remi, gracias por la respuesta

Te comento esto es lo que yo plantié

Utilizo las interrupciones externas en RB0 y ahí es donde tengo el contador de pulsos por segundo. No se si es posible de hacerlo así o como podría ser? no me doy cuenta como lo mencionas vos
Código: [Seleccionar]
#INCLUDE <16F876A.h>
#DEVICE ADC=10
#USE DELAY(CLOCK=4000000)
#FUSES XT,NOPROTECT,NOWDT,NOBROWNOUT,PUT,NOLVP
#INCLUDE <flex_lcd.C>
#DEFINE USE_PORTB_LCD TRUE
//Direcciones de memoria que utilizan los puertos A,B y C
#BYTE PORTA= 5
#byte PORTB= 6
#byte PORTC= 7

long contador=0;//Variable para contar los pulsos del encoder
int16 duty=0;//para guardar el ciclo duty del pwm
int Timer2,Poscaler;//para configurar el pwm
double RPM,P_RPM;//se guarda las revoluciones por minuto del motor
int i=0; //variable que servira como contador
int prueba=0;
//Interrubción por cambio en RB0
#INT_EXT
ext_isr()//esta funcion solo se activa cuando hay una interrupcion por flanco de subida (L TO H)
{
   contador++;             
}
void main()
{
   //Configura los Puertos del PIC
   set_tris_a(0b00000111);//RA0 RA1 RA2 como entrada, donde está el potenciometro
   set_tris_b(0b00000011); //RB0 como entrada, donde está conectado el encoder del motor y se utiliza interrupcion externa (que trabaja con este pin)
   set_tris_c(0b00000000);//todo el puerto C como salida
   lcd_init();
   lcd_gotoxy(1,1);
   printf(LCD_PUTC, "BIENVENIDO");
   delay_ms(200);
    //Habilita las Interrupcciones
    enable_interrupts(int_ext); //Activa interrupcion por RB0
    ext_int_edge(L_TO_H);    //Activa interrupción por flanco de subida
    enable_interrupts(global); //Habilita interrupciones de forma global, se hacen arriba del main como funcion global
   //Configura el PWM
   // Generemos una Señal cuadrada de 1 Khz
   Timer2=249;    //Se carga timer 2 con 249 como lo vimos en la pagina
   Poscaler=1;  //Preescaler solo puede tomar valores de: 1
   
   setup_timer_2(t2_div_by_4,Timer2,Poscaler);   //Configuracion de Timer 2 para establecer frec. PWM a 1kHz
   
   setup_ccp1(ccp_pwm); //Configura el modulo CCP1 en modo PWM
   set_pwm1_duty(70);    //Determina el ciclo de trabajo en escala de 0 a 255 (PARAMETRO DE INICIO)
   
    //Hace por siempre
    while(1)
    {
   if(INPUT(PIN_A0)==1) //condicion de la pulsacion de incremento
   {     
         P_RPM=200;
         i=P_RPM/30; //cantidad de pulsos que hay que contar por minuto para poder tener las revoluciones requeridas         
         while(contador<i)
         {           
            prueba++;
            set_pwm1_duty(prueba);
         }
   }
 
   if(INPUT(PIN_A1)==1) //condicion de la pulsacion de incremento
   {
           
   }
      if(INPUT(PIN_B1)==1) //condicion de la pulsacion de incremento
   {
      set_pwm1_duty(0);
      i=0;
   }
  //Espera por 1 segundo*/
     delay_ms(999);
     
     //Despues de 1 segundo multiplica el valor de los pulsos contados en
     //contador y los multiplica por 60 (para pasarlo a minutos) y lo divide
     //por el numero de pulsos que tiene el encoder, en este caso el encoder
     //da 10 pulsos en 1 giro completo
     RPM=contador*60/2;
     
   //  Reinicia el contador de Pulsos
     contador=0;
     
   //  Visualiza la Velocidad
     lcd_gotoxy(1,2);
     printf(lcd_putc,"RPM: %f   ",RPM);
   
    }
   
}

Saludos


Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Ajustar Velocidad de motor dada las RPM
« Respuesta #3 en: 12 de Agosto de 2020, 04:58:35 »
Hola. Lo que tienes hecho entonces te está funcionando ¿no?.   

  No está mal planteado.   La diferencia es que tú determinas las rpm contando pulsos que al ser un encoder de varios dientes tienes varios pulsos por rpm y por lo tanto más resolución. Pero a mi personalmente y habiendo timer libres siempre he preferido obtener el periodo y no contar pulsos.  Depende de la precisión y velocidad de respuesta del programa que quieras, pero en principio como lo planteas es válido.

  Un saludo.

Desconectado artemis

  • PIC10
  • *
  • Mensajes: 34
Re:Ajustar Velocidad de motor dada las RPM
« Respuesta #4 en: 12 de Agosto de 2020, 17:51:26 »
Hola. Lo que tienes hecho entonces te está funcionando ¿no?.   

  No está mal planteado.   La diferencia es que tú determinas las rpm contando pulsos que al ser un encoder de varios dientes tienes varios pulsos por rpm y por lo tanto más resolución. Pero a mi personalmente y habiendo timer libres siempre he preferido obtener el periodo y no contar pulsos.  Depende de la precisión y velocidad de respuesta del programa que quieras, pero en principio como lo planteas es válido.

  Un saludo.

Claro inicialmente dado un Voltaje de entrada, yo contaba los pulsos que hacía el encoder en un segundo y así después calculaba las RPM pero no se cómo hacer para dada unas RPM el motor se setee en ese valor. Ese código que adjunté fue algo que se me ocurrió pero no me funciona y no se cómo hacerlo utilizando interrupciones externas en RB0, alguna idea de por qué no funciona?

Saludos

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Ajustar Velocidad de motor dada las RPM
« Respuesta #5 en: 13 de Agosto de 2020, 06:41:45 »
Ahí lo que pasa es que ponerte a contar pulsos hace muy lento tu programa y hace que las correcciones sucedan cada segundo a saltos. No es lo suyo.

  Lo ideal y para que el programa sea rápido y fluido, tanto que el motor te haga caso inmediatamente al tocar el pulsador + o el - es tener un bucle infinito en main donde lo único que haces es leer pulsadores y gobernar el pwm. Nada más.

  Lo demás se hace en el handler de interrupción al que se entra por cambio de estado del pin del encoder como ya haces, pero en vez de contar pulsos, como tú ya has configurado la interrupción para que entre en el flanco de subida pues lo que yo haría dentro de ese handler de forma basica es:

    - Lo primero desactivar las interrupciones para que no haya reentrada.

    - mantener a la espera del flanco de bajada:
Código: C
  1. while (input(PIN_B0);   // esperando flanco de bajada.
  2.     set_timer3(0); //.  Pongo el “crono” a cero.
  3.     while(!input(PIN_B0); //  Espero flanco de subida.
  4.     while(input(PIN_B0); //  Espero flanco Bajada.
  5.     int16 periodo = get_timer3();  // capturo el valor del timer
      // ya tienes un periodo que es exactamente el tiempo que ha tardado en pasar una cresta y un valle completo del encoder. Con eso es suficiente.



    Ahora ese valor, que es una cuenta de un timer lo pasas a tiempo. Para calcular el tiempo tienes que saber:
   - La velocidad del oscilador.   La frecuencia de entrada al timer es fosc/4, es decir,’si tu micro va a 20 Mhz, la frecuencia de entrada al timer es 20/4 = 5 Mhz. 

    - El prescaler del timer. Si le has puesto por ejemplo 1/8, la salida del timer será 5 Mhz/8 = 625 Khz.

   Significa que en un segundo el Timer cuenta de 0 a 625000 y que tardaría  en hacer un incremento = 1/625000 = 1,6 uS.
 

  ( Aquí viene la importancia de contar los desbordamientos) por que el timer3 en modo 16 bits solo puede contar hasta 65535 + 1.  Por lo que en un segundo te va a desbordar 625000/65536 = 9 veces, y claro, ¿como totalizo todo eso?,  pues contando las veces que desborda durante las esperas de los flancos arriba en los while. Por lo que los while de arriba quedarían asi:
Código: C
  1. while (input(PIN_B0);   // esperando flanco de bajada.
  2.     set_timer3(0); //.  Pongo el “crono” a cero.
  3.     int overflow = 0;  // Para contar los desbordamientos del timer.
  4.     while(!input(PIN_B0) { //  Espero flanco de subida.
  5.          if (tmr3if) overflow ++;  // ¿Ha desbordado el timer3?, incremento el contador
  6.          tmr3if = 0;     // bajo la bandera y continuo esperando flanco.
  7. }
  8.  
  9.   // Y ahora lo mismo para el otro flanco:
  10.     while(input(PIN_B0) { //  Espero flanco Bajada.
  11.          if (tmr3if) overflow ++;  // ¿Ha desbordado el timer3?, incremento el contador
  12.          tmr3if = 0;     // bajo la bandera y continuo esperando flanco.
  13. }
Una vez recibido el flanco de bajada capturamos inmediata el valor actual del timer:

Código: C
  1. float periodo = get_timer3();  // capturo el valor del timer
  Y ahora a ese valor le sumamos todos los desbordamientos que hayan habido.
Código: C
  1. periodo += (65535 + 1) * overflow;
  Ahora lo pasamos a tiempo:
Código: C
  1. Periodo *= 0.00000165;   // Todo lo que hemos cronometrado con el timer * 1,65 uS.
Haces la inversa:
Código: C
  1. periodo = 1/periodo;   // ahora tienes la frecuencia de un solo diente del encoder. (Valle y cresta)
  2.  
  3.    periodo *= número de (dientes + valles);  // Ya tienes el total de lo que tardarían todos los dientes y valles en dar un giro completo.
  4.  
  5.    return periodo * 60;  //. Retorna el valor en rpm

   // fin de handler de interrupción. 



    Ahora ya en el bucle del main compáralo y vas corrigiendo.

  Hazlo todo por bloques, es decir, primero haz girar el motor con tensión externa y que el programa sea capaz de determinar sus rpm.

   Ya luego el control, lo que haría básicamente es:

  ¿ Cuantas rpm quiero?   vset.
  ¿ A cuanto gira?   v_current.

  ¿Diferencia?   signed int diferencia = vset - v_current;

  Si sale positivo, reduces las rpm en la proporción exacta de la diferencia.
  Si sale negativo, aumentas las rpm en la proporción.

  Y así sucesivamente....


   
   
« Última modificación: 13 de Agosto de 2020, 06:52:20 por remi04 »

Desconectado artemis

  • PIC10
  • *
  • Mensajes: 34
Re:Ajustar Velocidad de motor dada las RPM
« Respuesta #6 en: 13 de Agosto de 2020, 14:16:44 »
Ahí lo que pasa es que ponerte a contar pulsos hace muy lento tu programa y hace que las correcciones sucedan cada segundo a saltos. No es lo suyo.

  Lo ideal y para que el programa sea rápido y fluido, tanto que el motor te haga caso inmediatamente al tocar el pulsador + o el - es tener un bucle infinito en main donde lo único que haces es leer pulsadores y gobernar el pwm. Nada más.

  Lo demás se hace en el handler de interrupción al que se entra por cambio de estado del pin del encoder como ya haces, pero en vez de contar pulsos, como tú ya has configurado la interrupción para que entre en el flanco de subida pues lo que yo haría dentro de ese handler de forma basica es:

    - Lo primero desactivar las interrupciones para que no haya reentrada.

    - mantener a la espera del flanco de bajada:
Código: C
  1. while (input(PIN_B0);   // esperando flanco de bajada.
  2.     set_timer3(0); //.  Pongo el “crono” a cero.
  3.     while(!input(PIN_B0); //  Espero flanco de subida.
  4.     while(input(PIN_B0); //  Espero flanco Bajada.
  5.     int16 periodo = get_timer3();  // capturo el valor del timer
      // ya tienes un periodo que es exactamente el tiempo que ha tardado en pasar una cresta y un valle completo del encoder. Con eso es suficiente.



    Ahora ese valor, que es una cuenta de un timer lo pasas a tiempo. Para calcular el tiempo tienes que saber:
   - La velocidad del oscilador.   La frecuencia de entrada al timer es fosc/4, es decir,’si tu micro va a 20 Mhz, la frecuencia de entrada al timer es 20/4 = 5 Mhz. 

    - El prescaler del timer. Si le has puesto por ejemplo 1/8, la salida del timer será 5 Mhz/8 = 625 Khz.

   Significa que en un segundo el Timer cuenta de 0 a 625000 y que tardaría  en hacer un incremento = 1/625000 = 1,6 uS.
 

  ( Aquí viene la importancia de contar los desbordamientos) por que el timer3 en modo 16 bits solo puede contar hasta 65535 + 1.  Por lo que en un segundo te va a desbordar 625000/65536 = 9 veces, y claro, ¿como totalizo todo eso?,  pues contando las veces que desborda durante las esperas de los flancos arriba en los while. Por lo que los while de arriba quedarían asi:
Código: C
  1. while (input(PIN_B0);   // esperando flanco de bajada.
  2.     set_timer3(0); //.  Pongo el “crono” a cero.
  3.     int overflow = 0;  // Para contar los desbordamientos del timer.
  4.     while(!input(PIN_B0) { //  Espero flanco de subida.
  5.          if (tmr3if) overflow ++;  // ¿Ha desbordado el timer3?, incremento el contador
  6.          tmr3if = 0;     // bajo la bandera y continuo esperando flanco.
  7. }
  8.  
  9.   // Y ahora lo mismo para el otro flanco:
  10.     while(input(PIN_B0) { //  Espero flanco Bajada.
  11.          if (tmr3if) overflow ++;  // ¿Ha desbordado el timer3?, incremento el contador
  12.          tmr3if = 0;     // bajo la bandera y continuo esperando flanco.
  13. }
Una vez recibido el flanco de bajada capturamos inmediata el valor actual del timer:

Código: C
  1. float periodo = get_timer3();  // capturo el valor del timer
  Y ahora a ese valor le sumamos todos los desbordamientos que hayan habido.
Código: C
  1. periodo += (65535 + 1) * overflow;
  Ahora lo pasamos a tiempo:
Código: C
  1. Periodo *= 0.00000165;   // Todo lo que hemos cronometrado con el timer * 1,65 uS.
Haces la inversa:
Código: C
  1. periodo = 1/periodo;   // ahora tienes la frecuencia de un solo diente del encoder. (Valle y cresta)
  2.  
  3.    periodo *= número de (dientes + valles);  // Ya tienes el total de lo que tardarían todos los dientes y valles en dar un giro completo.
  4.  
  5.    return periodo * 60;  //. Retorna el valor en rpm

   // fin de handler de interrupción. 



    Ahora ya en el bucle del main compáralo y vas corrigiendo.

  Hazlo todo por bloques, es decir, primero haz girar el motor con tensión externa y que el programa sea capaz de determinar sus rpm.

   Ya luego el control, lo que haría básicamente es:

  ¿ Cuantas rpm quiero?   vset.
  ¿ A cuanto gira?   v_current.

  ¿Diferencia?   signed int diferencia = vset - v_current;

  Si sale positivo, reduces las rpm en la proporción exacta de la diferencia.
  Si sale negativo, aumentas las rpm en la proporción.

  Y así sucesivamente....


   
 

Hola remi, según lo que te entendí plantié hice este código aunque tengo errores al compilar porque no tengo un set_timer3 ni tmr3if, cuál debería usar?
De todas formas me quedan dudas sobre como combinar el conteo de pulsos y el código nuevo que va también dentro de la interrupción

Adjunto el código:

Código: [Seleccionar]
#INCLUDE <16F876A.h>
#DEVICE ADC=10
#USE DELAY(CLOCK=4000000)
#FUSES XT,NOPROTECT,NOWDT,NOBROWNOUT,PUT,NOLVP
#INCLUDE <flex_lcd.C>
#DEFINE USE_PORTB_LCD TRUE
//Direcciones de memoria que utilizan los puertos A,B y C
#BYTE PORTA= 5
#byte PORTB= 6
#byte PORTC= 7

long contador=0;//Variable para contar los pulsos del encoder
int16 duty=0;//para guardar el ciclo duty del pwm
int Timer2,Poscaler;//para configurar el pwm
double RPM,P_RPM;//se guarda las revoluciones por minuto del motor
int i=0; //variable que servirá como contador
//Interrupción por cambio en RB0
#INT_EXT
ext_isr()//esta función solo se activa cuando hay una interrupción por flanco de subida (L TO H)
{
    while (input(PIN_B0));   // esperando flanco de bajada.
       set_timer3(0); //.  Pongo el “crono” a cero.
       int overflow = 0;  // Para contar los desbordamientos del timer.
       while(!input(PIN_B0))
       { //  Espero flanco de subida.
          if (tmr3if) overflow ++;  // ¿Ha desbordado el timer3?, incremento el contador
         tmr3if = 0;     // bajo la bandera y continuo esperando flanco.
       }
         // Y ahora lo mismo para el otro flanco:
      while(input(PIN_B0))
      { //  Espero flanco Bajada.
         if (tmr3if) overflow ++;  // ¿Ha desbordado el timer3?, incremento el contador
         tmr3if = 0;     // bajo la bandera y continuo esperando flanco.
      }

      float periodo = get_timer2();  // capturo el valor del timer
      periodo += (65535 + 1) * overflow;
      periodo *= 0.00000165;   // Todo lo que hemos cronometrado con el timer * 1,65 uS.
      periodo = 1/periodo;   // ahora tienes la frecuencia de un solo diente del encoder. (Valle y cresta)
      periodo *= 2;  // el motor es de 2 pulsos
      RPM=periodo * 60;  //. Retorna el valor en rpm     
}
void main()
{
   //Configura los Puertos del PIC
   set_tris_a(0b00000111);//RA0 RA1 RA2 como entrada, donde está el potenciometro
   set_tris_b(0b00000011); //RB0 como entrada, donde está conectado el encoder del motor y se utiliza interrupcion externa (que trabaja con este pin)
   set_tris_c(0b00000000);//todo el puerto C como salida
   lcd_init();
   lcd_gotoxy(1,1);
   printf(LCD_PUTC, "BIENVENIDO");
   delay_ms(200);
    //Habilita las Interrupcciones
    enable_interrupts(int_ext); //Activa interrupcion por RB0
    ext_int_edge(L_TO_H);    //Activa interrupción por flanco de subida
    enable_interrupts(global); //Habilita interrupciones de forma global, se hacen arriba del main como funcion global
   //Configura el PWM
   // Generemos una Señal cuadrada de 1 Khz
   Timer2=249;    //Se carga timer 2 con 249 como lo vimos en la pagina
   Poscaler=1;  //Preescaler solo puede tomar valores de: 1
   
   setup_timer_2(t2_div_by_4,Timer2,Poscaler);   //Configuracion de Timer 2 para establecer frec. PWM a 1kHz
   
   setup_ccp1(ccp_pwm); //Configura el modulo CCP1 en modo PWM
   set_pwm1_duty(70);    //Determina el ciclo de trabajo en escala de 0 a 255 (PARÁMETRO DE INICIO)
   //Hace por siempre
   while(1)
   {
     //  Visualiza la Velocidad
     lcd_gotoxy(1,2);
     printf(lcd_putc,"RPM: %f   ",RPM);
   }
   
}
Espero que me puedas ayudar, desde ya muchas gracias

Saludos

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Ajustar Velocidad de motor dada las RPM
« Respuesta #7 en: 13 de Agosto de 2020, 14:54:33 »
Por que tu micro no tiene timer3.   Por eso te da fallo el set_timer3(0);

  El timer2 es para el PWM, así que usa el timer1 en modo 16 bits. y cambia los set_timer3, por set_timer1.

  Respecto a la bandera tmr1if tienes que definirla colocando la siguiente macro en la cabecera:
Código: C
  1. #bit tmr2if = 0x00c.0


 Y no olvides colocar un disable interrupt global al principio del handler y un Enable al salir para reanudarlas.
« Última modificación: 13 de Agosto de 2020, 16:54:07 por remi04 »

Desconectado artemis

  • PIC10
  • *
  • Mensajes: 34
Re:Ajustar Velocidad de motor dada las RPM
« Respuesta #8 en: 13 de Agosto de 2020, 20:13:31 »
Por que tu micro no tiene timer3.   Por eso te da fallo el set_timer3(0);

  El timer2 es para el PWM, así que usa el timer1 en modo 16 bits. y cambia los set_timer3, por set_timer1.

  Respecto a la bandera tmr1if tienes que definirla colocando la siguiente macro en la cabecera:
Código: C
  1. #bit tmr2if = 0x00c.0


 Y no olvides colocar un disable interrupt global al principio del handler y un Enable al salir para reanudarlas.
Hola remi

Hice lo que me dijiste pero no me funciona :( , no se donde tengo mal el código
*Agregué la linea para deshabilitar las interrupciones globales en el handler y luego las vuelvo a habilitar en el main
*Definí #bit tmr2if = 0x00c.0 y utilizo timer1

Código: [Seleccionar]
#INCLUDE <16F876A.h>
#DEVICE ADC=10
#USE DELAY(CLOCK=4000000)
#FUSES XT,NOPROTECT,NOWDT,NOBROWNOUT,PUT,NOLVP
#INCLUDE <flex_lcd.C>
#DEFINE USE_PORTB_LCD TRUE
//Direcciones de memoria que utilizan los puertos A,B y C
#BYTE PORTA= 5
#byte PORTB= 6
#byte PORTC= 7
#bit tmr2if = 0x00c.0

long contador=0;//Variable para contar los pulsos del encoder
int16 duty=0;//para guardar el ciclo duty del pwm
int Timer2,Poscaler;//para configurar el pwm
double RPM,P_RPM;//se guarda las revoluciones por minuto del motor
int i=0; //variable que servira como contador
//Interrubción por cambio en RB0
#INT_EXT
ext_isr()//esta funcion solo se activa cuando hay una interrupcion por flanco de subida (L TO H)
{
      disable_interrupts(global);
      while (input(PIN_B0));   // esperando flanco de bajada.
       set_timer1(0); //.  Pongo el “crono” a cero.
       int overflow = 0;  // Para contar los desbordamientos del timer.
       while(!input(PIN_B0))
       { //  Espero flanco de subida.
          if (tmr2if) overflow ++;  // ¿Ha desbordado el timer3?, incremento el contador
         tmr2if = 0;     // bajo la bandera y continuo esperando flanco.
       }
         // Y ahora lo mismo para el otro flanco:
      while(input(PIN_B0))
      { //  Espero flanco Bajada.
         if (tmr2if) overflow ++;  // ¿Ha desbordado el timer3?, incremento el contador
         tmr2if = 0;     // bajo la bandera y continuo esperando flanco.
      }

      float periodo = get_timer1();  // capturo el valor del timer
      periodo += (65535 + 1) * overflow;
      periodo *= 0.00000165;   // Todo lo que hemos cronometrado con el timer * 1,65 uS.
      periodo = 1/periodo;   // ahora tienes la frecuencia de un solo diente del encoder. (Valle y cresta)
      periodo *= 2;  // el motor es de 2 pulsos
      RPM=periodo * 60;  //. Retorna el valor en rpm     
}
void main()
{
   //Configura los Puertos del PIC
   set_tris_a(0b00000111);//RA0 RA1 RA2 como entrada, donde está el potenciometro
   set_tris_b(0b00000011); //RB0 como entrada, donde está conectado el encoder del motor y se utiliza interrupcion externa (que trabaja con este pin)
   set_tris_c(0b00000000);//todo el puerto C como salida
   lcd_init();
   lcd_gotoxy(1,1);
   printf(LCD_PUTC, "BIENVENIDO");
   delay_ms(200);
    //Habilita las Interrupcciones
    enable_interrupts(int_ext); //Activa interrupcion por RB0
    ext_int_edge(L_TO_H);    //Activa interrupción por flanco de subida
    enable_interrupts(global); //Habilita interrupciones de forma global, se hacen arriba del main como funcion global
   //Configura el PWM
   // Generemos una Señal cuadrada de 1 Khz
   Timer2=249;    //Se carga timer 2 con 249 como lo vimos en la pagina
   Poscaler=1;  //Preescaler solo puede tomar valores de: 1
   
   setup_timer_2(t2_div_by_4,Timer2,Poscaler);   //Configuracion de Timer 2 para establecer frec. PWM a 1kHz
   
   setup_ccp1(ccp_pwm); //Configura el modulo CCP1 en modo PWM
   set_pwm1_duty(70);    //Determina el ciclo de trabajo en escala de 0 a 255 (PARAMETRO DE INICIO)
   //Hace por siempre
   while(1)
   {
     //  Visualiza la Velocidad
     lcd_gotoxy(1,2);
     printf(lcd_putc,"RPM: %f   ",RPM);
   }
   
}

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Ajustar Velocidad de motor dada las RPM
« Respuesta #9 en: 14 de Agosto de 2020, 02:21:51 »
¿La señal del encoder llega correctamente al pin b0?.  ¿Lo has comprobado de forma clara, como con un osciloscopio o conectando un led en otro puerto para que encienda y apague con los pulsos del encoder moviendo el motor manualmente??. 

  Los encoder suelen llevar sensor hall que son en la mayoría Open Drain, lo que significa que tienes que ponerle al puerto b.0 una resistencia usualmente de 4k7 a vdd..   O habilitar las pullup internas del puerto b si ese micro cuenta con ellas.

 

Desconectado artemis

  • PIC10
  • *
  • Mensajes: 34
Re:Ajustar Velocidad de motor dada las RPM
« Respuesta #10 en: 14 de Agosto de 2020, 16:58:50 »
si estuve realizando pruebas pero no me funciona, si quieres te adjunto el proyecto en proteus

 
* Encoder.zip
(24.69 kB - descargado 178 veces)

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Ajustar Velocidad de motor dada las RPM
« Respuesta #11 en: 19 de Agosto de 2020, 05:55:25 »
Hola, he estado ausentado unos días. 

  ¿Puedes poner una foto del encoder del motor? y como lo estas conectando.

  Por ejemplo, el esquemático de proteus (No lo tengo instalado).  Si es el mismo que el del primer mensaje hay que ver el tipo de encoder y la señal que devuelve, si es una señal 0-5V o si es open drain (Caso mas probable).

  Si es open drain y lo tienes conectado como aparece en el diagrama del primer mensaje, no va a funcionar salvo que habilites las resistencias pullup internas del puerto B, y esto se hace poniendo a cero el bit 7 del registro option_reg.  Definelo con la siguiente macro:

Código: C
  1. #bit RBPU=0x81.7

  Luego en el main pones:

Código: C
  1. RBPU = 0;     // Pullup en puertos RB3 a RB0 activados.
Y empezar desde abajo del todo, lo primero, estar seguro de que el encoder está funcionando con un bucle de prueba, y un led conectado por ejemplo al portb4 por ejemplo:


Código: C
  1. output_low(PIN_B4);  // Establece el puerto b4 como salida y a nivel bajo.  (Led conectado a este puerto con su resistencia de limitación).
  2. while(1) {                         // Loop.
  3. if (input(PIN_B0)) output_high(PIN_B4);
  4. else output_low(PIN_B4);
  5. }

Desactiva las interrupciones.
Con este código puesto en tu main justo despues de realizar todas las configuraciones del micro, el led debe encender y apagarse conforme gires el motor con la mano. 









Desconectado artemis

  • PIC10
  • *
  • Mensajes: 34
Re:Ajustar Velocidad de motor dada las RPM
« Respuesta #12 en: 19 de Agosto de 2020, 19:17:37 »
Hola, he estado ausentado unos días. 

  ¿Puedes poner una foto del encoder del motor? y como lo estas conectando.

  Por ejemplo, el esquemático de proteus (No lo tengo instalado).  Si es el mismo que el del primer mensaje hay que ver el tipo de encoder y la señal que devuelve, si es una señal 0-5V o si es open drain (Caso mas probable).

  Si es open drain y lo tienes conectado como aparece en el diagrama del primer mensaje, no va a funcionar salvo que habilites las resistencias pullup internas del puerto B, y esto se hace poniendo a cero el bit 7 del registro option_reg.  Definelo con la siguiente macro:

Código: C
  1. #bit RBPU=0x81.7

  Luego en el main pones:

Código: C
  1. RBPU = 0;     // Pullup en puertos RB3 a RB0 activados.
Y empezar desde abajo del todo, lo primero, estar seguro de que el encoder está funcionando con un bucle de prueba, y un led conectado por ejemplo al portb4 por ejemplo:


Código: C
  1. output_low(PIN_B4);  // Establece el puerto b4 como salida y a nivel bajo.  (Led conectado a este puerto con su resistencia de limitación).
  2. while(1) {                         // Loop.
  3. if (input(PIN_B0)) output_high(PIN_B4);
  4. else output_low(PIN_B4);
  5. }

Desactiva las interrupciones.
Con este código puesto en tu main justo despues de realizar todas las configuraciones del micro, el led debe encender y apagarse conforme gires el motor con la mano.

Hola remi

Te adjunto una captura del tipo de encoder que estoy utilizando en proteus asi veo que camino tengo que seguir, muchas gracias por el apoyo


Saludos

Desconectado artemis

  • PIC10
  • *
  • Mensajes: 34
Re:Ajustar Velocidad de motor dada las RPM
« Respuesta #13 en: 19 de Agosto de 2020, 21:56:31 »
Hola, he estado ausentado unos días. 

  ¿Puedes poner una foto del encoder del motor? y como lo estas conectando.

  Por ejemplo, el esquemático de proteus (No lo tengo instalado).  Si es el mismo que el del primer mensaje hay que ver el tipo de encoder y la señal que devuelve, si es una señal 0-5V o si es open drain (Caso mas probable).

  Si es open drain y lo tienes conectado como aparece en el diagrama del primer mensaje, no va a funcionar salvo que habilites las resistencias pullup internas del puerto B, y esto se hace poniendo a cero el bit 7 del registro option_reg.  Definelo con la siguiente macro:

Código: C
  1. #bit RBPU=0x81.7

  Luego en el main pones:

Código: C
  1. RBPU = 0;     // Pullup en puertos RB3 a RB0 activados.
Y empezar desde abajo del todo, lo primero, estar seguro de que el encoder está funcionando con un bucle de prueba, y un led conectado por ejemplo al portb4 por ejemplo:


Código: C
  1. output_low(PIN_B4);  // Establece el puerto b4 como salida y a nivel bajo.  (Led conectado a este puerto con su resistencia de limitación).
  2. while(1) {                         // Loop.
  3. if (input(PIN_B0)) output_high(PIN_B4);
  4. else output_low(PIN_B4);
  5. }

Desactiva las interrupciones.
Con este código puesto en tu main justo despues de realizar todas las configuraciones del micro, el led debe encender y apagarse conforme gires el motor con la mano.

Probé el led con el código que sugeriste (lo agregué al código que ya tenía yo) y efectivamente prende y apaga todo el tiempo, el motor encoder también está encendido. El led está conectado al pin b4 con una resistencia

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Ajustar Velocidad de motor dada las RPM
« Respuesta #14 en: 25 de Agosto de 2020, 16:59:32 »
Pues ahora lo siguiente es comprobar que el programa entra en la interrupción, la antiende y regresa al main.

  Pones dentro del main un bucle infinito:

  while(1);

  Ya está, solo eso.

  En el handler ee interrupción lo primero es poner un disable interrupt global para que no reentre mientras se atiende.

     Lo que vamos a hacer es

  - encender el led
  - poner un delay_ms(1000);
   - apagar el led.
   - Reactivar las interrupciones y regresar al main.

    Probar que leo programa arranca y que al girar el motor manualmente muy lentamente, verificar que el led se enciende un segundo y se apaga de nuevo.   Volver a girar el motor y verificar que de nuevo el led enciende un segundo y se apaga.

   Una vez que esto funcione ya pasamos a configurar un timer para empezar a medir periodos.

  Un saludo.
« Última modificación: 25 de Agosto de 2020, 17:05:07 por remi04 »