What does this mean? (*(volatile unsigned char *)(0x22))
Using C, I was trying to assign a variable name to a register address so that my code would be readable. An example of how to do this is as follows:
#define DDRA (*(volatile unsigned char *)(0x22))
This means that if a register or memory location exists at address 0x22, I can
use DDRA to read or write to it like so..
DDRA = 0x05
in my C code.
The #define looks really cryptic at first. The way to understand this is by breaking it down into pieces. First of all,
unsigned char
means we are using a byte-sized memory location. Byte being 8-bits wide.
unsigned char *
means we are declaring a pointer that points to a byte-sized location.
(unsigned char *) (0x22)
means the byte-sized pointer points to address 0x22. The C compiler will refer to address 0x22 when the variable DDRA is used. The assembly code will end up using 0x22 in Load(LD) and Store (STR) insturctions.
(*(unsigned char *)(0x22))
The first asterisk from the left signifies that we want to manipulate the value in address 0x22. * means “the value pointed to by the pointer”.
volatile
volatile forces the compiler to issue a Load or Store anytime DDRA is accessed as the value may change without the compiler knowing it.
#define P0 (*(volatile __near unsigned char *)0xFF00)
#define P0_bit (*(volatile __near __bitf_T *)0xFF00)
#define P1 (*(volatile __near unsigned char *)0xFF01)
#define P1_bit (*(volatile __near __bitf_T *)0xFF01)
#define P2 (*(volatile __near unsigned char *)0xFF02)
#define P2_bit (*(volatile __near __bitf_T *)0xFF02)
#define P3 (*(volatile __near unsigned char *)0xFF03)
#define P3_bit (*(volatile __near __bitf_T *)0xFF03)
#define P4 (*(volatile __near unsigned char *)0xFF04)
#define P4_bit (*(volatile __near __bitf_T *)0xFF04)
#define P5 (*(volatile __near unsigned char *)0xFF05)
#define P5_bit (*(volatile __near __bitf_T *)0xFF05)
#define P6 (*(volatile __near unsigned char *)0xFF06)
#define P6_bit (*(volatile __near __bitf_T *)0xFF06)
#define P7 (*(volatile __near unsigned char *)0xFF07)
#define P7_bit (*(volatile __near __bitf_T *)0xFF07)
#define P12 (*(volatile __near unsigned char *)0xFF0C)
#define P12_bit (*(volatile __near __bitf_T *)0xFF0C)
#define P13 (*(volatile __near unsigned char *)0xFF0D)
#define P13_bit (*(volatile __near __bitf_T *)0xFF0D)
#define P14 (*(volatile __near unsigned char *)0xFF0E)
#define P14_bit (*(volatile __near __bitf_T *)0xFF0E)
C Code Support for Accessing Control Registers
The ‘iodefine.h’ file has C code constructs that make it easy to access each port with C code. Each port is defined as a structure and each register of the port is defined as a union of variables within that structure. An example of how the special function register P0 (the port register for port 0) is defined as follows.
First, a new data type called __bitf_T is defined. This allows easy C-level access to individual bits within a byte. Each field in the structure provides access to the corresponding bit. The C compiler will generate appropriate assembly code to ensure that only the bit of interest is accessed.
typedef struct
{
unsigned char no0:1;
unsigned char no1:1;
unsigned char no2:1;
unsigned char no3:1;
unsigned char no4:1;
unsigned char no5:1;
unsigned char no6:1;
unsigned char no7:1;
} __bitf_T;