Macro example for new people

I know using #define is frowned on but I thought this might be interesting to new users.
Here is how you can define a macro, in this case TOGGLEd0 thru d19, and use it in an Arduino sketch.

// macroUNO.h
// This file goes into the “C:\Users\YOURUSER\Documents\Arduino\libraries\macroUNO”  folder.
//
// These Macros can be used with Arduino UNO board
//
// NOTE:
// ***** Macros may have to be redefined for other types of Arduino boards *****
//
// Macro Format:
// #define XXXXX  YYYYY
//   where XXXXX = the macro name you what to define (might want to use capitals)
//   where YYYYY = the code that will be substituted prior to compiling
// #define TOGGLEd2 PORTD ^= B00000100
//         TOGGLEd2 = the macro name
//         PORTD ^= B00000100 = the microcontroller code   
//
// Toggle port pins 0-7
// Port D
//#define TOGGLEd0 PORTD^= B00000001 // Toggle digital pin D0 Shared with USB RX
//#define TOGGLEd1 PORTD^= B00000010 // Toggle digital pin D1 Shared with USB TX
#define TOGGLEd2  PORTD ^= B00000100 // Toggle digital pin D2
#define TOGGLEd3  PORTD ^= B00001000 // Toggle digital pin D3
#define TOGGLEd4  PORTD ^= B00010000 // Toggle digital pin D4  
#define TOGGLEd5  PORTD ^= B00100000 // Toggle digital pin D5  
#define TOGGLEd6  PORTD ^= B01000000 // Toggle digital pin D6  
#define TOGGLEd7  PORTD ^= B10000000 // Toggle digital pin D7  
  
// Toggle port pins 0-5            
// Port B                          
#define TOGGLEd8  PORTB ^= B00000001 // Toggle digital pin D8
#define TOGGLEd9  PORTB ^= B00000010 // Toggle digital pin D9
#define TOGGLEd10 PORTB ^= B00000100 // Toggle digital pin D10
#define TOGGLEd11 PORTB ^= B00001000 // Toggle digital pin D11
#define TOGGLEd12 PORTB ^= B00010000 // Toggle digital pin D12
#define TOGGLEd13 PORTB ^= B00100000 // Toggle digital pin D13
  
// Toggle port pins 0-5            
// Port C                          
#define TOGGLEd14 PORTC ^= B00000001 // Toggle digital pin D14 A0
#define TOGGLEd15 PORTC ^= B00000010 // Toggle digital pin D15 A1
#define TOGGLEd16 PORTC ^= B00000100 // Toggle digital pin D16 A2
#define TOGGLEd17 PORTC ^= B00001000 // Toggle digital pin D17 A3
#define TOGGLEd18 PORTC ^= B00010000 // Toggle digital pin D18 A4
#define TOGGLEd19 PORTC ^= B00100000 // Toggle digital pin D19 A5

//

This is a typical sketch:

#include <macroUNO.h>

/*
  TogglePin
  Toggles the condition of an O/P pin.
  This example code is in the public domain.
 */
 
// Pin 13 has a LED connected on most Arduino boards.
// give it a name:
int led = 13;

// the setup routine runs once when you press reset:
void setup()
{                
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);     
}
//****************** END of setup() *******************

// the loop routine runs over and over again forever:
void loop()
{                        
  TOGGLEd13;   // This toggles pin D13.       TOGGLEd2 through d19 are implemented
                        //                                      TOGGLEd0 and TOGGLEd1 are not defined
  delay(2000);   //  Wait a bit
  
}
//****************** END of loop() *******************

That would only be valid for the Arduino Uno and alike.
I rather not use number '14' for 'A0'.

// untested example for all pins of all Arduinos
#define TOGGLE(x) digitalWrite(x, digitalRead(x) ? LOW : HIGH)

Yes, thank you, that works too.
I was just introducing the idea of macros.

As I wrote this was an example for the UNO, you would have to have a macroUNO.h and a macroMEGA.h
One for each different board if you included hardware specific code.
Obviously TOGGLE(x) would be cross platform and TOGGLEd13 is for the UNO board.

TOGGLE(13) gives "Binary sketch size: 1,238 bytes (of a 32,256 byte maximum) "

TOGGLEd13 gives "Binary sketch size: 892 bytes (of a 32,256 byte maximum) " the advantage of direct port manipulation.

Macros are not necessary...

static void TOGGLEd13( void ) { PORTB ^= B00100000; }

const uint8_t led = 13;

void setup( void )
{
  pinMode(led, OUTPUT);     
}

void loop( void )
{
  TOGGLEd13();   // This toggles pin D13.       TOGGLEd2 through d19 are implemented
  delay(2000);   //  Wait a bit
}

Binary sketch size: 840 bytes (of a 32,256 byte maximum)

Macros are not necessary...

Thank you.
You are correct of course, I was just introducing the concept here for new people.

LarryD:
You are correct of course, I was just introducing the concept here for new people.

I understand. I was just pointing out that the GCC optimizer works well enough, in many cases, to eliminate the need to use macro-functions.

And to just wander off-topic a bit more, you can toggle more easily:

static void TOGGLEd13 (void) { PINB = 0b00100000; }

const byte led = 13;

void setup( void )
{
  pinMode(led, OUTPUT);     
}

void loop( void )
{
  TOGGLEd13();   // This toggles pin D13.       
  delay(2000);   //  Wait a bit
}

That shaved 4 bytes off the compiled size. :slight_smile:

And it's faster.

Thanks.
I am calling this the obscure "Nick Gammon TOGGLE"

LarryD:
I am calling this the obscure "Nick Gammon TOGGLE"

It is in the datasheet :smiley:

The optimizer will reduce constructs like

PINB |= _BV(PINB5);
PINB |= (1 << PINB5);
PINB |= 0b00100000;

to a single sbi instruction, and that saves two more bytes:

static void TOGGLEd13 (void) { PINB |= _BV(PINB5); }

const byte led = 13;

void setup( void )
{
  pinMode(led, OUTPUT);     
}

void loop( void )
{
  TOGGLEd13();   // This toggles pin D13.       
  delay(2000);   //  Wait a bit
}

Which I wrote.

Nah, just kidding.

LOL, you know, I was thinking along those lines! :smiley:

LarryD:
I am calling this the obscure "Nick Gammon TOGGLE"

Which of course is not to be confused with the "Tom Johnston SHUFFLE".

I'll try to remember these:

TOGGLE13S(); // uses the function with _BV size:886 Tom Shuffle
TOGGLE13P(); // uses the function PINB size:888 Nick Toggle
TOGGLE13X(); // uses the function below XOR size:892 C.B. XOR
TOGGLE(13); // function like macro size:1238 macro digitalWrite
TOGGLEd13; // object like macro size:892 macro XOR

I thought using #define is only frowned upon by some. Doing macro function could be dangerous when it is not carefully written with parentheses.

Macros are evil, although I can't find definitive proof.

They are however a necessary evil in some cases.

Personally I would try to not use them, for example use "const" variables instead of defines, and functions instead of the examples further up.

The OP acknowledges that macros are frowned upon. :slight_smile:

The worst part of them is when people use macros extensively to write really obscure code, which is a bad idea unless you are entering The International Obfuscated C Code Contest, in which case using them will probably help you win.

Here is an example, from that site, of what happens when you let defines get out of control:

#define o(a,b,c,d) a##f b##f c##f d; a##g b##g c##g d;q--
#define Z(z)if(*j==z)
#define c(z,p) Z(z){y;v p##=r;o(b,[q-1]=b,[q] p b,[q]);}
#define y q+=t;t=0
#define r w[q]
#define v w[q-1]
#define w(a,m,f) Z(a){y;r=m(r);q++;o(b,[q-1] = -b,[q-1]*f(r)+0*b,[0]);}
#define A(p,w,o) for(p=0;p<w;p++)_(o)
#define P(a) for(a=Z;a<Z;a++)
#define _ putchar
typedef double o;
typedef char z;
o A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y, E_, w[20], bf[20], bg[20],x=-1.3/8,p,d,l=0,h=4e-3,f,m;
z e[17] = "FKE<<gMAQUDIYO9\"=", *k, *j; o g(o p, o d){int q =-1,t=0;j=k;while( *j ){c(45,-);Z(100){y;q++;r=v;q[bf]=bf[q-1];q[bg]=bg[q-1];}Z(42)
     {y;v*=r;o(b,[q-1]=r*b,[q-1] + v*b,[q]);}Z(44){t=0;q++;}Z(116){f=v;v=r;r=f;f=bf[q];q[bf]=bf[q-1];bf[q-1]=f;f=q[bg];bg[q]=(q-1)[bg];bg[q-1]=f;



      }c(43,+);Z(47){y;v/=r;              o(b,[q-1]=b,[q-1]/r-v/                (r*r)*b,[q]);}Z(121){y;q++                        ;r=d; bf[ q]=0;bg[q]=1;}
      Z(94){y;f=v;v=pow(v,r)              ;o(b,[q-1]=r*b,[q-1]*                 pow(f,r-1)+0*b,[q]);}w(115                        ,sin,cos);w(99,cos,sin);
      Z(120){y;q++;r=p;bf[q]              =1;bg[q]=0;}if(*j>=48                 &&*j<58){q++;t=1;r=*j-48 ;                        bf[q] = 0;(q--)[bg] = 0;
                             }j++;}H=bf[0]                                                                ;K= bg[ 0]; return w[0];}
                             void s(){int                                                                 e=0;X=Q*8;f=g (Y*8, L*8 )
                             ;e=(f-X<0)?1:                                                                -1;l=0;while((l+=h)<8)  {
      V=Y*8+l*R;W=L* 8+l*D;X=             Q*8+l*U;f=g(V,W);if((f                                          -X)*e>0){if(V>-1&&V<1&&W>                   
      -1&&W<1){p=V;d=W;return            ;}else e/=-1;}}p=d=-10                                           ;}int main(int argc, z **
      argv){int c, f;z b[2],Z            ;S=0,C=1;k=argv[1];Z =                                           atoi(argv[2])>>1;b[1]=Z*2

Personally I would try to not use them, for example use "const" variables instead of defines, and functions instead of the examples further up.

I can put the #define in a .h file and have multiple files include it. I have however not tried to see if the same holds for const without any problems. Also, I don't know an alternative to #ifdef for conditional compilation (inside and outside arduino IDE).

I like the simple writing a 1 to PINx to toggle a bit:

PINA = 0x01;
PINA = 0x80;
etc.
that Nick showed me.

CrossRoads:
I like the simple writing a 1 to PINx to toggle a bit:

PINA = 0x01;
PINA = 0x80;
etc.
that Nick showed me.

Maybe this would be a good application for a macro if you are old like me and have trouble remembering.
PINB = 0x01 // . . . D8=0x01, D9=0x02, D10=0x04, D11=0x08, D12=0x10, D13=0x20 . . .
#define TOGGLEd13 PINB = 0x20
I have learned alot here!

Thanks

liudr:
Also, I don't know an alternative to #ifdef for conditional compilation (inside and outside arduino IDE).

Agreed, however #ifdef isn't a macro. #define is.

Maybe this would be a good application for a macro if you are old like me and have trouble remembering.

That's why I Don't do macros - can't remember what they are - faster to just write the code!

A relatively dangerous macro:

#define max(a,b) ((a)>(b)?(a):(b))

If I do

int i=1;
int j=1;
int k=max(++i,j);

I am expecting to get k=2 since ++i has increment then the new value is used for comparison for max. But after some careful thinking, I should get k=3 instead. Why? :wink:

This applies to return values of functions as well.