TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Miquel_S en 20 de Marzo de 2018, 16:44:26

Título: Array bidimensional con pic
Publicado por: Miquel_S en 20 de Marzo de 2018, 16:44:26
Buenas noches, necesitaría de vuestra ayuda, tengo problemas para sacar un array por el puerto b del pic y no se como hacerlo, ni tampoco encuentro nada por Internet relacionado con arrays y pics, este es el código con el que estoy trabajando:
Código: C
  1. #include <xc.h>
  2. #include "config_bits.h"
  3.  
  4. #define _XTAL_FREQ 8000000  // usado para delays
  5.  
  6. /* Secuencia de pasos (medio-paso) */
  7. int medio_paso [8][4] = {
  8.     {1, 0, 0, 0},
  9.     {1, 1, 0, 0},
  10.     {0, 1, 0, 0},
  11.     {0, 1, 1, 0},
  12.     {0, 0, 1, 0},
  13.     {0, 0, 1, 1},
  14.     {0, 0, 0, 1},
  15.     {1, 0, 0, 1}
  16. };
  17.  
  18.  
  19. void setupClock(void);
  20.  
  21. void main(void){
  22.    
  23. /* Configuracion de puertos */
  24.     ADCON1 = 0x0E;  // set RB<4:0> as digital I/O pins
  25.                     // (required if config bit PBADEN is set)
  26.     TRISB = 0x00;   // configuramos todo el PORTB como salidas
  27.    
  28.     setupClock();   // configuramos oscilador interno a 8MHz
  29.    
  30.     while(1){
  31.         for(unsigned int i = 0; i < 8; i++)
  32.         {
  33.             LATBbits.LATB0, medio_paso[i][0];
  34.             LATBbits.LATB1, medio_paso[i][1];
  35.             LATBbits.LATB2, medio_paso[i][2];
  36.             LATBbits.LATB3, medio_paso[i][3];
  37.             __delay_ms(10);
  38.         }
  39.     }
  40. }
  41.  
  42. void setupClock(void){
  43.     OSCCONbits.IRCF0 = 1;
  44.     OSCCONbits.IRCF1 = 1;
  45.     OSCCONbits.IRCF2 = 1;
  46.     OSCCONbits.SCS = 0b10;
  47. }

Muchas Gracias.
Título: Re:Array bidimensional con pic
Publicado por: KILLERJC en 20 de Marzo de 2018, 21:37:35
Primero y en principal no veo sentido a un array bidimensional.


Prefiero algo asi (Aprovechando que esta seguido y sin modificar RB4 a RB7):

Código: C
  1. int medio_paso [8] = { 0b1000, 0b1100, 0b0100, 0b0110, 0b0010, 0b0011, 0b0001, 0b1001};
  2.  
  3. // Y luego:
  4.  
  5.         for(unsigned int i = 0; i < 8; i++)
  6.         {
  7.             LATB = ( LATB & 0xF0 ) | medio_paso[i];
  8.             __delay_ms(10);
  9.         }

Si no estan seguidos se puede fabricar algo de la misma forma.
Pero si lo queres hacer como vos estas intentando entonces tu problema es que pusiste una coma, y no un igual.

Código: C
  1. LATBbits.LATB0, medio_paso[i][0];  //Mal
  2.             LATBbits.LATB0 = medio_paso[i][0]; //Correcto

Título: Re:Array bidimensional con pic
Publicado por: Miquel_S en 21 de Marzo de 2018, 03:44:50
Muchas gracias KILLERJC por la aclaración, una duda ¿Por motivos de consumo de recursos es mejor el uso de un array u otro?
Gracias de nuevo.
Título: Re:Array bidimensional con pic
Publicado por: KILLERJC en 21 de Marzo de 2018, 07:54:54
Yo me preocuparia por los recursos cuando me falten.
Personalmente considero que una opcion bastante simple seria poner el array en la flash y de alli hacer como hice en el primer codigo, de paso ponerlo como char, ya que int en XC8 es de 16 bits.


Código: C
  1. const uint8_t medio_paso [8] = { 0b1000, 0b1100, 0b0100, 0b0110, 0b0010, 0b0011, 0b0001, 0b1001};
  2.  
  3.         for(unsigned uint8_t i = 0; i < 8; i++)
  4.         {
  5.             LATB = ( LATB & 0xF0 ) | medio_paso[i];
  6.             __delay_ms(10);
  7.         }

Y si te preocupas por los recursos (tiempo de procesamiento,RAM,Flash,etc) tambien deberias pensar en ese delay de 10ms.
Por eso es un tire y afloje, podes ganar algo por un lado pero empeorarlo del otro. Ejemplo..
Podria hacerlo con un Timer al delay, gano tiempo de procesamiento, consumo un poco mas de Flash,
Podes hacerlo con delays como lo hiciste, pierdo tiempo de procesamiento, gano un poco de flash, un modulo, y tambien tiempo de desarrollo. Es mas facil poner un delay que calcular el timer y escribir todo el codigo para eso.
Ahora... ese delay molesta?, Si no molesta entonces no justifica que te tomes ese EXTRA para optimizarlo.
Te falta Flash? Te falta RAM, te faltan Timers (raro )? 
Título: Re:Array bidimensional con pic
Publicado por: tsk en 21 de Marzo de 2018, 15:06:39
Bueno, aunque esto no es un estire y afloja, también se puede observar la estructura del problema para obtener optimizaciones  que son triviales.

Por ejemplo, lo primero que se puede observar es que entre pasos existe un sólo cambio, al puro estilo del código grey, eso se puede aprovechar, ya que lo único que debes de hacer es estar atento cual es el bit que cambia.

0b1000, 0b1100, 0b0100, 0b0110, 0b0010, 0b0011, 0b0001, 0b1001

Considerando que tu estado inicial es 0b1000, el contenido del arreglo podría quedar así
Código: C
  1. const uint8_t medio_paso[] = {2,3,1,2,0,1,3,0};

y luego, en el lugar que decidas que debe ir, ya sea usando un delay o un timer, colocas

Código: C
  1. LATB^= 1 << medio_paso[i];

Estado Inicial
0b1000

Código: [Seleccionar]
1 << 2 -> 0b0100

0b1000 xor 0b0100 = 0b1100

1 << 3 -> 0b1000

0b1100 xor 0b1000 = 0b0100

1 << 1 -> 0b0010

0b0100 xor 0b0010 = 0b0110

1 << 2 -> 0b0100

0b0110 xor 0b0100 = 0b0010

1 << 0 -> 0b0001

0b0010 xor 0b0001 = 0b0011

1 << 1 -> 0b0010

0b0011 xor 0b0001 = 0b0001

1 << 3 -> 0b1000

0b0001 xor 0b1000 = 0b1001

1 << 0 -> 0b0001

0b1001 xor 0b0001 = 0b1000

1 << 2 -> 0b0100

0b1000 xor 0b0100 = 0b1100

En ASM esto puede representar tan sólo un bit set o un bit reset, que de todas formas también vienen en la siguiente secuencia:

{1,0,1,0,1,0...}

Donde 1 es un bit set y 0 es un bit reset.
Título: Re:Array bidimensional con pic
Publicado por: Miquel_S en 21 de Marzo de 2018, 15:53:32
Bueno, aunque esto no es un estire y afloja, también se puede observar la estructura del problema para obtener optimizaciones  que son triviales.

Por ejemplo, lo primero que se puede observar es que entre pasos existe un sólo cambio, al puro estilo del código grey, eso se puede aprovechar, ya que lo único que debes de hacer es estar atento cual es el bit que cambia.

0b1000, 0b1100, 0b0100, 0b0110, 0b0010, 0b0011, 0b0001, 0b1001

Considerando que tu estado inicial es 0b1000, el contenido del arreglo podría quedar así
Código: C
  1. const uint8_t medio_paso[] = {2,3,1,2,0,1,3,0};

y luego, en el lugar que decidas que debe ir, ya sea usando un delay o un timer, colocas

Código: C
  1. LATB^= 1 << medio_paso[i];

Estado Inicial
0b1000

Código: [Seleccionar]
1 << 2 -> 0b0100

0b1000 xor 0b0100 = 0b1100

1 << 3 -> 0b1000

0b1100 xor 0b1000 = 0b0100

1 << 1 -> 0b0010

0b0100 xor 0b0010 = 0b0110

1 << 2 -> 0b0100

0b0110 xor 0b0100 = 0b0010

1 << 0 -> 0b0001

0b0010 xor 0b0001 = 0b0011

1 << 1 -> 0b0010

0b0011 xor 0b0001 = 0b0001

1 << 3 -> 0b1000

0b0001 xor 0b1000 = 0b1001

1 << 0 -> 0b0001

0b1001 xor 0b0001 = 0b1000

1 << 2 -> 0b0100

0b1000 xor 0b0100 = 0b1100

En ASM esto puede representar tan sólo un bit set o un bit reset, que de todas formas también vienen en la siguiente secuencia:

{1,0,1,0,1,0...}

Donde 1 es un bit set y 0 es un bit reset.

 :shock: Aquí me has matado tsk, de todos modos voy a estudiar las dos opciones la tuya y la de KILLERJC y decantarme por la que mas me convenga al resultado final que quiero darle a todo el conjunto.

Muchas Gracias.
https://vimeo.com/124110129 (https://vimeo.com/124110129)
Título: Re:Array bidimensional con pic
Publicado por: planeta9999 en 21 de Marzo de 2018, 16:29:15
 
Los operadores bitwise se ven muy interesantes.

Los he visto con frecuencia en fuentes de otros, pero por ahora no los he aplicado en desarrollos míos, los de desplazamiento de bits los cazo, el resto no veo cuando puede ser recomendable usarlos.

Por ejemplo, en esta parte de un fuente, del que partí para una aplicación mía, no se exactamente que están haciendo con esos AND, luego le aplican también un desplazamiento de 1bit (o eso creo):

Código: C++
  1. uint16_t dotMask = 0x8000;
  2.     while (dotMask)
  3.     {
  4.       uint8_t colorEntry = 0;
  5.       if (dots0 & dotMask) colorEntry += 4;
  6.       if (dots1 & dotMask) colorEntry += 4;
  7.       if (dots2 & dotMask) colorEntry += 4;
  8.       if (dots3 & dotMask) colorEntry += 4;
  9.      *pixelBuffer = activePalette[colorEntry];
  10.       pixelBuffer++;
  11.       dotMask >>= 1;
  12.     }

Un día de estos me gustaría profundizar en el manejo de los operadores bitwise, deben de tener un potencial importante.
Título: Re:Array bidimensional con pic
Publicado por: tsk en 21 de Marzo de 2018, 20:03:28
Lo que se ve a simple vista es que te convierte de un conjunto de puntos a una paleta de 16 colores.

Con el AND lo que haces conocer si el punto está prendido o apagado, en cada vuelta puedes procesar una región o ventana conformada por una matriz de 4x16 puntos.

Así que, aunque los operadores bitwise sean interesantes, es más interesante el algoritmo que hay detrás del trabajo de procesamiento de imágenes.


A menos que que cada punto físico original esté conformado por 4 puntos más pequeños, si lo vemos como un filtro, aparte de convertir de unos puntos cualquiera a una paleta de colores, al realizar una combinación de los puntos que son adyacentes al punto que quieres convertir a pixel, generas mejores los contornos y suavizas la imagen resultante. Pero los puntos adyacentes pueden ser cualquiera. Por ejemplo, estos podrían ser los cuatro puntos que se encuentran alrededor del punto a convertir, y es lo más común.

Código: [Seleccionar]
  1
0 p 2
  3

Pero también podrían tomar cualquier otro forma como algunos de los puntos que se encuentran arriba y abajo, del punto a convertir.

Código: [Seleccionar]
0
1
2
3

1
2
3
4

2
3
4
5
...

Hablando de procesamiento digital de imágenes, a lo de arriba se le conoce como kernel y te indica las operaciones que vas a realizar y sobre cuales pixeles los vas realizar. Por ejemplo hay un filtro conocido como Sobel, el cual se usa para detectar bordes en imágenes, y su kernel toma la siguiente forma

X
Código: [Seleccionar]
+1 0 -1
+2 0 -2
+1 0 -1

Y
Código: [Seleccionar]
+1 +2 +1
 0  0  0
-1 -2 -1

En tu caso el kernel podría ser

Código: [Seleccionar]
   +4 
+4  p +4
   +4 

Y aplicas ese kernel a tu imagen (formada por puntos prendidos y apagados) por medio de un operador conocido como Convolución, con lo cual obtienes lo que deseas, ya sea suavizar bordes, extraer objetos, quitar o aplicar ruido, etc.
Título: Re:Array bidimensional con pic
Publicado por: planeta9999 en 21 de Marzo de 2018, 21:32:00
Lo que se ve a simple vista es que te convierte de un conjunto de puntos a una paleta de 16 colores.

Con el AND lo que haces conocer si el punto está prendido o apagado, en cada vuelta puedes procesar una región o ventana conformada por una matriz de 4x16 puntos.

Así que, aunque los operadores bitwise sean interesantes, es más interesante el algoritmo que hay detrás del trabajo de procesamiento de imágenes.

A menos que que cada punto físico original esté conformado por 4 puntos más pequeños, si lo vemos como un filtro, aparte de convertir de unos puntos cualquiera a una paleta de colores, al realizar una combinación de los puntos que son adyacentes al punto que quieres convertir a pixel, generas mejores los contornos y suavizas la imagen resultante. Pero los puntos adyacentes pueden ser cualquiera. Por ejemplo, estos podrían ser los cuatro puntos que se encuentran alrededor del punto a convertir, y es lo más común.

En este caso, se trata de una imagen que llega como cuatro frames o imágenes separadas, y la mezcla de las cuatro genera la imagen final, en la que cada punto tiene un nivel de brillo de 0 a 15. Esa función convierte cada nivel de brillo de 1 pixel (mezcla de 4) a un color de una paleta de 16 colores.

Lo que no cazo es lo de la máscara a 0x8000, y porque el bucle while está rodando hasta que la máscara dotMask deja de ser cierta. Supongo que el while se ejecuta mientras dosMask no sea cero.

La máscara empieza en 0x8000, y por cada pase por el bucle del while, le hace un desplazamiento de un bit a la derecha, no entiendo para que sirve esto.

Ahora que lo pienso, las variables dotsx son de 16 bit, y creo que cada una almacena el estado de 16 pixel de la imagen. Supongo que la máscara sirve para barrer, en cada paso del bucle, uno a uno los  16 pixel.

0x8000 en binario es 1000000000000000, entiendo que por cada pase por el bucle va desplazando un bit a la derecha, los siguientes serían 0100000000000000, 0010000000000000, etc... hasta llegar a 0000000000000000 que es cuando sale del while.

Código: C++
  1. uint16_t dotMask = 0x8000;
  2.     while (dotMask)
  3.     {
  4.       uint8_t colorEntry = 0;
  5.       if (dots0 & dotMask) colorEntry += 4;
  6.       if (dots1 & dotMask) colorEntry += 4;
  7.       if (dots2 & dotMask) colorEntry += 4;
  8.       if (dots3 & dotMask) colorEntry += 4;
  9.      *pixelBuffer = activePalette[colorEntry];
  10.       pixelBuffer++;
  11.       dotMask >>= 1;
  12.     }
Título: Re:Array bidimensional con pic
Publicado por: KILLERJC en 21 de Marzo de 2018, 23:41:59
Citar
Lo que no cazo es lo de la máscara a 0x8000, y porque el bucle while está rodando hasta que la máscara dotMask deja de ser cierta. Supongo que el while se ejecuta mientras dosMask no sea cero.

La máscara empieza en 0x8000, y por cada pase por el bucle del while, le hace un desplazamiento de un bit a la derecha, no entiendo para que sirve esto.

en binario
0x800 = 1000.0000.0000.0000
Rotado 1 ves
0x400 = 0100.0000.0000.0000
Otra ves rotado
0x200 = 0010.0000.0000.0000

Y revisa en las 4 imagenes el mismo bit aumentando el "brillo" si es que posee un 1 esa imagen. Cuando las 4 imagenes posean un 1 en ese bit, significa que el resultado sera maximo.

Como vos dijiste y en resumen...

Forma de 4 imagenes donde en cada una de esas imagenes cada pixel equivale a un bit ( 0 o 1 ), a una imagen donde cada pixel puede tener valores de 0 a 16

Cuando esta ene 0x001 = 0000.0000.0000.0001 al rotarlo otra ves, queda en 0x000, por lo tanto la condicion del while ya no se cumple y sale.
Título: Re:Array bidimensional con pic
Publicado por: planeta9999 en 22 de Marzo de 2018, 05:30:45

Si, eso mismo entendí, no hay como leer un programa unas cuantas veces y al final sale todo, aunque al principio me sonaba a chino mandarín.

El día que domine el DMA, ya puedo escribir un libro.   :P :P
Título: Re:Array bidimensional con pic
Publicado por: Miquel_S en 24 de Marzo de 2018, 15:21:45
Hola, sigo avanzando en mi pequeño proyecto y como era de esperar tengo errores y no doy con ellos, mi intención era que dependiendo del pulsador tuviera un movimiento u otro, pero creo tener un error en los switch-case y no consigo verlo. Algún buen samaritano me da una mano.

Código: C
  1. #include <xc.h>
  2. #include "config_bits.h"
  3.  
  4. #define _XTAL_FREQ 8000000  // usado para delays
  5.  
  6. /* Secuencia de pasos (medio-paso)
  7.    Motor derecho => bits de menor peso
  8.    Motor izquierdo => bits de mayor peso */
  9.  
  10. char forward_medio_paso [8] = {
  11.     0b10001001, 0b11000001,
  12.     0b01000011, 0b01100010,
  13.     0b00100110, 0b00110100,
  14.     0b00011100, 0b10011000};
  15.  
  16. char backward_medio_paso [8] = {
  17.     0b10011000, 0b00011100,
  18.     0b00110100, 0b00100110,
  19.     0b01100010, 0b01000011,
  20.     0b11000001, 0b10001001};
  21.  
  22. char right_medio_paso [8] = {
  23.     0b10001000, 0b11001100,
  24.     0b01000100, 0b01100110,
  25.     0b00100010, 0b00110011,
  26.     0b00010001, 0b10011001};
  27.  
  28. char left_medio_paso [8] = {
  29.     0b10011001, 0b00010001,
  30.     0b00110011, 0b00100010,
  31.     0b01100110, 0b01000100,
  32.     0b11001100, 0b10001000};
  33.  
  34. void setupClock(void);
  35.  
  36. char movimiento;
  37.  
  38. void main(void){
  39.    
  40. /* Configuracion de puertos */
  41.     ADCON1 = 0b00001111;    // todos los pines como digitales
  42.     //CMCON = 0x07;
  43.     TRISA = 0b00001111; // RA3:RA0 entradas
  44.     TRISB = 0x00;   // configuramos todo el PORTB como salidas
  45.  
  46. /* Configuracion oscilador interno */    
  47.     setupClock();   // configuramos oscilador interno a 8MHz
  48.    
  49.     while(1){
  50.        
  51.         switch(movimiento){
  52.             case 1:
  53.                 while(LATAbits.LATA0 == 1);
  54.                     for(char i = 0; i < 8; i++)
  55.                     {
  56.                         LATB = ( LATB & 0x00 ) | forward_medio_paso[i];
  57.                         __delay_ms(1);
  58.                     }
  59.             break;
  60.            
  61.             case 2:
  62.                 while(LATAbits.LATA1 == 1);
  63.                     for(char i = 0; i < 8; i++)
  64.                     {
  65.                         LATB = ( LATB & 0x00 ) | backward_medio_paso[i];
  66.                         __delay_ms(1);
  67.                     }
  68.             break;
  69.            
  70.             case 3:
  71.                 while(LATAbits.LATA2 == 1);
  72.                     for(char i = 0; i < 8; i++)
  73.                     {
  74.                         LATB = ( LATB & 0x00 ) | right_medio_paso[i];
  75.                         __delay_ms(1);
  76.                     }
  77.             break;
  78.            
  79.             case 4:
  80.                 while(LATAbits.LATA3 == 1);
  81.                     for(char i = 0; i < 8; i++)
  82.                     {
  83.                         LATB = ( LATB & 0x00 ) | left_medio_paso[i];
  84.                         __delay_ms(1);
  85.                     }
  86.             break;
  87.                
  88.         }
  89.     }
  90. }
  91.  
  92. void setupClock(void){
  93.     OSCCONbits.IRCF0 = 1;
  94.     OSCCONbits.IRCF1 = 1;
  95.     OSCCONbits.IRCF2 = 1;
  96.     OSCCONbits.SCS = 0b10;
  97. }

Gracias.
Título: Re:Array bidimensional con pic
Publicado por: KILLERJC en 24 de Marzo de 2018, 16:18:34
No tiene ningun sentido crear tantos arrays asi para manejar 2 motores. No se como estas conectando los motores pero podria llegar a ser mucho mas simple.

Tus errores son:

movimiento, no esta inicializado, deberias hacerlo a 0.
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)

Respecto a los arrays, porque crear 2 arrays distintos por ejemplo para fordward o backwards, cuando podes en ves de incrementar, podrias decrementar la variable i, y comenzar desde 7 en tu for.
Título: Re:Array bidimensional con pic
Publicado por: Miquel_S en 25 de Marzo de 2018, 07:29:52
Hola KILLERJC, gracias por la ayuda, he probado parte de lo que me aconsejas y me encuentro con un problema que no se muy bien el porque, probando de usar el mismo array para dos movimientos distintos (adelante-atrás), me pasa que si uso el array para el avance
Código: C
  1. for(char i = 0; i < 8; i++)
los motores funcionan de forma correcta, pero al usar
Código: C
  1. for(char i = 7; i > 0; i--)
para el giro en sentido contrario uno de los motores tarda en arrancar o sencillamente no arrancan ni uno ni otro.
Código: C
  1. #include <xc.h>
  2. #include "config_bits.h"
  3.  
  4. #define _XTAL_FREQ 8000000  // usado para delays
  5.  
  6. /* Secuencia de pasos (medio-paso)
  7.    Motor derecho => bits de menor peso
  8.    Motor izquierdo => bits de mayor peso */
  9.  
  10. char forward_medio_paso [8] = {
  11.     0b10001001, 0b11000001,
  12.     0b01000011, 0b01100010,
  13.     0b00100110, 0b00110100,
  14.     0b00011100, 0b10011000};
  15.  
  16. /*char backward_medio_paso [8] = {
  17.     0b10011000, 0b00011100,
  18.     0b00110100, 0b00100110,
  19.     0b01100010, 0b01000011,
  20.     0b11000001, 0b10001001};*/
  21.  
  22. /*char right_medio_paso [8] = {
  23.     0b10001000, 0b11001100,
  24.     0b01000100, 0b01100110,
  25.     0b00100010, 0b00110011,
  26.     0b00010001, 0b10011001};*/
  27.  
  28. /*char left_medio_paso [8] = {
  29.     0b10011001, 0b00010001,
  30.     0b00110011, 0b00100010,
  31.     0b01100110, 0b01000100,
  32.     0b11001100, 0b10001000};*/
  33.  
  34. void setupClock(void);
  35.  
  36. void main(void){
  37.    
  38. /* Configuracion de puertos */
  39.     ADCON1 = 0x0E;  // set RB<4:0> as digital I/O pins
  40.                     // (required if config bit PBADEN is set)
  41.     TRISB = 0x00;   // configuramos todo el PORTB como salidas
  42.    
  43.     setupClock();   // configuramos oscilador interno a 8MHz
  44.    
  45.     while(1){
  46.         for(char i = 7; i > 0; i--)
  47.         {
  48.             LATB = ( LATB & 0x00 ) | forward_medio_paso[i];
  49.             __delay_ms(1);
  50.         }
  51.     }
  52. }
  53.  
  54. void setupClock(void){
  55.     OSCCONbits.IRCF0 = 1;
  56.     OSCCONbits.IRCF1 = 1;
  57.     OSCCONbits.IRCF2 = 1;
  58.     OSCCONbits.SCS = 0b10;
  59. }

NOTA: Si uso un array diferente para cada movimiento funcionan todos de forma correcta.
Saludos!
Título: Re:Array bidimensional con pic
Publicado por: KILLERJC en 25 de Marzo de 2018, 07:57:53
Podes decir como tenes conectado el motor al PIC?, supongo que son 2 motores, para tener adelante/atras e izquierda/derecha.
Título: Re:Array bidimensional con pic
Publicado por: Miquel_S 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/ (https://programarfacil.com/blog/motor-paso-a-paso/)

Gracias.
Título: Re:Array bidimensional con pic
Publicado por: Miquel_S 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.


Título: Re:Array bidimensional con pic
Publicado por: KILLERJC 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.
Título: Re:Array bidimensional con pic
Publicado por: Miquel_S 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.
Título: Re:Array bidimensional con pic
Publicado por: tsk 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.
Título: Re:Array bidimensional con pic
Publicado por: Miquel_S 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.