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

Go To Last Post
237 posts / 0 new

Pages

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

Have you tried it out? (For this kind of stuff the simulator in AVR Studio is excellent.)

But yes, that looks reasonable.

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

Or you could do this:

typefef struct
{
    unsigned int data :8;
    unsigned int control :2;
    unsigned int address :2;
} whateverYouWantToCallIt;

or:

typefef struct
{
    unsigned int :4; //4 bits of fiiler
    unsigned int control :2;
    unsigned int address :2;
    unsigned int data :8;
 } whateverYouWantToCallIt;

depending on endianness.

whateverYouWantToCallIt word;
...
word.address = address;
word.control = control;
word.data = data;

Regards,
Steve A.

The Board helps those that help themselves.

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

This one doesnot make sense to me,

To set bit 0 in foo and then store the result back into foo:
Code:

foo = foo | 0x01; 

bit OR"|" with 0x01, we will set bit 1 in foo,,
why is it to set bit 0?
I am a newbie, forgive me if i am wrong. please explain it to me.

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

[Removed as I totally mis-understood the post above. Snigelen nailed the correct interpretation and answer below.]

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]

Last Edited: Wed. Jul 21, 2010 - 09:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

qli029 wrote:
This one doesnot make sense to me,

To set bit 0 in foo and then store the result back into foo:
Code:

foo = foo | 0x01; 

bit OR"|" with 0x01, we will set bit 1 in foo,,
why is it to set bit 0?


This is because bits in a byte are usually numbered from 0 to 7. So the first bit is number 0.

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

Just to add a little more to that:

bit     shift     mask

0       (1<<0) =  0x01
1       (1<<1) =  0x02
2       (1<<2) =  0x04
3       (1<<3) =  0x08
4       (1<<4) =  0x10
5       (1<<5) =  0x20
6       (1<<6) =  0x40
7       (1<<7) =  0x80

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

That was useful , Thanks .

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

Thanks!, i was looking for this information.

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

how should i access the registers R0-R32? using c programming.
Just give me an example..

Thank you

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

Quote:

how should i access the registers R0-R32? using c programming.
Just give me an example..

You don't - the point of C is that you don't need to directly access the CPU temporary registers. They are handled by the compiler in order to implement your code.

The I/O and peripheral registers (like the timer control registers) are manipulated by you, but not the CPU scratch registers.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

To illustrate what Dean has said consider this program:

#include 
#include 

int main(void)
{
	uint8_t mask = 0x55;

	DDRB = 0xFF;
    while(1)
    {
         PORTB ^= mask;
		 if (PIND & 1<<PD0) {
			 mask ^= 0xFF;
		 }
    }
}

when built by the compiler it generates:

