2023-07-18
int main(void)
{
unsigned char addr = 0xff; // reg addr
volatile unsigned char *reg = (volatile unisgned char *)addr; // reg ptr
unsigned char val; // reg value
// change the integer type if needed
read:
val = *(volatile unsigned char *)reg;
write:
*(volatile unsigned char *)reg = val;
return 0;
}
#define REG 0xff
#define READ_H(reg) (*(volatile unsigned char *)(reg))
#define WRITE_H(reg, val) (*(volatile unsigned char *)(reg)) = (val)
int main(void)
{
int val; // signed or unsigned
unsigned char position; // max at bit-length of val
unsigned char bit; // 0 or 1
unsigned char x; // unknown value, 0 or 1
setBit:
val |= (1 << position);
unsetBit:
val &= ~(1 << position);
toggleBit:
val ^= (1 << position);
verifyBit:
bit = (val >> position) & 0x1;
bit_to_x: // works with both x = 1 or 0
val = (val & ~(1 << position)) | (x << position);
return 0;
}
#define SET_BIT(val, bitIndex) (val) |= (1 << (bitIndex))
#define CLEAR_BIT(val, bitIndex) (val) &= ~(1 << (bitIndex))
#define TOGGLE_BIT(val, bitIndex) (val) ^= (1 << (bitIndex))
#define BIT_VALUE(val, bitIndex) (((val) >> (bitIndex)) & 1)
#define BIT_TO_X(val, x, bitIndex) (val) = ((val) & ~(1 << (bitIndex)) | ((x) << (bitIndex))
Following the last two sections:
#define REGD (*(volatile unsigned char *)(0xff))
#define D0 0
#define D1 1
#define D2 2 // etc
int main(void)
{
REGD = 0x00; // whole register
REGD |= (1 << D1); // set bit 1 of REGD
REGD &= ~(1 << D0); // unset bit 2 of REGD
return 0;
}
void Xpos(unsigned char x, unsigned char xIndex, unsigned char *dest, unsigned char destIndex, unsigned char bitLength)
{
unsigned char mask = 0x1;
unsigned char i = 1;
while (i++ < bitLength)
mask = (mask << 1) | 0x1;
*dest &= ~(mask << destIndex); // set the 0s
*dest |= (((x >> xIndex) & mask) << destIndex); // set the 1s
}
/*** Example ***/
// Registers
unsigned char E = 0xa5;
unsigned char D = 0xa5;
unsigned char C = 0xa5;
void drawBar(unsigned char x) // outputs x value on spread bits of E, D and C
{
Xpos(x, 7, &E, 6, 1); // x7 is on E6
Xpos(x, 6, &D, 7, 1); // x6 is on D7
Xpos(x, 5, &C, 6, 1); // x5 is on C6
Xpos(x, 4, &D, 4, 1); // x4 is on D4
Xpos(x, 3, &D, 0, 1); // x3 is on D0
Xpos(x, 2, &D, 1, 1); // x2 is on D1
Xpos(x, 0, &D, 2, 2); // x1-0 is on D3-2
}
int main(void)
{
unsigned char x = 0xff;
drawBar(x);
return 0;
}
#define MIN(A, B) ((A) <= (B) ? (A) : (B))
#define MAX(A, B) ((A) >= (B) ? (A) : (B))
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif
#ifndef NULL
#define NULL ((void *)0)
#endif
Careful: the bit order is compiler-dependent, this implementation is not portable.
#include <stdio.h>
union byte_t {
unsigned char val;
struct {
unsigned char A : 2;
unsigned char B : 1;
unsigned char C : 3;
};
struct {
unsigned char A0 : 1;
unsigned char A1 : 1;
unsigned char : 1;
unsigned char C0 : 1;
unsigned char C1 : 1;
unsigned char C2 : 1;
};
};
int main(void)
{
union byte_t reg = {0x2a}; // 0b101010
printf("%hhu\t0x%x\t0x%x\n", reg.C1, reg.A, reg.val);
// gives: 1, 0x2, 0x2a
return 0;
}
Static has three distinct uses in C
:
Examples of volatile variables are: