Set bit in C

Last post
76 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

Using ICCAVR and ATMEGA 323
I would like to know how can I make the setbit and clearbit function in C.
The same as SBR and CBR in assembly language

It is for using in the output ports.

thanks
Nico

admin's test signature
 

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

Hi,

You can either just make a macro that uses ASM code, or just do this:

PORTB = PORTB | (1 << 4);

this would set PORTB's bit 4. It OR's the current contents of the PORTB output register with 1 shifted left 4 bits.

I'm not sure, but I assume that the C compiler will take that an optimize it so that it uses the SBR and CBR when possible so it reduces to one or two lines of ASM.

-Colin

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

Hello Nicokiller,

I use Codevision AVR-C-Compiler (simple the best, kind regards to Pavel Haiduc). There I can write

PORTB.2 = 0;

to clear bit 0 of port B. You can also write:

dummybit = PORTC.3;

This assigns the pin level of port C, bit 3 to the variable dummybit.

Try it, I think it works on the IAR compiler too

Many greetings

Rainer

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

Hello eltrevisor.

Yes, the PORTB.2=0 are good, but not ANSI-C Standard

So set the bits with ANSI-C are better.

It's more easys if you are using different compilers.

Greetings
Richard Dahlström

admin's test signature
 

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

The PRORTB.2 is treating the PORTB as a structure rather than an unsigned char which it realy is so can lead you, as Richard has said, into a bad method.

I have fallen foul of the 'special' codes that come with some compilers and would not wish to do it again.
Mike

admin's test signature
 

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

Hi,

Try defining the bits first, it makes working with them easier.

#define BIT0 0b00000001;
#define BIT1 0b00000010;
#define BIT2 0b00000100; etc....

Then to set bit 2 you can say: PORTB = PORTB (or'ed with) 0b00000100
in ICCAVR you would write: PORTB |= BIT2;

To clear bit2 you can say: PORTB = PORTB (and with) 0b11111011
in ICC you would write: PORTB &= ~BIT2; ( The tild symbol means invert)

Hope I'm right.
Graeme

admin's test signature
 

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

Ok thanks everybody for you interesting answers.
It works now :)

Nicolas

admin's test signature
 

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

Again in ansi c there is no bit define as there is in an assembler. So using 0b00000001 can not be ported between compilers.

The actual bit locations are normally defined in the header
#define BIT0 0
#define BIT1 1
#define BIT2 2

you then have
PORTB |= (1<<BIT2);
or
PORTB &= ~(1<<BIT2);
Mike

admin's test signature
 

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

I use macros to simplify bit setting and I also use macros to test bits

#define BIT(x) (1 >(y)) & 1)

For example, if I want to set bit 2 in portd I would simply include the followin C command:
SETBIT(PORTD,2);

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

Hello mike

if you handle all bits in this way ypu can use every ANSI C compiler

#define a 01
#define b 02
#define c 04

d | = a | b;

or

d &= ~(a|b)

greetings Richard

admin's test signature
 

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

I agree with Richard, but be wary when extending it: :))

#define d 08

wouldn't work--ANSI C constants beginning with 0 are octal.

