Estoy usando un Atmega32 para leer varios sensores usando su ADC.
Usando lógica digital y algunos multiplexores, multiplexé la totalidad de PORTA, usando PA0:6 para la dirección y PA7 como entrada. Por lo tanto, puedo tener un máximo de 128 entradas desde un solo PUERTO.
Ahora, dado que el usuario operará el sistema a través de una computadora (usando RS232), será posible agregar o eliminar sensores, por lo que el sistema debe realizar un seguimiento de qué direcciones están libres para agregar sensores y de qué direcciones leer.
Estaba pensando en usar una matriz booleana de 128 bits como banderas para indicar si hay un sensor en una dirección determinada.
Si bien C no tiene soporte nativo para variables de un solo bit, es posible usar campos de bits para agrupar hasta 8 "variables booleanas" en un solo carácter sin firmar.
Entonces, he creado la siguiente estructura:
typedef struct bool_s{
uint8_t bit1:1;
}bool_t;
Luego, creé una matriz de tipo bool_t con un tamaño de 128, con la esperanza de que todo estuviera bien empaquetado, pero sizeof()
me dice que el tamaño de la matriz es de 128 bytes en lugar de los 16 bytes que esperaba.
Técnicamente, podría crear una sola estructura con 128 variables de 1 bit:
typedef struct Flag_s{
uint8_t F1:1;
uint8_t F2:1;
uint8_t F3:1;
[...]
uint8_t F128:1;
}Flag_t;
El problema con este enfoque es que si bien reduce el uso de memoria, no es muy práctico de usar y ocupa demasiado espacio en el código.
¿Hay alguna manera fácil de crear una gran cantidad de banderas o estoy pidiendo demasiado? Quiero decir, no es que ahorrar 112 bytes vaya a hacer una gran diferencia cuando tienes 2K disponibles, pero ¿y si necesito aún más banderas?
Los campos de bits no funcionan así. La respuesta de Cventu muestra una forma correcta de usarlos, pero en este caso, recomiendo evitarlos por completo.
En su lugar, cree una matriz de valores de 8 bits y use desplazamiento y enmascaramiento para acceder a ella:
uint8_t flags[16];
//Initialize the flags
void init_flags(void)
{
for (i = 0; i < 16; i++)
{
flags[i] = 0x00;
}
}
//Set one flag based on the address
void set_flag(uint8_t address)
{
flags[address/8] |= 0x1 << (address % 8);
}
//Clear one flag based on the address
void clear_flag(uint8_t address)
{
flags[address/8] &= ~(0x1 << (address % 8));
}
//Check whether a flag is set
bool get_flag_state(uint8_t address)
{
return (flags[address/8] & (0x1 << (address % 0x8))) != 0x00;
}
Esto es probablemente lo que hará el compilador con los accesos de campo de bits de todos modos, y es más fácil trabajar con él. Algunos optimizadores son malos para optimizar campos de bits, por lo que el compilador podría incluso hacerlo peor. Todos los compiladores que he visto convierten la división y el módulo por una potencia constante de dos en instrucciones de desplazamiento a la derecha y AND. Puede usar esas operaciones directamente si se siente paranoico:
flags[address>>3] |= 0x1 << (address & 0x7);
Los campos de bits se parecen más a estructuras que a matrices. En mi experiencia, solo son útiles para cosas que tienen nombres, como campos de registro.
<<
operador o definida como constantes con macrosSuena un poco confuso, pero tal vez algo como esto pueda ayudar:
struct bits_field {
unsigned char bit_7 :1;
unsigned char bit_6 :1;
unsigned char bit_5 :1;
unsigned char bit_4 :1;
unsigned char bit_3 :1;
unsigned char bit_2 :1;
unsigned char bit_1 :1;
unsigned char bit_0 :1;
};
union dt {
struct bits_field a;
unsigned char b;
};
Después de definirlos, declare la siguiente variable:
union dt my_data;
Podrá escribir un grupo completo de ocho bits juntos usando: my_data.b
O puede escribir cada bit individualmente usando: my_data.a.bit_7 (o 6,5,4,3,2,1,0)
En caso de que funcione para usted, replique esto 16 veces (usando una matriz o estructura) y podrá manejar 128 bits individualmente.
¡Háganos saber si funcionó! Buena suerte
Cree una estructura en la que declare banderas de ocho bits que terminen siendo un byte. Luego cree una matriz de estas estructuras de 8 bits.
sárima
Beto
Chi