[TUT] [C] Bit manipulation (AKA "Programming 101")

Go To Last Post
237 posts / 0 new

Pages

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

I haven't done bit twiddling in a long time but I thought that instead of shifting a one X positions, you just used an XOR to toggle a specific bit.

JWColby
AVRNubee
www.ColbyConsulting.com

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

That depends on what register and what AVR you are talking about. For the newer AVRs and port registers you simply write a 1 to the proper bit in the PINx register. But I think you are a bit confused. No one uses shifting to toggle a bit. You use the shifting to create the proper bit mask that will be used for toggling (or setting or clearing) a bit. In that case an expression like:

1<<PB4

takes no clock cycles at all since the shifting is done by the compiler, not the AVR.

Regards,
Steve A.

The Board helps those that help themselves.

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

Koshchi wrote:
In that case an expression like:

1<<PB4

takes no clock cycles at all since the shifting is done by the compiler, not the AVR.

Oh, shift on then. :)

JWColby
AVRNubee
www.ColbyConsulting.com

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

Hello
I feel stupid, because I read this and some more forums several times about bit set, clear, compare, etc. But, I still don't understand how to do sometihngs.

I'm working with a atmega32 in WinAVR.

For example:

PORTD = (PORTD ^ 0b00000001);

This code flipp bit0 of PORTD

PORTD = (PORTD & 0b11111110);

This code switch off PIND.0

PORTD = (PORTD | 0b00000001);

And this shoudl switch on PIND.0

This is an example to compare.
I use PIND.0 as input, and when PIND.0 is "H" the program show a "0" in the LCD, because I do salida+1, and salida-1, so salida keep "0".
But when I put ground in PIND.0 (externaly), the program shoudl increase de value of salida, but "0" continues in the LCD screen, why?.

#include //main program


int salida =0;
char y=0;


//MAIN PROGRAM
int main (void)
{

	//Configure Pins / Ports as input- (0) or output (1)  
		// Port D (Interupts)
		DDRD  = 0b11111110; //La entrada es INT0 Y DATAOUT 
		//activate Pull Ups (1) 
		PORTD = 0b11111111;  
        
		// Port B (LED's)                
		DDRB  = 0b00001100;   
		PORTB = 0b11110011;   
		
		lcd_clrscr();	
		lcd_init(LCD_DISP_ON);	
		lcd_gotoxy(0,0);  
		lcd_puts("NUMBER");
		
		
	while(1)//bucle principal, pone en pantalla y espera interrupciones
	{
	
		
		salida++;
		if(PIND0 & 0b11111111)//I KNOW THIS LINE IS WRONG
		{
		salida--;
		}
		
		lcd_gotoxy(0,1);  
		itoa (salida,&y,10);
		lcd_puts(&y);//I put salida as an string in the LCD
		// PIN3 PORTB set -> LED off
		PORTB |= (1<<PINB2);//to see program its running
		
	delay(2000);//to decrease the speed
 	
	}
}

Well, I want to do:
Compare de value of the input in PIND.0, and make something to know when is 0 or 1.

Thanks so much

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
     if(PIND0 & 0b11111111)//I KNOW THIS LINE IS WRONG 

try:

if (PIND & (1<<PD0))

Try to get away from 0b???????? - that's the whole point of bit shifts - you don't need to know or care what the other 7 bits are doing when you access just a single bit. So it's

TARGET ^= (1<<bit_pos); // flip the bit
TARGET |= (1<<bit_pos); // set the bit
TARGET &= ~(1<<bit_pos); // clear the bit
if (TARGET & (1<<bit_pos)) // test if the bit is set

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

Thanks very much, I writte this and works ok:

if (PIND & (1<<PD0))

My last question about this is:

if (PIND & ~(1<<PD0))

This code test if bit is not set?

Thanks very much.

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

Quote:

Code:
if (PIND & ~(1<<PD0))

This code test if bit is not set?


No, it tests if any other bit is set. Take it step by step:

1:

1<<PD0

make a bitmask 00000001.

2:

~(1<<PD0)

negates every bit in that mask so you get 11111110

3:
A bitwise and of that and PIND thus will produce a 1 in any position where the bitmask has a 1 and PIND has a 1. Or in other words, it will produce a non-zero value if any of bits 7 of PIND to 1 is non-zero.

What you want is

if ( !(PIND & (1<<PD0)))

Work through that, in a similar manner as I did above, step by step, to see why this is diferent and will do what you ask for. (Please note that the logical NOT operator (!) is used.)

An alternative way would be to

if (~(PIND) & (1<<PD0))

as BenG has pointed out in the first page of this thread.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Ok. Now I think I've got it.
Thanks very much

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

At this time i'm working on a little project and i just can't get my head around the following

Hardware: hef4052 multiplexer with a0 and a1 tied to PC0 and PC1 of Atmega168

I'm trying to find a nice way to define the four (0/1/2/3) states of those 2 bits and what i can come up with is:

# define Sensor0 PORTC &= ~((1<<PORTC0) & (1<<PORTC1))
# define Sensor1 PORTC &= ~((1<<PORTC0)
# define Sensor2 PORTC |= (1<<PORTC0)
# define Sensor3 PORTC |= (1<<PORTC0) | (1<<PORTC1)

Is it possible to combine an & and an | operation in a define?, and what is the best way to do it?

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

If you want to both clear some bits and then set some bits you need to do TWO read/modify/write operations. One to clear the bits and then another to set any bits that need setting. Something like

# define Sensor0 PORTC &= 0xFC 
# define Sensor1 PORTC &= 0xFC; PORTC |= (1<<PORTC0) 
# define Sensor2 PORTC &= 0xFC; PORTC |= (1<<PORTC1) 
# define Sensor3 PORTC &= 0xFC; PORTC |= ((1<<PORTC0) | (1<<PORTC1))

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
PORTC &= ~((1<<PORTC0) | (1<<PORTC1));        // 00
PORTC = (PORTC & ~(1<<PORTC1)) | (1<<PORTC0); // 01
PORTC = (PORTC & ~(1<<PORTC0)) | (1<<PORTC1); // 10
PORTC |= (1<<PORTC0) | (1<<PORTC1);           // 11

Stealing Proteus doesn't make you an engineer.

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

Ok, thats what i thought but didn't know how to do :-)

Will the compiler produce the same code from both your examples?

Thanks!! :D

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

Unlikely - I think Arnold's may be more efficient though personally I think mine maybe makes it a little more obvious what's going on at the cost of a bit of inefficiency (I'm a great fan of "obvious" code for the person who comes back to read this in 3 months)

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

clawson wrote:
I think mine maybe makes it a little more obvious what's going on
Hey, I even added comments. What more can you ask for? :P

Stealing Proteus doesn't make you an engineer.

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

ArnoldB wrote:
Hey, I even added comments. What more can you ask for? :P

No fighting please, LOL

As speed is needed i will go with ArnoldB his version.

Points go to the both of you,

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

Hello again
First of all thanks very much, because of all of you I can continue working in my project.
I think I understand your explanations. But I'm still confuse with one point.
Here it is my code


	//PORT INITIALITATION.(1)OUTPUT,(0) INPUT
	DDRB  = 0b00001100;//LEDS AS OUTPUT   
	PORTB = 0b11111111;//PULL-UP ACTIVE
	
	DDRD  = 0b11101011;//DDC112 COMUNICATION
	PORTD = 0b11111111;//PULL-UP ACTIVE


//	PORTD &= ~(1 << 6);//DCLK "LOW"->INITIALITATION
	dclksemiperiod=0;
   
	
	
	PORTB ^= (1 << 3); //Toggle the LED PB3
	PORTD ^= (1 << 6); //Toggle PD6
	
	if((PIND & (1<<PD6)) && (dclksemiperiod == 0) && (PIND & (1<<PD4)))
	

The problem is that when I uncomment the line

PORTD &= ~(1 << 6);

The condition in the if its not true, and I don't not why.
I suposse that, at the beggining PD6=1, after

PORTD ^= (1 << 6);

PD6 shoud be 0, but its not. Why?
(I know the problem is PD6, because I allready checked all the other things and are ok, of course PD4 its allways on by hardware)
THANKS

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

tigrezno wrote:
those are my definitions, i find them more user-friendly, tell me what you think.

#define LOW 0
#define HIGH 1

#define INPUT(port,pin) DDR ## port &= ~(1<<pin)
#define OUTPUT(port,pin) DDR ## port |= (1<<pin)
#define CLEAR(port,pin) PORT ## port &= ~(1<<pin)
#define SET(port,pin) PORT ## port |= (1<<pin)
#define TOGGLE(port,pin) PORT ## port ^= (1<<pin)
#define READ(port,pin) (PIN ## port & (1<<pin))

usage:

OUTPUT(D, 3); // port D, pin 3 as output
SET(D, 3); // set port D pin 3 to HIGH
CLEAR(D, 3); // set it to LOW

INPUT(B, 5);
if (READ(B, 5) == HIGH)
...

feel free to add them to the tutorial :)
[updated]

Hello All, I have extended this code one more step. I wanted to keep all the pin definition in one place or one file.

#define LED A, 0
#define SWITCH B, 1


SET(LED) // turn on

if(READ(SWITCH)== 0){ // switch active
}

The sequence of pre-processor substitution was causing compile problems. I found solution for this as variable arguments macro. http://en.wikipedia.org/wiki/Variadic_macro
The extended version is as follows

// ##############

// GPIO.h file
#define G_INPUT(port,pin) DDR ## port &= ~(1<<pin)
#define G_OUTPUT(port,pin) DDR ## port |= (1<<pin)
#define G_CLEAR(port,pin) PORT ## port &= ~(1<<pin)
#define G_SET(port,pin) PORT ## port |= (1<<pin)
#define G_TOGGLE(port,pin) PORT ## port ^= (1<<pin)
//#define G_READ(port,pin) (PIN ## port & (1<<pin))
#define G_READ(port,pin) ((PIN ## port & (1<<pin)) >> pin)


#define GPIO_INPUT(...)    G_INPUT(__VA_ARGS__)
#define GPIO_OUTPUT(...)   G_OUTPUT(__VA_ARGS__)
#define GPIO_CLEAR(...)    G_CLEAR(__VA_ARGS__) 
#define GPIO_SET(...)      G_SET(__VA_ARGS__)
#define GPIO_TOGGLE(...)   G_TOGGLE(__VA_ARGS__)
#define GPIO_READ(...)     G_READ(__VA_ARGS__)
#define GPIO_READ_N(...)   G_READ_N(__VA_ARGS__)

// ########

// project.h file : keep all the definitions here

#define LED A, 0
#define SWITCH B, 1

// ###########

// Project.c file
// This can be used as follows

#include "include/GPIO.h"
#include "include/project.h"



GPIO_SET(LED) // Turn on the LED

if ( GPIO_READ(SWITCH)==0){ // Switch on
}

Please note my version of READ is different. I prefer return values as either 1 or 0.

Just my 2 cents. Thank you.

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

Hi all,

I have one question about the bit's names definitions of AVR registers, as they are done in avrlib.

In avrlib are these defined like this :

#define PA0 0
#define PA1 1
#define PA2 2

and so on.

Is there any good reason why to not have them defined directly like this :

#define PA0 1
#define PA1 2
#define PA2 4
#define PA3 8

So You do not need to shift or use any _BV() macro everytime.

Who and when needs bits defined by their number, and not directly by their mask ?

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

Quote:
Is there any good reason why to not have them defined directly like this :

This is the way that Atmel defined them in assembler. Avrlibc (not avrlib, that is a separate product) gets the definitions from Atmel's definitions.

Quote:
Who and when needs bits defined by their number, and not directly by their mask ?

Assembler uses them directly in opcodes such a SBI, CBI, SBIC, SBIS.

You can always define your own versions of them that are bit masks instead of bit numbers.

Regards,
Steve A.

The Board helps those that help themselves.

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

Thanks for reply.
Now it is clear.
Of course I was talking about avr-libc, sorry for that.

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

Bit Manipulation is clear for me, until it gets to negative values.
I have a function which returns an int16 value with following values:
-1 // OK
-2 // Failure
-3 // something
...
-75 // do something special
-128 // special detail

And of course some combinations with the special detail (-128)
-129 // OK and special detail
-130 // Not OK and special detail

But no combnination with the -75
And I don't have to use the special detail.

I have a working solution on how to check this, but in my opinion it is not a nice solution.

if (ret == -75){  // do something
   SendEvent(DO_SOMETHING);
}
else if (~(ret) & 128)	//special detail
{
   ret +=128;	//we don't need to check the special detail
   SendEvent(ret);	
}
else
   Send_Event(ret);

So, how can I easily handle negative return values?

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

I don't wholly see the relevance of your question to this tutorial but to try and drag it slowly back on topic how about using negative binary return codes:

#define ERROR_CONDITION_1 -1
#define ERROR_CONDITION_2 -2
#define ERROR_CONDITION_3 -4
#define ERROR_CONDITION_4 -8
...

In a 16 bit signed int you could hold 15 such conditions with multiple error conditions combined with & and individual conditions tested on the return with bit testing instructions.

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

OK, maybe you're right. It's not really bit manipulation what I need.
I cannot change the return value, because the function is in a Lib. I have to live with the strange return values, but I'm searching for a nice solution to handle this life :-)

Edit:
Ok. Found an easy solution:

ret *= -1; // and now I have nice positive values
...
else if (ret & 0x80)   // 128 special detail
{
   ret = ret & ~0x80;   //we don't need to check the special detail
   SendEvent(ret);   
}
else
   Send_Event(ret); 

Then I changed the events to positive values. And after that delete the magic numbers by #defines
i.e. #define SPECIAL_DETAIL 0x80

Now I'm happy :-)

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

I have gone through this tutorial with the view of putting all the "good stuff" in one document. The aim was to pick out the eyes out of it to keep it on track. Ie. Programming 101 - Bit manipulation, Is anyone interested in doing a proof read. Please PM me.
Lee

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

This was already put into one document: an article in Circuit Cellar magazine, July 2005 issue:

Bit Flipping Tutorial
An Uncomplicated Guide to Controlling MCU Functional
Eric Weddington
http://www.circuitcellar.com/mag...

Unfortunately it's not a free article. However, the "Programming 101" post at the top of this thread is free. The magazine article is essentially the same information (but with grammar/spelling corrections).

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

I am busy learning C, and busy writing my first GCC program, and I read in the GCC FAQ:

Quote:
Why does the compiler compile an 8-bit operation that uses bitwise operators into a 16-bit operation in assembly?
Bitwise operations in Standard C will automatically promote their operands to an int, which is (by default) 16 bits in avr-gcc.

To work around this use typecasts on the operands, including literals, to declare that the values are to be 8 bit operands.

This may be especially important when clearing a bit:

var &= ~mask;  /* wrong way! */

The bitwise "not" operator (~) will also promote the value in mask to an int. To keep it an 8-bit value, typecast before the "not" operator:

var &= (unsigned char)~mask;


This made me cringe!! As all my variables are 1 byte, and I figured my code is probably 4x as long as it needs to be because of this casting to 2 bytes (since AVR is an 8-bit processor). So I added (unsigned char) in front of all my operations. Re-compiled and my code was the exact same size??
.... "Program: 1138 bytes (13.9% Full)"

I see this topic has been posted multiple times, in the forum the general consensus is you just accept it, in the FAQ it says use casting?

Just a noob in this crazy world trying to get some electrons to obey me.

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

In many cases the explicite cast is unnecessary. Before using casts, I would look at the assembly output to see if it is really needed.

Quote:
and I figured my code is probably 4x as long as it needs to be

Why 4 times? Surely the casting only occurs occasionally, not for every single operation.

Regards,
Steve A.

The Board helps those that help themselves.

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

Just to note that a common culprit for "bloated" code is if any of the math library function is used (this can even be */-+) and the code is not set to link against libm.a but links with inferior code in libgcc.a instead. This can "cost" up to about 3K. Another culprit is over-sized versions of printf.a being used.

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

abcminiuser wrote:
A recent thread had a very nice solution which extends on the basic bit-manipulation macros. IIRC it went something along the lines of:

Defines:

#ifndef _AVR035_H_
#define _AVR035_H_

// from AVR035: Efficient C Coding for AVR

#define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define CLEARBIT(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
#define FLIPBIT(ADDRESS,BIT) (ADDRESS ^= (1<<BIT))
#define CHECKBIT(ADDRESS,BIT) (ADDRESS & (1<<BIT))

#define SETBITMASK(x,y) (x |= (y))
#define CLEARBITMASK(x,y) (x &= (~y))
#define FLIPBITMASK(x,y) (x ^= (y))
#define CHECKBITMASK(x,y) (x & (y))

#define VARFROMCOMB(x, y) x
#define BITFROMCOMB(x, y) y

#define C_SETBIT(comb) SETBIT(VARFROMCOMB(comb), BITFROMCOMB(comb))
#define C_CLEARBIT(comb) CLEARBIT(VARFROMCOMB(comb), BITFROMCOMB(comb))
#define C_FLIPBIT(comb) FLIPBIT(VARFROMCOMB(comb), BITFROMCOMB(comb))
#define C_CHECKBIT(comb) CHECKBIT(VARFROMCOMB(comb), BITFROMCOMB(comb))

#endif

Use:

#define Status_LED  PORTA, 3

C_SETBIT(Status_LED);
C_CLEARBIT(Status_LED);

- Dean :twisted:

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

First of all - I would like to wish a safe and happy new year and a prosperous 2010 to everyone.

I have a question about clearing bits. I am sorry if this is a stupid question, but I wanted to confirm that I am understanding the following concept regarding "clearing" a bit.

abcminiuser wrote:
To clear bit 0 in foo requires 2 bit operators:

foo = foo & ~0x01;

This uses the AND operator and the NOT operator. Why do we use the NOT operator? Most programmers find it easier to specify a mask wherein the bit that they are interested in changing, is set. However, this kind of mask can only be used in setting a bit (using the OR operator). To clear a bit, the mask must be inverted and then ANDed with the variable in question. It is up to the reader to do the math to show why this works in clearing the desired bit.


In the case of clearing the 0 bit, instead of "ANDing" the 0 bit against the complement of 0x01, couldn't you just "AND" it against 0x00? Further, if you were clearing the 3rd bit, for example, couldn't you "AND" it against 0b11111011?

Is the answer that you can do this, but it just isn't "good form?" And, as clawson says above:

clawson wrote:
Try to get away from 0b???????? - that's the whole point of bit shifts - you don't need to know or care what the other 7 bits are doing when you access just a single bit.

I am just trying to confirm that there isn't some other, more fundamental reason, why you need to "AND" the bit against the complement?

Thanks.

Russ

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

Quote:

couldn't you just "AND" it against 0x00?

No, as that would clear the whole byte.
Quote:

if you were clearing the 3rd bit, for example, couldn't you "AND" it against 0b11111011?

Absolutely, but, I would consider that less clear than anding it with ~0b00000100, which in tuen is less clear than ANDing it with ~(1<<2).

I guess it is a matter of getting used to the notation. For a beginner it might be clearer with 0b00000100, but most of us think "I want to manipulate bit 2 and once you get used to 1<<2 for that, where the "two" is spelled out so to say, then this technique is less error prone.

Sooner or later you start to use symbolic bit number for a lot of things, eg the different bits in the registers for eg timer and then you start to write things like

((1<<WGM01) | (1<<WGM00))

which says a lot more about what you are doing than eg

0b00011000

Add to this that the "0b" notation is not standard C and the argument in favour of the shift-notation becomes rather strong.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

JohanEkdahl wrote:
Quote:

couldn't you just "AND" it against 0x00?

No, as that would clear the whole byte.

:oops: Yes, I guess you would have to "AND" it against 0b11111110 or 0xFE.

Thanks, for your response. Doing it the way I suggested seems like it would be more work, as you would essentially be calculating the complement in your head.

Russ

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

Just for new users:
When a bit is checked, the "PINA" must be used.
I.E. #define foo_input PINA,0.

In the same manner "PORTA" are used when bits are set or cleared.
I.E. #define foo_output PORTA,1

Correct me someone if I'm wrong

/Sebastian

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

You are correct about the function of the ports is correct. But your defines will work only in assembly, not C which is the focus of this thread.

Regards,
Steve A.

The Board helps those that help themselves.

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

I'm not sure what you mean by this, please elaborate.
I have been coding C for some time and these kind of definitions work perfectly when I.E. C_CLEARBIT expects only one argument, which is the whole idea.

I might be wrong as usual, but it has worked for a few years now.

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

Quote:
I'm not sure what you mean by this, please elaborate.

In what context do you think that PINA,0 will generate legal C syntax? Perhaps it is you who should elaborate as to how C_CLEARBIT is defined.

Regards,
Steve A.

The Board helps those that help themselves.

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

These were defined earlier in the thread:
#define CLEARBIT(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
#define VARFROMCOMB(x, y) x
#define BITFROMCOMB(x, y) y
#define C_CLEARBIT(comb) CLEARBIT(VARFROMCOMB(comb), BITFROMCOMB(comb))

"PORTA" replaces x which replaces ADDRESS while "1"
replaces y which replaces bit, both in the CLEARBIT definition ->

(PORTA &= ~(1<<1))

Bad syntax or good syntax, I dunno, it works though...

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

I guess it is just that I would not use such trash in my programs. I have never seen the point of using 5 separate macros to generate one very simple line of code, particularly when most of those macros are simply designed to get around the limitations of macros. The define of PINA,0 makes sense only in the very specific circumstance of this particular sequence of macros.

Regards,
Steve A.

The Board helps those that help themselves.

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

Sure, I agree, it is not pretty with all these macros.
However, it's nice to only use one simple argument when dealing with almost 100IO's, especially if I have to change pins.
But I don't have to tell you that.

If you have a simpler/prettier way of doing the very same thing please enlighten me.

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

I still don't get your argument. How is:

C_CLEARBIT(PORTA,5);

any clearer than:

PORTA&=~(1<<5);

It's actually MORE typing so it doesn't simplify the text entry for the programmer. Also the second line will be immediately familiar to any C programmer (perhaps once they've read this thread? ;-)) while the former will require even the most seasoned professional to go digging through .h files to unwind the layers of the onion. This does not make for easily readable/maintainable code (which should be the goal of all programmers - especially those who plan to do it professionally).

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

It has been argued here from time to time that the abstraction could be placed slightly higher than the "set/clear bit" level. Instead of letting you application code be full of

C_CLEARBIT(PORTx, n)

you would write a thin hardware abstraction layer, eg

LED_ON()

Now, the details on where the LED is wired up are in one place, and now it makes even less sense to use the C_CLEARBIT() construct, as you only in one place have (sketchy)

inline void LED_ON() { PORTB &= ~(1<<5); }

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Not only is the method that Johan showed more readable, it is far more safe. With the macros you could easily do this:

C_CLEARBIT(foo_input);

and the preprocessor wouldn't bat an eye, even though the clearing of bit 0 in PINA doesn't make any sense at all.

Regards,
Steve A.

The Board helps those that help themselves.

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

what does it mean when the left shift operation is used in statements such as this?

REG |= (1<<BIT)

or

if(REG & (1<<BIT)){}

where BIT is a bit belonging to the register REG.

this use seems to differ from your examples of building a bit mask such as:

(0x01<<2)

which sets bit number 2 of an 8-bit mask.

Thanks

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

Quote:

what does it mean when the left shift operation is used in statements such as this?

Have you actually READ this thread? It gives a total and unequivocal explanation of this - that's the WHOLE POINT of the tutorial (to save having to explain it to the 1 millionth newbie)

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

Quote:

what does it mean when the left shift operation is used in statements such as this?

Code:
REG |= (1<<BIT)


Surprise: The answer to your question is on page 1 of this thread, more specifically in a post by "clawson" made on Jun 28, 2007.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

danni wrote:
Another approach:

I like it to access bit variables like any other variables and then I can write:

if(i == 1)
if(i == 0)
i = 0;
i = 1;

which looks easy readable for me.

This can easy be done by casting a portbit as a member of a bit field.

On the attachment there is the definition of the macro SBIT.

Following an example code:

#include 
#include "sbit.h"


#define KEY0            SBIT( PINB, 0 )
#define KEY0_PULLUP     SBIT( PORTB, 0 )

#define LED0            SBIT( PORTB, 1 )
#define LED0_DDR        SBIT( DDRB, 1 )


int main( void )
{
  LED0_DDR = 1;         // output
  KEY0_PULLUP = 1;      // pull up on

  for(;;){

    if( KEY0 == 0 )     // if key pressed (low)
      LED0 = 0;         // LED on (low)
    else
      LED0 = 1;         // LED off (high)
  }
}

Naturally this macro can also be used for internal flag variables, not only for IO registers.

Peter

Hi Everybody,

I'm just getting started with micro-controllers and have pieced together a little learning project for myself from various tutorials to match what I have available to work with, namely VMLAB and WinAVR. I have found some interesting results using this:

R0 VDD RESET 4.7K
R1 N001 PB1 300
R2 N002 PB3 300
D1 VDD N001
D2 VDD N002
K1 VSS PB0
K2 VSS PB2 MONOSTABLE(30u)
#include 

#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)

#define KEY1            SBIT( PINB, 0 )
#define KEY1_PRESET     SBIT( PORTB, 0 )

#define LED1            SBIT( PORTB, 1 )
#define LED1_DDR        SBIT( DDRB, 1 )

#define KEY2				SBIT( PINB, 2 )
#define KEY2_PRESET		SBIT( PORTB, 2 )

#define LED2				SBIT( PORTB, 3 )
#define LED2_DDR			SBIT( DDRB, 3 )


// ***********************************************************
// Main program
//

int main(void) {

	LED1_DDR = 1;          // output
  	KEY1_PRESET = 1;       // high
  	
  	LED2_DDR = 1;          // output
  	KEY2_PRESET = 1;       // high

  	for(;;){

    	if( KEY1 )         // if ( key == 1 ) (high)
      	LED1 = 1;       // LED off (high)
    	else
      	LED1 = 0;       // LED on (low)
      	
     	if( KEY2 == 0 )	{
     		if ( LED2 )
     			LED2 = 0;
     		else
     			LED2 = 1;
     	}
    	      	 	
  	}

}

I dropped sbit.h into the WinAVR header folder. First thing I noticed is that VMLAB complains about accessing reserved memory the first time a write to DDRB is made.

As you can see I extended the example to include a toggled LED. This worked out less well than I thought. I started with a latched key, then found the toggle action was undependable, so I migrated to a monostable key. That helped, although only after I found a pulse width that worked well. I presume reliable toggling take some code for debouncing etc.

Lastly I found the "^= 0x01" technique fails to work for toggling bit field variables, so I had to do it the long way.

Fred

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

Why are you putting "#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)" in your code? Isn't it already defined in sbit.h? Also I noticed that the download link is SBIT.H, not sbit.h. Did you change the name of that file to lowercase?

Regards,
Steve A.

The Board helps those that help themselves.

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

I had all the code in the c section first, the extraneous sbit define is remnant. I changed the case of the include statement. Under wine that seems to have worked. I changed it back.

It's been years since I did any coding. It's almost like beginning all over again. :)

For some reason the stimulation starts up with LED2 on. From the scope it looks like the state test is made before the voltage at PB2 is pulled high, so the toggle is triggered without a key press. After it gets running it works as expected.

I wonder if that is just a simulator thing.

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

Quote:

I wonder if that is just a simulator thing.

No sh*t?

(trust simulators about as far as you can comfortably spit them)

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

Hi, I'm trying to build a 16-bit word made up from three integer variables; address, control (both in range 0x00-0x03), and data (0x00-0xFF).

The most significant four bits of the word are irrelevant, the next two hold the address, the next two the control information, and the final 8 hold the data.

Will something like this allow me to contruct the word from these variables?

word = (address<<10) | (control<<8) | data

Pages