[I've been bitten by that more than once.]

Lee

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

Programming 101

To really understand what's going, it's best to learn C languages bit operators and about truth tables.
| bit OR
& bit AND
~ bit NOT
^ bit EXLUSIVE OR (XOR)
> bit RIGHT SHIFT

These operators work on bits and not logical values. Take two 8 bit bytes, combine with any of these operators, and you will get another 8 bit byte according to the operator's function. These operators work on the individual bits inside the byte.

A truth Ttble helps to explain each operation. In a truth table, a 1 bit stands for true, and a 0 stands for false.

The OR operation truth table:
0 OR 0 = 0
0 OR 1 = 1
1 OR 0 = 1
1 OR 1 = 1

The AND operation truth table:
0 AND 0 = 0
0 AND 1 = 0
1 AND 0 = 0
1 AND 1 = 1

The XOR operation truth table:
0 XOR 0 = 0
0 XOR 1 = 1
1 XOR 0 = 1
1 XOR 1 = 0

The NOT operator inverts the sense of the bit, so a 1 becomes a 0, and a 0 becomes a 1.

So let's say I have a byte foo that is initialized to 0:
unsigned char foo = 0;

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

foo = foo | 0x01;

The OR operation is used between the variable that we want to change and a constant which is called a BIT MASK or simply the MASK. The mask is used to identify the bit that we want changed.

Remember that we write the constants in hexadecimal because it's shorter than writing it in binary. It is assumed that the reader knows how to convert back and forth between hex and binary. ;-)

Usually, though the statement is made shorter in real programming practice to take advantage of C's compound assignment:

foo |= 0x01;

This is equivalent to the statement above.

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.

Again, the statement is made shorter with a compound assignment:

foo &= ~0x01;

To see if a bit is set or clear just requires the AND operator, but with no assignment. To see if bit 7 is set in the variable foo:

if(foo & 0x80)
{
}

The condition will be zero if the bit is clear, and the condition will be non-zero if the bit is set. NOTE! The condition will be NON-ZERO when the bit is set. But the condition will not NECESSARILY BE ONE. It is left to the reader to calculate the value of the condition to understand why this is the case.

There is another useful tool that is not often seen, and that is when you want to flip a bit, but you don't know and you don't care what state the bit is currently in. Then you would use the XOR operator:

foo = foo ^ 0x01;

Or the shorter statement:

foo ^= 0x01;

A lot of times the bit mask is built up dynamically in other statements and stored in a variable to be used in the assignment statement:

foo |= bar;

Sometimes, a programmer wants to specify the bit NUMBER that they want to change and not the bit MASK. The bit number always starts at 0 and increases by 1 for each bit. An 8 bit byte has bit numbers 0-7 inclusive. The way to build a bit mask with only a bit number is to LEFT SHIFT a bit by the bit number. To build a bit mask that has bit number 2 set:

(0x01 << 2)

To build a bit mask that has bit number 7 set:

(0x01 << 7)

To build a bit mask that has bit number 0 set:

(0x01 << 0)

Which ends up shifting the constant 0 bytes to the left, leaving it at 0x01.

MACROS

Because there are a number of programmers who don't seem to have a familiarity with bit flipping (because they weren't taught it at school, or they don't need to know it because of working on PCs), most programmers usually write macros for all of these operations. Also, it provides a fast way of understanding what is happening when reading the code, or it provides additional functionality.

Below is a set of macros that works with ANSI C to do bit operations:

#define bit_get(p,m) ((p) & (m))
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m) ((p) ^= (m))
#define bit_write(c,p,m) (c ? bit_set(p,m) : bit_clear(p,m))
#define BIT(x) (0x01 << (x))
#define LONGBIT(x) ((unsigned long)0x00000001 << (x))

To set a bit:
bit_set(foo, 0x01);

To set bit number 5:
bit_set(foo, BIT(5));

To clear bit number 6 with a bit mask:
bit_clear(foo, 0x40);

To flip bit number 0:
bit_flip(foo, BIT(0));

To check bit number 3:
if(bit_get(foo, BIT(3)))
{
}

To set or clear a bit based on bit number 4:
if(bit_get(foo, BIT(4)))
{
bit_set(bar, BIT(0));
}
else
{
bit_clear(bar, BIT(0));
}

To do it with a macro:
bit_write(bit_get(foo, BIT(4)), bar, BIT(0));

If you are using an unsigned long (32 bit) variable foo, and have to change a bit, use the macro LONGBIT which creates un unsigned long mask. Otherwise, using the BIT() macro, the compiler will truncate the value to 16-bits.

Any questions?

Eric

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

In addition

To do multiple bits at a time requires the use of a mask. To set bits 2 and 3 at the same time:

foo |= 0x0C;

or with the macros:

bit_set(foo, 0x0C);

Now, there are a number of people who can't quickly figure out that 0x0C corresponds to having only bits 2 and 3 set and the other bits clear. So using the BIT() macro, you can create the equivalent mask. Note that the BIT macro only works on a single bit, so you write a compound statement to create the mask:

bit_set(foo, BIT(2) | BIT(3));

This can be used with the other macros as well:

bit_clear(foo, BIT(2) | BIT(3));
bit_flip(foo, BIT(2) | BIT(3));
if(bit_get(foo, BIT(2) | BIT(3)))
{
}

And, it doesn't matter what order they are specified:

bit_set(foo, BIT(7) | BIT(0) | BIT(3));

And it shouldn't matter if it is a variable or a memory-mapped register:

bit_set(DDRB, BIT(0));
bit_set(PORTB, BIT(0));

Caveat: As long as the port definitions are defined correctly, which with all of the compilers that I know of that are discussed here, it is.

Eric

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

thanx eric for the lession.

I'm going to use som of those macros if it's ok with you

greetings Richard

admin's test signature
 

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

Permission granted. Anybody can use those or create their own.

Eric

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

Eric
A question about
#define LONGBIT(x) ((unsigned long)0x00000001 << (x))

Would 1 have done instead of 0x00000001
Regards
Mike

Keep it simple it will not bite as hard

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

ASM rules... zero overhead, except you must see through it, takes more time than C thats true... well ASM still rules ? hhuhuhhuh cool Butthead

admin's test signature
 

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

Mike--

Not necessarily. Depending on items to the left, the phase of the Moon, and current offerings to the gods of C, "1" might be treated as an "int" constant, which is often (usually?) 16 bits on microprocessors.

A constant can be "tagged" as long by "1L".

Sometimes even the casting can fool you in complex expressions. I tend to use lots of parentheses when casting so I know next month what I intended to cast.

Lee

admin's test signature
 

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

Hi,

I like the idea of these Macros, but why does this not work ??

if (bit_get(PORTA, BIT(7)))
{
bit_set(PORTB, BIT(0));
}
else
{
bit_clear(PORTB, BIT(0));
}

This works fine:

if ((PINA & (1 << 7)) != 0)
{
bit_set(PORTB, BIT(0));
}
else
{
bit_clear(PORTB, BIT(0));
}

Hope to get some help.........

Jakob

admin's test signature
 

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

Shouldn't you be doing a bit_get() on PINA instead of PORTA?

Lee

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

May Thanks to Eric for that explanation on using macros for the bits. Makes code reading much more eazier. But I wonder if it possible to make it more eazier....

I have a pieve of software running on several board releases. So there are little differences in the port an bit definitions for one function pin.

Example: I hava an ON/OFF button called TEIN in my software. It is defined as

#define TEIN_P PORTA
#define TEIN_B 3

main()
{
  if (GETBIT(TEIN_P,TEIN_B)
  {
    do something
  }
}

Now there is the question: How could it be made more simple?
I tried

#define TEIN  PORTA,3

....
if GETBIT(TEIN)
....

Compiler Error

Is there a way to shorten that bit definitions to one line per bit?
Is it possible to #define an array of constants that should be passed to another macro?

Where is a brief documentation on that mega powerfull compiler that could be read and understood without going off business for a year?

Thanks in advance and best regards to all that people in here

Ulrich

best regards

Ulrich
-------------------------->>>
connecting to car mains means connecting to the power supply from hell....

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

Remember that on AVRs you [usually] want to read or do a getbit() on PINA, not PORTA.

The CodeVision compiler already uses direct syntax such as:

if (PINA.3)
  {
  }

Eric can clean up on this, but I believe he will say something that getbit() macro and its friends have been deprecated in favor of a direct syntax.

If this is indeed a gcc question, the experts on that Forum can probably give better answers.

Lee

You can put lipstick on a pig, but it is still a pig.

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

Sheesh, why dig up an old thread?......

Ok first off, for the AVR GCC compiler (and avr-libc C library), the macros: outp, inp, outb, inb, are all deprecated. These were holdovers from a Linux-type implementation that had no bearing on this type of embedded environment.

That means that "direct access" or "direct assignment", or whatever you want to call it, is the preferred method for assigning values to registers. This method is the most common method used to assign values to memory-mapped registers in embedded compilers, commercial or otherwise.

The Codevision compiler has another way of assigning bits in a register that is not Standard C syntax. But you can still use Standard C syntax with it too, and that is by using the bit-wise operators and compound assignment operators to do bit manipulation. See above in my "Programming 101" post.

Therefore if you write your C code in Standard C syntax, it becomes portable across multiple compilers. Which may, or may not, be something you care about.

Those additional macros that I mentioned in that "Programming 101" post, just make the Standard C syntax easier to read, especially for you newbies that can't tell at a glance what

PORTD ^= 0x5A;

is doing. :wink:

Now, you should look at your C Preprocessor manual for why it is difficult to "shorten" those macros to something like

#define TEIN  PORTA,3 

If you're using the GCC toolset, look at the CPP manual in the GCC docs.

There is also another reason why you don't want to shorten them, and that is so you can simultaneously operate on multiple, non-contiguous bits. Think about that for a moment. Someday you may want to do something like:

#define BIT(x)   (1 << (x))
#define bit_flip(v, m)   ((v) ^= (m))

bit_flip(PORTD, (BIT(4) | BIT(3) | BIT(6) | BIT(1)));

And you can't do that in Codevision's non-standard syntax.

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

There is a big difference between "shortening" your C code and reducing the resulting assembler instructions. One does not necessarily follow the other, and, in fact, sometimes the opposite occurs.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA There are some answers that have no questions.

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

Sorry, EW, I thought it was getbit() that was somewhat passe.

I can't argue over the portability issue. I suspect, though, that there WILL be differences between architectures and even AVR compilers on exactly what is a sfrb/sfrw. In thinking, all I/O instructions would need to be examined within a platform-dependent layer--even using the portable syntax, the bits to control Timer3 may be vastly different from TCCR3's definition.

I also find that apps up to the '4433/Mega8 size usually need to be pretty well carefully crafted to fit-in desired features, and even the modest increment of a separate layer is a luxury. YMMV.

Anyway, you can ALMOST :) do what you posted, with one more paren.

         ;     124 #define BIT(x)   (1 << (x)) 
         ;     125 #define bit_flip(v, m)   ((v) ^= (m)) 
         ;     126 
         ;     127 bit_flip(PORTD, (BIT(4) | BIT(3) | BIT(6) | BIT(1))); 
00006a b3e2      	IN   R30,0x12
00006b e5aa      	LDI  R26,LOW(90)
00006c 27ea      	EOR  R30,R26
00006d bbe2      	OUT  0x12,R30

so even lowly CodeVision users may follow the straight-and-narrow path.

Lee

You can put lipstick on a pig, but it is still a pig.

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

theusch wrote:
Sorry, EW, I thought it was getbit() that was somewhat passe.

Hi, Lee. BTW, EW = Eric Weddington, who wrote the "Programming 101" post.

theusch wrote:
I can't argue over the portability issue. I suspect, though, that there WILL be differences between architectures and even AVR compilers on exactly what is a sfrb/sfrw. In thinking, all I/O instructions would need to be examined within a platform-dependent layer--even using the portable syntax, the bits to control Timer3 may be vastly different from TCCR3's definition.

You'll have to explain this one a bit more. The acronym SFRB = Special Function Register Byte (with the W = Word). What is there to argue about what it is? It's a memory-mapped register (8 or 16 bits wide).

theusch wrote:
I also find that apps up to the '4433/Mega8 size usually need to be pretty well carefully crafted to fit-in desired features, and even the modest increment of a separate layer is a luxury.

Agreed, but I thought that we're talking about preprocessor macros which don't add any extra layer of assembly.

theusch wrote:
Anyway, you can ALMOST :) do what you posted, with one more paren.

Ah, thanks for catching that. I've edited my previous post above to show that.

theusch wrote:
so even lowly CodeVision users may follow the straight-and-narrow path.

Well that's why I mentioned that only if one is interested in compiler portability, then it's useful. If all you're ever going to use is CV, and you don't care about being able to operate on multiple, non-continguous bits, go ahead and knock yourself out. :wink:

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

Quote:
Hi, Lee. BTW, EW = Eric Weddington, who wrote the "Programming 101" post.

I knew that, but was too lazy to look up whether it was Eric or Erik so I copped out.

Quote:
Ah, thanks for catching that. I've edited my previous post above to show that.

Yes, the two-edged sword of editing posts--it makes my response look like an idiot. But I'm used to that. [Hmmm--I can call someone a malingering SOB, then edit it out after it's had the proper effect and claim it never happened--like subliminal advertising or many current politicians or "1984".]

Quote:
... and you don't care about being able to operate on multiple, non-continguous bits, go ahead and knock yourself out.

I posted that you could operate the same way on CV, as well as direct addressing. Actually, for I/O bits I do use one level of abstaction that helps me to cope with hardware pin assignment changes, along with active high/active low issues, as well as remembering what is assigned to what. Fragment:

#define	OUT_BACKLITE		PORTB.7
#define	OUT_COMPRESSOR		PORTB.4
#define	OUT_AUGER			PORTB.3
// Active high
#define	OUTPUT_ON			1
#define	OUTPUT_OFF			0

so that I only need to go to one spot to reconfigure.

Quote:
You'll have to explain this one a bit more.

Let's take an AVR timer as an example. To stop/disable an active timer, you write 0 to a variable number of pre-scaler selection bits in TCCRx. On an '8051 or MSP403 or Moto '08 there is probably going to be a completely different mechanism to enable/disable a timer.

So as long as I have my timer_on() and timer_off() macros or functions in one spot (like alongside the pin assignment fragment above), it doesn't matter >>what<< syntax I use within that macro--it has to be changed anyway when porting--it >>is<< platform-dependent.

Take care. Thanks for your efforts.

Lee

You can put lipstick on a pig, but it is still a pig.

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

theusch wrote:

Yes, the two-edged sword of editing posts--it makes my response look like an idiot. But I'm used to that. [Hmmm--I can call someone a malingering SOB, then edit it out after it's had the proper effect and claim it never happened--like subliminal advertising or many current politicians or "1984".]

:lol:

theusch wrote:
I posted that you could operate the same way on CV, as well as direct addressing. Actually, for I/O bits I do use one level of abstaction that helps me to cope with hardware pin assignment changes, along with active high/active low issues, as well as remembering what is assigned to what. Fragment:

#define	OUT_BACKLITE		PORTB.7
#define	OUT_COMPRESSOR		PORTB.4
#define	OUT_AUGER			PORTB.3
// Active high
#define	OUTPUT_ON			1
#define	OUTPUT_OFF			0

so that I only need to go to one spot to reconfigure.

Quote:
You'll have to explain this one a bit more.

Let's take an AVR timer as an example. To stop/disable an active timer, you write 0 to a variable number of pre-scaler selection bits in TCCRx. On an '8051 or MSP403 or Moto '08 there is probably going to be a completely different mechanism to enable/disable a timer.

So as long as I have my timer_on() and timer_off() macros or functions in one spot (like alongside the pin assignment fragment above), it doesn't matter >>what<< syntax I use within that macro--it has to be changed anyway when porting--it >>is<< platform-dependent.

Take care. Thanks for your efforts.

Lee

Oh I totally agree. Having another layer of "abstraction" via macros definitely helps both with portability (whether target or compiler) as well as maintainability / readability.

Eric

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

Is this one "Worthy" to get into the "Bit-Macro" library :?:

#define GET_BITS(num, from, to) (((num) >> (from)) & ((0x1 << ((to) - (from) + 1)) - 1))

/Bingo

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

Ultimately, it's totally up to you. There is no central library for these macros. Well at least not yet.

