Autor Tema: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)  (Leído 10298 veces)

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

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5362
    • Picmania by Redraven
Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« en: 01 de Febrero de 2007, 18:00:16 »
Hace poco el amigo migsantiago nos hacía una pregunta sobre Alternativa a arreglos de 1 bit

Ahí tienes, ahí tenéis mi propuesta.

He montado una estructura que puede manejar un Array de 8, 16 o 32 bits para no complicarlo demasiado. Con igual pretensión no le he colocado tampoco el control de errores por parámetros incongruentes (como intentar leer el bit nº 12 habiendo definido un array de sólo 8 bits)

Para empezar defino el tamaño del array a utilizar mediantes los defines (Comentando o descomentando el que necesito)

#define bits_array_8
//#define bits_array_16
//#define bits_array_32


En función de estos defines creo en la RAM el tipo de variable correspondiente:

#ifdef bits_array_8
   int8  bits_array=0;
#endif

#ifdef bits_array_16
   int16 bits_array=0;
#endif
#ifdef bits_array_32
   int32 bits_array=0;
#endif


Al final lo que tengo es una variable llamada bits_array con el tamaño necesario.

Y ahora me defino dos funciones, una para poner a un valor dado el bit que desee y otra para leerlo:

int1 get_array_bit(int8 pbit){
   int1 r;
   r=bit_test(bits_array,pbit);
   return r;
}

int1 set_array_bit(int1 vbit, int8 pbit){
   int1 r;
   r=bit_test(bits_array,pbit);
   if(vbit==0)
      bit_clear(bits_array,pbit);
   else
      bit_set(bits_array,pbit);
   return r;
}


De forma que get_array_bit me devuelve el valor del bit en la posición pbit, que al ser un parámetro puede ser incluido en un bucle for{] por ejemplo.

Y set_array_bit en la que coloco al valor vbit en la posición pbit; esta función me devuelve además el valor anterior que tenía el bit de la posición pbit, asi puedo comparar, si lo deseo, si el bit ha cambiado o no. Al igual que en la función anterior el parámetro puede ser incluido en un bucle for{].

Lo he probado y funciona perfectamente.  :mrgreen:

         if(isdigit(Command)){             // Bit
            xbit=Command-'0';
            set_array_bit(1,xbit);
            printf("Despues de Poner : %u %x\r\n",get_array_bit(xbit),bits_array);
         }


Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado migsantiago

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8257
    • Sitio de MigSantiago
Re: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« Respuesta #1 en: 02 de Febrero de 2007, 13:45:46 »
Vientos Diego

Ahora propongo una alternativa más, derivada de una propuesta de Manolo...

Código: [Seleccionar]
int8 bateria[5]; //40bits
int8 posicion; //no. de bit del arreglo de 40 a leer o escribir
int1 soyunbit; //él es un bit

//para poner a 1 cualquier bit
bit_set(bateria[posicion/8],(posicion%8));

//para poner a 0 cualquier bit
bit_clear(bateria[posicion/8],(posicion%8));

//para leer cualquier bit
soyunbit=bit_test(bateria[posicion/8],(posicion%8));

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5362
    • Picmania by Redraven
Re: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« Respuesta #2 en: 02 de Febrero de 2007, 18:42:40 »
Ok. Me pongo a ello (pero no sé cuando ni cuanto tardaré  :D)
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado maunix

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4751
    • Mi Sitio Web Personal
Re: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« Respuesta #3 en: 02 de Febrero de 2007, 22:06:14 »
Creo que la "Manolo's solution" , en mi humilde opinión es más veloz para la mayoría de los casos e incluso debiera ocupar menor código de programa.

Saludos
« Última modificación: 02 de Febrero de 2007, 22:09:48 por maunix »
- La soberbia de un Einstein es entendible.. la de un salame es intolerable (A.Dolina)
- En teoría no hay diferencia entre la teoría y la práctica. En la práctica... si la hay.
- Lee, Lee, Lee y luego pregunta.(maunix)
- Las que conducen y arrastran al mundo no son las máquinas, sino las ideas (V. Hugo)
- Todos los hombres se parecen por sus palabras; solamente las obras evidencian que no son iguales.(Moliere)
- Todo debería ser hecho tan simple como sea posible pero no mas simple que eso.(A.Einstein)

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5362
    • Picmania by Redraven
