Bit variables in a byte variable

Hello,

I am having trouble finding a good solution to my problem.

I need to assign a single byte variable and give it a name. For exampled status. which is a single byte.
I would then like to name each bit of status. For example bit 0 is called home_bit and assign it as bit or Boolean type of variable.

Then I want to be able to set or clear each of the bits, by name, so I can i keep track of some things in my code. I want everything contained in one byte so I can access the status serially. As in send the status byte out on the UART port.

Basically, I want to create a register called status and access the all the named bits withing status.
I tried using Structs but failed.

What's the best way to do this.

Thanks

byte status;

const byte home_bit = 0;
const byte other_bit = 5;
...
bitSet(status, home_bit);
...
bitClear(status, other_bit);
...
if (bitRead(status, other_bit) == 1) { ... }
1 Like

I think a struct with bit fields can provide another solution; below a simple demo.

struct STATUS
{
  uint8_t s0: 1;
  uint8_t s1: 1;
  uint8_t s2: 1;
  uint8_t s3: 1;
  uint8_t s4: 1;
  uint8_t s5: 1;
  uint8_t s6: 1;
  uint8_t s7: 1;
};

STATUS status;

void setup()
{
  Serial.begin(115200);
  Serial.print(F("S0 = ")); Serial.println(status.s0);
  Serial.print(F("S1 = ")); Serial.println(status.s1);
  status.s1 = 1;
  Serial.print(F("S1 = ")); Serial.println(status.s1);
}

void loop()
{
}
3 Likes

@sterretje will your suggested code allow this?

Let's find out

struct STATUS
{
    uint8_t s0 : 1;
    uint8_t s1 : 1;
    uint8_t s2 : 1;
    uint8_t s3 : 1;
    uint8_t s4 : 1;
    uint8_t s5 : 1;
    uint8_t s6 : 1;
    uint8_t s7 : 1;
};

STATUS status;

void setup()
{
    Serial.begin(115200);
    Serial.print("size of status is ");
    Serial.println(sizeof(status));
    Serial.print(F("S0 = "));
    Serial.println(status.s0);
    Serial.print(F("S1 = "));
    Serial.println(status.s1);
    status.s1 = 1;
    Serial.print(F("S1 = "));
    Serial.println(status.s1);
}

void loop()
{
}

Outputs

size of status is 1
S0 = 0
S1 = 0
S1 = 1
1 Like

Thank you for your replies.
A few questions.

STATUS status;

What does this do? The rest of the code makes sense.

Also, although not a big problem, I was hoping that when I reference the individual bits, I can simply do this by the bit name.
So, for example:

home_pos = 1; 

Would simply set the home_pos bit of status to a 1.

Looks like the struct may do what I need as I need to send the byte status to another controller serially when requested.

Thanks

STATUS status;

declares a struct named status of type STATUS

Thanks @UKHeliBob

It will actually allow a lot more. Assume that you only need 4 status bits; the below shows how you can have an additional 4-bit counter in the struct.

struct STATUS
{
  uint8_t s0: 1;
  uint8_t s1: 1;
  uint8_t s2: 1;
  uint8_t s3: 1;
  uint8_t cnt: 4;
};

STATUS status;

void setup()
{
  Serial.begin(115200);
  Serial.print(F("sizeof(status) = ")); Serial.println(sizeof(status));
  Serial.print(F("S0 = ")); Serial.println(status.s0);
  Serial.print(F("S1 = ")); Serial.println(status.s1);
  status.s1 = 1;
  Serial.print(F("S1 = ")); Serial.println(status.s1);
}

void loop()
{
  status.cnt++;
  Serial.println(status.cnt);
  Serial.print(F("S0 = ")); Serial.println(status.s0);
  Serial.print(F("S1 = ")); Serial.println(status.s1);
  Serial.print(F("S2 = ")); Serial.println(status.s2);
  Serial.print(F("S3 = ")); Serial.println(status.s3);
  delay(1000);
}

The printing of the status bits was added to demonstrate that the incrementing of the counter above 16 does not influence the status bits.

1 Like

It creates a variable of type STATUS.

I get the following error when compiling:

Compilation error: conflicting declaration 'STATUS status'
Still not sure what this STATUS status; means, looked up TYPES but still confused.

Which sketch are you compiking ?

Please copy the whole sketch from the IDE on your PC and post it here in code tags

As to what STATUS means, this portion of code

struct STATUS
{
  uint8_t s0: 1;
  uint8_t s1: 1;
  uint8_t s2: 1;
  uint8_t s3: 1;
  uint8_t cnt: 4;
};

creates a new data type named STATUS which can then use to declare variables of that type

The codes that I provided do compile. You will need to show your code :slight_smile: We can't possibly say what you did wrong without it.

1 Like

1. We can use struct keyword to declare a conglomerate data stucture which can contain variables of dissimilar data types. For example:

struct 
{
    byte x;
    int    y;
    float z;
    bool status0;
};

2. Let us define a varible (s) that refers to all the data items of Step-1.
(a)

struct 
{
    byte x;
    int    y;
    float z;
    bool status0;
} y1;

(b)

struct 
{
    byte x;
    int    y;
    float z;
    bool status0;
} y2;

3. C++ allows to use a Tag (called user-defiined data type) so that we don't need to type the data items of the structure everytime we declare a variable. The syntax is:

struct STATUS
{
    byte x;
    int    y
    float z;
    bool status0;
};

Here, STATUS is a Tag (also known as user-defined data type) which refers to all the data items of the structure.

4. Now, we can simplify the declaration of variables y1 and y2 of Step-2 as follows:

STATUS y1;
STATUS y2;

Here, y1/Y2 is a variable whose data type is STATUS which refers to four data items of different types (byte, int, float, and bool) of the structure.

5. Now, we can access the variables of the structure using member operator (.). Example:

struct STATUS
{
  byte x;
  int  y;
  float z;
  bool status0;  
};

STATUS y1;  //variable declaration of user-defined type

void setup()
{
  Serial.begin(9600);
  y1.x = 0x06;    //value is assigned to variable x which is a member of variable y1
  Serial.println(y1.x); //shows: 6
  y1.status0 = true;
  byte rdStatus0 = y1.status0;    //reading the value of status0 -- member of y1
  Serial.println(rdStatus0); //shows 1 = HIGH = true
}

void loop()
{

}

Learn to use the Arduino "bit" macros, check out the "bits and bytes" section here:

As demonstrated in post #2

So it will allow

Serial.write(status);

to write the structure to Serial?

Yes, Ya, Si, uh-huh.

1 Like

No, but you can teach the struct to print itself:

#include "Printable.h"

struct STATUS : public Printable {
  uint8_t s0: 1;
  uint8_t s1: 1;
  uint8_t s2: 1;
  uint8_t s3: 1;
  uint8_t cnt: 4;

  virtual size_t printTo(Print & p) const {
    size_t charsPrinted = 0;
    charsPrinted = p.print(F("S0 = ")); charsPrinted += p.println(s0);
    charsPrinted += p.print(F("S1 = ")); charsPrinted += p.println(s1);
    charsPrinted += p.print(F("S2 = ")); charsPrinted += p.println(s2);
    charsPrinted += p.print(F("S3 = ")); charsPrinted += p.println(s3);
    return charsPrinted;
  }
};

STATUS status;

void setup() {
  Serial.begin(115200);
  delay(2000);
  status.s1 = 1;
  Serial.print(F("sizeof(status) = ")); Serial.println(sizeof(status));
  Serial.print(status);
}

void loop() {
  status.cnt++;
  Serial.print(status);
  delay(1000);
}
1 Like

Great, that's things that I do not quite know.

A simple cast would do

Serial.write(byte*)&status);

I know that this is not the correct way; @gfvalvo, is there a correct way to cast and what would it be? Some reinterprete....?

1 Like

What would be the purpose of doing this? The write() function sends the data as binary. I don't know why you'd want to do that. But ....
Serial.write(reinterpret_cast<uint8_t *>(&status), sizeof(status));