Um, it would also help if you had a description of what this is supposed to do....

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

Uhmm
Description :oops:

It is supposed to return the bits in the range from .. to , from the parameter num.

so GETBITS(uint16_t ,10,14) should return bit 10 to 14 of Parameter

/Bingo

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

I am also looking to set and clear I/O port bits
I have read the design note #008 “Efficient I/O handling with bitfields” but am unable to get it working. I am running IAR 3.10C for the Mega 64 and when I compile, with the example code, I get the error “pe029 expected an expression “ pointing at LED1 = 0; Why?
My goal is to manipulate a single bit of an I/O port with out having to read the port, mask it and rewrite the port. App note #008 would be a nice way if it works, if not, is there another way? I am not to concerned with portability as this is a one time project for a product already past mature.

Butch

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

Bingo600 wrote:
Uhmm
Description :oops:

It is supposed to return the bits in the range from .. to , from the parameter num.

so GETBITS(uint16_t ,10,14) should return bit 10 to 14 of Parameter

Ok.
Except that this macro shifts the resulting bits to the right.

#define GET_BITS(num, from, to) (((num) >> (from)) & ((0x1 << ((to) - (from) + 1)) - 1))

I would implement it as something like:

#define bits_read(v, s, f)     ((v) & ((~(0xFFFF << ((f) - (s)))) << (s)))

Hopefully I've gotten all the parentheses correct. :lol: (What is this? LISP?!) Parameters: v = variable to read, s = start bit number, f = finish bit number.

This implementation reads multiple, contiguous bits but leaves them in their original positions. Oh and it has one less operator than the other macro. Note that this is only good on 8 or 16 bit values and that the result would more than likely be an int (it's up to C's promotion rules). One would have to make a seperate 32-bit macro using 0xFFFFFFFF as the constant.

Oh, and yes, I've actually written and used something like this before. :D

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

Butch wrote:
I am also looking to set and clear I/O port bits
I have read the design note #008 “Efficient I/O handling with bitfields” but am unable to get it working. I am running IAR 3.10C for the Mega 64 and when I compile, with the example code, I get the error “pe029 expected an expression “ pointing at LED1 = 0; Why?
My goal is to manipulate a single bit of an I/O port with out having to read the port, mask it and rewrite the port. App note #008 would be a nice way if it works, if not, is there another way? I am not to concerned with portability as this is a one time project for a product already past mature.

Butch

I would suggest either re-reading this thread, or start a new topic.

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

He..He

Eric you are a living preprocessor :lol: :lol:

It was my intention to shift the result to the right , i was using it to get bitvalues (numbers) embedded within an Int.

/Bingo

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

Bingo600 wrote:

Eric you are a living preprocessor :lol: :lol:

Thanks, but I am by no means an expert with the preprocessor.

Bingo600 wrote:

It was my intention to shift the result to the right , i was using it to get bitvalues (numbers) embedded within an Int.

Oh, well that makes sense then.

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

Please add Eric's excellent discription of Bit operations to the Docs and example code - or at least make it sticky to the forum - I'ts excellent and answers a million of the "How do I (Check, Set, Clear, Flip) a Bit - including my own questions - and I have been programming for 20 years!

Thanks Eric - very much

Tom

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

geneo wrote:
I use macros to simplify bit setting and I also use macros to test bits

#define BIT(x) (1 << (x))
#define SETBITS(x,y) ((x) |= (y))
#define CLEARBITS(x,y) ((x) &= (~(y)))
#define SETBIT(x,y) SETBITS((x), (BIT((y))))
#define CLEARBIT(x,y) CLEARBITS((x), (BIT((y))))
#define BITSET(x,y) ((x) & (BIT(y)))
#define BITCLEAR(x,y) !BITSET((x), (y))
#define BITSSET(x,y) (((x) & (y)) == (y))
#define BITSCLEAR(x,y) (((x) & (y)) == 0)
#define BITVAL(x,y) (((x)>>(y)) & 1)

For example, if I want to set bit 2 in portd I would simply include the followin C command:
SETBIT(PORTD,2);

Why is it that when I include these macros in a .h file , the code doesn't compile, however, if i copy it to the program itself it runs fine ?

I have a modifiedio.h file which I add stuff that I frequently use into, and I wanted to add these macros too so I could use them without having to define them all thet time...

How could I do that ?

Thanks guys

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

Quote:

Why is it that when I include these macros in a .h file , the code doesn't compile

Why is it that you neither don't copy the actual error message(s), nor quote any "code snippets", into your post so that we get a fair chance of giving a good answer? :wink:

Also, did you notice that you revived a thread that has been silent for almost three years?

"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]

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

I copy pasted the same exact lines quoted above into my modifiedio.h file...

/* Bit Operations */
#define BIT(x) 			(1 << (x)) 
#define SETBITS(x,y) 	((x) |= (y)) 
#define CLEARBITS(x,y) 	((x) &= (~(y))) 
#define SETBIT(x,y) 	SETBITS((x), (BIT((y))))			/* EXAMPLE SETBIT(PORTB,2) sets the 2 bit of PORTB */
#define CLEARBIT(x,y) 	CLEARBITS((x), (BIT((y)))) 
#define BITSET(x,y) 	((x) & (BIT(y))) 
#define BITCLEAR(x,y) 	!BITSET((x), (y)) 
#define BITSSET(x,y) 	(((x) & (y)) == (y)) 
#define BITSCLEAR(x,y) 	(((x) & (y)) == 0) 
#define BITVAL(x,y) 	(((x)>>(y)) & 1) 

then..in my actual program , i include my modifiedio.h as i always do...

then when i try to use SETBIT.. I get the following error :

