Pack bits in a uint8_t

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Preface: I am more than familiar with normal bitwise operations to mask/shift/etc. 

 

I recall seeing [nifty] code once that essentially created a struct out of a uint8_t.  Meaning, there were multiple "variables" (with binary values) that were packed into a single byte.  I know it was in some AVR code that I did not write, but cannot remember where it was.

 

I have an application where I have a bunch of flags (<8).  In the interest of efficiency, rather than creating 8 uint8_t's (of which I am only really using one bit), I would like to use the method described above.  Unfortunately, I do not remember the syntax, and my google-fu is failing me.

 

Am I crazy, or is there some way to do what I described?  Please let me know if hte description itself is confusing, and I will attempt to rephrase.

 

Edit: never mind... Of course, two minutes after posting, I finally found what I was looking for.  For anyone interested (or anyone perplexed by my explanation above), what I was referring to are bitfields.

 

Example:

/* define a structure with bit fields */
struct {
   unsigned int widthValidated : 1;
   unsigned int heightValidated : 1;
} status2;

Science is not consensus. Science is numbers.

Last Edited: Sat. Dec 5, 2015 - 03:19 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Take a look at post #18 in this thread:

 

https://www.avrfreaks.net/comment...

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hobbss wrote:
 For anyone interested (or anyone perplexed by my explanation above), what I was referring to are bitfields.

 

A standard 'C' language feature: http://publications.gbdirect.co....

 

Note, however, that compilers do not necessarily implement this any more efficiently than doing your own masks & shifts - and some are actually less efficient.

 

Note also,

K&R wrote:
Almost everything about [bit] fields is implementation-dependent

So do not rely upon them for anything that needs to be portable!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Good points, all.  Thanks for the responses.

Science is not consensus. Science is numbers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Read the "Bit manipulation 101" thread in tutorial. There are two posts in it by "danni" with a file attached called "sbit.h". Get that!

 

If you have sbit.h you can do this:

#include "sbit.h"

#define GOING_LEFT SBIT( GPIOR0, 0 )
#define INVERTED   SBIT( GPIOR0, 1 )
#define FAST       SBIT( GPIOR0, 2 )

int main(void) {
    GOING_LEFT = 1;
    INVERTED = 0;
    FAST = 1;
}

which yields..

$ avr-gcc -mmcu=atmega168 -g -Os avr.c -o avr.elf
$ avr-objdump -S avr.elf

avr.elf:     file format elf32-avr
Disassembly of section .text:

00000000 <__vectors>:
   0:	0c 94 34 00 	jmp	0x68	; 0x68 <__ctors_end>
        [SNIP]

00000068 <__ctors_end>:
  68:	11 24       	eor	r1, r1
  6a:	1f be       	out	0x3f, r1	; 63
  6c:	cf ef       	ldi	r28, 0xFF	; 255
  6e:	d4 e0       	ldi	r29, 0x04	; 4
  70:	de bf       	out	0x3e, r29	; 62
  72:	cd bf       	out	0x3d, r28	; 61
  74:	0e 94 40 00 	call	0x80	; 0x80 <main>
  78:	0c 94 44 00 	jmp	0x88	; 0x88 <_exit>

0000007c <__bad_interrupt>:
  7c:	0c 94 00 00 	jmp	0	; 0x0 <__vectors>

00000080 <main>:
#define GOING_LEFT SBIT( GPIOR0, 0 )
#define INVERTED   SBIT( GPIOR0, 1 )
#define FAST       SBIT( GPIOR0, 2 )

int main(void) {
    GOING_LEFT = 1;
  80:	f0 9a       	sbi	0x1e, 0	; 30
    INVERTED = 0;
  82:	f1 98       	cbi	0x1e, 1	; 30
    FAST = 1;
  84:	f2 9a       	sbi	0x1e, 2	; 30
}
  86:	08 95       	ret

00000088 <_exit>:
  88:	f8 94       	cli

0000008a <__stop_program>:
  8a:	ff cf       	rjmp	.-2      	; 0x8a <__stop_program>

As you can see, by casting these variables onto the GPIOR0 register (available in most recent AVRs) you get SBI/CBI for up to 8 of your most accessed binary variables.

 

PS for an easy life I attached sbit.h to this post too.

Attachment(s):