Re: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« Respuesta #4 en: 02 de Febrero de 2007, 22:25:57 »
De China viene un barco cargaditooooo deeeee .... bits  :mrgreen:

No me preguntéis por qué pero el código del gran M.Nocturno no funciona exactamente como está, al menos en mi compilador CCS C 3.242 ... pero ya lo tengo funcionando con una ligerísima modificacion.

El caso es que las operaciones posicion/8 para obtener la parte entera o byte donde está alojado el bit a utilizar y posicion%8 para obtener el resto o posición del bit dentro del byte no parecen funcionar dentro, embebidas, de las mismas instrucciones de bit_set, bit_clear o bit_test.

Así que lo único que he hecho ha sido hacer estas operaciones fuera, forzándolas a devolver el resultado como int8 especificándolo así y después utilizar las funciones tal cual están.

int1 get_array_bit(int8 pbit){

   int1 r;
   int8 a,b;
   a = (int8) pbit/8;
   b = (int8) pbit%8;
   r=bit_test(bits_array[a],b);
   return r;
}

int1 set_array_bit(int1 vbit, int8 pbit){

   int1 r;
   int8 a,b;
   a = (int8) pbit/8;
   b = (int8) pbit%8;
   r=bit_test(bits_array[a],b);
   bit_clear(bits_array[a],b);
   if(vbit==1) bit_set(bits_array[a],b);
   return r;
}


Para declarar la variable Array de bytes (los contenedores de los bits) he utilizado la declaración siguiente:

#define bytes_for_bits 5                     // 5 * 8 = 40 bits (0..39)
int8 bits_array[bytes_for_bits];            // Array de 40 bits dividido en bytes_for_bits bytes


Y para poder monitorizar todos los bits dentro de bits_array me he contruido una función que me convierte en string de bits ASCII el byte que le envíe, devolviéndome un puntero a dicho string:

char* int8_to_bits_string(int8 val){
   char s[]="00000000";
   char* ptr;
   int8 i;
   for(i=0;i<8;i++) s[ i ]=bit_test(val,i)+'0';
   s[8]='\0';
   ptr=&s[0];
   return ptr;
}


Y para comprobar que todo va como debe ir me he contruido en el main() un modo de ir poniendo a 1 cada uno de los bits cada vez que le pulso algo a través del canal serie, y con cada pulsación me muestra el estado de los cuarenta bits. Y cuando llega al bit 39 se reinicializa el índice comenzando de nuevo desde el 0 pero si está ya puesto a 1 lo coloca ahora a 0.

El trozo de código del main es:

         if(Command=='1'){                 // Next Bit a 1 si 0 ó a 0 si 1
            if(get_array_bit(nextbit)==0)
               set_array_bit(1,nextbit);
            else
               set_array_bit(0,nextbit);
            printf(">Set bit %2u ",nextbit);
            for(i=0;i<bytes_for_bits;i++){
               ptr=int8_to_bits_string(bits_array[ i ]);
               strcpy(s,ptr);
               printf("%s",s);
            }
            printf("\r\n");
            if(++nextbit==bytes_for_bits * 8 ) nextbit=0;
         }


Y como todo está construido alrededor del define bytes_for_bits podemos cambiarle el valor y montar el número de bits que queramos, siempre múltiplo de 8.






« Última modificación: 02 de Febrero de 2007, 22:33:34 por RedPic »
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado maunix

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4751
    • Mi Sitio Web Personal
Re: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« Respuesta #5 en: 02 de Febrero de 2007, 22:34:25 »
Diego, ¿¿acaso no se duerme en España??   :shock: :shock:

Mi dios!!

Genial, menudo post!!  Te felicito. 
- La soberbia de un Einstein es entendible.. la de un salame es intolerable (A.Dolina)
- En teoría no hay diferencia entre la teoría y la práctica. En la práctica... si la hay.
- Lee, Lee, Lee y luego pregunta.(maunix)
- Las que conducen y arrastran al mundo no son las máquinas, sino las ideas (V. Hugo)
- Todos los hombres se parecen por sus palabras; solamente las obras evidencian que no son iguales.(Moliere)
- Todo debería ser hecho tan simple como sea posible pero no mas simple que eso.(A.Einstein)

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5362
    • Picmania by Redraven
Re: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« Respuesta #6 en: 02 de Febrero de 2007, 22:36:29 »
Gracias Mauricio  :mrgreen:

No, en España no dormimos ... caemos desmayados sobre el teclado del PC ja ja ja  :D :D :D :D
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado migsantiago

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8257
    • Sitio de MigSantiago
Re: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« Respuesta #7 en: 02 de Febrero de 2007, 23:54:35 »

No, en España no dormimos ... caemos desmayados sobre el teclado del PC ja ja ja  :D :D :D :D
aajajajajja  :D :D :D :lol: :lol: :lol:

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 17452
    • MicroPIC
Re: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« Respuesta #8 en: 03 de Febrero de 2007, 04:10:05 »
Ten cuidado que la baba es corrosiva; pobre teclado :D

Es raro que eso no funcione dentro de las otras funciones.

En la anterior ocasión expuse un método para leer un bit dentro de un array de bits:
BitLeido = bateria[PosicionALeer / 8] >> (PosicionALeer % 8 );

Como os veo preocupados por la escritura, se me ocurre que podría hacerse también con una fórmula rápida:

// Para colocar un 1
bateria[PosicionAEscribir / 8] |= (1 <<  (PosicionAEscribir % 8 ));

// Para colocar un 0
bateria[PosicionAEscribir / 8] &= (0xFF - (1 <<  (PosicionAEscribir % 8 )));

Al igual que en la ocasión anterior, no lo he probado, pero espero que sirva la idea.

A mí particularmente no me gusta llamar a subrutinas para hacer esto porque se pierden muchos ciclos por cada bit.
« Última modificación: 03 de Febrero de 2007, 04:12:30 por Nocturno »
Un saludo desde Sevilla, España.
Visita MicroPIC                                                                                        ɔ!doɹɔ!ɯ ɐʇ!s!ʌ

Desconectado maunix

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4751
    • Mi Sitio Web Personal
Re: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« Respuesta #9 en: 03 de Febrero de 2007, 11:02:19 »
A mí particularmente no me gusta llamar a subrutinas para hacer esto porque se pierden muchos ciclos por cada bit.

Si manolo, coincido, a eso me refería en que tu función era más veloz para la mayoría de las condiciones. 

Repensando lo visto anteriormente, creo que hacer arreglos de bits usando variables de 16bits, 24bits o 32bits es correctísimo en C pero tenemos que reconsiderarlo en función de qué micro usaremos o en qué micro irá destinado ese código en C.

Si el micro destino es un PIC de 8 bits -> lo mejor es usar variables de 8 bits
Si es un micro de 16 bits -> casi seguro será mejor usar variables de 8 bits
Y así sucesivamente.

Lo más eficiente suele ser usar variables del tamaño del bus de datos del micro que utilicemos.  Si usamos de menos, es probable que perdamos perfomance (salvo que algún caso puntual en que sea lo mismo) y si usamos de más es seguro que perderemos perfomance.

Ni hablar si tenemos un micro de 16 bits y usamos variables de 24 bits (usea, de 1 y medio veces el tamaño del bus)!!

Manolo yo he usado esa modalidad que tu usas para el código pero también he usado otra que es muy veloz que es reemplazar la rotación a la izquierda por un arreglo 8 chars, donde tengo la opción para hacer la OR y la opción para hacer la AND.  Eso es más veloz pero ocupa algunos bytes más en memoria.  Si usamos el arreglo de chars en la memoria de programa, no ocuparemos memoria ram pero la operación se hará algo más lenta.

Es decir, yo reemplazo

(1 <<  (PosicionAEscribir % 8 ));

