Autor Tema: Problemas "Encoder Quadrature Module"  (Leído 3979 veces)

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

Desconectado RiBerZerO

  • PIC12
  • **
  • Mensajes: 52
Problemas "Encoder Quadrature Module"
« en: 01 de Agosto de 2007, 17:10:22 »
Estoy realizando un proyecto el cual debe probar los encoders en cuadratura, mi problema es pequeño puedo contar los pulsos pero nececito poder quitar y poner el reseteo por Index, el modulo lo configuro con "100 = x2 index pulse reset of position counter", pero se resetea siempre sin importarle el valor que tenga el POSRES que es el que realiza la funcion que quiero.

Programa

Código: C
  1. #include <p30f4012.h>
  2. #include <qei.h>
  3.  
  4. /******************Puertos***************************************/
  5. #define LCD_D1  LATEbits.LATE2  //
  6. #define LCD_D2  LATEbits.LATE3  //Macros para los puertos
  7. #define LCD_D3  LATEbits.LATE4  //Que tendran la interconexion
  8. #define LCD_D4  LATEbits.LATE5  //
  9.  
  10.  
  11. #define LCD_RS  LATEbits.LATE0
  12. #define LCD_EN  LATEbits.LATE1
  13. #define LCD_LED LATDbits.LATD0
  14.  
  15. #define LCD_D1_TRIS     TRISEbits.TRISE2
  16. #define LCD_D2_TRIS     TRISEbits.TRISE3
  17. #define LCD_D3_TRIS     TRISEbits.TRISE4
  18. #define LCD_D4_TRIS     TRISEbits.TRISE5
  19.  
  20. #define LCD_RS_TRIS             TRISEbits.TRISE0
  21. #define LCD_EN_TRIS             TRISEbits.TRISE1
  22. #define LCD_LED_TRIS    TRISDbits.TRISD0
  23.  
  24. /******************Comandos************************/
  25.  
  26. #define LCD_CLR         0x01                // Clear Display
  27. #define LCD_HOME        0x02                // Cursor to Home position
  28.  
  29. #define  CURSOR_DIRECCTION_Increment    0x6             //
  30. #define  CURSOR_DIRECCTION_Decrement    0x4             // Entry mode set
  31. #define  Accompanies_display_shift      0x5             //ejemplo: LCD_CMD( CURSOR_DIRECCTION_Decrement | NO_Accompanies_display_shift );
  32. #define  No_Accompanies_display_shift   0x4     //
  33.  
  34. #define DISPLAY_ON                      0x0C                    //
  35. #define DISPLAY_OFF             0x08                    //
  36. #define CURSOR_ON                       0x0A                    // Display on/off control
  37. #define CURSOR_OFF                      0x08                    // ejemplo: LCD_CMD( DISPLAY_ON | CURSOR_ON | CURSOR_BLINKING_OFF );
  38. #define CURSOR_BLINKING_ON      0x09                    //
  39. #define CURSOR_BLINKING_OFF 0x08                        //
  40.  
  41. #define Display_shift           0x18                    //
  42. #define Cursor_move             0x10                    //Cursor or display shift
  43. #define Shift_to_the_right      0x14                    //ejemplo: LCD_CMD( Cursor_move |  Shift_to_the_left );  
  44. #define Shift_to_the_left       0x10                    //
  45.  
  46. /***************Movimiento del cursor***************/
  47.  
  48. #define LCD_linea1      0x80
  49. #define LCD_linea2      0xC0
  50.  
  51. /**************************************************/
  52.  
  53. /***************Fuses de configuracion*************/
  54.  
  55. _FOSC(CSW_FSCM_OFF&XT_PLL16);
  56. _FWDT(WDT_OFF);
  57. _FBORPOR(PBOR_OFF&MCLR_DIS);
  58. _FGS(CODE_PROT_OFF);
  59.  
  60. /******************Prototipos de funciones***********/
  61.  
  62. void MsDelay(int x);
  63. void USDelay(int x);
  64. void LCD_INIT(void);
  65. void LCD_NIBBLE_OUT(unsigned char c);
  66. void LCD_STROBE(void);
  67. void LCD_CLEAR();
  68. void LCD_CMD(char c);
  69. void LCD_STRING(char *s);
  70. void LCD_CHAR(unsigned char c);
  71. void LCD_GOTO(char line, char posicion);
  72. void LCD_PUTUN (unsigned char Digitos , unsigned long valor);
  73.  
  74.  
  75. /************* START OF MAIN FUNCTION ***************/
  76.  
  77. int main ( void ){
  78.         DisableIntADC;
  79.         ADPCFG=0xFF;
  80.         LCD_LED=1;
  81.         ConfigIntQEI(QEI_INT_DISABLE&QEI_INT_PRI_2);
  82.        
  83.         POSCNT = 0;
  84.         OpenQEI(QEI_DIR_SEL_QEB &
  85.                         QEI_INDEX_RESET_DISABLE &
  86.                         QEI_INPUTS_NOSWAP &
  87.                         QEI_MODE_x2_PULSE ,0
  88.                         );
  89.  
  90.         LCD_INIT();
  91.         LCD_GOTO(1,1);
  92.         LCD_STRING("Pulsos");
  93.         while(1){
  94.                         LCD_GOTO(2,6);
  95.                         LCD_PUTUN(7,POSCNT);
  96.         }
  97. }
  98.  
  99.  
  100. /***********Retardo para microsegundos**********/
  101.  
  102. void USDelay(int x){
  103.         while(x!=0){
  104.  
  105.                 Nop();  Nop();
  106.                 Nop();  Nop();
  107.                 Nop();  Nop();
  108.                 Nop();  Nop();
  109.  
  110.                 Nop();  Nop();
  111.                 Nop();  Nop();
  112.                 Nop();  Nop();
  113.                 Nop();  Nop();
  114.  
  115.                 Nop();  Nop();
  116.                 Nop();  Nop();
  117.                 Nop();  Nop();
  118.                 Nop();  Nop();
  119.                
  120.                 Nop();
  121.  
  122.                 x--;
  123.         }
  124.         return;
  125. }
  126.  
  127. /***************Funcion de milisegundos****************/
  128.  
  129. void MsDelay(int x){
  130.         while(x!=0){
  131.                 USDelay(1000);
  132.                 x--;
  133.         }
  134. }
  135.  
  136. /**************Escribir un Nibble*********************/
  137.  
  138. void LCD_NIBBLE_OUT(unsigned char c){
  139.         LCD_D1=c;       c>>=1;
  140.         LCD_D2=c;       c>>=1;
  141.         LCD_D3=c;       c>>=1;
  142.         LCD_D4=c;
  143.         LCD_STROBE();
  144. }
  145.  
  146. /***********Activar el LCD para leer el dato**********/
  147.  
  148. void LCD_STROBE(void){
  149.         LCD_EN=1;
  150.         USDelay(1);
  151.         LCD_EN=0;
  152. }
  153.  
  154. /**************Inicializar la pantalla de LCD************/
  155.  
  156. void LCD_INIT(void){
  157.  
  158.         LCD_LED_TRIS=0;
  159.        
  160.         LCD_RS_TRIS=0;  //Seleccion de registro
  161.         LCD_EN_TRIS=0;  //Enable
  162.  
  163.         LCD_D1_TRIS=0;  //
  164.         LCD_D2_TRIS=0;  //      Puertos para enviar
  165.         LCD_D3_TRIS=0;  //      los datos
  166.         LCD_D4_TRIS=0;  //
  167.  
  168.         LCD_RS=0;
  169.         MsDelay(20);
  170.         LCD_NIBBLE_OUT(0x02);
  171.         USDelay(100);
  172.  
  173.         LCD_CMD(0x28);
  174.         LCD_CMD(0x28);
  175.        
  176.         LCD_CMD(DISPLAY_OFF);
  177.         LCD_CMD(DISPLAY_ON |  CURSOR_OFF | CURSOR_BLINKING_OFF);
  178.         LCD_CMD(CURSOR_DIRECCTION_Increment | No_Accompanies_display_shift);
  179.         LCD_CLEAR();
  180. }
  181.  
  182. /*************lIMPIAR LA PANTALLA********************/
  183.  
  184. void LCD_CLEAR(){
  185.         LCD_CMD(LCD_CLR);
  186.         MsDelay(3);
  187. }
  188. /*************Escribir 1 byte al LCD*****************/
  189.  
  190. void LCD_WRITE(unsigned char c){
  191.         LCD_NIBBLE_OUT(c>>4);
  192.         LCD_NIBBLE_OUT(c);
  193.         USDelay(50);
  194. }
  195.  
  196. /**************Escribir un caracter*******************/
  197.  
  198. void LCD_CHAR(unsigned char c){
  199.         LCD_RS=1;
  200.         LCD_WRITE(c);
  201.        
  202. }
  203.  
  204. /************Enviar un comando************************/
  205.  
  206. void LCD_CMD(char c){
  207.         LCD_RS=0;
  208.         LCD_WRITE(c);
  209. }
  210.  
  211. /************Enviar una cadena de caracteres*************/
  212.  
  213. void LCD_STRING(char *s){
  214.         LCD_RS=1;
  215.         while(*s)
  216.                 LCD_WRITE(*s++);
  217. }
  218.        
  219. /********************Funcion ir a****************/
  220.  
  221. void LCD_GOTO(char line, char pos){
  222.         switch(line){
  223.                 case 1: LCD_CMD((LCD_linea1-1)+pos);
  224.                                 break;
  225.                 case 2: LCD_CMD((LCD_linea2-1)+pos);
  226.                         break;
  227.         }
  228. }
  229.  
  230. /****************************************/
  231. /*  Escribe Valor numerico al LCD       */
  232. /*  Max 1 a 9 digitos                   */
  233. /*  ceros a la izquierda blancos        */
  234. /*  puno de miles y millones            */
  235. /****************************************/  
  236. /*  ejemplo :  341.000.780   1.886  23  */
  237.  
  238. void LCD_PUTUN (unsigned char Digitos , unsigned long valor) {
  239.         unsigned char t1,i,wrote;
  240.         unsigned long k=0;
  241.         wrote=0;
  242.         for (i=Digitos-1; i>=1; i--){
  243.                 switch(i){
  244.                         case 8: k=100000000;
  245.                                         break;
  246.                 case 7: k=10000000;
  247.                                         break;
  248.                         case 6: k=1000000;
  249.                                         break;
  250.                         case 5: k=100000;  
  251.                                         if (Digitos > 6){
  252.                                                 if (wrote==1){
  253.                                                         LCD_CHAR(' ');
  254.                                                 }
  255.                                                 else {
  256.                                                         LCD_CHAR(' ');
  257.                                                 }
  258.                                         } // millones
  259.                                         break;
  260.                         case 4: k=10000;        
  261.                                         break;
  262.                         case 3: k=1000;  
  263.                                         break;
  264.                         case 2: k=100;    
  265.                                         if (Digitos > 3){
  266.                                                 if (wrote==1){
  267.                                                         LCD_CHAR(' ');
  268.                                                 }
  269.                                                 else {
  270.                                                         LCD_CHAR(' ');
  271.                                                 }
  272.                                         } // miles
  273.                                         break;
  274.                         case 1: k=10;
  275.                 }
  276.         t1=valor/k;
  277.                 if((wrote)||(t1!=0)){
  278.                         LCD_CHAR(t1+'0');
  279.                         wrote=1;
  280.                 }
  281.         else LCD_CHAR(' ');                               // Ceros izquierda blanco
  282.         valor-=(t1*k);
  283.         }      
  284.         LCD_CHAR( valor +'0');
  285. }

