PORTB actúa como un entero (int). Cuando escribe en PORTB, escribe en todos los 8 bits a la vez. Solo puede usar corchetes (var [i]) con matrices y campos (var.fieldname) con estructuras. No puedes usar una variable en un nombre de campo.
Para establecer y borrar bits, use los operadores bitwise C:
PORTB |= (1 << 4); //Set bit 4
PORTB &= ~(1 << 6); //Clear bit 6
PORTB = 0x03; //Set bits 0 and 1, clear all others
Estos te permiten usar una variable:
PORTB |= (1 << i); //Set bit i
PORTB &= ~(1 << i); //Clear bit i
Hay otras formas de hacer lo que quieres, pero esta es la más sencilla.
Su código parece encender un LED a la vez, yendo de B0 a B7 y viceversa. Si desea hacer un contador binario real, podría hacer algo como esto:
unsigned long i;
while (1)
{
for (i = 0; i < 256; i++)
{
PORTB = i;
Delay_ms(1000);
}
}
En los PIC más recientes, es mejor usar LATB en lugar de PORTB.
ACTUALIZACIÓN: La regla básica para los operadores a nivel de bits es que usted O con 1 para configurar los bits, Y con 0 para borrar los bits, y XOR con 1 para alternar los bits. Las operaciones bitwise que usé anteriormente funcionan así:
PORTB |= (1 << 4); //Set bit 4
es equivalente a:
PORTB = PORTB | (1 << 4); //Set bit 4
(1 < < 4) es igual a 00010000. En decimal, eso es \ $ 1 \ cdot 2 ^ 4 \ $, o 16. En hexadecimal, es 0x10. El operador OR (|) funciona al ORAR cada bit en PORTB con el bit correspondiente en (1 < < 4). Por ejemplo, si PORTB solo tiene el bit 1 establecido para comenzar, obtendrás:
00000010 PORTB
| 00010000 (1 << 4)
-----------
00010010 PORTB with bit 4 set
El bit 4 se establece sin molestar a ningún otro bit.
Borrar un poco es un poco más complicado. Empecemos con un ejemplo binario. Si PORTB tiene los bits 2 y 4 establecidos, y desea borrar el bit 2, debe hacer esto:
00010100 PORTB
& 11111011 Mask value for clearing bit 2
-----------
00010000 PORTB with bit 2 cleared
El bit 2 se borra sin molestar a ningún otro bit. ¿Ves cómo el segundo operando es casi todos? Podríamos escribir eso manualmente en hexadecimal como 0xFB:
PORTB = PORTB & 0xFB; //Clear bit 2
Pero entonces quienquiera que lea el código debe detenerse y pensar qué bit (s) 0xFB borra. Podemos aclarar el código estableciendo el bit que nos importa en 2 e invirtiendo el resultado:
~(1 << 2);
que da:
~ 00000100 (1 << 2)
-----------
11111011 ~(1 << 2) = Mask value for clearing bit 2
Esto es más claro que un valor hexadecimal:
PORTB = PORTB & ~(1 << 2); //Clear bit 2
que se acorta a:
PORTB &= ~(1 << 2) //Clear bit 2
Cuando está configurando o borrando varios bits, es más común usar valores hexadecimales en lugar de escribir un grupo de valores desplazados. La única forma de lidiar con esto es aprender cómo se relaciona el hexadecimal con el binario, lo cual no es muy difícil.
Una advertencia importante es que los compiladores de C interpretan los números como entradas firmadas. Si un int es solo de 16 bits (lo que suele ser cierto en las MCU), algo como esto puede fallar:
unsigned long a;
a = (1 << 20); //Needs more than 16 bits -- too big for an int!
//a could now be equal to zero
Puedes arreglar esto lanzando uno de los números a un largo. Haga que no esté firmado para evitar advertencias cuando se establece el bit superior:
unsigned long a;
a = (1UL << 20); //Should now work correctly
Casi siempre es mejor usar uint8_t, uint16_t y uint32_t en lugar de los tipos C nativos, pero el uso del sufijo UL sigue siendo común.