por


array_on[PosicionAEscribir % 8 ]

donde array_on y su correspondiente negado es


char array_on[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};

char array_off[8] = {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F};



luego


// Para colocar un 1
bateria[PosicionAEscribir / 8] |= array_on[PosicionAEscribir % 8 ];

// Para colocar un 0
bateria[PosicionAEscribir / 8] &= array_off[PosicionAEscribir % 8];
- La soberbia de un Einstein es entendible.. la de un salame es intolerable (A.Dolina)
- En teoría no hay diferencia entre la teoría y la práctica. En la práctica... si la hay.
- Lee, Lee, Lee y luego pregunta.(maunix)
- Las que conducen y arrastran al mundo no son las máquinas, sino las ideas (V. Hugo)
- Todos los hombres se parecen por sus palabras; solamente las obras evidencian que no son iguales.(Moliere)
- Todo debería ser hecho tan simple como sea posible pero no mas simple que eso.(A.Einstein)

Desconectado Sispic

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 1405
    • winpic800
Re: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« Respuesta #10 en: 03 de Febrero de 2007, 17:06:06 »
Mas ideas+maneras :

Código: [Seleccionar]
int8 MisBits_B[3];       // Aqui tenemos 24 bits
#locate MisBits_B = 0x10  // Asi veremos si lo hace bien


 #define borra_mi_bit(x)  #asm BCF &MisBits_B[(x/8)] , x % 8 #endasm
 #define setea_mi_bit(x)  #asm BSF &MisBits_B[(x/8)] , x % 8 #endasm
 #define mi_bit(x)        bit_test( MisBits_B[x/8] ,  x % 8 )



void main(){

borra_mi_bit(0);
borra_mi_bit(7);
borra_mi_bit(8);
borra_mi_bit(23);
setea_mi_bit(11);

 if ( mi_bit(21))setea_mi_bit(10);

}

Lo hara bien ?

Código: [Seleccionar]
.................... void main(){

.................... borra_mi_bit(0);
001C:  BCF    10.0
.................... borra_mi_bit(7);
001E:  BCF    10.7
.................... borra_mi_bit(8);
0020:  BCF    11.0
.................... borra_mi_bit(23);
0022:  BCF    12.7
.................... setea_mi_bit(11);
0024:  BSF    11.3

....................  if ( mi_bit(21))setea_mi_bit(10);
0026:  BTFSS  12.5
0028:  BRA    002C
002A:  BSF    11.2
002C:
.................... }

Pero eso solo permite verificar un bit en constante . no vale -> borra_mi_bit[a]


Desconectado pikman

  • Moderador Local
  • PIC24F
  • *****
  • Mensajes: 673
Re: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« Respuesta #11 en: 03 de Febrero de 2007, 17:17:56 »
Bueno, Diego no deja de sorprender, siempre aplicando su ingenio para ayudar, gracias, Sispic no dejas de sorprenderme tambien.
Interesante esto del manejo de Arrays de Bits, de cualquier modo hasta la version 3.249 CCS es cierto no lo permite, pero si en la 4.023 deja definir como decia migsantiago:

int1 bateria[40];

bateria[35]=1;


No encontre esta novedad en los readme, pero funciona, por lo menos al compilar no da errores, incluyendo lo que esta mas arriba, ahora voy a probarlo en un programa.

saludos
PikMan

Desconectado maunix

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4751
    • Mi Sitio Web Personal
Re: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« Respuesta #12 en: 04 de Febrero de 2007, 13:11:06 »
Quiero hacer una aclaración por si algún incauto usuario del C18 lee este hilo.

El método de Sisco claro que funciona pero no está mas que definiendo un macro con código assembler embebido en el C.  Esa es la razón por la cual hay que pasarle una "constante" y no una variable, ya que el macro es como "copiar y pegar" el código donde este sea requerido.

Pero eso solo permite verificar un bit en constante . no vale -> borra_mi_bit[a]

Esto es muy veloz y eficiente.  Se logra el resultado en una instrucción!

