Created
October 22, 2018 07:18
-
-
Save Jeff-Russ/c9b471158fa7427280e6707d9b11d7d2 to your computer and use it in GitHub Desktop.
C/C++ Macros for Bit Manipulation i.e. Arduino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Bit Manipulation Macros | |
A good article: http://www.coranac.com/documents/working-with-bits-and-bitfields/ | |
x is a variable that will be modified. | |
y will not. | |
pos is a unsigned int (usually 0 through 7) representing a single bit position where the | |
right-most bit is bit 0. So 00000010 is pos 1 since the second bit is high. | |
bm (bit mask) is used to specify multiple bits by having each set ON. | |
bf (bit field) is similar (it is in fact used as a bit mask) but it is used to specify a | |
range of neighboring bit by having them set ON. | |
*/ | |
/* shifts left the '1' over pos times to create a single HIGH bit at location pos. */ | |
#define BIT(pos) ( 1<<(pos) ) | |
/* Set single bit at pos to '1' by generating a mask | |
in the proper bit location and ORing x with the mask. */ | |
#define SET_BIT(x, pos) ( (x) |= (BIT(pos)) ) | |
#define SET_BITS(x, bm) ( (x) |= (bm) ) // same but for multiple bits | |
/* Set single bit at pos to '0' by generating a mask | |
in the proper bit location and ORing x with the mask. */ | |
#define UNSET_BIT(x, pos) ( (x) &= ~(BIT(pos)) ) | |
#define UNSET_BITS(x, bm) ( (x) &= (~(bm)) ) // same but for multiple bits | |
/* Set single bit at pos to opposite of what is currently is by generating a mask | |
in the proper bit location and ORing x with the mask. */ | |
#define FLIP_BIT(x, pos) ( (x) ^= (BIT(pos)) ) | |
#define FLIP_BITS(x, bm) ( (x) ^= (bm) ) // same but for multiple bits | |
/* Return '1' if the bit value at position pos within y is '1' and '0' if it's 0 by | |
ANDing x with a bit mask where the bit in pos's position is '1' and '0' elsewhere and | |
comparing it to all 0's. Returns '1' in least significant bit position if the value | |
of the bit is '1', '0' if it was '0'. */ | |
#define CHECK_BIT(y, pos) ( ( 0u == ( (y)&(BIT(pos)) ) ) ? 0u : 1u ) | |
#define CHECK_BITS_ANY(y, bm) ( ( (y) & (bm) ) ? 0u : 1u ) | |
// warning: evaluates bm twice: | |
#define CHECK_BITS_ALL(y, bm) ( ( (bm) == ((y)&(bm)) ) ? 0u : 1u ) | |
// These are three preparatory macros used by the following two: | |
#define SET_LSBITS(len) ( BIT(len)-1 ) // the first len bits are '1' and the rest are '0' | |
#define BF_MASK(start, len) ( SET_LSBITS(len)<<(start) ) // same but with offset | |
#define BF_PREP(y, start, len) ( ((y)&SET_LSBITS(len)) << (start) ) // Prepare a bitmask | |
/* Extract a bitfield of length len starting at bit start from y. */ | |
#define BF_GET(y, start, len) ( ((y)>>(start)) & SET_LSBITS(len) ) | |
/* Insert a new bitfield value bf into x. */ | |
#define BF_SET(x, bf, start, len) ( x = ((x) &~ BF_MASK(start, len)) | BF_PREP(bf, start, len) ) | |
/***************************************************************************************** | |
****************************************************************************************** | |
DEMONSTRATIONS - Particularly for Arduino | |
*/ | |
#ifndef Arduino_h | |
inline void print_bin8(unsigned x, unsigned short spacenib=0) { | |
for (unsigned n=0; n<8; n++) { | |
( (x&0x80) !=0 ) ? printf("1") : printf("1"); | |
if (spacenib && (n==3)) printf(" "); /* insert a space between nibbles */ | |
x = x<<1; | |
} | |
} | |
inline void println_bin8(unsigned x, unsigned short spacenib=0) { | |
print_bin8(x, spacenib); printf("%s", postch); | |
} | |
inline char *toS_BIN8(uint8_t x) { | |
static char schp[9]; | |
unsigned short d, count = 0; | |
for (short n = 7 ; n >= 0 ; n--) { | |
d = x >> n; | |
*(schp+count) = (d & 1) ? '1' : '0'; | |
count++; | |
} | |
*(schp+count) = '\0'; | |
return schp; | |
#else | |
inline void print_bin8(unsigned x, bool spacenib=true) { | |
for (unsigned n=0; n<8; n++) { | |
( (x&0x80) !=0 ) ? Serial.print("1") : Serial.print("0"); | |
if (spacenib && (n==3)) Serial.print(" "); /* insert a space between nibbles */ | |
x = x<<1; | |
} | |
} | |
inline void println_bin8(unsigned x, bool spacenib=true) { | |
print_bin8(x, spacenib); Serial.print("\n"); | |
} | |
#define print Serial.print | |
#define println Serial.println | |
#define toS(var) ( String((var)) ) | |
inline String toS_BIN8(int x) { | |
String str = ""; | |
unsigned short d, count = 0; | |
for (short n = 7 ; n >= 0 ; n--) { | |
d = x >> n; | |
str.concat( (d & 1) ? '1' : '0' ); | |
count++; | |
} | |
str.concat('\0'); | |
return str; | |
} | |
void test_BIT(uint8_t pos) { | |
println("BIT("+toS(pos)+") == "+toS_BIN8(BIT(pos))); | |
} | |
void test_SET_BIT(uint16_t x, uint8_t pos) { | |
println("SET_BIT("+toS_BIN8(x)+", "+toS(pos)+") == "+toS_BIN8(SET_BIT(x, pos))); | |
} | |
void test_SET_BITS(uint16_t x, uint16_t bm) { | |
println("SET_BITS("+toS_BIN8(x)+", "+toS_BIN8(bm)+") == "+toS_BIN8(SET_BITS(x, bm))); | |
} | |
void test_UNSET_BIT(uint16_t x, uint8_t pos) { | |
println("UNSET_BIT("+toS_BIN8(x)+", "+toS(pos)+") == "+toS_BIN8(UNSET_BIT(x, pos))); | |
} | |
void test_UNSET_BITS(uint16_t x, uint16_t bm) { | |
println("UNSET_BITS("+toS_BIN8(x)+", "+toS_BIN8(bm)+") == "+toS_BIN8(UNSET_BITS(x, bm))); | |
} | |
void test_FLIP_BIT(uint16_t x, uint8_t pos) { | |
println("FLIP_BIT("+toS_BIN8(x)+", "+toS(pos)+") == "+toS_BIN8(FLIP_BIT(x, pos))); | |
} | |
void test_FLIP_BITS(uint16_t x, uint16_t bm) { | |
println("FLIP_BITS("+toS_BIN8(x)+", "+toS_BIN8(bm)+") == "+toS_BIN8(FLIP_BITS(x, bm))); | |
} | |
void test_CHECK_BIT(uint16_t y, uint8_t pos) { | |
println("CHECK_BIT("+toS_BIN8(y)+", "+toS(pos)+") == "+toS_BIN8(CHECK_BIT(y, pos))); | |
} | |
void test_CHECK_BITS_ANY(uint16_t y, uint16_t bm) { | |
println("CHECK_BITS_ANY("+toS_BIN8(y)+", "+toS_BIN8(bm)+") == "+toS_BIN8(CHECK_BITS_ALL(y, bm))); | |
} | |
void test_CHECK_BITS_ALL(uint16_t y, uint16_t bm) { | |
println("CHECK_BITS_ALL("+toS_BIN8(y)+", "+toS_BIN8(bm)+") == "+toS_BIN8(CHECK_BITS_ALL(y, bm))); | |
} | |
void test_SET_LSBITS(uint8_t len) { | |
println("SET_LSBITS("+toS(len)+") == "+toS_BIN8(SET_LSBITS(len))); | |
} | |
void test_BF_MASK(uint8_t start, uint8_t len) { | |
println("BF_MASK("+toS(start)+", "+toS(len)+") == "+toS_BIN8(BF_MASK(start, len))); | |
} | |
void test_BF_PREP(uint16_t y, uint8_t start, uint8_t len) { | |
println("BF_PREP("+toS_BIN8(y)+", "+toS(start)+", "+toS(len)+") == "+toS_BIN8(BF_PREP(y, start, len))); | |
} | |
void test_BF_GET(uint16_t y, uint8_t start, uint8_t len) { | |
println("BF_GET("+toS_BIN8(y)+", "+toS(start)+", "+toS(len)+") == "+toS_BIN8(BF_GET(y, start, len))); | |
} | |
void test_BF_SET(uint16_t y, uint16_t bf, uint8_t start, uint8_t len) { | |
println("BF_SET("+toS_BIN8(y)+", "+toS_BIN8(bf)+", "+toS(start)+", "+toS(len)+") == "+toS_BIN8(BF_PREP(y, start, len))); | |
} | |
void setup() | |
{ | |
Serial.begin(9600); // open the serial port at 9600 bps | |
// modify everything below here to experiment with bit macros | |
uint8_t pos = 1; | |
uint16_t x = 0b01010101; | |
uint16_t y = 0b10101010; | |
uint16_t bm = 0b00000000; | |
uint8_t len = 1; | |
uint8_t start = 1; | |
uint16_t bf = 0b0000010; | |
test_BIT(pos); | |
test_SET_BIT(x, pos); | |
test_SET_BITS(x, bm); | |
test_UNSET_BIT(x, pos); | |
test_UNSET_BITS(x, bm); | |
test_FLIP_BIT(x, pos); | |
test_FLIP_BITS(x, bm); | |
test_CHECK_BIT(y, pos); | |
test_CHECK_BITS_ANY(y, bm); | |
test_CHECK_BITS_ALL(y, bm); | |
test_SET_LSBITS(len); | |
test_BF_MASK(start, len); | |
test_BF_PREP(y, start, len); | |
test_BF_GET(y, start, len); | |
test_BF_SET(x, bf, start, len); | |
} | |
void loop() { } | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
in more compact form: