| Author |
Message |
|
|
Posted: Apr 22, 2006 - 02:26 PM |
|


Joined: Jan 23, 2004
Posts: 9826
Location: Trondheim, Norway
|
|
The following text is a slightly reformatted version of a post made by Eric quite a while ago. It has been referred to by so many users (it's now the post for bit-manipulations), and has helped so many that I have reposted it here so it is more easily found.
Programming 101 - By Eric Weddington
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 LEFT SHIFT
>> 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 table 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:
Code:
unsigned char foo = 0;
To set bit 0 in foo and then store the result back into foo:
Code:
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:
Code:
foo |= 0x01;
This is equivalent to the statement above.
To clear bit 0 in foo requires 2 bit operators:
Code:
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:
Code:
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:
Code:
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:
Code:
foo = foo ^ 0x01;
Or the shorter statement:
Code:
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:
Code:
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:
Code:
(0x01 << 2)
To build a bit mask that has bit number 7 set:
Code:
(0x01 << 7)
To build a bit mask that has bit number 0 set:
Code:
(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:
Code:
#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:
Code:
bit_set(foo, 0x01);
To set bit number 5:
Code:
bit_set(foo, BIT(5));
To clear bit number 6 with a bit mask:
Code:
bit_clear(foo, 0x40);
To flip bit number 0:
Code:
bit_flip(foo, BIT(0));
To check bit number 3:
Code:
if(bit_get(foo, BIT(3)))
{
}
To set or clear a bit based on bit number 4:
Code:
if(bit_get(foo, BIT(4)))
{
bit_set(bar, BIT(0));
}
else
{
bit_clear(bar, BIT(0));
}
To do it with a macro:
Code:
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.[/list] |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
Last edited by abcminiuser on Apr 25, 2006 - 12:23 AM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Apr 22, 2006 - 02:59 PM |
|


Joined: Nov 17, 2004
Posts: 6137
Location: Great Smokey Mountains.
|
|
|
|
|
|
|
Posted: May 04, 2006 - 10:58 PM |
|

Joined: Apr 21, 2006
Posts: 9
|
|
this is also touched on in "AVR035: Efficient C Coding for AVR" http://www.atmel.com/dyn/resources/prod_documents/doc1497.pdf
I based a few macros off of that app note, and created avr035.h:
Code:
#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))
#endif
|
|
|
| |
|
|
|
|
|
Posted: May 05, 2006 - 06:30 AM |
|


Joined: Jan 23, 2004
Posts: 9826
Location: Trondheim, Norway
|
|
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:
Code:
#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:
Code:
#define Status_LED PORTA, 3
C_SETBIT(Status_LED);
C_CLEARBIT(Status_LED);
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Mar 19, 2007 - 03:37 PM |
|


Joined: May 03, 2006
Posts: 155
Location: Manchester, UK
|
|
As an additional item to check if a bit is clear:
Code:
if(~(foo) & 0x80)
{
}
|
_________________ Ben
-Using IAR (& ocasionally CodeVision)
0.7734
1101111011000000110111101101
|
| |
|
|
|
|
|
Posted: Mar 20, 2007 - 02:49 AM |
|


Joined: Jan 03, 2004
Posts: 1637
Location: Apalachin, NY, USA
|
|
|
BenG wrote:
As an additional item to check if a bit is clear:
Code:
if(~(foo) & 0x80)
{
}
My 1st choice would be for the following which, IMHO, is easier to "read":
Code:
if ( ( foo & 0x80 ) == 0 )
{
...
}
should result in the same compiler generated code.
Don |
|
|
| |
|
|
|
|
|
Posted: Mar 24, 2007 - 01:37 PM |
|


Joined: Apr 25, 2004
Posts: 3809
Location: Denmark
|
|
With regards to the above i'd use
if(!CHECKBITMASK(foo,0x80))
or
if(!CHECKBIT(foo,7))
But i agree Don's code is more readable
/Bingo |
|
|
| |
|
|
|
|
|
Posted: May 11, 2007 - 11:01 AM |
|

Joined: Sep 05, 2001
Posts: 2497
|
|
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:
Code:
#include <io.h>
#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 |
|
|
| |
|
|
|
|
|
Posted: Jun 28, 2007 - 02:50 PM |
|

Joined: Dec 24, 2006
Posts: 201
|
|
|
Code:
TCCR1B |= (1 << CS10);
You might want to explain what this means. I didn't realize you could actually left shift a bit to a specific place using this actual name of the bit. It drove me crazy because the timer tutorial was directing me here and your tutorial makes no mention of this. |
|
|
| |
|
|
|
|
|
Posted: Jun 28, 2007 - 03:18 PM |
|


Joined: Dec 17, 2005
Posts: 1498
Location: Europe- Estonia- Tallinn
|
|
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  |
|
|
| |
|
|
|
|
|
Posted: Jun 28, 2007 - 03:44 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
I think this tutorial is trying to be as generic as possible. Not all the AVR C compilers have all the bit names defined in the header files for each AVR part so
Code:
TCCR1B |= (1 << CS10);
won't necessarily work on all compilers.
There's no "magic" to it anyway, a typical part definition file that does include the bit positions simply has something like (for mega16):
Code:
#define CS10 0
#define CS11 1
#define CS12 2
#define WGM12 3
#define WGM13 4
#define ICES1 6
#define ICNC1 7
For those C compilers that don't have the bit definitions in their .h collection the AVR Studio file \Program Files\Atmel\AVR Tools\AvrStudio4\xmlconvert.exe will probably prove useful to generate .h files from Atmel's own XML part definition files:
Code:
C:\Program Files\Atmel\AVR Tools\AvrStudio4>xmlconvert
xmlconvert: No source file specified
Usage: xmlconvert [-f output-format] [-o outdir] [-1nbclV] infile ...
Output formats: a[vrasm] | g[cc] | i[ar] | c[c] (generic c)
Options:
-1 = Don't generate AVRASM2 #pragma's
-n = Don't warn about bad names
-b = use DISPLAY_BITS attribute to limit bit definitions
-c = Add some definitions for compatibility with old files
-l = Produce linker file (IAR only)
-q = Allow linked register quadruple (32-bit)
-V = print xmlconvert version number
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: Jun 29, 2007 - 02:52 AM |
|


Joined: Feb 14, 2007
Posts: 1858
Location: San Diego California
|
|
Thanks all; I'm going to use most of the above for next yr's class. And another lesson you just taught. Show Dons, BenG, and then Bingos to show writing style and how they accomplish the same thing.
I couldn’t write (copy) the curriculum without this site.
Thanks for the help and making the world a better place,
John |
_________________ Resistance is futile…… You will be compiled!
|
| |
|
|
|
|
|
Posted: Jun 29, 2007 - 05:32 PM |
|

Joined: Dec 24, 2006
Posts: 201
|
|
|
clawson wrote:
I think this tutorial is trying to be as generic as possible. Not all the AVR C compilers have all the bit names defined in the header files for each AVR part so
Code:
TCCR1B |= (1 << CS10);
won't necessarily work on all compilers.
There's no "magic" to it anyway, a typical part definition file that does include the bit positions simply has something like (for mega16):
Code:
#define CS10 0
#define CS11 1
#define CS12 2
#define WGM12 3
#define WGM13 4
#define ICES1 6
#define ICNC1 7
Where are the definitions in AVR GCC? I am guessing in the IO header file or each header has every single part defined for only the related registers. |
|
|
| |
|
|
|
|
|
Posted: Jun 29, 2007 - 05:34 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Yup in GCC all your programs include <avr/io.h> and your Makefile will define a MCU=. As a consequence of these two things it will lead to io.h choosing to pull in one of the io????.h files in \winavr\avr\include\avr\
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: Jun 29, 2007 - 05:53 PM |
|

Joined: Dec 24, 2006
Posts: 201
|
|
|
clawson wrote:
Yup in GCC all your programs include <avr/io.h> and your Makefile will define a MCU=. As a consequence of these two things it will lead to io.h choosing to pull in one of the io????.h files in \winavr\avr\include\avr\
Cliff
I am guessing Avr Studio is handling the making the Makefile when I compile my program. Oddly enough I don't even think I defined the correct MCU when I first created the project. I defined it as a Mega 168 and only figured out that it was a Mega 48 when my Dragon complained that the parts didn't match up. Is this because the parts are in the same data sheet? |
|
|
| |
|
|
|
|
|
Posted: Jun 29, 2007 - 06:03 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| There's several MAJOR difference between 48 and 168. For example one uses RJMPs for its interrupt vectors and one uses JMPs (because the entire memory is no longer reachable with an RJMP). Far more worryingly the 168 has 1K of SRAM while the 48 has 512 bytes. So the RAMEND used to initialise the stack pointer will be different between the two. I'm therefore astonished that you found that code built for a 168 worked in a 48 !?! |
_________________
|
| |
|
|
|
|
|
Posted: Jun 29, 2007 - 06:51 PM |
|

Joined: Dec 24, 2006
Posts: 201
|
|
|
clawson wrote:
There's several MAJOR difference between 48 and 168. For example one uses RJMPs for its interrupt vectors and one uses JMPs (because the entire memory is no longer reachable with an RJMP). Far more worryingly the 168 has 1K of SRAM while the 48 has 512 bytes. So the RAMEND used to initialise the stack pointer will be different between the two. I'm therefore astonished that you found that code built for a 168 worked in a 48 !?!
Well the code I wrote was only five lines long and didn't use interrupts. Though I might want to make sure that the I actually did program for the 168. I don't have access to the computer I wrote the code in at the moment. |
|
|
| |
|
|
|
|
|
Posted: Jul 03, 2007 - 08:03 PM |
|

Joined: May 10, 2007
Posts: 396
Location: Brussels, Belgium
|
|
Another thing I've just learned, you can toggle the PORTxn pins by writhing to the PINxn register.
So instead of toggling the bits with the XOR operator, you can write to the PINxn address.
Do not know if the compiler optimization already does that? |
|
|
| |
|
|
|
|
|
Posted: Jul 03, 2007 - 08:42 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| But that only works on the recent AVRs, not all of them. |
_________________
|
| |
|
|
|
|
|
Posted: Nov 06, 2007 - 08:19 PM |
|

Joined: Aug 14, 2006
Posts: 118
|
|
|
Quote:
BenG wrote:
As an additional item to check if a bit is clear:
Code:
if(~(foo) & 0x80)
{
}
My 1st choice would be for the following which, IMHO, is easier to "read":
Code:
if ( ( foo & 0x80 ) == 0 )
{
...
}
should result in the same compiler generated code.
Don
and another way...
Code:
if (!( foo & 0x80 ))
{
...
}
|
|
|
| |
|
|
|
|
|
Posted: Feb 05, 2008 - 04:17 PM |
|

Joined: Apr 06, 2004
Posts: 71
|
|
I know this is compiler generic, but I do have a related question:
I've been using (1<<PIN_NAME) for some time in my code, but I am working on a project now where the developer is using _BV(PIN_NAME) all over. Is there a best practice on which to use?
Jim |
_________________ Jim Brain
|
| |
|
|
|
|
|
Posted: Apr 13, 2008 - 08:52 PM |
|

Joined: Oct 14, 2007
Posts: 112
Location: U.S.A. Rules Yaaaaaaaaaahhhhh!!!!
|
|
Will this blink an LED?
Code:
#inculde <avr/io.h>
#inculde <util/delay.h>
DDRB = 0b11111111;
while(1)
{
PORTB |= (0x01 << 7);
_delay_ms(250);
PORTB &= (0x00 << 7);
_delay_ms(250);
}
|
_________________ Life Is Like A Bucket Of Chicken.
|
| |
|
|
|
|
|
Posted: Apr 13, 2008 - 10:19 PM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
|
Quote:
Will this blink an LED?
Well, yes, but it isn't doing what you really want.
Code:
PORTB |= (0x01 << 7);
This sets bit 7 (and only bit 7) to 1. This is because it translates into:
Code:
PORTB = PORTB | 0b10000000;
So bit 7 is changed, and the rest of the bits remain what they were.
Code:
PORTB &= (0x00 << 7);
This sets all bits to 0, not just bit 7.
This is because this translates into:
Code:
PORTB = PORTB & 0b00000000;
since 0 shifted by any amount is still going to be 0, and 0 ANDed with anything is 0. You want:
Code:
PORTB &= ~(0x01 << 7);
|
_________________ Regards,
Steve A.
The Board helps those that help themselves.
|
| |
|
|
|
|
|
Posted: Apr 14, 2008 - 07:04 PM |
|

Joined: Oct 14, 2007
Posts: 112
Location: U.S.A. Rules Yaaaaaaaaaahhhhh!!!!
|
|
Thank You Koshchi,
That is exactly what I wanted. I was going to ask this next:
Quote:
This sets all bits to 0, not just bit 7.
This is because this translates into:
Code:
PORTB = PORTB & 0b00000000;
since 0 shifted by any amount is still going to be 0, and 0 ANDed with anything is 0. You want:
Code:
Code:
PORTB &= ~(0x01 << 7);
Thanks again, |
_________________ Life Is Like A Bucket Of Chicken.
|
| |
|
|
|
|
|
Posted: Apr 30, 2008 - 02:42 PM |
|

Joined: May 26, 2007
Posts: 6
|
|
|
Taco_Bell wrote:
Will this blink an LED?
Code:
#inculde <avr/io.h>
#inculde <util/delay.h>
DDRB = 0b11111111;
while(1)
{
PORTB |= (0x01 << 7);
_delay_ms(250);
PORTB &= (0x00 << 7);
_delay_ms(250);
}
It would blink a led, but it would be a inefficient way to do so.
This is how I would solve it:
Code:
#include <avr/io.h>
#include <util/delay.h>
int main(void) {
DDRB = 0xFF;
while(1) {
PORTB ^= (1 << 7);
_delay_ms(250);
}
}
Here I use the XOR operator which is ideal for flipping a bit. Using the 1 XOR as opposed to 1 OR and 1 AND also reduced the code size from 443 bytes (your example) to 398 bytes (my example)
The logic behind it is that on the first run the 8th bit of PORTB, which is 0, is XOR'ed with a 1 which results in a 1.
0 XOR 1 = 1
On the next loop iteration the 8th bit of PORTB, which is now 1, will be XOR'ed with a 1 which will result in a 0.
1 XOR 1 = 0 |
|
|
| |
|
|
|
|
|
Posted: May 30, 2008 - 08:52 AM |
|

Joined: Sep 13, 2005
Posts: 9
Location: Bucharest
|
|
Hello ,
Please excuse my dumb question :
how do I do octet/byte rotation in avrgcc ?
I mean how do I wrote in C the equivalent of asm rol cmd ?
Kind regards,
Daniel |
|
|
| |
|
|
|
|
|
Posted: May 30, 2008 - 11:22 AM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
I guess the first question is WHY you'd want to. But there's no easy way, you'd need to use something like
Code:
topbit = (bytevar & 0x80) ? 0 : 1;
bytevar <<= 1;
bytevar |= topbit;
|
_________________
|
| |
|
|
|
|
|
Posted: May 30, 2008 - 02:50 PM |
|

Joined: Sep 13, 2005
Posts: 9
Location: Bucharest
|
|
First of all thanks for answer.
I will answer why I need to do this : I writing an dmx receiver and I need to read the address of that receiver from a dipswitch pack. Because I was restricted to single side pcb I have inverted the traces to get the routing done.
I will abuse of your kindness and I would like to ask if it is possible to wrote an inline asm macro like :
http://www.nongnu.org/avr-libc/user-man ... e_asm.html
something like this would work ?
asm volatile("rol %0" : "=r" (value) : "0" (value));
Thanks
Daniel |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2008 - 09:41 PM |
|

Joined: May 19, 2008
Posts: 35
|
|
those are my definitions, i find them more user-friendly, tell me what you think.
Code:
#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:
Code:
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] |
Last edited by tigrezno on Jun 17, 2008 - 04:56 PM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Jun 16, 2008 - 08:59 PM |
|

Joined: Apr 17, 2008
Posts: 18
Location: Crestline, Ca. USA
|
|
Tigrezno,
I am been C ing with AVR for a few months. I am a novice. I got an A/D working with interrupts and putting the data to RS232 to RealTerm on a PC working!
Big accomplishment for me, lots of hours.
I have tried a few of the examples on this topic posted here and ran into problems. Mostly with the fact that PORTs need indirection methods to do bit fiddling? I think?
I just tried your "toggle" on a mega128 PORTA Bit 1 and it compiled and the hardware worked! Thanks, I wanted PORT bit setting and flipping, not just variables. This seems to be the best method discussed here yet? I will try the rest of thems soon.
Where is the #Define documentation for AVR C, or is it per standard C practice and I find it in a C book?
In the DOC directory in my AVR C installation there are many many HTML files. They seem to just compare features to standard C, with no examples? Not much help for a beginner?
Am I missing a manual for this AVR C somewhere?
I didn't know you could use # for parameter subsitution.
Thanks, I put your defines in my first AVR learning C project!
Mike |
|
|
| |
|
|
|
|
|
Posted: Jun 16, 2008 - 10:15 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
#define is just one of the C Pre Processor functions. The facilities available are standard to most c compilers so this manual for the GCC variant should be as good as any:
http://gcc.gnu.org/onlinedocs/cpp/ |
_________________
|
| |
|
|
|
|
|
Posted: Jun 16, 2008 - 11:15 PM |
|

Joined: Apr 17, 2008
Posts: 18
Location: Crestline, Ca. USA
|
|
Thanks!
I am looking at it now. Lots there.
The use of the # # to pass those port parameters still confuses me? I'll keep thinkin on it! |
|
|
| |
|
|
|
|
|
Posted: Jun 17, 2008 - 12:54 AM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
## is just the concatenation operator in macros. #define is just a text replacement tool, not a C programming construct. So something like:
Quote:
READ(B, 5)
simply gets replaced by:
Quote:
PORTB & (1<<5)
|
_________________ Regards,
Steve A.
The Board helps those that help themselves.
|
| |
|
|
|
|
|
Posted: Jun 17, 2008 - 02:00 AM |
|

Joined: Apr 17, 2008
Posts: 18
Location: Crestline, Ca. USA
|
|
Got it!
Thanks, this if from the manual Clawson sent the link too! "I wooda never known!"
"This is called token pasting or token concatenation. The `##' preprocessing operator performs token pasting. When a macro is expanded, the two tokens on either side of each `##' operator are combined into a single token, which then replaces the `##' and the two original tokens in the macro expansion." |
|
|
| |
|
|
|
|
|
Posted: Jun 17, 2008 - 11:42 AM |
|


Joined: Mar 12, 2004
Posts: 1174
Location: Linköping, Sweden
|
|
|
Code:
#define READ(port,pin) PORT ## port & (1<<pin)
tigrezno, did you actually use this? To read you have to use the PIN register. Additionally you can not compare the & result with 1 as you do here:
Code:
if (READ(B, 5) == HIGH)
This would work if you need to compare:
Code:
#define READ(port,pin) ((PIN ## port & (1<<pin)) != 0)
or just
Code:
#define READ(port,pin) ((PIN ## port & (1<<pin))
if you are ok with the simpler test condition:
Code:
if (READ(B,5)) {
/Lars |
|
|
| |
|
|
|
|
|
Posted: Jun 17, 2008 - 04:54 PM |
|

Joined: May 19, 2008
Posts: 35
|
|
ouch that was a typo!
You're correct, it should be PIN and not PORT, sorry, i'll change it.
The comparation issue is true too, me bad, very very bad.
I wrote them without using the "input" defines, sorry.
I hope you found the other methods usefull. |
|
|
| |
|
|
|
|
|
Posted: Sep 02, 2008 - 11:25 AM |
|

Joined: Sep 13, 2005
Posts: 9
Location: Bucharest
|
|
I'm a beginner in embedded development and for small applications I really enjoy a simple mode to access a port pin directly ( like PORTA.1 or PORTA_1).
I have found this example a while ago and I would like to hear your comments on it :
Quote:
#include <avr/io.h>
// Define the bits in the port
typedef struct
{
unsigned char bit0 : 1,
bit1 : 1,
bit2 : 1,
bit3 : 1,
bit4 : 1,
bit5 : 1,
bit6 : 1,
bit7 : 1;
} bit_field;
// Define macro to get the value of each bit
#define GET_BIT(port) (*(volatile bit_field *) (_SFR_ADDR(port)))
// Define functions for each bit of the I/O ports in the program
#define SIG GET_BIT(PINB).bit0
#define LED GET_BIT(PORTD).bit0
int main (void)
{
for (;;)
{
if (SIG) LED = 1;
else LED = 0;
}
}
I would really like to understood how this code is working ... especially part with setting a bit. |
|
|
| |
|
|
|
|
|
Posted: Sep 02, 2008 - 11:58 AM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Well break it down as the pre-processor will be doing for you. Let's say you use:
Code:
LED = 1;
firstly that becomes:
Code:
GET_BIT(PORTD).bit0;
which in turn is:
Code:
(*(volatile bit_field *) (_SFR_ADDR(PORTD))).bit0;
and from the GCC header files the _SFR_ADDR() and PORTD macros further break this down to be:
Code:
(*(volatile bit_field *) (((uint16_t) &((*(volatile uint8_t *)((0x12) + 0x20)))))).bit0 = 1;
The 0x12 in there will vary depending on your AVR - the above is correct for mega16.
So ultimately it's casting a bitfield structure onto memory address 0x32 and then setting 1 into "bit0" of that struct.
When you see:
Code:
struct {
:1
:1
}
it's effectively assigning one bit for each element. So this is just allowing individual bit access to the 8 bits being held in memory location 0x32.
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: Sep 12, 2008 - 12:30 AM |
|

Joined: Sep 11, 2008
Posts: 5
Location: Poland
|
|
Thank you for the tutorial. I found it very useful coming from beeing used to only sbi(), cbi() macros.
Somewhere else on the net i found these two macros beeing called obsolete... Any idea why is it so? Is it indeed more justified to acces the bits as shown in the tutorial?
This article is helping a lot in understanding many other articles around here.
Thanks once more.
Take care. |
|
|
| |
|
|
|
|
|
Posted: Sep 12, 2008 - 12:10 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
Somewhere else on the net i found these two macros beeing called obsolete... Any idea why is it so? Is it indeed more justified to acces the bits as shown in the tutorial?
There are three ways to change a single bit using the AVR. If the register in question is in IO space locations 0x00..0x1F then SBI/CBI can be used to set/clear individual bits. Those opcodes occupy 16 bits and execute in 1 cycle. If the register is between 0x20..0x3F then it is no longer reachable using SBI/CBI but it is using IN/OUT but in this case to set a bit it wil require IN/OR/OUT and to clear a bit it will require IN/AND/OUT which is 3 16 bit opcodes and takes 3 cycles. If the register is beyond IO address 0x3F (that is beyond RAM address 0x5F) then the only access is LDS/STS and to set it wil be LDS/OR/STS and to clear it will be LDS/AND/STS. In this case it's five 16 bit opcodes (LDS and STS are 2 each) and takes 5 cycles to execute.
Now when the early versions of the GCC compiler appeared it did not have an optimisation to spot when LDS/OR/STS could be reduced to IN/OR/OUT or even SBI so a macro sbi() was defined to use inline assembler so the programer could force SBI to be used even though the compiler didn't realise it.
In later compiler versions the code generator was improved so that it would always generate the most optimal code (as long as -O0 was not used!) so the need for the programmer to take control and force when SBI should be used was no longer required.
In the latest GCC (and the other AVR C compilers) the totally portable, totally standard PORTB |= (1<<PB5) will always generate just an SBI PORTB,5 as long as PORTB is between 0x00 and 0x1F and the optimiser is enabled.
The joy of using that standard construct is that you don't need the code to rely on some extra .h file that provides sbi()/cbi() so it makes it more portable between copilers and other architectures.
If using GCC then (for the time being) there is still <compat/deprecated.h> and this now includes:
Code:
#define sbi(port, bit) (port) |= (1 << (bit))
#define cbi(port, bit) (port) &= ~(1 << (bit))
so, as you can see, this is just supporting "old" code and turning the macro into the "standard" construct that's been explained above anyway.
As the file is deprecated there's a chance it may be withdrawn from future distributions so it's unwise to write code these days to use it because next time you upgrade compiler you may find that the file has gone.
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: Sep 13, 2008 - 02:02 PM |
|

Joined: Sep 11, 2008
Posts: 5
Location: Poland
|
|
Thanks a lot.
Thins makes it clear. You'v definitely convinced me to get used to the current stnadard notation. |
|
|
| |
|
|
|
|
|
Posted: Sep 15, 2008 - 10:04 AM |
|

Joined: Sep 15, 2008
Posts: 3
|
|
I just have small query regarding syntax:
Is this syntax valid:
PORTC = (0<<PC0); eg. driving the PC0 pin low.
or are you only able to do bit shift operations with "1"
PORTC = (1<<PC0)
I have tried this out on ATMEGA8 and it seems to work but many ppl have told me that that it is not wise to use the bit shift operation with 0 as it can lead to bugs. Could someone please clarify this for me?
Thanks in Advance. |
|
|
| |
|
|
|
|
|
Posted: Sep 15, 2008 - 11:05 AM |
|


Joined: Jan 23, 2004
Posts: 9826
Location: Trondheim, Norway
|
|
Zero shifted left or right is always zero, so your code there just clears the entire PORTC register by setting it to zero.
You should never need to shift 0 at all, other than to indicate clearly that a bit is not set.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Sep 15, 2008 - 11:41 AM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
Could someone please clarify this for me?
You did read the whole of this thread didn't you?
Hopefully it should have been obvious to you that to achieve what you think:
Code:
PORTC = (0<<PC0);
might do (assuming the intention is only to set bit PC0 to zero) you would actually use:
Code:
PORTC &= ~(1<<PC0);
Remeber you can only set bits with | and you can only clear them with &. Though you can obviously set/clear all 8 bits in a register in one go with a simple =, but then you cannot affect just single bits.
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: Oct 07, 2008 - 05:45 PM |
|

Joined: Oct 07, 2008
Posts: 3
|
|
| Can somebody help me out pls, I just cant access the register definitions because it says undeclared after compiling. Im using atmega324p chip. Thanks. |
|
|
| |
|
|
|
|
|
Posted: Oct 07, 2008 - 05:54 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
Can somebody help me out pls, I just cant access the register definitions because it says undeclared after compiling. Im using atmega324p chip. Thanks
Any particular language or variant thereof ? |
_________________
|
| |
|
|
|
|
|
Posted: Nov 04, 2008 - 03:26 PM |
|

Joined: Jun 29, 2006
Posts: 1
|
|
I'm working on a project with an external 16-bits adc using SPI. The first 5 bits are for settling of the adc and can be discarded, I am however receiving them.
I'm reading the following bytes in 3 chars (where x is either 1 or 0):
0-7
msb|0|0|0|0|0|x|x|x|
8-15
|x|x|x|x|x|x|x|x|
& 16-23
|x|x|x|x|x|0|0|0|lsb
I want to put 0-7 in a long and shift it 5+16 to the left, put 8-15 in a long and shift it 5+8 to the left and add it to 0-7, put 16-23 in a long and shift it 5 to the left and also add it. Then convert it to a double.
so:
|0|0|0|0|0|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|0|0|0|
<<5
|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|0|0|0|0|0|0|0|0|
typecast
|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|
how can I shift all bits to the left in a long? |
|
|
| |
|
|
|
|
|
Posted: Nov 04, 2008 - 03:41 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Code:
unsigned int result = (byte1 << 13) | (byte2 << 5) ( (byte3 >> 3);
at a rough guess. |
_________________
|
| |
|
|
|
|
|
Posted: Nov 04, 2008 - 11:37 PM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
| I would use a union. |
_________________ Regards,
Steve A.
The Board helps those that help themselves.
|
| |
|
|
|
|
|
Posted: Nov 10, 2008 - 01:33 PM |
|

Joined: Sep 25, 2006
Posts: 51
Location: 28638
|
|
When I was a boy... I learned to fix "mainframes" for the Navy. Understand that was 35 years ago so my memory of the details is questionable at best but I seem to remember that a shift took X clocks per shift position. For example to shift one position left took one clock, 2 positions took 2 cycles etc.
Is that true in the Atmega processors, or does it shift any number of positions in a single clock? |
_________________ JWColby
AVRNubee
www.ColbyConsulting.com
|
| |
|
|
|
|
|
Posted: Nov 10, 2008 - 01:55 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
The ROL/ROR/LSL/LSR instructions are all shown as being 1 cycle but to shift 5 places might take 5 of them and cost 5 cycles. Though an intelligent optimiser will spot that a shift of 4 can probably be achieved with a SWAP, an AND mask and one shift for the cost of 3 cycles
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: Nov 10, 2008 - 03:12 PM |
|

Joined: Sep 25, 2006
Posts: 51
Location: 28638
|
|
| 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
|
| |
|
|
|
|
|
Posted: Nov 10, 2008 - 03:49 PM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
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:
Code:
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.
|
| |
|
|
|
|
|
Posted: Nov 10, 2008 - 04:30 PM |
|

Joined: Sep 25, 2006
Posts: 51
Location: 28638
|
|
|
Koshchi wrote:
In that case an expression like:
Code:
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
|
| |
|
|
|
|
|
Posted: Dec 22, 2008 - 11:30 AM |
|

Joined: Dec 12, 2008
Posts: 9
|
|
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:
Code:
PORTD = (PORTD ^ 0b00000001);
This code flipp bit0 of PORTD
Code:
PORTD = (PORTD & 0b11111110);
This code switch off PIND.0
Code:
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?.
Code:
#include <main.h>//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 |
|
|
| |
|
|
|
|
|
Posted: Dec 22, 2008 - 11:51 AM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Code:
if(PIND0 & 0b11111111)//I KNOW THIS LINE IS WRONG
try:
Code:
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
Code:
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
|
_________________
|
| |
|
|
|
|
|
Posted: Dec 22, 2008 - 01:16 PM |
|

Joined: Dec 12, 2008
Posts: 9
|
|
Thanks very much, I writte this and works ok:
Code:
if (PIND & (1<<PD0))
My last question about this is:
Code:
if (PIND & ~(1<<PD0))
This code test if bit is not set?
Thanks very much. |
|
|
| |
|
|
|
|
|
Posted: Dec 22, 2008 - 01:54 PM |
|


Joined: Mar 27, 2002
Posts: 18547
Location: Lund, Sweden
|
|
|
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:
Code:
1<<PD0
make a bitmask 00000001.
2:
Code:
~(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
Code:
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
Code:
if (~(PIND) & (1<<PD0))
as BenG has pointed out in the first page of this thread. |
|
|
| |
|
|
|
|
|
Posted: Dec 22, 2008 - 02:52 PM |
|

Joined: Dec 12, 2008
Posts: 9
|
|
Ok. Now I think I've got it.
Thanks very much |
|
|
| |
|
|
|
|
|
Posted: Jan 08, 2009 - 02:17 PM |
|

Joined: Apr 01, 2006
Posts: 84
|
|
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? |
|
|
| |
|
|
|
|
|
Posted: Jan 08, 2009 - 03:36 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
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
Code:
# 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))
|
_________________
|
| |
|
|
|
|
|
Posted: Jan 08, 2009 - 04:04 PM |
|

Joined: Nov 29, 2007
Posts: 3219
|
|
|
Code:
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.
|
| |
|
|
|
|
|
Posted: Jan 08, 2009 - 04:32 PM |
|

Joined: Apr 01, 2006
Posts: 84
|
|
Ok, thats what i thought but didn't know how to do
Will the compiler produce the same code from both your examples?
Thanks!!  |
|
|
| |
|
|
|
|
|
Posted: Jan 08, 2009 - 04:37 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| 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) |
_________________
|
| |
|
|
|
|
|
Posted: Jan 08, 2009 - 05:29 PM |
|

Joined: Nov 29, 2007
Posts: 3219
|
|
|
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?  |
_________________ Stealing Proteus doesn't make you an engineer.
|
| |
|
|
|
|
|
Posted: Jan 08, 2009 - 06:05 PM |
|

Joined: Apr 01, 2006
Posts: 84
|
|
|
ArnoldB wrote:
Hey, I even added comments. What more can you ask for?
No fighting please, LOL
As speed is needed i will go with ArnoldB his version.
Points go to the both of you, |
|
|
| |
|
|
|
|
|
Posted: Jan 09, 2009 - 07:04 PM |
|

Joined: Dec 12, 2008
Posts: 9
|
|
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
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
Code:
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
Code:
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 |
|
|
| |
|
|
|
|
|
Posted: Jul 08, 2009 - 04:12 AM |
|

Joined: Jun 23, 2005
Posts: 3
|
|
|
tigrezno wrote:
those are my definitions, i find them more user-friendly, tell me what you think.
Code:
#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:
Code:
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.
Code:
#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
Code:
// ##############
// 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. |
|
|
| |
|
|
|
|
|
Posted: Oct 09, 2009 - 11:53 PM |
|

Joined: Oct 09, 2009
Posts: 2
|
|
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 ? |
|
|
| |
|
|
|
|
|
Posted: Oct 10, 2009 - 12:13 AM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
|
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.
|
| |
|
|
|
|
|
Posted: Oct 10, 2009 - 04:04 PM |
|

Joined: Oct 09, 2009
Posts: 2
|
|
Thanks for reply.
Now it is clear.
Of course I was talking about avr-libc, sorry for that. |
|
|
| |
|
|
|
|
|
Posted: Oct 13, 2009 - 08:47 AM |
|


Joined: Jul 10, 2008
Posts: 174
Location: Ruhrpott, Germany
|
|
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.
Code:
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? |
_________________ http://xkcd.com/221/
|
| |
|
|
|
|
|
Posted: Oct 13, 2009 - 09:31 AM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
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:
Code:
#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. |
_________________
|
| |
|
|
|
|
|
Posted: Oct 13, 2009 - 09:50 AM |
|


Joined: Jul 10, 2008
Posts: 174
Location: Ruhrpott, Germany
|
|
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:
Code:
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  |
_________________ http://xkcd.com/221/
|
| |
|
|
|
|
|
Posted: Oct 18, 2009 - 04:39 AM |
|


Joined: May 04, 2007
Posts: 3529
Location: Geelong Australia, Home of the "Cats"
|
|
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 -.-
(If you haven't already done so, edit your PostNuke profile and let let us know where you are, what you do & what your interests are.)
|
| |
|
|
|
|
|
Posted: Oct 20, 2009 - 02:16 AM |
|


Joined: Mar 01, 2001
Posts: 4953
Location: Rocky Mountains
|
|
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/magazine/180toc.htm
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). |
|
|
| |
|
|
|
|
|
Posted: Oct 25, 2009 - 05:35 PM |
|

Joined: Jan 15, 2009
Posts: 165
Location: South Africa
|
|
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:
Code:
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:
Code:
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.
|
| |
|
|
|
|
|
Posted: Oct 25, 2009 - 06:57 PM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
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.
|
| |
|
|
|
|
|
Posted: Oct 26, 2009 - 09:02 AM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| 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. |
_________________
|
| |
|
|
|
|
|
Posted: Dec 07, 2009 - 10:37 AM |
|

Joined: May 06, 2009
Posts: 12
Location: Stockholm, Sweden
|
|
|
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:
Code:
#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:
Code:
#define Status_LED PORTA, 3
C_SETBIT(Status_LED);
C_CLEARBIT(Status_LED);
- Dean
|
|
|
| |
|
|
|
|
|
Posted: Jan 01, 2010 - 02:56 PM |
|

Joined: Feb 16, 2008
Posts: 75
|
|
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:
Code:
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
|
| |
|
|
|
|
|
Posted: Jan 01, 2010 - 08:28 PM |
|


Joined: Mar 27, 2002
Posts: 18547
Location: Lund, Sweden
|
|
|
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
Code:
((1<<WGM01) | (1<<WGM00))
which says a lot more about what you are doing than eg
Code:
0b00011000
Add to this that the "0b" notation is not standard C and the argument in favour of the shift-notation becomes rather strong. |
|
|
| |
|
|
|
|
|
Posted: Jan 01, 2010 - 09:31 PM |
|

Joined: Feb 16, 2008
Posts: 75
|
|
|
JohanEkdahl wrote:
Quote:
couldn't you just "AND" it against 0x00?
No, as that would clear the whole byte.
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
|
| |
|
|
|
|
|
Posted: Jan 29, 2010 - 05:26 PM |
|

Joined: May 06, 2009
Posts: 12
Location: Stockholm, Sweden
|
|
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 |
|
|
| |
|
|
|
|
|
Posted: Jan 29, 2010 - 08:33 PM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
| 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.
|
| |
|
|
|
|
|
Posted: Jan 31, 2010 - 10:08 PM |
|

Joined: May 06, 2009
Posts: 12
Location: Stockholm, Sweden
|
|
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. |
|
|
| |
|
|
|
|
|
Posted: Jan 31, 2010 - 10:18 PM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
|
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.
|
| |
|
|
|
|
|
Posted: Jan 31, 2010 - 10:33 PM |
|

Joined: May 06, 2009
Posts: 12
Location: Stockholm, Sweden
|
|
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... |
|
|
| |
|
|
|
|
|
Posted: Feb 01, 2010 - 01:58 AM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
| 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.
|
| |
|
|
|
|
|
Posted: Feb 01, 2010 - 07:26 AM |
|

Joined: May 06, 2009
Posts: 12
Location: Stockholm, Sweden
|
|
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. |
|
|
| |
|
|
|
|
|
Posted: Feb 01, 2010 - 09:32 AM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
I still don't get your argument. How is:
Code:
C_CLEARBIT(PORTA,5);
any clearer than:
Code:
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). |
_________________
|
| |
|
|
|
|
|
Posted: Feb 01, 2010 - 11:33 AM |
|


Joined: Mar 27, 2002
Posts: 18547
Location: Lund, Sweden
|
|
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
Code:
C_CLEARBIT(PORTx, n)
you would write a thin hardware abstraction layer, eg
Code:
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)
Code:
inline void LED_ON() { PORTB &= ~(1<<5); }
|
|
|
| |
|
|
|
|
|
Posted: Feb 01, 2010 - 07:25 PM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
Not only is the method that Johan showed more readable, it is far more safe. With the macros you could easily do this:
Code:
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.
|
| |
|
|
|
|
|
Posted: Mar 13, 2010 - 10:25 PM |
|

Joined: Sep 16, 2009
Posts: 39
|
|
what does it mean when the left shift operation is used in statements such as this?
Code:
REG |= (1<<BIT)
or
Code:
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:
Code:
(0x01<<2)
which sets bit number 2 of an 8-bit mask.
Thanks |
|
|
| |
|
|
|
|
|
Posted: Mar 13, 2010 - 10:31 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
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) |
_________________
|
| |
|
|
|
|
|
Posted: Mar 13, 2010 - 10:34 PM |
|


Joined: Mar 27, 2002
Posts: 18547
Location: Lund, Sweden
|
|
|
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. |
|
|
| |
|
|
|
|
|
Posted: Mar 18, 2010 - 02:49 PM |
|

Joined: Mar 14, 2010
Posts: 60
|
|
|
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:
Code:
#include <io.h>
#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:
Code:
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)
Code:
#include <avr\sbit.h>
#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 |
|
|
| |
|
|
|
|
|
Posted: Mar 18, 2010 - 05:03 PM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
| 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.
|
| |
|
|
|
|
|
Posted: Mar 18, 2010 - 06:21 PM |
|

Joined: Mar 14, 2010
Posts: 60
|
|
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. |
|
|
| |
|
|
|
|
|
Posted: Mar 18, 2010 - 06:23 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
I wonder if that is just a simulator thing.
No sh*t?
(trust simulators about as far as you can comfortably spit them) |
_________________
|
| |
|
|
|
|
|
Posted: Jul 04, 2010 - 12:40 AM |
|

Joined: Sep 16, 2009
Posts: 39
|
|
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?
Code:
word = (address<<10) | (control<<8) | data
|
|
|
| |
|
|
|
|
|
Posted: Jul 04, 2010 - 01:15 AM |
|


Joined: Mar 27, 2002
Posts: 18547
Location: Lund, Sweden
|
|
Have you tried it out? (For this kind of stuff the simulator in AVR Studio is excellent.)
But yes, that looks reasonable. |
|
|
| |
|
|
|
|
|
Posted: Jul 04, 2010 - 04:57 AM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
Or you could do this:
Code:
typefef struct
{
unsigned int data :8;
unsigned int control :2;
unsigned int address :2;
} whateverYouWantToCallIt;
or:
Code:
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.
Code:
whateverYouWantToCallIt word;
...
word.address = address;
word.control = control;
word.data = data;
|
_________________ Regards,
Steve A.
The Board helps those that help themselves.
|
| |
|
|
|
|
|
Posted: Jul 21, 2010 - 04:47 AM |
|

Joined: Jun 30, 2010
Posts: 13
|
|
This one doesnot make sense to me,
To set bit 0 in foo and then store the result back into foo:
Code:
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. |
|
|
| |
|
|
|
|
|
Posted: Jul 21, 2010 - 09:16 AM |
|


Joined: Mar 27, 2002
Posts: 18547
Location: Lund, Sweden
|
|
| [Removed as I totally mis-understood the post above. Snigelen nailed the correct interpretation and answer below.] |
Last edited by JohanEkdahl on Jul 21, 2010 - 10:08 AM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Jul 21, 2010 - 09:55 AM |
|


Joined: Jan 08, 2009
Posts: 1153
Location: Lund, Sweden
|
|
|
qli029 wrote:
This one doesnot make sense to me,
To set bit 0 in foo and then store the result back into foo:
Code:
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. |
|
|
| |
|
|
|
|
|
Posted: Jul 21, 2010 - 10:53 AM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Just to add a little more to that:
Code:
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
|
_________________
|
| |
|
|
|
|
|
Posted: Jul 24, 2010 - 10:22 AM |
|

Joined: Feb 08, 2010
Posts: 12
|
|
| That was useful , Thanks . |
|
|
| |
|
|
|
|
|
Posted: Jan 09, 2011 - 02:01 AM |
|

Joined: Jan 02, 2011
Posts: 1
|
|
| Thanks!, i was looking for this information. |
|
|
| |
|
|
|
|
|
Posted: Mar 02, 2011 - 01:27 PM |
|


Joined: Jun 05, 2009
Posts: 67
Location: bangalore, India
|
|
how should i access the registers R0-R32? using c programming.
Just give me an example..
Thank you |
|
|
| |
|
|
|
|
|
Posted: Mar 02, 2011 - 01:32 PM |
|


Joined: Jan 23, 2004
Posts: 9826
Location: Trondheim, Norway
|
|
|
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  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Mar 02, 2011 - 02:12 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
To illustrate what Dean has said consider this program:
Code:
#include <avr/io.h>
#include <util/delay.h>
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:
Code:
00000080 <main>:
int main(void)
{
uint8_t mask = 0x55;
DDRB = 0xFF;
80: 8f ef ldi r24, 0xFF ; 255
82: 84 b9 out 0x04, r24 ; 4
#include <avr/io.h>
#include <util/delay.h>
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 <main+0x6>
mask ^= 0xFF;
90: 80 95 com r24
92: f9 cf rjmp .-14 ; 0x86 <main+0x6>
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. |
_________________
|
| |
|
|
|
|
|
Posted: Mar 30, 2011 - 06:51 PM |
|

Joined: Mar 30, 2011
Posts: 1
|
|
What this program does not work help me
Code:
//***********************************************************
// 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 <avr\io.h>
#include <avr\interrupt.h>
#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
}
}
|
|
|
| |
|
|
|
|
|
Posted: Mar 30, 2011 - 07:54 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
ghost800,
How does your post extend the discussion of the article in the first post of this thread?
Moderator. |
_________________
|
| |
|
|
|
|
|
Posted: Mar 30, 2011 - 09:10 PM |
|


Joined: Mar 27, 2002
Posts: 18547
Location: Lund, Sweden
|
|
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! |
|
|
| |
|
|
|
|
|
Posted: Apr 01, 2011 - 07:27 AM |
|

Joined: Jul 21, 2010
Posts: 5
|
|
can the macros be used with ports?
for eg
Code:
int totalcomplete()
{
int retval;
if ((bit_get(PORTC, BIT(1))) && (bit_get(PORTC, BIT(0)))==0)
{
retval = 1;
}
else retval = 0;
return retval;
}
|
|
|
| |
|
|
|
|
|
Posted: Apr 01, 2011 - 10:33 AM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
I'm curious. What would make you want to type:
Code:
if ((bit_get(PORTC, BIT(1))) && (bit_get(PORTC, BIT(0)))==0)
{
when you could have typed:
Code:
if ((PORTC & 3) == 0)
{
Do the tortuous macros really help?
(BTW do you mean to read PORTC or PINC?) |
_________________
|
| |
|
|
|
|
|
Posted: Apr 01, 2011 - 08:15 PM |
|

Joined: Jul 21, 2010
Posts: 5
|
|
| thanks! ya my mistake it should have been PINC .sorry but am new to programming an ya thanks i guess i could use
Code:
if ((PORTC & 3) == 0)
{
but what i meant was does this macro
Code:
#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
Code:
#define READ(port,pin) ((PIN ## port & (1<<pin))
|
|
|
| |
|
|
|
|
|
Posted: Apr 01, 2011 - 08:44 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| 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! |
_________________
|
| |
|
|
|
|
|
Posted: Apr 01, 2011 - 09:02 PM |
|

Joined: Jul 21, 2010
Posts: 5
|
|
| 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. |
|
|
| |
|
|
|
|
|
Posted: Apr 01, 2011 - 09:55 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
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? |
_________________
|
| |
|
|
|
|
|
Posted: Apr 01, 2011 - 10:57 PM |
|

Joined: Jul 21, 2010
Posts: 5
|
|
| 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. |
|
|
| |
|
|
|
|
|
Posted: Apr 02, 2011 - 01:09 AM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
|
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.
|
| |
|
|
|
|
|
Posted: Apr 02, 2011 - 01:39 AM |
|

Joined: Jul 21, 2010
Posts: 5
|
|
| 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. |
|
|
| |
|
|
|
|
|
Posted: Apr 02, 2011 - 08:13 AM |
|

Joined: Mar 17, 2011
Posts: 11
|
|
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? |
|
|
| |
|
|
|
|
|
Posted: Apr 02, 2011 - 01:08 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
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:
http://www.avrfreaks.net/index.php?name ... highlight=
Quote:
Just needed the macros to hopefully make it easier to explain.
First rule of programming: simplest is best.
"simplest" rarely involves macros. |
_________________
|
| |
|
|
|
|
|
Posted: May 14, 2011 - 06:20 AM |
|

Joined: May 13, 2011
Posts: 5
|
|
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/issues/detail?id=146
I don't see anyone disabling interrupts in their code-- why not? Is there a reason I've overlooked why it's not necessary? |
|
|
| |
|
|
|
|
|
Posted: May 14, 2011 - 09:51 PM |
|


Joined: Mar 27, 2002
Posts: 18547
Location: Lund, Sweden
|
|
|
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
Code:
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. |
|
|
| |
|
|
|
|
|
Posted: May 15, 2011 - 05:15 AM |
|


Joined: Jan 23, 2004
Posts: 9826
Location: Trondheim, Norway
|
|
|
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  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: May 17, 2011 - 12:55 AM |
|

Joined: May 13, 2011
Posts: 5
|
|
| 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. |
|
|
| |
|
|
|
|
|
Posted: May 17, 2011 - 08:27 AM |
|


Joined: Mar 27, 2002
Posts: 18547
Location: Lund, Sweden
|
|
|
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. |
|
|
| |
|
|
|
|
|
Posted: Jun 09, 2011 - 04:09 PM |
|

Joined: Sep 05, 2001
Posts: 2497
|
|
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.:
Code:
#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:
http://www.avrfreaks.net/index.php?name ... 198#318198 |
|
|
| |
|
|
|
|
|
Posted: Jun 14, 2011 - 03:26 PM |
|


Joined: Jun 01, 2011
Posts: 38
Location: Waterloo, Ontario, Canada
|
|
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 |
|
|
| |
|
|
|
|
|
Posted: Jun 14, 2011 - 03:57 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
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:
Code:
DDRB |= 0x20;
is almost as readable as:
Code:
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:
Code:
UCSRB |= 0x20;
or
Code:
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:
Code:
#define UDRIE 0x20
rather than
Code:
#define UDRIE 5
then the usage in C would just be:
Code:
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:
Code:
#define _BV(x) (1<<x)
so that at least:
Code:
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 by clawson on Jun 14, 2011 - 03:59 PM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Jun 14, 2011 - 03:58 PM |
|


Joined: Mar 27, 2002
Posts: 18547
Location: Lund, Sweden
|
|
|
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
Code:
something &= (1<<4) | (1<<3);
or this
Code:
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. |
|
|
| |
|
|
|
|
|
Posted: Jun 14, 2011 - 08:27 PM |
|


Joined: Jun 01, 2011
Posts: 38
Location: Waterloo, Ontario, Canada
|
|
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  |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2011 - 06:10 AM |
|

Joined: Jun 15, 2011
Posts: 1
|
|
| Thanks for your information. |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2011 - 12:59 PM |
|

Joined: May 31, 2011
Posts: 13
|
|
|
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. |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2011 - 01:02 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| 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. |
_________________
|
| |
|
|
|
|
|
Posted: Jun 15, 2011 - 01:05 PM |
|


Joined: Mar 27, 2002
Posts: 18547
Location: Lund, Sweden
|
|
|
Quote:
Is OR ('|') really needed there
That depends on the circumstances.
Quote:
or both will work the same
Definitively not.
Code:
TCCR1B |= (1 << CS10);
is a shorthand for the equivalent
Code:
TCCR1B = TCCR1B | (1 << CS10);
so all bits that was set before this operation will still be set.
OTOH, if you do
Code:
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.. |
|
|
| |
|
|
|
|
|
Posted: Jul 18, 2011 - 06:06 PM |
|

Joined: Aug 26, 2008
Posts: 27
Location: Arkansas
|
|
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? |
|
|
| |
|
|
|
|
|
Posted: Jul 18, 2011 - 08:55 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
No,
But the fact that it's not obvious kind of proves how pointless these kind of macros are in aiding readability. Think about:
Code:
bit_set(foo, 0x20);
bit_clear(foo, 0x08);
if (bit_set(foo,0x80)) {
which really says (without all the parenthesis):
Code:
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! |
_________________
|
| |
|
|
|
|
|
Posted: Jul 18, 2011 - 09:07 PM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
|
Code:
if (bit_set(foo,0x80))
You mean "bit_get" don't you? |
_________________ Regards,
Steve A.
The Board helps those that help themselves.
|
| |
|
|
|
|
|
Posted: Jul 19, 2011 - 12:13 AM |
|

Joined: Aug 26, 2008
Posts: 27
Location: Arkansas
|
|
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 |
|
|
| |
|
|
|
|
|
Posted: Sep 13, 2011 - 08:47 PM |
|


Joined: Jun 01, 2011
Posts: 38
Location: Waterloo, Ontario, Canada
|
|
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)
Code:
PORTD &= (0<<D_I);
And this one does work properly?
Code:
PORTD &= ~(1<<D_I);
|
|
|
| |
|
|
|
|
|
Posted: Sep 13, 2011 - 09:12 PM |
|


Joined: Nov 17, 2004
Posts: 6137
Location: Great Smokey Mountains.
|
|
They would both work just fine as written.
Did you read the tutorial?
What do you mean by properly?
Smiley |
_________________ FREE TUTORIAL: 'Quick Start Guide for Using the WinAVR C Compiler with ATMEL's AVR Butterfly' AVAILABLE AT: http://www.smileymicros.com
|
| |
|
|
|
|
|
Posted: Sep 13, 2011 - 09:25 PM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
|
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.
|
| |
|
|
|
|
|
Posted: Sep 14, 2011 - 02:02 AM |
|


Joined: Jan 23, 2004
Posts: 9826
Location: Trondheim, Norway
|
|
|
Quote:
They would both work just fine as written.
ಠ_à²
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Sep 14, 2011 - 04:47 AM |
|


Joined: Nov 17, 2004
Posts: 6137
Location: Great Smokey Mountains.
|
|
|
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 |
_________________ FREE TUTORIAL: 'Quick Start Guide for Using the WinAVR C Compiler with ATMEL's AVR Butterfly' AVAILABLE AT: http://www.smileymicros.com
|
| |
|
|
|
|
|
Posted: Sep 14, 2011 - 08:30 AM |
|


Joined: Mar 27, 2002
Posts: 18547
Location: Lund, Sweden
|
|
|
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
Code:
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. |
|
|
| |
|
|
|
|
|
Posted: Sep 14, 2011 - 09:13 AM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
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:
Code:
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:
Code:
SFR |= (1 << bit);
but then see variants of:
Code:
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. |
_________________
|
| |
|
|
|
|
|
Posted: Sep 14, 2011 - 09:37 AM |
|


Joined: Mar 27, 2002
Posts: 18547
Location: Lund, Sweden
|
|
|
Quote:
As we all know
Exchange "some" for "all" and we're closer to the actual situation. |
|
|
| |
|
|
|
|
|
Posted: Sep 14, 2011 - 03:22 PM |
|


Joined: Jun 01, 2011
Posts: 38
Location: Waterloo, Ontario, Canada
|
|
Hey Guys, Thanks for all your input but I believe Koshchi nailed what I was looking for, and smiley was just being ragging on me for not stating my intent explicitly.
Either way Cheers! |
|
|
| |
|
|
|
|
|
Posted: Sep 14, 2011 - 04:34 PM |
|


Joined: Nov 17, 2004
Posts: 6137
Location: Great Smokey Mountains.
|
|
|
clawson wrote:
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:
Code:
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:
Code:
SFR |= (1 << bit);
but then see variants of:
Code:
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.
Cliff - It was late and my thought was 'jeez this guy didn't even glance at the tutorial' since all it would have taken was a glance to answer his question. Usually I just pass on by but for some reason this one exceeded a threshold, thus my response which the poster sees correctly as me ragging on him. And as usual, your response fully explains why his first usage doesn't make sense and the real 'proper' use of (0<<xxx).
Smiley |
_________________ FREE TUTORIAL: 'Quick Start Guide for Using the WinAVR C Compiler with ATMEL's AVR Butterfly' AVAILABLE AT: http://www.smileymicros.com
|
| |
|
|
|
|
|
Posted: Oct 14, 2011 - 01:46 PM |
|

Joined: Oct 12, 2011
Posts: 1
|
|
|
robinsm wrote:
Quote:
BenG wrote:
As an additional item to check if a bit is clear:
Code:
if(~(foo) & 0x80)
{
}
My 1st choice would be for the following which, IMHO, is easier to "read":
Code:
if ( ( foo & 0x80 ) == 0 )
{
...
}
should result in the same compiler generated code.
Don
and another way...
Code:
if (!( foo & 0x80 ))
{
...
}
 |
|
|
| |
|
|
|
|
|
Posted: Dec 19, 2011 - 06:30 PM |
|

Joined: Dec 09, 2010
Posts: 144
|
|
now wait a moment if the compiler knows a bit's name as variable then why it hasn ot been writen like this:
while (CS10==0); |
|
|
| |
|
|
|
|
|
Posted: Dec 19, 2011 - 06:35 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Do not cross post and do not post to tutorials except to suggest improvements to the original article.
The last 202,030 people who have read this thread clearly understood the reason. If you don't I can only suggest you re-read until you understand. Also see the point I just made regarding bit number vs. bit mask in your cross-post. |
_________________
|
| |
|
|
|
|
|
Posted: Dec 30, 2011 - 09:42 PM |
|

Joined: Dec 30, 2011
Posts: 4
|
|
how to manipulate each bit of a unsigned char variable doing something like that?
#define bit0 variable_unsigned_char
#define bit1 variable_unsigned_char
#define bit2 variable_unsigned_char
#define bit3 variable_unsigned_char
#define bit4 variable_unsigned_char
#define bit5 variable_unsigned_char
#define bit6 variable_unsigned_char
#define bit7 variable_unsigned_char
//in code do something like that
bit0 = 1;
bit3 = 0;
?????????????????? |
|
|
| |
|
|
|
|
|
Posted: Dec 30, 2011 - 10:06 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
|
|
|
|
Posted: Dec 31, 2011 - 01:37 AM |
|

Joined: Dec 30, 2011
Posts: 4
|
|
I'm trying to do something like this.
//*************************************
ram far unsigned char RAM_used[5];
#define p0 RAM_used[0]
#define p1 RAM_used[1]
#define p2 RAM_used[2]
#define p3 RAM_used[3]
#define p4 RAM_used[4]
//than I'm trying to control every bit of p0,p1,p2,p3,p4
struct _8bits
{
unsigned bit0:1;
unsigned bit1:1;
unsigned bit2:1;
unsigned bit3:1;
unsigned bit4:1;
unsigned bit5:1;
unsigned bit6:1;
unsigned bit7:1;
}
#define p0_b0 p0.bit0
#define p0_b1 p0.bit1
...
matriz
-----> byte
-----------> bit
//for when I do something like this
p0_b0 = 1;
// bit p0_b0 = 1
// byte p0 = 0x01
// RAM_used[0] = 0x01
//because, sometimes I will modify a single bit, sometimes the entire byte and the entire RAM too.
//for writing the EEPROM, I used a pointer to RAM_used;
//for some situations I move some value to the byte
//and for rapidly actions I set the bit
//I'm having some troubles... everything that I try generate a error....
HELP! |
|
|
| |
|
|
|
|
|
Posted: Dec 31, 2011 - 02:37 AM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
|
Code:
struct _8bits
{
unsigned bit0:1;
unsigned bit1:1;
unsigned bit2:1;
unsigned bit3:1;
unsigned bit4:1;
unsigned bit5:1;
unsigned bit6:1;
unsigned bit7:1;
}
First, this requires a ";" at the end of it. Second, once you define it, you never use it (just putting .bit0 after some random variable will not work). Third, stop using macros until you actually know how to code. Using macros at this point can only introduce more errors than you already have. |
_________________ Regards,
Steve A.
The Board helps those that help themselves.
|
| |
|
|
|
|
|
Posted: Dec 31, 2011 - 05:15 AM |
|

Joined: Dec 30, 2011
Posts: 4
|
|
yeahhh! I did it!
Let's pass to other guys! ;D
Code:
//***************************************************************************************
/*
======================================
#define var (*(type*) &address)
======================================
1.create unsigned char with fix address in ram
#define var_A (*(unsigned char*) 0x10)
2.create unsigned char into the RAM_test[0]
#define var_B (*(unsigned char*) &RAM_test[0])
2a.It looks like crazy because you already created the matrix, so, do that (SAME THING)
#define var_B RAM_test[0] // <----
3.create a struct into the RAM_test[0]
typedef union
{
unsigned char byte;
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;
};
} estrutura;
//************
#define var_C (*(estrutura*) &RAM_test[0])
/*************
****** bit:field wide has to be the same wide of RAM_test[0] ******
OBS.: var_C full access variable
>>to access it value
var_C.byte
>>to access a single bit
var_C.bit0
//for make it more easily
#define vb0 var_C.bit0
#define vb1 var_C.bit1
#define vb2 var_C.bit2
#define vb3 var_C.bit3
#define vb4 var_C.bit4
#define vb5 var_C.bit5
#define vb6 var_C.bit6
#define vb7 var_C.bit7
//example
vb0 = 1; //bit
var_C.byte = 0x01; //byte
RAM_test[0] = 0x01; //matrix
*/
|
|
|
| |
|
|
|
|
|
Posted: Dec 31, 2011 - 06:46 AM |
|

Joined: Nov 17, 2004
Posts: 13839
Location: Vancouver, BC
|
|
|
Code:
1.create unsigned char with fix address in ram
#define var_A (*(unsigned char*) 0x10)
And how do you know that this does not stomp on something that is already at that address?
What are var_A and var_B for when you never use them?
Where do you ever define RAM_test?
Quote:
//for make it more easily
The only thing that I see that it does is obfuscate the code. |
_________________ Regards,
Steve A.
The Board helps those that help themselves.
|
| |
|
|
|
|
|
Posted: Dec 31, 2011 - 12:49 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| I don't get it - I gave a link back to danni's excellent sbit.h and you still battle on in this half baked attempt to replicate it - why? |
_________________
|
| |
|
|
|
|
|
Posted: Mar 12, 2012 - 05:28 PM |
|

Joined: Feb 14, 2012
Posts: 60
|
|
#define READ(port,pin) PIN ## port & (1<<pin)
Can anyone explain how this one works
and is it possible to make one that reads when using pullup resistor on pin, Not sure if this one does it.
Is this a valid statement if(Read(port,pin) == 1)
 |
|
|
| |
|
|
|
|
|
Posted: Mar 12, 2012 - 05:40 PM |
|


Joined: Jan 12, 2002
Posts: 7829
Location: Canada
|
|
the macro uses the past operator to join the text PIN with whatever value is in 'port' thus if you said read(A, 1) the intermediate stage is "PIN ## A" which is converted to "PINA".
There is no difference in reading a PIN register whether the pullups are enabled or not, so the statement works equally as well in both cases.
Unfortunately your if statement does not work, because the result of the read is the setting of the bit in it's natural position, not in the 1's position. [unless reading pin 0].. you can test for 0, but not 1 like that. Consider the result to be boolean, where 0=false, and any non-zero value is true.
if you want 1 or 0, you can sue a little obfuscated c trickery.
if(!!Read(port,pin) == 1)
I'll leave it to you to figure that one out  |
|
|
| |
|
|
|
|
|
Posted: Mar 12, 2012 - 05:42 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Or just drop the ==1, anything non-zero is true. hence:
Code:
if (Read(port,pin)) {
But why not use danni's macros:
http://www.avrfreaks.net/index.php?name ... 728#835728
then you can:
Code:
#define SENSOR PIN_B3
if (SENSOR) {
which seems more readable to me than having to invoke some Read() macro. |
_________________
|
| |
|
|
|
|
|
Posted: Mar 12, 2012 - 05:57 PM |
|

Joined: Feb 14, 2012
Posts: 60
|
|
Would work but I can't use that statement, I just wanted to learn how to use Read, my sensor values will come from the adc so I would just use the standard
Code:
If(sensor_Value (operator) WHATEVER_VALUE)
{
do this
}
thanks anyways, I guess it would work if I was using digital sensors maybe?
One question can you do a double define;
for example
Code:
#define READ(port,pin) PIN ## port & (1<<pin)
#define LED_CHECK READ(A,1)
Does that make sense, so whenever I want to check led status I just
Code:
if(LED_CHECK){}
I guess it's same as danni's macro, just more crap |
|
|
| |
|
|
|
|
|
Posted: Mar 28, 2012 - 04:40 AM |
|

Joined: Aug 24, 2009
Posts: 21
|
|
Hi,
I'm new to the assembly
could you explain these instructions (in the datasheet, USART section)
Code:
/* Enable receiver and transmitter */
UCSRnB = (1<<RXENn)|(1<<TXENn);
/* Set frame format: 8data, 2stop bit */
UCSRnC = (1<<USBSn)|(3<<UCSZn0);
I don't know how to use the left shift operator to set these bits
Thanks,
Mahyar |
|
|
| |
|
|
|
|
|
Posted: Mar 28, 2012 - 09:35 AM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
I don't know how to use the left shift operator to set these bits
Suggest you read the thread:
Bit manipulation 101
in Tutorial Forum which will explain everything.
.... Oh, wait a minute ...
OK so which bit of the explanation in this thread did you not understand exactly? |
_________________
|
| |
|
|
|
|
|
Posted: Mar 28, 2012 - 05:49 PM |
|

Joined: Aug 24, 2009
Posts: 21
|
|
I sort of get it,
but to make sure:
Code:
/* Set frame format: 8data, 2stop bit */
UCSRnC = (1<<USBSn)|(3<<UCSZn0)
it means shift 1 to the left for USBSn times (as USBSn is bit no.3 in UCSRnC register, we shift 1, 3 times and get 00001000)
the same pattern for UCSZn0(bit no.1) provides us 00000110
Is it correct?
another question is why we write 1 in UCSZn0 and UCSZn1 for the USART? (the code is from datasheet, page 177, mega1284p)
because datasheet says the initial values for these bits are set to 1 by default.
(register in page 191 )
Thanks
Mahyar |
|
|
| |
|
|
|
|
|
Posted: Mar 28, 2012 - 06:08 PM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
Is it correct?
You got it. But I doubt you want to set USBS as almost always you just want 1 stop bit.
Quote:
another question is why we write 1 in UCSZn0 and UCSZn1 for the USART? (the code is from datasheet, page 177, mega1284p)
because datasheet says the initial values for these bits are set to 1 by default.
(register in page 191 )
Yup it's quite ridiculous isn't it (even worse on CPUs that use the URSEl bit which makes it more complex). 99% of users will always want the 8N1 default. |
_________________
|
| |
|
|
|
|
|
Posted: Apr 02, 2012 - 04:06 AM |
|

Joined: Mar 31, 2012
Posts: 1
|
|
| really nice instruction for newbies like me |
|
|
| |
|
|
|
|
|
Posted: Apr 19, 2012 - 02:01 AM |
|

Joined: Mar 29, 2012
Posts: 24
|
|
|
clawson wrote:
I think this tutorial is trying to be as generic as possible. Not all the AVR C compilers have all the bit names defined in the header files for each AVR part so
Code:
TCCR1B |= (1 << CS10);
won't necessarily work on all compilers.
Grat Tutorial Dean!! Im reading all of your tutos from your web!!
About the part of the code wrote here by clawson, if some one is able to answer a silly question...
why do you use |= ?? I download al the example codes and they work the seam without it. I really dont understand why the OR operation bet (1 << CS10) and TCCR1B ... and there's other thing like in the case of:
Code:
TCCR1B |= (1 << CS10) | (1 << CS12)
prescaling to 1024 (ATMEGA2560)
Why all the ORs. Didt understand well that part.
Thanks for the time you spend reading.
Alex |
|
|
| |
|
|
|
|
|
Posted: Apr 19, 2012 - 11:04 AM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
why do you use |= ??
But that is EXACTLY what's explained in this very tutorial? I'm not going to repeat the text of the tutorial here so I suggest you go back to page 1 and re-read it until you understand what it is saying.
Maybe it helps to add that:
1) OR and only switch additional bits from 0 to 1
2) AND can only switch additional bits from 1 to 0
3) << means move the thing on the left the number of places given on the right. If the thing on the left is just 1 then it's saying "form a number with 1 in bit position <whatever is on the right>". This therefore converts a bit number to a bit mask. |
_________________
|
| |
|
|
|
|
|
Posted: Jul 24, 2012 - 02:16 PM |
|

Joined: Jul 19, 2012
Posts: 26
|
|
Hi, thanks for the superb tutorial.
I am having a little bit of trouble wrapping my head around the code:
Code:
if(foo & 0x80)
{
}
So this checks if foo's bit number 7 is a 1 or 0, right?
Supposing foo was, for example, 10100110 and we use the & operator with 10000000 as shown in your if statement above.
Now, this will return 10000000, right? But in order for the if statement to execute, shouldn't the code in the brackets result in a value of 1? I suppose it makes sense if the if statement executes for any value greater than zero.
Sorry if I am not explaining my problem well, I hope you understand.
Thanks again! |
|
|
| |
|
|
|
|
|
Posted: Jul 24, 2012 - 02:26 PM |
|

Joined: Dec 30, 2004
Posts: 8765
Location: Melbourne,Australia
|
|
| True is a non-zero value, false is zero. Therefore, since the result is non-zero, the code in the brackets will execute. You might want to read up on the difference between logical and bitwise operstors whichis covered in any half decent book on C. |
|
|
| |
|
|
|
|
|
Posted: Jul 24, 2012 - 02:48 PM |
|

Joined: Jul 19, 2012
Posts: 26
|
|
| Got it, thanks. Makes perfect sense now. And I will read up on that to refresh my memory too. |
|
|
| |
|
|
|
|
|
Posted: Aug 09, 2012 - 10:40 AM |
|

Joined: Oct 12, 2011
Posts: 16
|
|
Hi, Great tutorial and how I got to get to grips with bit manipulation, still v new to it all though.
Now I am writing a program with several I/Os and I used the SBIT posted and mentioned a few times in this Tutorial.
I used it in places for control of pins eg
Code:
#define VALVE SBIT(PORTD,7)
#define ALARM SBIT (PORTB,2)
also I defined ON=1 and OFF=0
so something like
Code:
ALARM=OFF;
seems to work.
Then I needed some flags for telling me various states of things so I added a register
Code:
volatile unsigned char CONTROL_REG;
and thought I could use this eg
Code:
#define Start_FLAG SBIT(CONTROL_REG,0)
so
Code:
if (Start_FLAG ==ON)
{ }
.
I saw at the bottom of the entry in the TUT that
Quote:
Naturally this macro can also be used for internal flag variables, not only for IO registers.
Now when I compile with Studio 6 I get warnings where I refer to the regester eg
Quote:
dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
If I compile again they go away.
Please can anyone tell me if I am doing something daft and help me understand what the warning means Thanks
Mark |
|
|
| |
|
|
|
|
|
Posted: Aug 09, 2012 - 11:36 AM |
|


Joined: Jul 18, 2005
Posts: 62290
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
In the miscellaneous section of AVR/GNU C Compiler options you may find it illuminating to add --save-temps. When you build the output directory (probably GccApplicationN\Debug) will then contain a foo.i and foo.s for each foo.c in the build. If I build:
Code:
#include <avr/io.h>
#include "sbit.h"
#define OFF 0
#define ON 1
volatile unsigned char CONTROL_REG;
#define Start_FLAG SBIT(CONTROL_REG,0)
int main(void) {
while(1) {
if (Start_FLAG == ON) {
PORTB = 0x55;
}
}
}
and then study the .i file I find that the macros have expanded to be:
Code:
if (((*(volatile struct bits*)&CONTROL_REG).b0) == 1) {
If you read this interesting page:
http://blog.worldofcoding.com/2010/02/s ... blems.html
You'll understand the issue. As it says there one "fix" is to modify sbit.h to have:
Code:
struct bits {
uint8_t b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
} __attribute__((__packed__, __may_alias__));
but I don't think adding "__may_alias__" in that is really much different from switching off the -Wstrict-alias option.
The bottom line is that it's just a warning of something you may need to be concerned about but as the struct is clearly the same size as the unsigned char I don't really see an issue with it. |
_________________
|
| |
|
|
|
|
|
Posted: Aug 09, 2012 - 02:57 PM |
|

Joined: Oct 12, 2011
Posts: 16
|
|
Thanks again for your help,
I think I get it, makes for interesting reading, a little bit over the head of me as a novice. They say a little knowledge is dangerous!
I'm still not sure if I should worry about it.
There seems to be conflicting opinnion in the blog. |
|
|
| |
|
|
|
|
|
Posted: Sep 25, 2012 - 03:57 PM |
|

Joined: Aug 06, 2008
Posts: 141
Location: Montréal, QC
|
|
I am using these defines for bit manipulation (source)
Code:
// Copyright (c) 2007 Roboterclub Aachen e.V.
#define PORT(x) _port2(x)
#define DDR(x) _ddr2(x)
#define PIN(x) _pin2(x)
#define REG(x) _reg(x)
#define PIN_NUM(x) _pin_num(x)
// use this block of macros in your code
#define RESET(x) RESET2(x)
#define SET(x) SET2(x)
#define TOGGLE(x) TOGGLE2(x)
#define SET_OUTPUT(x) SET_OUTPUT2(x)
#define SET_INPUT(x) SET_INPUT2(x)
#define SET_PULLUP(x) SET2(x)
#define IS_SET(x) IS_SET2(x)
#define SET_INPUT_WITH_PULLUP(x) SET_INPUT_WITH_PULLUP2(x)
#define _port2(x) PORT ## x
#define _ddr2(x) DDR ## x
#define _pin2(x) PIN ## x
#define _reg(x,y) x
#define _pin_num(x,y) y
#define RESET2(x,y) PORT(x) &= ~(1<<y)
#define SET2(x,y) PORT(x) |= (1<<y)
#define TOGGLE2(x,y) PORT(x) ^= (1<<y)
#define SET_OUTPUT2(x,y) DDR(x) |= (1<<y)
#define SET_INPUT2(x,y) DDR(x) &= ~(1<<y)
#define SET_INPUT_WITH_PULLUP2(x,y) SET_INPUT2(x,y);SET2(x,y)
#define IS_SET2(x,y) ((PIN(x) & (1<<y)) != 0)
In the code you then use the macro (you do not have to use the one ending with '2').
Code:
#define EnablePin C,1
#define lbuttonPin B,1
...
SET_OUTPUT(EnablePin);
SET_INPUT_WITH_PULLUP(lbuttonPin);
...
RESET(EnablePin);
...
SET(EnablePin);
...
if (IS_SET(lbuttonPin)) {...}
I prefer them to using sbit.h because you do not have to use DDR_ or PORT_ or PIN_, you just use the same name everywhere, wherever you set/reset/test/etc |
|
|
| |
|
|
|
|
|
Posted: Nov 02, 2012 - 05:22 AM |
|

Joined: Aug 26, 2011
Posts: 1
|
|
| Grateful information , I was following this information for 3 days, finally, I found it.... , thank you moderator |
|
|
| |
|
|
|
|
|
Posted: May 03, 2013 - 07:12 AM |
|


Joined: Apr 15, 2011
Posts: 11
Location: India
|
|
| Thanks to all freaks for this tutorial.This is like a gift for noobs like me. |
_________________ When you do ask questions, you may look stupid.
When you do NOT ask questions, you will STAY stupid.
|
| |
|
|
|
|
|