Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
danni
PostPosted: Mar 21, 2010 - 06:51 PM
Raving lunatic


Joined: Sep 05, 2001
Posts: 2496


We all know, how a port pin can be cleared:
Code:

PORTB &= ~(1<<PB3);


But then it can happen, that we make mistakes, e.g.:
Code:

PORTB &= ~1<<PB3;         // forget brackets
PORTB &= (1<<PB3);        // forget negation
PORTB &= !(1<<PB3);       // wrong negation


So using a macro can avoid mistakes:
Code:

#define   bit_clear_(x,y)      x &= ~(1<<y)         // clear a bit

bit_clear( PORTB, PB3);


But this was not really helpful, since we must always look on the schematic to know, which function has this pin.

So we can define further macros:
Code:

#define   bit_clear_(x,y)      x &= ~(1<<y)         // clear a bit

#define LED0_PORT PORTB
#define LED0_BIT PB3

bit_clear( LED0_PORT, LED0_BIT);


But this looks not fully nice, since we need always two defines for every pin.
If we try to write port and pin into a single define, we get an error message, that the argument count was different.
For such cases we can define a second macro to switch off the argument check:
Code:

#define   bit_clear(...)      bit_clear_(__VA_ARGS__)
#define   bit_clear_(x,y)      x &= ~(1<<y)         // clear a bit

#define   LED0      PORTB, PB3

bit_clear( LED0 );


This looks pretty nice, so we can write further macros to set and to read a bit:
Code:

#define   bit_set(...)      bit_set_(__VA_ARGS__)
#define   bit_set_(x,y)      x |= 1<<y         // set a bit
#define   bit_clear(...)      bit_clear_(__VA_ARGS__)
#define   bit_clear_(x,y)      x &= ~(1<<y)         // clear a bit
#define   bit_test(...)      bit_test_(__VA_ARGS__)
#define   bit_test_(x,y)      (!!(x & (1<<y)))      // test a bit


#define   LED0      PORTB, 0
#define   LED0_DDR   DDRB, 0
#define   KEY0      PINB, 2
#define   KEY0_PULLUP   PORTB, 2


#include <avr/io.h>


int main( void )
{
  bit_set( KEY0_PULLUP;      // pullup on
  bit_set( LED0_DDR );      // output

  for(;;){
    if( bit_test( KEY0 ))
      bit_set( LED0 );
    else
      bit_clear( LED0 );
  }
}



This looks better, but we can prettify it further.
We see, that we often need to access PORTx, DDRx and PINx registers together and then we need separate bit names for this.
But the address relation of these registers on the AVRs was constant, so we can define further macros to access different functions of a port pin and need only one definition on every port pin.
To do so, the definition was related to the PORTx register, even, we want to read the input register.
So we get finally the following macro definitions on this code example:
Code:

#define   bit_set(...)      bit_set_(__VA_ARGS__)
#define   bit_set_(x,y)      x |= 1<<y         // set a bit
#define   bit_clear(...)      bit_clear_(__VA_ARGS__)
#define   bit_clear_(x,y)      x &= ~(1<<y)         // clear a bit
#define   bit_test(...)      bit_test_(__VA_ARGS__)
#define   bit_test_(x,y)      (!!(x & (1<<y)))      // test a bit

/*** following macros related to the PORTx - register only !   ***/
/***                        ***/
#define   bit_dir_outp(...)   bit_dir_outp_(__VA_ARGS__)
#define   bit_dir_outp_(x,y)   *(&x-1) |= 1<<y         // access DDRx of PORTx !
#define   bit_dir_inp(...)   bit_dir_inp_(__VA_ARGS__)
#define   bit_dir_inp_(x,y)   *(&x-1) &= ~(1<<y)      // access DDRx of PORTx !
#define   bit_test_in(...)   bit_test_in_(__VA_ARGS__)
#define   bit_test_in_(x,y)   (!!(*(&x-2) & (1<<y)))      // access PINx of PORTx !


#define   LED0      PORTB, 0
#define   KEY0      PORTB, 2


#include <avr/io.h>


int main( void )
{
  bit_dir_inp( KEY0 );      // input
  bit_set( KEY0 );      // pullup on
  bit_set( LED0 );      // LED off
  bit_dir_outp( LED0 );      // output

  for(;;){
    if( bit_test_in( KEY0 ))
      bit_clear( LED0 );
    else
      bit_set( LED0 );
  }
}



Peter
 
 View user's profile Send private message  
Reply with quote Back to top
tubecut
PostPosted: Mar 25, 2010 - 10:14 PM
Resident


Joined: May 27, 2002
Posts: 737
Location: Alabama USA

I am not familiar with: (__VA_ARGS__).
Is that for the GCC compiler only?
I currently use ICCAVR.

Thanks.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
danni
PostPosted: Mar 25, 2010 - 11:21 PM
Raving lunatic


Joined: Sep 05, 2001
Posts: 2496


If your compiler meet the C99 standard, it should support variadic macros:

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


Peter
 
 View user's profile Send private message  
Reply with quote Back to top
Koshchi
PostPosted: Mar 25, 2010 - 11:23 PM
10k+ Postman


Joined: Nov 17, 2004
Posts: 13814
Location: Vancouver, BC

Quote:
I am not familiar with: (__VA_ARGS__).

It is the preprocessor equivalent to "..." used for representing a variable number of arguments to a macro.

_________________
Regards,
Steve A.

The Board helps those that help themselves.
 
 View user's profile Send private message  
Reply with quote Back to top
Bingo600
PostPosted: May 11, 2010 - 07:29 AM
Raving lunatic


Joined: Apr 25, 2004
Posts: 3808
Location: Denmark

@Peter

Nice ..

But AFAIK you "Will be bitten" if using PORTF on a M64/128 , as &DDRF isn't &(PORTF-1)

You could "ifdef" you out of it , or emit a warning if it's a M64/128

/Bingo
 
 View user's profile Send private message  
Reply with quote Back to top
gromit64
PostPosted: May 14, 2010 - 12:37 AM
Newbie


Joined: Nov 26, 2009
Posts: 1


hello all

maybe a safer way for this could be :

Code:

#define   bit_set(...)       bit_set_(__VA_ARGS__)
#define   bit_set_(x,y)      PORT ## x |= 1<<y
#define   bit_clear(...)     bit_clear_(__VA_ARGS__)
#define   bit_clear_(x,y)    PORT ## x &= ~(1<<y)
#define   bit_test(...)      bit_test_(__VA_ARGS__)
#define   bit_test_(x,y)     (!!(PORT ## x & (1<<y)))

#define   bit_dir_outp(...)  bit_dir_outp_(__VA_ARGS__)
#define   bit_dir_outp_(x,y) DDR ## x |= 1<<y
#define   bit_dir_inp(...)   bit_dir_inp_(__VA_ARGS__)
#define   bit_dir_inp_(x,y)  DDR ## x &= ~(1<<y)
#define   bit_test_in(...)   bit_test_in_(__VA_ARGS__)
#define   bit_test_in_(x,y)  (!!(PIN ## x & (1<<y)))

usage :
#define   LED0      B, 0
#define   KEY0      B, 2


it uses the concatenation feature of the preprocessor (##) to replace with the real names of registers (DDRx and so on).

But I admit it forces to define our pins in a less pretty way (#define LED0 B, 0 instead of "PORTB, 0")
 
 View user's profile Send private message  
Reply with quote Back to top
danni
PostPosted: May 19, 2010 - 01:29 PM
Raving lunatic


Joined: Sep 05, 2001
Posts: 2496


Bingo600 wrote:
But AFAIK you "Will be bitten" if using PORTF on a M64/128 , as &DDRF isn't &(PORTF-1)


Yes, you are right. Exclamation

But I assume, a new user start not to program the old M64/128.

And on the pin compatible ATmega1281 this rule fits again. Very Happy


Peter
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits