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

Go To Last Post
237 posts / 0 new

Pages

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

Quote:

As we all know

Exchange "some" for "all" and we're closer to the actual situation.

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

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

 

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

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

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!

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

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:

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

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

SFR |= (1 << bit);

but then see variants of:

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

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

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

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

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

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

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...


if (!( foo & 0x80 )) 
{ 
  ... 
} 

:D

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

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);

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

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.

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

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;

??????????????????

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

Quote:

how to manipulate each bit of a unsigned char variable doing something like that

You came to the wrong tutorial, try this one:

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

Having said that it's pretty clear you haven't even read the whole of this thread:

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

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

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!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
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.

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

yeahhh! I did it!

Let's pass to other guys! ;D

//***************************************************************************************
/*
======================================
#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

*/

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
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.

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

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?

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

#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)

:?:

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

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 ;)

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

Or just drop the ==1, anything non-zero is true. hence:

if (Read(port,pin)) {

But why not use danni's macros:

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

then you can:

#define SENSOR PIN_B3

if (SENSOR) {

which seems more readable to me than having to invoke some Read() macro.

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

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

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

#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

if(LED_CHECK){}

I guess it's same as danni's macro, just more crap

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

Hi,

I'm new to the assembly
could you explain these instructions (in the datasheet, USART section)

/* 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

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

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?

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

I sort of get it,
but to make sure:

/* 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

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

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.

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

really nice instruction for newbies like me

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

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

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:

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

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

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 ". This therefore converts a bit number to a bit mask.

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

Hi, thanks for the superb tutorial.

I am having a little bit of trouble wrapping my head around the 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!

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

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.

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

Got it, thanks. Makes perfect sense now. And I will read up on that to refresh my memory too.

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

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

#define VALVE   SBIT(PORTD,7)
#define ALARM	SBIT (PORTB,2)

also I defined ON=1 and OFF=0
so something like

ALARM=OFF;

seems to work.
Then I needed some flags for telling me various states of things so I added a register

volatile unsigned char CONTROL_REG;

and thought I could use this eg

#define Start_FLAG SBIT(CONTROL_REG,0)

so

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

markah

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

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:

#include 
#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:

  if (((*(volatile struct bits*)&CONTROL_REG).b0) == 1) {

If you read this interesting page:

http://blog.worldofcoding.com/20...

You'll understand the issue. As it says there one "fix" is to modify sbit.h to have:

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.

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

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.

markah

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

I am using these defines for bit manipulation (source)

// 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').

#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

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

Grateful information , I was following this information for 3 days, finally, I found it.... , thank you moderator

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

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.

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

hello
i am new in avr programing.

it is not good that we search 2 or 3 weeks to find out what << or >> do in avr-gcc.

please tell me:
1- what does
<< bit LEFT SHIFT
>> bit RIGHT SHIFT mean?
what is this output?

0b11110000 << 4
output:
0b00001111 or 0b00000000

2- is there any official web site for avr-gcc to help us what is keywords, operators and etc in avr-gcc?

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

Quote:

it is not good that we search 2 or 3 weeks to find out what << or >> do in avr-gcc.


Surely if you type "C << operator" into Google you come to:

http://en.wikipedia.org/wiki/Ope...

On that page it explains it is a "bitwise left shift" and that is a link to:

http://en.wikipedia.org/wiki/Bit...

"See Also" on that page leads you to:

http://en.wikipedia.org/wiki/Bit...

and apart from anything else how on earth are you learning to program in C if you don't have a manual?

2) none of this is specific to avr-gcc. It is the C Programming Language. It wil be the same in any C compiler that adheres to the C Standard. Most people by a copy of this:

http://en.wikipedia.org/wiki/The...

because it explains exactly how C will operate no matter which C compiler you use.

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

Quote:
it is not good that we search 2 or 3 weeks to find out what << or >> do in avr-gcc.

1. Welcome to AVRfreaks!

2. Your remark shows that you need to trim your search skills. 2 or 3 weeks to find that tutorial is your problem.

3. You have been searching "for 2 or 3 weeks", but yet you joined AVRfreaks today.. :roll:

Quote:
is there any official web site for avr-gcc to help us what is keywords, operators and etc in avr-gcc?

The shift operators, as has been remaked by clawson above, are not specific to avr-gcc. They are standard C. Get a good C book. Read. (Or would you expect avr-gcc documentation to hold information about the if- and while-statements, on assignments, on the assignment operator etc too? Of-course bot. The avr-gcc documentation coers what is specific to avr-gcc. For standard C it is any document describing standard C. For GCC specifics it is the GCC documentation. For avr-gcc, most of it is also in the GCC documentation. The GCC documentation is available on The Web. Google it.)

Also, avr-gcc/avrlibc is the work of devoted voluntaries. They do not get paid. You either more or less accept the state of those tools and the documentation that come with them, or you pay money to buy a commercial compiler/IDE and support for it. There is no such thing as a free lunch.

If you not only are new to AVRs and avr-gcc but also to the C programming language then you will have a learning experience ahead of you. There will be no one-stop solution to satisfy all your information needs. You will need at least these:

1. A good C book, or tutorial on the net.

2. The avr-gcc/avrlibc help. If you are using Atmel Studio and the avr-gcc that comes with that then the help is on your hard disk and integrated in Atmel Studio.

3. The data sheet for your AVR model.

4. Tutorials etc on programming AVRs. AVRfreaks have a whole forum devoted to tutorials. Get yourself acquainted with the contents of that forum, and it will serve you well.

5. Help on The Web by unpaid voluntaries. We are here. Your job is to ask your questions in a manner that gets us interested in your problem. Present clear and complete information. Read and give feedback on advice that is given. (A whining post like yours above is not the best way to start out...) By and large the AVRfreaks community will treat you as you treat it.

Once again, welcome to AVRfreaks!

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

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

 

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

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

thank you all.
your links are my answer exactly.

finally i write my first project and test it in VMLAB.
so happy.

I was programing Turbo C and Pascal in 1996-2002.
but i studied management in university.

I try to program Atmega16.
where can i find my answers?

my questions are about timer:
how can i turn timer on?
how can i stop timer?
how can i enable timer overflow interrupt?
how should be timer overflow interrupt procedure?

thank you again.

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

Quote:
where can i find my answers?

my questions are about timer:

Right here in the tutorial section.

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:

Right here in the tutorial section.

Combined with the atmega16 datasheet.

If you have further questions about this can you start a new thread in AVR Forum. The purpose of this thread is simply for corrections and clarifications of issues about Bit Manipulation that are outlined in the first post - not timers.

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

noob need help.
can tell me what the different in a simple way

PORTB |= (1<<6);
PORTB |=  (1 << PB6);
PORTB |=  (1 << PORTB6);
PORTB |= _BV(6);
PORTB |= _BV(PB6);
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

noob need help.

First thing to do: Shift to the first page and read the tutorial. If someone put time into that then do them the honor of reading it. Then ask specific questions, referring to that text, on what you don't understand in it.

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

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

 

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

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

Quote:
can tell me what the different in a simple way
No difference whatsoever. Once the pre-processor is done with parsing the macros and resolving the constants, they all end up as:

PORTB |= 0x40;

Regards,
Steve A.

The Board helps those that help themselves.

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

JohanEkdahl wrote:
Quote:

noob need help.

First thing to do: Shift to the first page and read the tutorial. If someone put time into that then do them the honor of reading it. Then ask specific questions, referring to that text, on what you don't understand in it.

i'm sorry, but i have read the 1st page, and i don't have the answer, i mean why do program have many way to write that code (PORTB |= 1<<PB1,etc) if only have one purpose?

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

Quote:
i mean why do program have many way to write that code (PORTB |= 1<<PB1,etc) if only have one purpose?

The << operator is a part of the C language itself.

The rest of the variations comes not form the C language as such but from what different people have written in header files that you include.

So, to set bit 6 in PORTB you write

PORTB |= (1<<6);

E.g. some people think that the use of the << operator is not pretty, or understandable (or whatever) so they hide it behind a macro that they define like so:

#define _BV(bitnumber) (1<<bitnumber)

And can then write

PORTB |= _BV(6);

Now, the use of the explicit '6' here might not seem so troublesome, but for other registers where bits have special meanings it will make for obscure code if the bit number is given as a number. So there are definitions of bit numbers for all the bits of all special purpose registers (the ones where you control UARTS, timers etc..).

If a Timer/Counter Control Register has a bit at position 4 for Timer Overflow Interrupt Enable then you might write

TCCR |= 1<<4;

but it would be much clearer to code e.g.

TCCR |= 1<<TOIE;

This has then been worked back to the digital I/O ports where the names of those bit numbers simply become e.g. PB0, PB1, PB2...

So now someone can code

PORTB |= (1<<PB6);

or

PORTB |= _BV(PB6);

Again, all variation here is due to what is coded in header files. They are not defined in the C language as such.

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

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

 

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

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

To this specific part of the question:

PORTB |= (1<<6);
PORTB |=  (1 << PB6);
PORTB |=  (1 << PORTB6); 

the choice amongst those is purely down to personal taste. If you take a typical device header file (I used mega16) and look at the definitions of bit 6 relating to PORTB it has all of:

#define PINB6   6
#define DDB6    6
#define PB6     6

(no definition of PORTB6 in fact - just PB6) so yuou can use anything that will expand out to be "6" in either (1<<n) or _BV(n) or whatever other way you want to expand it out to be a bit mask. So you could use:

PORTB |= (1 << DDB6);
PORTB |= _BV(PINB6);

Sure those bits are supposedly for the DDR register and the PIN register but they are all 6 so any of them could be used. My own personal preference in fact is always to use the Ppn form so PB6 or whatever and use it for all three when accessing any of PORTB, PINB or DDRB. But each to their own - you may choose something else.

BTW there's nothing magic in any of this a pre-processor macro is just a string substitution so you can use anything that would equate to 6 in order to access bit 6. If you look at the iom16.h file it has:

C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.2.1002\avr8-gnu-toolchain\avr\include\avr>grep #define iom16.
h | grep -w 6
#define TWS6    6
#define TWA5    6
#define ADSC    6
#define REFS0   6
#define ACBG    6
#define TXCIE   6
#define TXC     6
#define SPE     6
#define WCOL    6
#define PIND6   6
#define DDD6    6
#define PD6     6
#define PINC6   6
#define DDC6    6
#define PC6     6
#define PINB6   6
#define DDB6    6
#define PB6     6
#define PINA6   6
#define DDA6    6
#define PA6     6
#define UMSEL   6
#define WGM20   6
#define ICES1   6
#define COM1A0  6
#define ADTS1   6
#define WGM00   6
#define ISC2    6
#define SE      6
#define TWEA    6
#define RWWSB   6
#define TOV2    6
#define TOIE2   6
#define INTF0   6
#define INT0    6
#define TIMER1_COMPA_vect_num   6

So any of those thing *could* be used. You could write:

PORTB |= (1 << TXCIE);

and it would still set bit 6. You could even use:

PORTB |= (1 << TIMER1_COMPA_vect_num);

I'm not suggesting you do this (unless you deliberately wanted to make the code very confusing for the reader!) but simply pointing out that there's nothing special about where the 6 you use comes from.

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

Interesting Tutorial. I am going to have to include a lot of this into what I am doing. Makes C so much easier to work with.

EDIT:

In these defines:

Quote:
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m) ((p) ^= (m))

Is the 'p' and 'm' a standard 'c' tag, or could I use 'x' and 'y' in their place for example?

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

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

jgmdesign wrote:
In these defines:
Quote:
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m) ((p) ^= (m))

Is the 'p' and 'm' a standard 'c' tag, or could I use 'x' and 'y' in their place for example?

You can use whatever you like, even whole words like:

#define bit_set(port,mask) ((port) |= (mask))

Does this perhaps give you an idea why 'p' and 'm' were originally chosen? ;-)

Stefan Ernst

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

Quote:

a standard 'c' tag,

Just to be a pedant but this is not C. This is the pre-processor. A lot of people have a lot of trouble trying to see the distinction between the two. When you type:

bit_set(0x1234, 0x40);

in your code the C compiler never "see" bit_set() nor p nor m. All it sees is:

((0x1234) |= (0x40));

The pre-processor has already "eaten" all the bit_set(p,m) stuff before the .i file is even seen by the C compiler.

It can be enlightening to add --save-temps to your compiler options then for a foo.c file you will find that a foo.i file is generated. If you used:

#include 

#define bit_set(p,m) ((p) |= (m))
#define BIT(x) (0x01 << (x))

int main(void) {
	bit_set(PORTB, BIT(5));
	while(1) {
	}	
}

the C compiler sees:

int main(void) {
 (((*(volatile uint8_t *)((0x05) + 0x20))) |= ((0x01 << (5))));
 while(1) {
 }
}

(it's because you don't usually want to type such convoluted nonsense that you use pre-processor macros in the first place - most of the above actually comes from "PORTB" which is also a macro).

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

I 'C'. ;)

Thanks

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

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

JohanEkdahl wrote:
Quote:

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

This code test if bit is not set?


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

1:

1<<PD0

make a bitmask 00000001.

2:

~(1<<PD0)

negates every bit in that mask so you get 11111110

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

What you want is

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

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

An alternative way would be to

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

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

I read this several times and although I thought it made sense I of course must be missing something.
In the code below I want to upon start up display two lines of text. Which worked. I then want to look at portb.0 and if it is pressed display what is inside the {}

I tried using the example above but it does not appear to get teh unit to change the screen. I know I am doing something wrong because when I hit pause during debugging, the disassembly window pops up. I am using AS6 and an STK600 with a MEGA2560

#include 
#include 
#include 
#include 
#include "lcd.h"



void avrinit(void)
{
	DDRA = 0xFF;	//porta all outputs for LCD
	PORTB = 0xFF;
}
int main(void)
{	avrinit();
	lcd_init(LCD_DISP_ON_CURSOR_BLINK);
	
	 /* put string to display (line 1) with linefeed */
	 lcd_puts("LCD Test Line 1\n");

	 /* cursor is now on second line, write second line */
	 lcd_puts("Line 2");

while (~(PIND) & (1<<PD0))
{lcd_clrscr();
	lcd_puts("AVRfreaks");
	

}
}

What I end up with is the screen scrolling through both sets of texts at a very high rate. And if I hit pause, I get the disassembly window letting me know I screwed up. I am gonna work on this for a few more hours before bed.

EDIT:
I GOT IT TO WORK!!
I found my boo boo's with a lot of reading and google :? but it works now.

#include 
#include 
#include 
#include 
#include "lcd.h"



void avrinit(void)
{
	DDRA = 0xFF;	//porta all outputs for LCD
	PORTB = 0xFF;
}
int main(void)
{	avrinit();
	lcd_init(LCD_DISP_ON_CURSOR_BLINK);
while(1)
{ 
	

if(bit_is_set(PINB,0))	
	{ lcd_clrscr();
		/* put string to display (line 1) with linefeed */
	 lcd_puts("LCD Test Line 1\n");

	 /* cursor is now on second line, write second line */
	 lcd_puts("Line 2");
	 while(bit_is_set(PINB,0))
	 {
	 }
	 
	}
	
if(bit_is_clear(PINB,0))
{lcd_clrscr();
	lcd_puts("AVRfreaks");
	while(bit_is_clear(PINB,0))
	{
	}

}

}
}

I know the indentation sucks. I figured that out after I lost track of my {}'s. But I needed to hold after the screen did it's write. In other words, the screen kept refreshing, so I insert the WHILE statements and there it goes.
I have to admit I have some more reading to do as I found a post elsewhere using the Bit_is_set/Bit_is_clear shortcut as opposed to the & != stuff that made it all happen. I will need to look into how those two statements work better.

Ok off to bed. 3:30am is fast approaching

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

Pages