00000080 
: int main(void) { uint8_t mask = 0x55; DDRB = 0xFF; 80: 8f ef ldi r24, 0xFF ; 255 82: 84 b9 out 0x04, r24 ; 4 #include #include int main(void) { uint8_t mask = 0x55; 84: 85 e5 ldi r24, 0x55 ; 85 DDRB = 0xFF; while(1) { PORTB ^= mask; 86: 95 b1 in r25, 0x05 ; 5 88: 98 27 eor r25, r24 8a: 95 b9 out 0x05, r25 ; 5 if (PIND & 1<<PD0) { 8c: 48 9b sbis 0x09, 0 ; 9 8e: fb cf rjmp .-10 ; 0x86 mask ^= 0xFF; 90: 80 95 com r24 92: f9 cf rjmp .-14 ; 0x86

In this code the compiler initially uses R24 to output 0xFF to DDRB. It then reuses R24 as 'mask' and initialises it to be 0x55. It reads PORTB into R25 then exclusive-or's this with 'mask' (R24). It then checks bit 0 of PIND and if that is set it complements the contents of 'mask' (so 0x55 switches to 0xAA).

You, the programmer, need never be aware which registers the compiler has chosen to put values or variables into.

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

What this program does not work help me

//***********************************************************
// Project:  Analog Comparator example	
// Author: winavr.scienceprog.com	
// Module description: Analog comparator example with positive comparator
// input connected to Vref 1.23V. When compared voltage exceed 1.23V LED lighst on.
// When voltage drops bellow - LED turns OFF. Comparator inputis connected to ADC3 pin.
// ***********************************************************
#include        
#include   
#define AINpin PA3
#define LED PD0
void Init(){
	DDRA&=~(1<<AINpin);//as input
	PORTA&=~(1<<AINpin);//no Pull-up
	DDRD|=(1<<LED); //Led pin as output
	PORTD|=(1<<LED);//Initally LED is OFF
	SFIOR|=(1<<ACME);//enable multiplexer
	ADCSRA&=~(1<<ADEN);//make sure ADC is OFF
	ADMUX|=(0<<MUX2)|(1<<MUX1)|(1<<MUX0); //select ADC3 as negative AIN
	ACSR|=
	(0<<ACD)|	//Comparator ON
	(1<<ACBG)|	//Connect 1.23V reference to AIN0
	(1<<ACIE)|	//Comparator Interrupt enable
	(0<<ACIC)|	//input capture disabled
	(0<<ACIS1)| //set interrupt on output toggle
	(0<<ACIS0);
	sei();//enable global interrupts
}
// Interrupt handler for ANA_COMP_vect
//
ISR(ANA_COMP_vect) {
if bit_is_clear(ACSR, ACO)
	PORTD&=~(1<<LED);//LED is ON
	else 	PORTD|=(1<<LED);//LED is OFF
}
// ***********************************************************
// Main program
//
int main(void) {
     Init();
	 while(1) {     // Infinite loop; interrupts do the rest
   }
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ghost800,

How does your post extend the discussion of the article in the first post of this thread?

Moderator.

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

Cliff!

When those post totally unrelated to the thread occur I think we should tossin an explanation of the difference between the "new topic" and the "new reply" buttons. I have a feeling that the distinction is not clear for many newcomers, or thet they even do not see the buttons and think that the only way to post on the forum is the "Quick Reply" area.

ghost800!

If you want to start a discussion on a new topic, use the "new topic" button at the top or bottom thread pages and forum listings here at AVRfreaks. Each discussion should commence in a separate "thread" (topic) or things become very confused and out of order. When creating a new thread please take the time to think out a really smart title (subject) so that it reflects the content of your post (extremely bad subjects are things like "Help!", "Why does my code not work" etc).

Hope this helps!

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

can the macros be used with ports?
for eg

int totalcomplete()
{
int retval;
if ((bit_get(PORTC, BIT(1))) && (bit_get(PORTC, BIT(0)))==0)
{
retval = 1;
}
else retval = 0;

return retval;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm curious. What would make you want to type:

if ((bit_get(PORTC, BIT(1))) && (bit_get(PORTC, BIT(0)))==0)
{

when you could have typed:

if ((PORTC & 3) == 0)
{

Do the tortuous macros really help?

(BTW do you mean to read PORTC or PINC?)

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

thanks! ya my mistake it should have been PINC .sorry but am new to programming an ya thanks i guess i could use

if ((PORTC & 3) == 0)
{ 

but what i meant was does this macro

#define bit_get(p,m) ((p) & (m)) 

work when a pin is specified in place of variable p. Or do we have to use macro such as

#define READ(port,pin) ((PIN ## port & (1<<pin)) 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes and my question is why obfuscate code with layers of macros when the plain C to achieve the same would actually be simpler. There seems to be a recent trend to try and wrap code in N levels of macro at the drop of a hat. As someone who has to read/maintain other programmers code I find that it very rarely aids the mainatainability/readability of the code but instead just makes it more difficult to follow. Perhaps you can explain what how your bit_get() macro makes the code easier to follow. ALL programmers know what an AND operation is!

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

thanks, and well as u said it will be simpler to use plain c but the reason is that, i am working on a project and the panel where i have to present it to has a few members who have well little or no knowledge of programming so i am hoping the macros will help in making them understand more easily.

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

Quote:

so i am hoping the macros will help in making them understand more easily.

Eh? You have the option of teaching them your very specific macro or the generic C & operator. With the latter they can write 1000's of programs, with the former they are tied to some very specific code for a single situation. Why not teach them how AND works?

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

well cos i am a student myself. and i am showing a presentation to justify the funding of my project, and the people on the panel will be staff of various departments, some of who may not know programming .that's why am using the macros to give a generalized presentation. I have even broken down my whole code into functions with general names for hopeful easier understanding.

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

Quote:
well cos i am a student myself.
Yet you obviously don't know yourself how the macros work. So if one of them happens to ask how the macros work, you'll have a big problem, won't you.

Regards,
Steve A.

The Board helps those that help themselves.

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

i do have some idea on the working of macros now,thanks to the tutorial. And i do know basic programming so i know what happens when u use a particular macro. I am already done with my coding using c. Just needed the macros to hopefully make it easier to explain.

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

Thanks for the great Tutorial, it's awsome!

I just got a really crazy idea and Im not sure if it can actually be impemented.

To create a byte object in which every bit corresponds to a certain Pin on a port?

I'm not sure if Im using the right words here but an example should help:

create some object, maybe a structure (?) that looks like this:
object {Bit0 = Portb bit 3
Bit1 = Portc bit 1
...
Bit7 = Portb bit 0
}

so when you store a value into this object it will assign the respective value to those pins
for example,
object = 0xFF
would set Portb bit 3 high, Portc bit 1 high etc.

just wondering, maybe by doing a complicated macro or somethig?

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

Quote:

To create a byte object in which every bit corresponds to a certain Pin on a port?

Search in this very forum for "bitfield". The bottom line is that struct members can be defined to be 1 bit long and so you can conglomerate 8 on a single byte address. Anyway read the tutorial.

EDIT: I meant this thread:

https://www.avrfreaks.net/index.p...

Quote:
Just needed the macros to hopefully make it easier to explain.

First rule of programming: simplest is best.

"simplest" rarely involves macros.

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

I've read this whole thread, and one topic that's not mentioned regarding port bit twiddling (with or without macros) is interrupts.

Is it considered good practice to disable interrupts when modifying a port pin? Especially if you're using some kind of bit_set() or bit_clear() macro?

The reason is that if the bit being set/cleared is not a constant expression at compile time, then the compiler will have to generate several instructions to read the current port value into a register, manipulate the value, and write it back. If an interrupt triggers after the port value is read, and that interrupt modifies another pin on the same port, when the main program resumes it will write back the stale value for that pin. This issue was previously a bug in the Arduino digitalWrite() implementation: http://code.google.com/p/arduino...

I don't see anyone disabling interrupts in their code-- why not? Is there a reason I've overlooked why it's not necessary?

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

Quote:

the compiler will have to generate several instructions to read the current port value into a register, manipulate the value, and write it back.

The compiler will not have to generate several instructions, if only one bit is manipulated. AVRs have single machine instructions to manipulate one bit. E.g. activate the optimizer of avr-gcc and see what

PORTB |= 1;

generates.

If several bits are modified, then a read-modify-write sequence will be generated, and you will need to turn off interrupts if the port that is manipulated is shared with ISR code. The subject has been discussed in length here at 'freaks. The search words you need are e.g. "re modify write", "atomic" etc...

Ther are also tutorials on interrupt handling in general IIRC.

The avr-gcc support library avrlibc has stuff contributed by Dean Camera ('abcminiuser') that makes atomic sequences, saving and restoring state etc easy to code.

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

Quote:

The compiler will not have to generate several instructions, if only one bit is manipulated.

It will generate several instructions for RMW if the extended IO space or SRAM is used, which can indeed lead to atomicity issues. Note that the XMEGA and AVR32s have a larger register address space with dedicated SET and CLEAR registers that allow for single-cycle RMW sequences.

On the older AVRs, you'll need to protect against interrupts if you're writing anything but a single bit to the regular IO space.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Thanks, that makes sense, and I'll search for the atomic write threads. And to clarify, the situation I was asking about is when the bit being set/cleared is not a constant expression at compile time. I've looked at the disassembly for contant expressions like PORTB |= 1 and it is a single sbi machine instruction, as JohanEkdahl said.

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

Quote:

And to clarify, the situation I was asking about is when the bit being set/cleared is not a constant expression at compile time.

Oh, I missed that vital part of the question. Yes, in that case you are at risk even with single bit operations.

Sorry for any confusion.

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

I have added some predefined names to my "sbit.h".

Then you can use "PORT_cn", "DDR_cn", "PIN_cn" direct on the code (c = A..L, n = 0..7).
E.g.:

#include "sbit.h"


int main( void )
{
  DDR_B3 = 1;                   // output
  DDR_B7 = 1;

  for(;;){
    PORT_B3 = PIN_D0;
    PORT_B7 = !PIN_D0;
  }
}

Peter

P.S.:
The original article:
https://www.avrfreaks.net/index.p...

Attachment(s): 

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

Hello, this is a very good tutorial and thank you but I was wondering if some one could explain something.

When I learned this stuff in school a few years back we only ever masked like you did in the 1st half (ie. foo &= 0x01). Why and when is it necessary to use these shift masks? I was taught using motorola micro's and I was wondering if it was some architecture thing? But as far as I can see they both do the same thing.

Thanks in advance

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

Quote:

Why and when is it necessary to use these shift masks? I was taught using motorola micro's and I was wondering if it was some architecture thing?

Nothing says you HAVE to use bitnumbers with shifts. Some would argue that if you are only setting bit 5 of a DDR register to be an output that:

DDRB |= 0x20;

is almost as readable as:

DDRB |= (1<<5);

(thought the former may make the engineer count on his fingers to remember that 0x20 is bit 5! ;-))

However where this bit shifting comes into play is to make SFR bit usage more self-documenting. For example in many AVRs bit 5 of the UCSRB register is the bit to enable the UART data register empty interrupt. Now if you read code that says:

UCSRB |= 0x20;

or

UCSRB |= (1<<UDRIE);

many engineers (at least those with a passing knowledge of the AVR) will instantly recognise that the second of those is enabling the UDRE interrupt. However it would require a VERY fastidious reader to know that 0x20 (or even (1<<5)) happens to be the UDRIE bit in that register.

Now one might then ask why do I have to use 1<<, if Atmel had written the XML file that is used for Assembler and C header file generation such that:

#define UDRIE 0x20

rather than

#define UDRIE 5

then the usage in C would just be:

UCSRB |= UDRIE;

but the reason they defined the bit names as 0..7 is so that the number can be used with the AVR SBI and CBI opcodes (assuming UCSRB is at the right location). This introduces the minor inconvenience of having to use (1<<UDRIE) to convert 5 into 0x20. In at least one C compiler there is a macro defined as:

#define _BV(x) (1<<x)

so that at least:

UCSRB |= _BV(UDRIE);

can be used which maybe looks a little less "complex" than (1<<UDRIE). However *all* C programmers will recognise the (1<<UDRIE) version but not all are going to know what _BV() achieves without digging into header files - which kind of destroys the readability "gain" in using it.

Remember that at the end of the day all C (and Asm) code should be written with the "next reader" in mind - which could either be the poor sap who has to fix your code 3 years after you left the company or it could simply be you in 9 months when you've forgotten that setting 0x20 in UCSRB is setting the UDRIE bit! (1<<UDRIE) tells you which bit is being set without looking it up (assuming you can at least remember the purpose of "UDRIE")

Cliff

Last Edited: Tue. Jun 14, 2011 - 02:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Why and when is it necessary to use these shift masks? [...] But as far as I can see they both do the same thing.

They do. It is just about clarity of code. And it is opinous.

Which is clearer? This

something &= (1<<4) | (1<<3);

or this

something &= 0x18;

?

In the next step, e.g. when dealing with bits in a special purpose register (like a timer control register) it helps a lot to use the symbolic bit numbers rather than some magic numerical constants). Since the bit numbers are, uhmmm..., bit numbers rather than bit masks we need to construct the masks from the numbers. To do this, the shift operator is used.

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

Cheers, Thanks both of you that makes a lot of sense. Especially since I am that sap that is fixing the code 3 years later :)

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

Thanks for your information.

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

bloody-orc wrote:
That means, that nr 1 is shifted left as many times as it is needed to reach bit named CS10. Where does the compiler know that CS10 is that? well you give him the AVR's name and it's smart enough to know such things thanks to some smart programmers on the GCC side ;)

What is the difference between
TCCR1B |= (1 << CS10);
and
TCCR1B = (1 << CS10);

Is OR ('|') really needed there or both will work the same.

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

The first only sets one bit and leaves the other 7 bits in the register untouched. The second sets all 8 bits - the other 7 are set to 0.

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

Quote:

Is OR ('|') really needed there

That depends on the circumstances.
Quote:

or both will work the same

Definitively not.

TCCR1B |= (1 << CS10);

is a shorthand for the equivalent

TCCR1B = TCCR1B | (1 << CS10);

so all bits that was set before this operation will still be set.

OTOH, if you do

TCCR1B = (1 << CS10);

then only the CS10 bit will be set, and all other will be cleared.

I seriously suspect that this has been covered earlier in this thread, so you might have something to gain from browsing through the complete 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

In the bit manipulation macros of the orignal post:

#define bit_get(p,m) ((p) & (m))
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))

... etc., should the & in the first one be &= ? Would it make any difference?

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

No,

But the fact that it's not obvious kind of proves how pointless these kind of macros are in aiding readability. Think about:

bit_set(foo, 0x20);
bit_clear(foo, 0x08);
if (bit_set(foo,0x80)) {

which really says (without all the parenthesis):

foo |= 0x20;
foo &= ~0x08;
if (foo & 0x80) {

As you can see you don't want an '=' in the last one as it's used in a different context to the other two. The confusion here is that then macro names are so similar you might think they'd all be used in the same context.

Stay clear of macros - you know it makes sense!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
if (bit_set(foo,0x80)) 

You mean "bit_get" don't you?

Regards,
Steve A.

The Board helps those that help themselves.

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

OK, I see it now. It was just my poor reading. Or poor reading glasses.

But I do like these macros. I agree I should make sure I understand how they work, but think they can prevent careless errors if I understand their proper use.

Nick

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

In regard to a problem I just had could some one explain to me the reason this doesn't work properly (it affects all the bits)

PORTD &= (0<<D_I);

And this one does work properly?

PORTD &= ~(1<<D_I);
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

They would both work just fine as written.

Did you read the tutorial?

What do you mean by properly?

Smiley

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

Quote:
They would both work just fine as written.
No they wouldn't. The first clears all bits of PORTD.
Quote:
I just had could some one explain to me the reason this doesn't work properly
Break it down: 0<<D_I means that you are shifting the number 0 by some number of bits (whatever number D_I is). Shifting 0 by anything will always result in 0. You then AND that with PORTD. ANDing anything with 0 will always result in 0.
Quote:
And this one does work properly?
Again, break it down. 1<<D_I will shift the number 1 by D_I bits. If D_I is 2, that makes the result 4 (so in binary you went from 0b00000001 to 0b00000100). You then invert that (the ~), which in binary gives you 0b11111011. You then AND that with PORTD.

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:

They would both work just fine as written.

ಠ_ಠ

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Koshchi wrote:
Quote:
They would both work just fine as written.
No they wouldn't. The first clears all bits of PORTD.
Which is a perfectly valid use for that notation so I repeat: 'They would both work just fine as written'. I'd never use the first notation, but who am I to say someone shouldn't use a valid C notation? In fact I've seen (0<<XXX) used in the Atmel Butterfly code, so somebody somewhere must think is okay to do this.

Now if you want to make assumptions about the intent which is unstated, then maybe they don't do what the poster wants them to do, but is that for us to decide or should he tell us what he is trying to do?

Smiley

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

Quote:
In fact I've seen (0<<XXX) used in the Atmel Butterfly code, so somebody somewhere must think is okay to do this.

Perhaps, but most likely not in a statement lacking ~ and using &= . Discussing if (0<<XXX) is meaningful or clarifying must be done in the context of the complete statement.

E.g. you might very well do

someRegister = (1<<someBitNumber) | (0<<anotherBitNumber);

to make it clear that you relly want anotherBit to be clear. Not that the code actually (0<<anotherBitNumber) has the exact effect to actually clears that bit, but you are doing some documentation of intent in the code.

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

Quote:

In fact I've seen (0<<XXX) used in the Atmel Butterfly code, so somebody somewhere must think is okay to do this.

No, no , no. The only use of a 0<< is when you want to document the fact that something is deliberately not being set. maybe something like:

TCCRB = (1 << CS02) | (0 << CS01) | (1 << CS00);

Too often we see threads here where the user has grasped the fact that to set a bit they use:

SFR |= (1 << bit);

but then see variants of:

SFR |= (0 << bit);
SFR &= (0 << bit);
SFR &= ~(0 << bit);

where they believe that using 0 in the mask is the way to switch things off. As we all know, it isn't.

This notion should be stomped on from a great height before it confuses more beginners (especially in this thread we all point them towards to learn this stuff!).

The only use of (0 << foo) is to document that foo is not being used.

Pages