Espero me puedan ayudar gracias de antemano
No SUEÑES tu vida, VIVE tu sueño

Desconectado Renatox_

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 541
    • máquinas cnc
Re: Problemas "Encoder Quadrature Module"
« Respuesta #1 en: 02 de Agosto de 2007, 00:06:35 »
hola RiBerZerO veo que pusiste esta línea en tu código:

ConfigIntQEI(QEI_INT_DISABLE&QEI_INT_PRI_2);

Has usado la librería QEI.h y al parecer has deshabilitado la interrupción cuando el POSCNT iguala a MAXCNT pero si te fijas en el bit QEIIE del registro IEC2 se ha puesto a uno, al menos me ha pasado a mi, asi que al parecer hay un error o bug en esa librería. Te recomiendo que lo configures bit a bit como esta configuración que uso:

Código: [Seleccionar]
void configQEI()
{
   CloseQEI();
   POSCNT = 0;
   MAXCNT = 30000;

   //ConfigIntQEI(QEI_INT_DISABLE);
   IEC2bits.QEIIE=0;

   _IPL=0;   
   ADPCFG = 0xFFFE;
   _TRISB3=1; _TRISB4=1; _TRISB5=1;
   QEICON = 0x2F4C;
   DFLTCON = 0x0190;
}

De esta forma al poner IEC2bits.QEIIE=0; deshabilito la interrupción.

Al principio tu POSCNT está en cero y cuando lo girás en reversa pasa al valor de MAXCNT y se produce la interrupción que no quisiste habilitar, y como no has puesto su vector de interrupción el dspic se resetea, eso mismo me pasó a mi. Trabaja mejor con los registros de tu dspic.

suerte
control de movimiento

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18310
    • MicroPIC
Re: Problemas "Encoder Quadrature Module"
« Respuesta #2 en: 02 de Agosto de 2007, 01:57:43 »
¡Impresionante análisis haces Renatox!, nunca se me habría ocurrido eso de la interrupción que se ejecuta antes de tener definido el vector de interrupción.

En mi caso estuve probando con el QEIM y me funcionó perfecto, pero también lo configuro tocando el registro y sin usar la librería. Mi ejemplo está aquí: dsPIC33F - Capítulo 3: Quadrature Encoder Interface (QEIM)

Desconectado Renatox_

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 541
    • máquinas cnc
Re: Problemas "Encoder Quadrature Module"
« Respuesta #3 en: 03 de Agosto de 2007, 02:27:53 »
Hola Nocturno, esta muy bien hecho tu trabajo veo que los módulos QEI de los 30f se parecen bastante al de los 33f.

El registro POSCNT se resetea por coincidencia con el MAXCNT, QEIM<0>=1, en el sentido directo POSCNT se incrementa e iguala a MAXCNT y en el siguiente pulso pasa a cero. Y en el sentido inverso POSCNT decrece hasta llegar a cero y en el siguiente pulso toma el valor de MAXCNT.

Si se deshabilitó la interrupción este proceso continua sin ningún problema, pero si se activó, el PC salta al vector de interrupción que es este:

void __attribute__((interrupt, no_auto_psv))  _QEIInterrupt(void)

Si no se pone ese vector el PC empezará en la primera línea del int main void(); es decir es como si se hubiera reseteado.

Para desactivar la interrupción hay dos formas una es con la librería qei.h y la otra con el registro, asi:

   ConfigIntQEI(QEI_INT_DISABLE);
   IEC2bits.QEIIE=0;

El problema que tuve fue que al poner ConfigIntQEI(QEI_INT_DISABLE) el bit QEIIE se ponia a uno y no a cero como debe ser, por eso dejé de trabajar con esa librería.

saludos
control de movimiento

Desconectado blackcat

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 600
Re: Problemas "Encoder Quadrature Module"
« Respuesta #4 en: 03 de Agosto de 2007, 15:28:52 »
Hola

 Hablando del QEI tengo un pequeño problema de concepto respecto a las interrupciones. Debo realizar un proyecto en donde debo utilizar el modulo QEI ... bueno debía ... porque mi jefe, sin consultarme, compro dsPIC30F4013 el cual NO tiene el QEI  :x ahora me la voy a tener que ingeniar sin utilizar componentes extra, pensaba usar las interrupciones por cambio de nivel del dsPIC... creo que asi se llaman  :?: ... la serie 16F tiene ese tipo de interrupcion ... Ahora el problema es que eso significa tres interrupciones: Canal A, Canal B e Index, cuando se de una interrupcion por cambio de nivel nada mas se verifica el estado de los niveles de los tres canales y conociendo el estado anterior se sabrá si la cuenta es para arriba o para abajo .... Bueno ese no es el problema, el asunto es que tambien se tienen activadas las interrupciones por USART (RX), el Timer1 y Timer2 ..... TODAS las interrupciones son importantes y necesarias y ninguna se puede ignorar ... Tengo entendido que el dsPIC puede dar prioridad si dos o mas interrupciones se ejecutan al mismo tiempo pero ¿Una vez ejecutada la interrupcion de mayor prioridad se ejecuta la segunda, despues la tercera, etc, es decir, NO se ignoran, y una vez atendidas todas las interrupciones el dsPIC continua con el programa? el dsPIC funciona asi??  Lei que las rutinas de servicio deben tener el menor codigo posible aunque el dsPIC soporta interrupciones anidadas, es decir un interrupcion sobre la rutina de servicio de otra interrupcion pero que pasa en el caso de dos interrupciones exactamente al mismo tiempo.
Control Automático, DSP & Microcontroladores

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18310
    • MicroPIC
Re: Problemas "Encoder Quadrature Module"
« Respuesta #5 en: 03 de Agosto de 2007, 16:13:12 »
Si dos interrupciones se producen exactamente a la vez, se ejecuta primero la más prioritaria y cuando se termine de ejecutar, se ejecuta la otra.
Si una interrupción de baja prioridad se produce durante la ejecución de una de alta prioridad, se espera a que termine para ejecutarla.
Si una interrupción de alta prioridad se produce durante la ejecución de una de baja prioridad, se ejecuta de inmediato y, cuando acabe, sigue ejecutando la de baja prioridad por donde iba.

Desconectado blackcat

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 600
Re: Problemas "Encoder Quadrature Module"
« Respuesta #6 en: 03 de Agosto de 2007, 16:33:38 »
Ahhh que bien que bien  :P... JAJAJAJA  :D :D .... Muchas gracias!!!
Control Automático, DSP & Microcontroladores