undefined reference to `SETBIT'
undefined reference to `SETBIT'
undefined reference to `SETBIT'

#include 

int main(void)
{

	
	DDRB = 0xFF;  	/* Set PORTB as Output */
	DDRD = 0 ;		/* Set PORTD as Input  */

	int READ_BIT = 0 ;	/* READ is bit 0 of Output Port */
	int WRITE_BIT = 1 ;	/* WRITE is bit 1 of Output Port */
	int INTR_BIT = 2 ;	/* INTR is bit 2 of Ouput Port */
		
	while(1)	
	{
		SETBIT(PORTB,READ_BIT) ;
		SETBIT(PORTB,WRITE_BIT) ;
		SETBIT(PORTB,INTR_BIT) ;
	
	}

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

OK, my bet is that you have multiple instances of modifiedio.h on your system and that you edited one but anotherone is included.

Tip:

Temporarily rename the modifiedio.h that you edited to another name. Then do a build. You should get en error message saying something to the effect that the header file could not be found. If you do not get this error message then the file you renamed is not the file that got included. Go hunt the duplicate!

Another way to detect this situation is to deliberately edit in something that will guarantee a compilation error in modifiedio.h, say a erroneous function prototype

void BadFunc(void;

Notice the missing closing parenthesis. Now if you build and do not get one or several error messages pertaining to the code above then the file you are editing is not the file that is being included. Go hunt...

"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]

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

In AVR studio, how do I set the directory where the compiler will look for the #include files ?

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

In Project menu, Configuration Options, Include Directories.

If you actually have placed your modifiedio.h in WinAVR-installation-root-dir\avr\include\avr then your include directive should work without adding any include path in Studio.

IMO, placing the file there is a bad idea though: You risk loosing the file if you reinstall or update the WinAVR installation. Generally speaking the installation trees of any toolchain should be kept clean of user-supplied files.

Better to create a directory outside of the WinAVR installation directory, place the file there and point to it by adding the path to the project settings in Studio. You'd have to add this path to every new Studio project if I understand things correctly.

Alternatively you could copy the file to the directory where the specific project has it's souce files, and do an

#include "modifiedio.h"

with "quotes" rather than . This #include variant looks in the current directory before searching the "system include" directories for the header file. The drawback here is that you will end up with many copies of the file, and you'd have to update them all when you fix a bug or add/improve functionality.

"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]

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

Please start a new thread when asking completely different questions.

Although its nice to see that the "Programming 101" thread refuses to die. ;)

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

Originally for ATMega162 ... need to modify for other AVR's....

// Bit Field Conversion for PORT Access
typedef struct
{
unsigned bit0:1;
unsigned bit1:1;
unsigned bit2:1;
unsigned bit3:1;
unsigned bit4:1;
unsigned bit5:1;
unsigned bit6:1;
unsigned bit7:1;
} BYTE_BITFIELD;

// Data Direction
#define ddra (*((volatile BYTE_BITFIELD*)(&DDRA)))
#define ddrb (*((volatile BYTE_BITFIELD*)(&DDRB)))
#define ddrc (*((volatile BYTE_BITFIELD*)(&DDRC)))
#define ddrd (*((volatile BYTE_BITFIELD*)(&DDRD)))

// Output Port
#define porta (*((volatile BYTE_BITFIELD*)(&PORTA)))
#define portb (*((volatile BYTE_BITFIELD*)(&PORTB)))
#define portc (*((volatile BYTE_BITFIELD*)(&PORTC)))
#define portd (*((volatile BYTE_BITFIELD*)(&PORTD)))

// Input Port
#define pina (*((volatile BYTE_BITFIELD*)(&PINA)))
#define pinb (*((volatile BYTE_BITFIELD*)(&PINB)))
#define pinc (*((volatile BYTE_BITFIELD*)(&PINC)))
#define pind (*((volatile BYTE_BITFIELD*)(&PIND)))

Now you can just use:

porta.bit1 = 0

You can use them like a structure object.

Have fun.

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

cfavreau: that code should compile efficiently in my previous testing on GCC and IAR. However, because of Imagecraft. When I checked last month, it's compiler did not create efficient code for bit fields like you are using. I sent an email to Imagecraft illustrating this can be an area they can work on optimizing.

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

For IO registers with address less than 0x20 u can use this macros:

#define SBI(port, bit) \
    asm volatile("sbi [percent]0, [percent]1" \
        : \
        : "I" (_SFR_IO_ADDR(port)), "I" (bit))

#define CBI(port, bit) \
    asm volatile("cbi [percent]0, [percent]1" \
        : \
        : "I" (_SFR_IO_ADDR(port)), "I" (bit))

For all other IO registers use classic set/clear bit macros. There are a lot of them (see above). I use this ones:

#define SETBIT(reg, bit) reg |= 1 << bit
#define CLRBIT(reg, bit) reg &= ~(1 << bit)

P.S.:
[Percent] - is a '%' charater. AVRFreaks forum engine fails to process posts with [percent][digit] constructions.

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

The original post was nearly 8 years ago. The previous post was over two years ago. And with avr-gcc your second set of macros are all you need, they will use SBI or CBI if they can.

Regards,
Steve A.

The Board helps those that help themselves.

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

You right. But if I write small projects I prefer -O0. In this case SETBIT produces a lot of instructions. If -O2 is set SETBIT really produces single SBI instruction.

About old posts. I founded this thread yesterday, and I was surprised that there is nothing about SBI/CBI macros. I think, that some threads helps me and now I know about SBI and CBI, and know may be I can help another people too. After all this thoughts I registered and write my post :-)

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

Quote:

But if I write small projects I prefer -O0.

Apart from temporary use for debugging what possible advantage can -O0 possibly have?

At other optimisation levels the compiler will recognise when SBI/CBI can be used and just make use of them automatically which is one of the many reasons to use the optimiser. You don't need to do anything "special":

PORTB |= (1<<PB6);

will simply generate:

SBI PORTB, 6

as long as PORTB lies in 0x00..0x1F range.

 

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

Active delays, for example, are optimized to nothing. And sometimes, when u write asm-like code, optimization should be turned off to avoid some unwanted conversions.

Pages