View previous topic :: View next topic |
Author |
Message |
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
Help With Struct/Union of Bits |
Posted: Sat Nov 04, 2006 3:38 am |
|
|
3.236
I'm trying to store status bits in a byte. Id like to have a structure so that I can declare a variety of variables in this fashion. I've done the following to declare a single variable in the way I'd like, but I'm unsure of how to convert this into a structure... or if a union is necessary.
Code: | int8 unit_status_byte = 0b00000000;
#bit status_bat = unit_status_byte.0 //unit has low battery
#bit status_dead_bat = unit_status_byte.4 //unit has dead battery, will be shutting down
#bit status_tampered = unit_status_byte.1 //unit has been tampered with
#bit status_bad_comms = unit_status_byte.2 //some failed packets or bad acks
#bit status_off_air = unit_status_byte.3 //unit is not communicating
|
I had read: http://www.ccsinfo.com/forum/viewtopic.php?t=25068 but I don't understand if that's what I need.
Can I make the #bit declarations in the structure?
Thanks for any help,
John
EDIT:
I think I've got the solution. Is this the correct approach:
Code: | typedef struct t_status_byte {
int1 status_bat : 1; //unit has low battery
int1 status_dead_bat : 1; //unit has dead battery, will be shutting down
int1 status_tampered : 1; //unit has been tampered with
int1 status_bad_comms : 1; //some failed packets or bad acks
int1 status_off_air : 1; //unit is not communicating
int1 unused1 : 1;
int1 unused2 : 1;
int1 unused3 : 1;
} |
Will this guarantee that t_status_byte is actually a byte and those bits will occur in the came locations in each instance declared?
Thanks again. |
|
|
Ttelmah Guest
|
|
Posted: Sat Nov 04, 2006 8:24 am |
|
|
The syntax should be:
Code: |
typedef struct t_status_byte {
int8 status_bat : 1; //unit has low battery
int8 status_dead_bat : 1; //unit has dead battery, will be shutting down
int8 status_tampered : 1; //unit has been tampered with
int8 status_bad_comms : 1; //some failed packets or bad acks
int8 status_off_air : 1; //unit is not communicating
int8 unused1 : 1;
int8 unused2 : 1;
int8 unused3 : 1;
};
|
The ':' declaration, makes the variable a 'bit field', _in_ a larger storage location (int8). The 'int1' declaration, itself defines a single bit.
Best Wishes |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Sat Nov 04, 2006 10:14 am |
|
|
Thanks.
I'm going to be using this to send statuses back and forth by radio between units and need to have the bits in the same place in each system and each instance of the variable. I'll have the declarations in a common header file. Will the compiler always put the bits in the same place in the byte?
John
EDIT:
OK. I've had a chance to start playing with this. I'm trying this:
Code: | typedef struct {
int8 status_bat : 1; //unit has low battery
int8 status_dead_bat : 1; //unit has dead battery, will be shutting down
int8 status_tampered : 1; //unit has been tampered with
int8 status_bad_comms : 1; //some failed packets or bad acks
int8 status_off_air : 1; //unit is not communicating
int8 unused1 : 1;
int8 unused2 : 1;
int8 unused3 : 1;
} t_status_byte;
t_status_byte unit_status_byte = 0b00000000;
t_status_byte unit_prev_status_byte = 0b00000000; |
And it says the value that I'm trying to initialize the variable with has to evaluate to a constant. Will I be able to access both the individual bits and the byte as a whole with this scheme?
Thanks.
John
EDIT part deux:
I've just done some quick reading. It sounds like I don't want to use bitfields. How should I go about putting status bits in a byte for a TYPEDEF so I can declare a bunch of variables with the same structure? |
|
|
Ttelmah Guest
|
|
Posted: Sat Nov 04, 2006 11:00 am |
|
|
Code: |
struct bfield {
int8 status_bat : 1; //unit has low battery
int8 status_dead_bat : 1; //unit has dead battery, will be shutting down
int8 status_tampered : 1; //unit has been tampered with
int8 status_bad_comms : 1; //some failed packets or bad acks
int8 status_off_air : 1; //unit is not communicating
};
union t_status_byte {
struct bfield bits;
int8 b;
};
union t_status_byte unit_status_byte;
union t_status_byte unit_prev_status_byte;
|
You will have to initialise the values yourself in the code:
unit_status_byte.b=0b00000000;
unit_prev_status_byte.b=0b00000000;
Which accesses the bytes.
The bits are then accessible with:
unit_status_byte.bits.status_bat etc..
You can obviously typedef the final union declaration if required.
Best Wishes |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Sat Nov 04, 2006 11:43 am |
|
|
Thanks a bunch. It took me a few minutes to figure out what was happening and do a little reading.
It worked great the way you had it in your post. But when I modified the code to use TYPEDEF it spit out an error: 'Expecting a ('. Anu idea what I'm doing wrong?
Code: | struct bfield {
int8 bat : 1; //unit has low battery
int8 dead_bat : 1; //unit has dead battery, will be shutting down
int8 tampered : 1; //unit has been tampered with
int8 bad_comms : 1; //some failed packets or bad acks
int8 off_air : 1; //unit is not communicating
};
typedef union u_status_byte {
struct bfield bit;
int8 byt;
};
u_status_byte unit_status;
u_status_byte unit_prev_status; |
Again, thanks for all your time,
John |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1907
|
|
Posted: Sat Nov 04, 2006 12:01 pm |
|
|
This is something I use for human input. A joystick with 4 momentary switches (north, south, east, west) and 3 buttons (top, bottom, trigger) as well as one more switch (compressor off) are connected to port C on a PIC. All of port C's lines are pulled high - closing a switch grounds the line.
Code: | union {
int8 portc;
struct {
int1 s; // c0
int1 n; // c1
int1 e; // c2
int1 w; // c3
int1 trigger; // c4
int1 bottom; // c5
int1 top; // c6
int1 comp_off; // c7
} bits;
} input;
#byte portc = 0xf82 |
A timer interrupt set to go off every 13 ms (roughly) triggers a read of the entire port. That looks like this:
Code: | input.portc = portc; |
I then check to see if the value I just read has changed from the last time I read it. Then to test if a particular line is down (active):
Code: | if (!input.bits.trigger) {
...
} |
etc etc etc |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Sat Nov 04, 2006 12:08 pm |
|
|
Newguy,
Thanks. I like that way also. But still, no one has come out and said in either solution whether, there is a guarantee that the bits will always be located in the same location in the byte in each declaration of the byte size variable. These bytes are going to be sent back and forth by radio, in a packet, and the receiving unit has to have each status bit in the same location.... Does that make sense? I'm not sure if I'm explaining it clearly enough?
Thanks.
John |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Nov 04, 2006 12:08 pm |
|
|
Quote: | union t_status_byte {
struct bfield bits;
int8 b;
};
union t_status_byte unit_status_byte;
union t_status_byte unit_prev_status_byte;
unit_status_byte.b=0b00000000;
unit_prev_status_byte.b=0b00000000;
|
You don't need a union. You can zero the whole structure with one
line of code.
Code: |
// Create two structures.
t_status_byte unit_status_byte;
t_status_byte unit_prev_status_byte;
//============================
void main()
{
// Zero both structures.
unit_status_byte = 0;
unit_prev_status_byte = 0;
while(1);
} |
Here's the symbol table:
Code: |
unit_status_byte 00000021
unit_prev_status_byte 00000022
|
Here's the .LST file:
Code: | 0000 00326 .... unit_status_byte = 0;
0016 01A1 00327 CLRF 21
0000 00328 .... unit_prev_status_byte = 0;
0017 01A2 00329 CLRF 22 |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Nov 04, 2006 12:18 pm |
|
|
Quote: | But still, no one has come out and said in either solution whether,
there is a guarantee that the bits will always be located in the same
location in the byte in each declaration of the byte size variable |
Only CCS would know the answer for certain, because it depends upon
the internal compiler code. All that we could do, is to run a few tests
and then make an assessment based on that.
With regard to portability, I remembered that bitfields can't be
depended upon to be portable across machines. That's not really
your question, but it's still of interest. There are several comments
on this at the end of the bitfields section on this page:
http://icecube.wisc.edu/~dglo/c_class/odds_n_ends.html |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Sat Nov 04, 2006 12:27 pm |
|
|
EDIT:
Just caught your second reply. I'll experiment and report back. Any idea on the error during compilation described above?
PCM,
Thanks for the reply. I think I may have confused the issue by assigning 0b00000000 to the variable in the declaration. I'm not having a problem doing that.
I've got a variety of sensors that are communicating with a hub. A number of statuses will be tracked and I thought I'd save room in my comm packet if I just packed them into a single byte. I can use the standard bit set/test/clear functions but I thought I'd try something a little more 'elegant'.... (complex). So I need to be able to send the byte back and forth by radio (standardized bit location required) and I'd like to be able to easily get at each of those status bits.
John |
|
|
Ttelmah Guest
|
|
Posted: Sat Nov 04, 2006 12:42 pm |
|
|
You have to give the 'typedef' a name, as opposed to the 'union' a name.
When you define a union or structure, the layout is:
Code: |
struct/union struct/union_name {
declared stuff;
} variable/typedef_name;
|
So just move the name declaration from where I have it (to declare the union), to the end where you had it (for typedef).
Personally, I slightly prefer to 'know' that I am dealing with a structure or union, so name these, rather than hiding it behind a typedef, but this is purely a 'personal' thing.
Best Wishes |
|
|
Ttelmah Guest
|
|
Posted: Sat Nov 04, 2006 12:46 pm |
|
|
Bitfields are meant to declare from LSB upwards, so, the bits will be in the order you expect. You can test this by just looking at the byte value, or the access code. For instance, the line:
unit_status_byte.bits.status_bat=1;
Codes as:
000A4: BSF 05.0
With the symbol table, showing:
005 unit_status_byte
So the behaviour is exactly as expected.
Best Wishes |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Sat Nov 04, 2006 12:50 pm |
|
|
Ttelmah wrote: | Personally, I slightly prefer to 'know' that I am dealing with a structure or union, so name these, rather than hiding it behind a typedef, but this is purely a 'personal' thing. |
Got both replies. Thanks!
Your approach makes sense and will be helpful in six months when I have to make revisions.
John |
|
|
|