Autor Tema: Array bidimensional con pic  (Leído 6155 veces)

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

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re:Array bidimensional con pic
« Respuesta #15 en: 25 de Marzo de 2018, 08:08:36 »
Hola KILLERJC estos son los motores que estoy usando con el mismo tipo de driver, y uso todo el puerto B para los dos motores cuatro bits de menor peso para un motor y los cuatro bits de mayor peso para el otro.
https://programarfacil.com/blog/motor-paso-a-paso/

Gracias.
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re:Array bidimensional con pic
« Respuesta #16 en: 25 de Marzo de 2018, 08:15:55 »
Luego no hay incremento de movimiento, es decir falta un movimiento++, y ademas verificar que sea valido de 1 a 4, o de 0 a 3 (es mas facil este)
Lo siento pero no entiendo muy bien esta parte, entiendo que debo de empezar el primer case en 0 en vez de 1 pero no entiendo lo de verificar que sea valido.
El incremento de la variable movimiento debe de ir en cada case.

Gracias.


Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Array bidimensional con pic
« Respuesta #17 en: 25 de Marzo de 2018, 08:44:07 »
Tu problema es que estas intentando cambiar ambos motores a la ves...

Utiliza un solo patron de encendido de salidas para todos los motores, asi tengas 100 motores, solo necesitas 1. Sea el que te dio tsk o el que te di yo, ambos casos ocupan la misma cantidad de memoria, incluso el de el seguramente sea mas rapido.
Luego si manejas 3 motores, utilizas 3 indices. Ese programa lo podes hacer tranquilamente con 1 indice, pero estoy buscando hacer algo mas general. El que vos simplemente puedas cambiar un indice y ya tener tu motor moviendose..

Sino en PROYECTOS Abner esta tambien con problemas con los PaP y ya se paso este tema.

Tu codigo escrito con un array solo:

Código: C
  1. const uint8_t medio_paso [8] = { 0b1000, 0b1100, 0b0100, 0b0110, 0b0010, 0b0011, 0b0001, 0b1001};
  2. uint8_t indiceX,indiceY;
  3.  
  4. void setupClock(void);
  5.  
  6. void main(void){
  7.    
  8. /* Configuracion de puertos */
  9.     ADCON1 = 0x0E;  // set RB<4:0> as digital I/O pins
  10.                     // (required if config bit PBADEN is set)
  11.     TRISB = 0x00;   // configuramos todo el PORTB como salidas
  12.    
  13.     setupClock();   // configuramos oscilador interno a 8MHz
  14.    
  15.     while(1)
  16.     {
  17.  
  18.         for(indiceX = 0; indiceX < 8; indiceX++)
  19.         {
  20.             LATB = ( LATB & 0xF0 ) | medio_paso[indiceX];
  21.             __delay_ms(10);
  22.         }
  23.  
  24.         for(indiceX = 7; indiceX > 7; indiceX--)
  25.         {
  26.             LATB = ( LATB & 0xF0 ) | medio_paso[indiceX];
  27.             __delay_ms(10);
  28.         }
  29.  
  30.         for(indiceY = 0; indiceY < 8; indiceY++)
  31.         {
  32.             LATB = ( LATB & 0x0F ) | (medio_paso[indiceY] << 4);
  33.             __delay_ms(10);
  34.         }
  35.  
  36.         for(indiceY = 7; indiceY > 7; indiceY--)
  37.         {
  38.             LATB = ( LATB & 0x0F ) | (medio_paso[indiceY] << 4);
  39.             __delay_ms(10);
  40.         }
  41.     }
  42. }

Despues podes jugar con defines para que sea mas simple de escribir ejemplo:

Código: C
  1. #DEFINE TO_HIGHBYTE(a,b)    (((a) & 0x0F) | (( (b) << 4 ) | ( (b) >> 4 ))
  2. #DEFINE TO_LOWBYTE(a,b)    (((a) & 0xF0) | (b))

Donde el highbyte tiene un swap (asi lo hace al swap XC8 )
Y usarlo:

Código: C
  1. TO_HIGHBYTE(LATB,medio_paso[indiceY]);
  2. TO_LOWBYTE(LATB,medio_paso[indiceX]);

PD: Los macros ni el programa los probe, pienso que deberian estar bien.

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

Si quisieras no "renegar" con tantos shift, podes crear otro array, para la parte alta:

Código: C
  1. const uint8_t medio_paso [8] = { 0b1000, 0b1100, 0b0100, 0b0110, 0b0010, 0b0011, 0b0001, 0b1001};
  2. const uint8_t medio_pasoh [8] = { 0b10000000, 0b11000000, 0b01000000, 0b01100000, 0b00100000, 0b00110000, 0b00010000, 0b10010000};

Y de esa forma el programa para la parte Y es casi igual a la del X, quedando:

Código: C
  1. LATB = ( LATB & 0xF0 ) | medio_pasoh[indiceY];

Esto ya queda a tu criterio.
« Última modificación: 25 de Marzo de 2018, 08:48:26 por KILLERJC »

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re:Array bidimensional con pic
« Respuesta #18 en: 25 de Marzo de 2018, 11:12:18 »
Excelente explicación KILLERJC voy a intentar entenderlo y ponerlo en practica y lo que no entienda lo siento pero tendré que preguntar, con eso no quiero menospreciar la ayuda de tsk pero me cuesta entender su planteamiento.

Gracias por las ayudas.
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado tsk

  • PIC18
  • ****
  • Mensajes: 258
Re:Array bidimensional con pic
« Respuesta #19 en: 25 de Marzo de 2018, 15:49:26 »
Es sencillo el planteamiento, ya que lo único que cambia entre dos pasos consecutivos es un sólo bit, por lo tanto es lo único que tienes que cambiar.

Por ejemplo tienes

0b1001 Estado Anterior
0b1000 Estado actual
0b1100 Estado Siguiente

Observa que entre estados contiguos sólo cambia un bit, ya sea prendiéndolo o apagándolo, con lo cual reduces el número de operaciones.

Esto sigue lo que se conoce como código grey y es empleado mucho en telecomunicaciones para que si ocurre un error, el cambio es por un sólo bit, y por lo tanto sea más fácil identificar y corregir el error.

No es lo mismo detectar un error al pasar de un

0b0011 -> 0b0100

que pasar de un

0b0011 -> 0b0010

Como ejemplo te muestro lo que en Telecomunicación se conoce como una constelación 16-QAM

Código: [Seleccionar]
. . | . .
. . | . .
 ---|---
. . | . .
. . | . .

Tienes un total de 16 puntos en la constelación, los cuales en un inicio vamos a codificar de la siguiente manera.

Código: [Seleccionar]
0000 0100 | 1000 1100
0001 0101 | 1001 1101
----------|----------
0010 0110 | 1010 1110
0011 0111 | 1011 1111

Supongamos que el valor que se envió fue un 0001, que se encuentra en el cuadrante 1, en caso de que exista ruido en el medio de comunicación, y este ruido es lo suficientemente grande como para mandarlo para que se transforme en cualquiera de los puntos que tiene más cerca, que serían 0000,0010, 0101.

En el mejor de los casos se va a mover a 0000 o 0101, lo cual implica cambiar un sólo bit, por lo tanto tienes error en un sólo bit, pero en el peor de los casos, se va a mover a 0010, lo cual lo va a dejar con dos bits de error.

Cuando sigues una codificación grey, como el cambio entre adjuntos es en un sólo bit, el error se va a mantener en un sólo bit, a menos que el error ya sea exagerando que no permita una comunicación confiable.

Por ejemplo, una constelación 16-QAM siguiendo el código grey

Código: [Seleccionar]
0000 0100 | 1100 1000
0001 0101 | 1101 1001
----------|----------
0011 0111 | 1111 1011
0010 0110 | 1110 1010

Por ejemplo mandamos un 1111, con suficiente ruido este se puede transformar en 1101, 1110, 0111 o 1011, pero el error se mantiene en un sólo bit.

Por otro lado, hace tiempo hice lo siguiente para controlar dos motores, pero usé máquinas de estados y una interrupción de timer para manejar varias tareas, como la adquisición de datos externos que le permitieran decidir la dirección del robot, y por lo tanto la dirección de los motores. Para ello usé un pic16f628a con SDCC.

Primero definí los estados del Robot
Código: C
  1. //Robot global state
  2. #define HLD 0
  3. #define FW 1
  4. #define BW 2
  5. #define LFT 3
  6. #define RGT 4
  7. #define IDLE 5
  8. //Individual Motor States
  9. #define M_HLD 0
  10. #define M_CW 1
  11. #define M_CCW 2
  12. #define M_IDLE 3

El robot puede estar en uno de 6 estados, Hold, Forward, Backward, Left,  Right, Idle, y por lo tanto cada motor puede estar en Hold, Clock Wise, Counter Clock Wise e Idle. Esto es porque los motores lo único que saben es ir en sentido de las manecillas del reloj o encontra de las manecillas del reloj.

No usé medio paso así que definí una variable llamada M_STEPS_F con pasos completos

Código: C
  1. unsigned char M_STEPS_F[] = {0x0C, 0x06,0x03,0x09};
Además de definir variables extras como:

Código: C
  1. unsigned char adc_lectures[3] = {0,0,0};  //[MIC, RLDR, LLDR]
  2. unsigned char current_channel = 0;
  3. unsigned char c_task = 0;
  4. unsigned char GLOBAL_STATE = IDLE;
  5. unsigned char M1_STATE = M_IDLE;
  6. unsigned char M2_STATE = M_IDLE;

Entonces cada vez que entraba a la interrupción del timer, leía un canal de ADC y llamaba una función para aplicar el estímulo al estado del robot, y si estaba relacionado con los canales de RLDR y LLDR y el valor estaba de bajo de cierto límite, entonces cambiaba el estado global del robot y llamaba la función set_direction().

Código: C
  1. void set_direction()
  2. {
  3.     switch(GLOBAL_STATE)
  4.     {
  5.         case HLD:
  6.             M1_STATE = M_HLD;
  7.             M2_STATE = M_HLD;
  8.             break;
  9.         case FW:
  10.             M1_STATE = M_CW;
  11.             M2_STATE = M_CCW;
  12.             break;
  13.         case BW:
  14.             M1_STATE = M_CCW;
  15.             M2_STATE = M_CW;
  16.             break;
  17.         case LFT:
  18.             M1_STATE = M_CCW;
  19.             M2_STATE = M_CCW;
  20.             break;
  21.         case RGT:
  22.             M1_STATE = M_CW;
  23.             M2_STATE = M_CW;
  24.             break;
  25.         case IDLE:
  26.             M1_STATE = M_IDLE;
  27.             M2_STATE = M_IDLE;
  28.             break;
  29.         default:
  30.             M1_STATE = M_IDLE;
  31.             M2_STATE = M_IDLE;
  32.             break;
  33.     }
  34. }

Lo mas seguro es la función set_direction va a ser diferente a lo que tu estas haciendo, ya que en lugar de ruedas, los motores estaban viendo hacia abajo.

Para mover el robot, lo único que hacía falta era que en la misma interrupción del timer llamar una función llamada move() solo en el caso que el contador de velocidad fuera mayor a cierto valor predefinido.

Código: C
  1. void move()
  2. {
  3.     unsigned char m1_move, m2_move;
  4.     if(GLOBAL_STATE == HLD){}
  5.     else if(GLOBAL_STATE == IDLE)
  6.     {
  7.         PORTC = 0x00;
  8.     } else {
  9.         if(M1_STATE==M_CW)
  10.         {
  11.             m1_step_count++;
  12.         } else {
  13.             m1_step_count--;
  14.         }
  15.         if(M2_STATE==M_CW)
  16.         {
  17.             m2_step_count++;
  18.         } else {
  19.             m2_step_count--;
  20.         }
  21.     }
  22.     m1_move = M_STEPS_F[m1_step_count&0x03];
  23.     m2_move = M_STEPS_F[m2_step_count&0x03]<<4;
  24.     PORTC = m2_move + m1_move;
  25. }

Si observas, sólo se requirió un definir una sóla vez el arreglo que contiene la secuencia de pasos, que es lo que KILLERJC está explicando.

¿Porqué m1_step_count&0x03 y m2_step_count&0x03 ?

Sólo me interesan los últimos dos bits del contador porque sólo tengo 4 elementos en el arreglo, así que los puedo dejar correr libremente.

Por ejemplo:

m = 0

m++

m = 1

indice = m&0x03
indice = 1
o

m--

m=255
indice = m&0x03
indice = 3

En tu caso, tienes un arreglo que tiene 8 entradas, de 0b00000000 a 0b00000111, así que también podrías dejar correr los contadores de los pasos libremente sólo que en lugar de m&0x03 tendrías un m&0x07.

Aquí la función de interrupción (SDCC).

Código: C
  1. void isr(void) __interrupt 0 {
  2.     if(T0IF)
  3.     {
  4.         m_velocity_task_counter++;
  5.         adc_lectures[current_channel] = read_adc();
  6.         apply_stimulus(current_channel,adc_lectures[current_channel]);
  7.         current_channel = (current_channel+1)%3;
  8.         set_adc_channel(current_channel);
  9.         if(m_velocity_task_counter > m_velocity)
  10.         {
  11.             move();
  12.             m_velocity_task_counter = 0;
  13.         }
  14.         switch(c_task&0x01)
  15.         {
  16.             case LEDS:
  17.                 c_task++;
  18.                 leds();
  19.                 break;
  20.             case SOUND:
  21.                 c_task++;
  22.                 sound();
  23.                 break;
  24.         }
  25.         TMR0 = STMR0;
  26.         T0IF = 0;
  27.     }
  28.     GIE = 1;
  29. }

No muy elegante pero en ese momento hacía su trabajo ya que lo que quería mostrarle a mi sobrino como reciclar ciertos objetos que por lo general tenemos en las casas para hacer un robot. Después de tiempo que le mostré esto, ahora quiere un robot que caminé, tenga brazos y que lo pueda mover con el cuerpo.

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re:Array bidimensional con pic
« Respuesta #20 en: 26 de Marzo de 2018, 04:35:07 »
Gracias tsk por tomarte la molestia en explicarlo, ahora toca estudiar las excelentes explicaciones que tanto tu como KILLERJC me habéis ofrecido y entenderlas.

Muchas gracias a los dos.
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.


 

anything