¿Por qué la gente usa (1 << PA0) al configurar el puerto?

En los tutoriales de AVR a menudo veo:

DDRA |= (1 << PA0);
PORTA |= (1 << PA0);

utilizado en lugar de:

DDRA |= PA0;
PORTA |= PA0;

¿Cuál es el propósito de esto?

No sé mucho sobre AVR, pero (1 << 2) no es lo mismo que 2.
Debido a que están programando en C. En ensamblador, usaría una instrucción de configuración de bits directamente, en Ada tiene varias opciones, para una, simplemente puede asignar Verdadero o Falso a un miembro de una matriz empaquetada de booleanos:PortA(PAO) := True;
Si PA0 especifica un número de bit (como del 0 al 31), entonces (1 << PA0) representa una máscara de bits o un campo de bits en el que se establece ese bit.
Parece que no entiendes los operadores bit a bit. Aquí hay uno que usé: Manipulación de bits Comienza desde lo básico y va tan lejos como se requiere.
Aparte, en AVR C normalmente también puede usar la _BV()macro para obtener el "valor de bit" (p. ej PORTA |= _BV(PA0);., personalmente creo que hace que el código sea más legible, pero las opiniones difieren bastante en la comunidad).
Re Ada: también tienes campos de bits en C.

Respuestas (4)

PA0se definirá como 0 por lo que la siguiente línea:

DDRA |= (1 << PA0);

Equivale a desplazar 1 a la izquierda por cero bits, dejando un OR con el valor 1 para establecer el primer bit. Considerando que la siguiente línea:

 DDRA |= PA0;

Está haciendo un OR con cero, por lo que no cambiará los registros en absoluto.

Eso me hace preguntarme por qué no usarían simplemente DDRA |= 1. ¿Esperan PA0cambiar en diferentes entornos?
@corsiKa: ¿cuál es más fácil de leer y entender: DDRA |= 72;o DDRA |= (1<<PA6) | (1<<PA3);?
Ah, hay otras partes en el patrón. Gotchya. No, me gusta.
@corsiKa incluso cuando configura solo 1 bit, tiene |= 128más sentido que |= (1 << 7). ¿Cómo sabes que establecerá el bit 7 al mirar valores como 128?
@LưuVĩnhPhúc Por supuesto que no. Pero para alguien que no usa ese marco, no está claro que le importe "configurar un poco" a primera vista, por eso pregunté. Baste decir PA0que no es muy descriptivo de lo que realmente está haciendo.

¿Por qué hacen esto? Probablemente porque todos los demás a quienes piden ayuda o de quienes aprendieron lo hicieron de esa manera. Y porque las definiciones estándar están extrañamente hechas.

Cambiar por un número, típicamente un número decimal, moverá ese valor por tantas posiciones binarias. 1 << PA0desplazará 1 PA0a la izquierda. Como PA0es 0, no hay desplazamiento. Pero dado 1 << 61 se convertirá en 0b1000000. Dado 13 << 6, cambiará 13, en binario que es 0b1101, por 6 para convertirse en 0b1101000000 o 832.

Ahora, necesitamos ver cómo se definen PA0 - PA7. Por lo general, se definen en el encabezado específico para su microcontrolador específico, incluido a través de io.h o portpins.h

#define     PA7   7
#define     PA6   6
~
#define     PA1   1
#define     PA0   0

¡Se definen como su posición numérica, en decimal!

No se pueden asignar directamente, como bits, porque no son bits individuales.

Si supusiera que PORTA |= PA7;PORTA es 0b00000000 (todo apagado), obtendrá:

PORTA = PORTA | PA7;o PORTA = 0 | 7;oPORTA = 0 | 0b111

¿Ves el problema? Acaba de encender PA0, PA1, PA2, en lugar de PA7.

Pero PORTA |= (1 << PA7);funciona como esperas.

PORTA = PORTA | (1 << PA7);o PORTA = 0 | (1 << 7);oPORTA = 0 | 0b10000000;


La forma más inteligente

El otro microcontrolador mejor, el MSP430, tiene una definición estándar de bits como:

#define BIT0                (0x0001)
#define BIT1                (0x0002)
~
#define BIT6                (0x0040)
#define BIT7                (0x0080)

Estos se definen como su posición binaria, en hexadecimal. BIT0 es 0b0001, no como PA0, que es 0. BIT7 es 0b10000000, no como PA7, que es 0b111.

Entonces, las asignaciones directas P1OUT |= BIT7;funcionarán de la misma manera P1OUT |= (1 << 7);.

Su pregunta ya ha sido respondida, pero quiero presentar una alternativa que fue demasiado para un comentario. Una de las primeras cosas que hago cuando empiezo un proyecto incrustado es definir mi conjunto de bits y borrar macros.

#define bitset(var,bitno) ((var) |= 1 << (bitno))
#define bitclr(var,bitno) ((var) &= ~(1 << (bitno)))

Usando las macros, su código se convierte en:

bitset(DDRA,0);
bitset(PORTA,0);

El resultado final es una instrucción de conjunto de bits en ensamblador.

Hiciste un error tipográfico, la segunda línea debería ser, por ejemplo, "bitclear".
Su segundo #define, no su segundo ejemplo.

Eche un vistazo aquí: http://nongnu.org/avr-libc/user-manual/FAQ.html#faq_use_bv

Esas macros se usan cuando se configuran bits particulares en un registro. Por ejemplo: si PORTA tiene 8 bits de ancho, entonces PA0 es el bit más bajo, PA7 es el más alto. Para establecer PA0 en 1, debe escribir ("o escribir") 0x01 en el registro. Si desea configurar PA2, necesita un valor que en binario tenga un uno en el lugar correcto, para PA2 será 0x04.

La gente no quiere recordar qué bit tiene una posición particular (ya que otros registros pueden tener diferentes nombres de bits, por ejemplo, CS12, CS10, ADSC, etc.), por lo que usan nombres más abstractos. En lugar de escribir: PORTA = 0x04, escribe PORTA = _BV (PA2) e instantáneamente sabe que el pin PA2 se volverá alto.