Una pregunta matemática de bits simple sobre la manipulación de bits de registro

1

Leí en un tutorial tales descripciones:

DDRD |= (1 << DDD0);        // sets bit DDD0 to 1 within register DDRD

PORTD |= (1 << PORTD0);     // turn on PD0

Puedo entender paso a paso el siguiente ejemplo:

SREG |= (1 << 7);

Por encima de significa tomar 1 = 00000001

Cambia a 7 dígitos a la izquierda para que se convierta en 10000000

Ahora la expresión se convierte en SREG | 10000000

Hasta ahora todo bien, pero ¿qué hay de nuevo en lo siguiente:

DDRD |= (1 << DDD0);  

¿Cómo podemos analizarlo paso a paso? Si tomo DDD0 como cero, 1 vuelve a ser 1 como 00000001 y la expresión se convierte en DDRD | 00000001.

¿Es DDD0 simplemente el número 0 aquí?

    
pregunta user1234

3 respuestas

3

Supongo que está utilizando un AVR de Atmel con avr-libc basado en los nombres de registro. En cuyo caso, si se refiere al directorio <libc>\include\avr\ , encontrará archivos con el nombre del procesador. Por ejemplo, si toma el ATMega328p, hay un archivo llamado iom328p.h . En su interior encontramos un montón de cosas como:

#define DDRD _SFR_IO8(0x0A)
#define DDD0 0
#define DDD1 1
#define DDD2 2

Observe que DDRD no es más que una dirección especial para el registro DDRD. Imagine tener que crear un puntero a ese registro y buscar su dirección cada vez. Es mucho más fácil # definirlo con un nombre legible.

Considere que desea escribir en el tercer bit en el registro DDRD . Puedes hacer lo siguiente:

DDRD |= 1<<2;
DDRD |= 4
DDRD |= 1<<DDD2;

Notarás que DDD2 es simplemente # definido como el número 2, por lo que es idéntico a las otras líneas. Sin embargo, es mucho más legible, especialmente si desea consultar la hoja de datos que utiliza los mismos nombres para los bits.

Puede que te preguntes: ah, pero nunca querré buscar un poco así, ya que sé que es 2. Bueno, considera otro ejemplo. Vamos a tomar los temporizadores. Tenemos por ejemplo:

#define TCCR0B _SFR_IO8(0x25)
#define CS00 0
#define CS01 1
#define CS02 2
#define WGM02 3
#define FOC0B 6
#define FOC0A 7

Ahora digamos que queremos configurar el bit WGM02 para que sea un 1. Podríamos hacer cualquiera de las siguientes acciones:

TCCR0B |= 1 << 3;
TCCR0B |= 8;

Pero esos son muy ilegibles, ridículamente. ¿Quién sabe qué 1 < < 3 está en el registro, tendríamos que buscarlo en la hoja de datos. Por otro lado:

TCCR0B |= 1 << WGM02;

es inmediatamente obvio qué bit está configurando.

Además, hay un elemento de portabilidad aquí. Muchos de los AVR tienen el mismo módulo de temporizador pero tienen bits en diferentes lugares: WGM02 podría estar en el bit 1 en otro AVR, por ejemplo.

Si luego se mudó a un dispositivo diferente, tendría que revisar cada número mágico aleatorio, buscar en la hoja de datos antigua a qué bit corresponde, hacer coincidir eso con la hoja de datos nueva y cambiar la constante. Mientras que si usas #define, sabrás qué bit es sin mirar la hoja de datos anterior, y es posible que no tengas que cambiarlo porque el nuevo #define se encargará de ello.

TL; DR; Estás pensando demasiado sobre las cosas. Se hace únicamente por pulcritud y para que sea más fácil seguir las cosas, no más difícil.

    
respondido por el Tom Carpenter
1

DDD0 y PORTD0 serán macros definidas en uno de los archivos de encabezado.

Entonces diga DDD0 si el primer bit en el registro DDRD entonces en algún lugar del encabezado habrá una línea #define DDD0 0 , si es el segundo bit en el registro que #define será 1 en lugar de 0, etc ...

Una vez que se haya escrito el archivo de encabezado, no es necesario saber qué bit del registro DDD0 es, solo debe saber que 1<<DDD0 lo llevará al bit correcto.

    
respondido por el Andrew
0

Como se mencionó en los comentarios, confundió al operador | con el operador || .

¿Por la apariencia de lo que se define aquí está programando un chip AVR?

Supongo que DDRD y SREG son registros. La razón por la que los programadores usan constantes definidas con nombre es porque pone legibilidad y significado en el código en lugar de un grupo de números mágicos. Realmente no te importa cuáles son los números, pero sí te importa lo que significan y su función. Darles un nombre ayuda con esto.

DDRD |= (1<<DDD0); //is the same as
DDRD = DDRD | (1<<DDD0); 
// so take the current value of DDRD and do a OR operation on each corresponding bit
/* 
   if we say that for example DDRD is currently 0b10100010
   and DDD0 is 0 then (1<<DDD0) --> 0b00000001
   then we do a BITWISE OR
   --> 10100010
   OR  00000001 
     = 10100011
*/

Espero que eso tenga algún tipo de sentido, pero para reiterar cada bit de cada variable se ORO junto.

    
respondido por el crowie

Lea otras preguntas en las etiquetas