Looking for good ways to change bits in a byte.

i am looking for different way to change certain bits in a byte.

for example, lets say i am talking to some audio chip and register 0x04 is the sound control byte. the bit definitions are as follows.

AudioControl (register location 0x04)

Bit 7:5 is for volume level. (000 lowest & 111 is highest volume)

Bit 6 is for mute. (1 = mute, 0 = unmute)

Bit 3:2 is for base level. (00 lowest & 11 highest base)

Bit 1:0 is for treble. (00 lowest & 11 highest treble)

now, if there are over 30 registers like this all with different bit settings controlling different things, and i want to allow the user to be able to control all these parameters. how would some of you tackle it?

It seems your problem has two sides:

  1. how to set/clear bits

  2. how to present control of these bits to the user

For 1), use #defines for the specific bits and their bit positions.

Example:

#define TREBLE_LEVEL_SHIFT 0

#define TREBLE_LEVEL_MASK 0x03

#define BASS_LEVEL_SHIFT 2

#define BASS_LEVEL_MASK 0x0C

#define MUTE_BIT 4

#define VOL_LEVEL_SHIFT 5

#define VOL_LEVEL_MASK 0xE0

To set bass level

AudioControl = (AudioControl & ~BASS_LEVEL_MASK) | (bass_level << BASS_LEVEL_SHIFT);

To get bass level

bass_level = (AudioControl & BASS_LEVEL_MASK) >> BASS_LEVEL_SHIFT;

To set a single bit, like the mute bit

AudioControl |= (1<<MUTE_BIT);

To clear a single bit, like the mute bit

AudioControl &= ~(1<<MUTE_BIT);

(I’m assuming that you have direct read/write access to the AudioControl register)

thanks for the reply.

with 30+ registers i guess i am looking for somthing more acomodating for all the registers.

if AudioControl is at register location 0x04, i suppose i am looking to do somthing like this:

#define AudioControl 0x04

#define BassBoost 0x05

UpdateRegister( AudioControl, mute, 1); // to set mute bit.

and

UpdateRegister( AudioControl, mute, 0); // to clear mute bit.

or

UpdateRegister( AudioControl, volume_level, 5); // to set volume

and finaly

UpdateRegister( BassBoost, boost_level, 12); //

Or how about a table with an entry for each control you want to set, something like

typedef struct {
	int control_id;
	int audio_register;
	int bit_offset;
	int num_bits;
	char *description;
} control_entry;

static const control_entry control_table[] = {
	{	0,	0x04,	0,	2,	"treble"},
	{	1,	0x04,	2,	2,	"bass"},
	{	2,	0x04,	4,	1,	"mute"},
	{	3,	0x04,	5,	3,	"volume"},
etcetera
	// terminating entry
	{	-1,	0x00,	0,	0,	NULL}
};

int SetAudioControl(int control_id, int setting)
{
	control_entry *p;
	int mask, value;	

	// find entry in table
	for (p = control_table; p->control_id >= 0; p++) {
		if (p->control_id == control_id) {
			break;
		}
	}
	if (p->control_id < 0) {
		// control not found!
		return -1;
	}
	
	// check if setting fits into 'num_bits' bits
	mask = (1 << p->num_bits) - 1;
	if ((setting & ~mask) != 0) {
		// setting does not fit!
		return -2;
	}
	
	// insert the setting into the audio register
	value = AudioRegister[p->audio_register];
	value &= ~(mask << num_bits);		// clear specific bits
	value |= (setting<< num_bits);		// insert 'setting'
	AudioRegister[p->audio_register] = value;
	
	return 0;
}

Then you can simply call it like:

SetAudioControl(0, 3);		// treble max
SetAudioControl(1, 3);		// bass max
SetAudioControl(2, 0);		// unmute

It should even be very simple to modify the code to reference the audio control by string so you can simply do

SetAudioControl("treble", 3);

thanks, i wound up doing something like this instead, using your previous example.

//

// Fan 1 Configuration Register 1 (0x10)

//

#define F1CR1 0x10 // Resgister Address

#define F1CR1_PWM_Mode 0x80

#define F1CR1_PWM_Mode_Mask 7

#define F1CR1_StepSizeDelay 0x70

#define F1CR1_StepSizeDelay_Mask 4

#define F1CR1_Fan1Channel 0x0c

#define F1CR1_Fan1Channel_Mask 2

#define F1CR1_RPM_RangeSelect 0x03

#define F1CR1_RPM_RangeSelect_Mask 0

then i just call one function for all registers defined like the above:

Max6640RegisterUpdate(F1CR1,F1CR1_Fan1Channel,F1CR1_Fan1Channel_MASK,2);

//***************************************************

//************ UPDATE REGISTERS ********************

//***************************************************

void Max6640RegisterUpdate(unsigned char address,unsigned char mask,unsigned char bit,unsigned char data)

{

unsigned char temp;

temp = Max6640_Read(address);

temp = (temp & ~mask) | (data << bit);

Max6640_Write(address, temp);

}