| Author |
Message |
|
|
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: 18520
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: 13815
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: 13815
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: 13815
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: 62220
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: 18520
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: 13815
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: 62220
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: 18520
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: 13815
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: 62220
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) |
_________________
|
| |
|
|
|
|
|