Amén de eso creo que su uso para alguien que quiere trabajar con un arreglo de bits no se vería muy utilizado ya que haría falta una instrucción por cada bit que querramos acceder.

La otra desventaja y he aquí atención a los usuarios de C18 (en esto el C18 es realmente pobrísimo) es que hacer un código de assembler embebido dentro del C desactiva las optimizaciones del compilador dentro de la función que lo contiene con lo cual la velocidad que ganamos en el seteo del bit la perdemos en el resto de la subrutina por el código mayor.  Tal vez esto también sea cierto para el C30 pero aún no lo he usado.

Este ítem, la posibilidad de que el código siga siendo optimizado a pesar de haber código assembler al medio es algo que "supuestamente" van a mejorar pero no hay fecha.

Quiero aclarar que solo quiero aportar y no criticar la sugerencia de Sisco que me parece muy buena pero que hay que tener cuidado de en qué casos y con qué compilador se usa.

He tenido algunos inconvenientes con los "inasm" de C18 y por eso quisiera que otros no pasen por las mismas penurias que yo.

Saludos
- La soberbia de un Einstein es entendible.. la de un salame es intolerable (A.Dolina)
- En teoría no hay diferencia entre la teoría y la práctica. En la práctica... si la hay.
- Lee, Lee, Lee y luego pregunta.(maunix)
- Las que conducen y arrastran al mundo no son las máquinas, sino las ideas (V. Hugo)
- Todos los hombres se parecen por sus palabras; solamente las obras evidencian que no son iguales.(Moliere)
- Todo debería ser hecho tan simple como sea posible pero no mas simple que eso.(A.Einstein)

Desconectado Sispic

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 1405
    • winpic800
Re: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« Respuesta #13 en: 05 de Febrero de 2007, 07:29:39 »
Citar
desactiva las optimizaciones del compilador


Bueno , ojalá las desactivase todas :D , el C18 de optimizar ...nada de nada . menudo petardo les salio.
El C30 tambien sigue sus pasos , ademas de tener que adivinar como funciona .

Pero haces muy bien en comentarlo .


Desconectado maunix

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4751
    • Mi Sitio Web Personal
Re: Manejando Arrays de Bits (simulado en CCS C que no lo implementa)
« Respuesta #14 en: 05 de Febrero de 2007, 08:16:11 »
Citar
desactiva las optimizaciones del compilador


Bueno , ojalá las desactivase todas :D , el C18 de optimizar ...nada de nada . menudo petardo les salio.

Si, pero han mejorado bastante.  De hecho para que optimice hay que tener en cuenta algunas cosas y conocer bien al compilador.  Luego de eso creo que anda muy bien, pero bueno, eso ya es mi opinión personal, al menos las versiones 3.x

El C30 tambien sigue sus pasos , ademas de tener que adivinar como funciona .

No lo he usado pero creo que para hacer códigos óptimos en velocidad y espacio ocupado en C para microcontroladores se hace imprescindible saber cómo funciona el compilador y también conocer la arquitectura del micro y su set de instrucciones.  De esa forma uno sabe cómo hacer una instrucción que lleve a un mejor resultado.

En el foro de Microchip están constantemente posteando 'trucos' que tienen que ver con estas cuestiones, de que si uno hace una cosa de una forma o de otra no es lo mismo, ya que de una forma se le facilita la tarea al compilador.

Hay cosas que son genéricas a todos los compiladores  y otras que son bastante particulares pero sí, es un tema que es bastísimo y lleva tiempo depurarlo.

Por cierto Sisco, tú que compilador C usas?
- La soberbia de un Einstein es entendible.. la de un salame es intolerable (A.Dolina)
- En teoría no hay diferencia entre la teoría y la práctica. En la práctica... si la hay.
- Lee, Lee, Lee y luego pregunta.(maunix)
- Las que conducen y arrastran al mundo no son las máquinas, sino las ideas (V. Hugo)
- Todos los hombres se parecen por sus palabras; solamente las obras evidencian que no son iguales.(Moliere)
- Todo debería ser hecho tan simple como sea posible pero no mas simple que eso.(A.Einstein)