PORTBbits.RX
Es realidad una estructura donde se define los 8bits y un entero de 8bits puesto sobre la direccion del PORTB, XC8 tiene un operador especial para eso y es lo que usa en su .h que es el @
En esa estructura define cada bit... PORTB no es un puntero como esta definido en el .h de XC8, sino que es como una variable que tiene una direccion fija y vos dices: "Lo que hay en la direccion 0x06 le correspondo a esta estructura", dentro de la estructura estan definidos todos los bits.
Lo mismo podes hacer con una variable copio la definicion de un .h
// Register: PORTB
#define PORTB PORTB
extern volatile unsigned char PORTB @ 0x006; //Aca dice que tenes una variable de 8bits sin signo llamada PORTB en la direccion 0x006
#ifndef _LIB_BUILD
asm("PORTB equ 06h");
#endif
// bitfield definitions
typedef union {
struct {
unsigned RB0 :1;
unsigned RB1 :1;
unsigned RB2 :1;
unsigned RB3 :1;
unsigned RB4 :1;
unsigned RB5 :1;
unsigned RB6 :1;
unsigned RB7 :1;
};
} PORTBbits_t;
extern volatile PORTBbits_t PORTBbits @ 0x006; // Aca tenes que define la estructura como PORTBbits y dice que esta ubicada tambien en la direccion 0x006
Esto se resuelve en tiempo de compilacion pero no en run-time.
Si tenemos que guardar algo del puerto, lo unico que nos queda guardar es la direccion y el pin, ya que el pin solo no posee direccion propia. Por eso debemos tener guardado ambas cosas. Y por eso usamos un puntero al puerto.
pin1 = 0b00000001;
pin2 = 0b00000010;
pin3 = 0b00000100;
if((*data->canal_A & mask_A) == pin1); //si queremos usar el pin 0
if((*data->canal_B & mask_B) == pin2); //si queremos usar el pin 1
if((*data->canal_C & mask_C) == pin3); //si queremos usar el pin 3
Hacer eso quita toda ventaja de hacer el codigo como te pase.. intenta cargar cualquier puerto y pin, esto requiere que cada estructura posea minimo 8 punteros a puerto y 8 enteros de 8 bits. Ademas cuando lo inicializas tenes que cargar la mascara exacta.. termina siendo un exceso que no tiene sentido por achicar un poco mas los ifs.