Simpler alternative to #if ! defined() ... #endif ?

I am writing a program that will eventually run on an Attiny 45 but it is much easier to develop it on an Uno.

While developing it on the Uno I can use Serial.println() to display useful debugging information but, of course, hardware Serial doesn't work on an Attiny.

I can make the Serial.println() stuff "disappear" when the Attiny version is compiled by doing this sort of thing

#if defined(UNODEV)
   Serial.println("a test message");
#endif

but it is very tedious having to make three lines of text for every Serial.println() and it makes it difficult to follow the code.

Is there any simpler method to have Serial.println() compiled in one version and not in another version.

I don't need to see any of the development messages on the Attiny.

...R

#ifdef x
#define dprint(y) Serial.print(y)
#else
#define dprint(y)
#endif

Works in most cases; sometime you may need to jazz it up with a do...while(0)

The code in HardwareSerial.h that declares Serial looks like this:

#if defined(UBRRH) || defined(UBRR0H)
  extern HardwareSerial Serial;
#elif defined(USBCON)
  #include "USBAPI.h"
//  extern HardwareSerial Serial_;  
#endif
#if defined(UBRR1H)
  extern HardwareSerial Serial1;
#endif
#if defined(UBRR2H)
  extern HardwareSerial Serial2;
#endif
#if defined(UBRR3H)
  extern HardwareSerial Serial3;
#endif

I haven't bothered to go see what UBRRH and UBRR0H are but I guess they indicate the presence of the hardware UART. In any case, as long as nobody goes making any sweeping changes to HardwareSerial.h I don't see any problem using similar preprocessor conditions to select your macro definitions along the lines AWOL suggested.

#if defined(UBRRH) || defined(UBRR0H) || defined(USBCON)
#define dprint(y) Serial.print(y)
#else
#define dprint(y)
#endif

Thanks @awol.

I had been thinking of writing a routine that was a proxy for Serial.print but I had assumed I would need to allow for all the different data types that can be passed to Serial.print. I hadn't thought of using a macro.

I presume, based on your example, that everywhere I would normally use Serial.print() I will just use dprint().

This has the another enormous advantage of reducing the number of characters to be typed. If it works I think I will use it all the time.

...R

The method I showed is only an outline - it doesn't define "println" or methods where you want to have a radix specifier (e.g. "Serial.print (val, HEX);"), but once you've written your macros, you can stick them in an include file and mostly forget about them.

I've analyzed verbose compilation output, but i still can't understand how compiler detects if UBRRH is defined or not. Can you explain it to me? I don't see any #include for product family headers

Definitions for things like UBRRH are buried in AVR header files like iom32.h, look in

\hardware\tools\avr\avr\include\avr\

For all the chip definition files


Rob

If you use a program like notepad++ you have the ability to search and replace.

To remove all Serial.print stuff:
Search
Replace...
Find what: Serial.
Replace with: //Serial.
Replace all.

Graynomad:
Definitions for things like UBRRH are buried in AVR header files like iom32.h, look in

\hardware\tools\avr\avr\include\avr\

For all the chip definition files


Rob

Yes i did it and i found avr, avr-3, avr-4 folders in my desktop Arduino distribution and i've found definitions for UBRRH. But i need to understand the algo how to define what header should be included to -I paths or compiled libraries to -L paths

LarryD:
If you use a program like notepad++ you have the ability to search and replace.

To remove all Serial.print stuff:
Search
Replace...
Find what: Serial.
Replace with: //Serial.
Replace all.

You did not understand. i do WRITE smth like Notepad++ with autocomplete for Arduino so i need to know how to build command-line for compile (autocomplete to be more detailed) dependent on board type

@4ntoine
My comment was for Robin2
@Robin2
Could expand AWOL suggestion to:

// #define DEBUG
#ifdef DEBUG
#define DPRINT Serial.print
#define DPRINTLN Serial.println
#else
#define DPRINT(x)
#define DPRINTLN(x)
#endif

So the file io.h decides what to include based on some definitions, for example

#elif defined (__AVR_ATmega32__)
#  include <avr/iom32.h>

Is "AVR_ATmega32" etc defined in the command line with a -D?...no I don't see it, there is a "-mmcu=" switch that I think gets its value from boards.txt. That probably causes the correct file to be included but the link escapes me at this point.


Rob

Graynomad:
So the file io.h decides what to include based on some definitions, for example

#elif defined (__AVR_ATmega32__)

#  include <avr/iom32.h>




Is "__AVR_ATmega32__" etc defined in the command line with a -D?...no I don't see it, there is a "-mmcu=" switch that I think gets its value from boards.txt.

Absolutely correct:
in "boards.txt" file

uno.name=Arduino Uno
...
uno.build.mcu=atmega328p

and i know mcu for the board and pass -mmcu argument just like desktop IDE does:

12-09 16:16:32.729: INFO/System.out(15329): /Users/me/sdk/hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=105 -I/Users/me/sdk/hardware/arduino/cores/arduino -I/Users/me/sdk/hardware/arduino/variants/standard /Users/me/sdk/hardware/arduino/cores/arduino/wiring.c -o /data/data/name.antonsmirnov.android.arduinodroid/build/wiring.c.o

but it's not working. I' not sure it's not working because of Clang and it should work or -mmcu does not affect to board-related headers inclusion.

That probably causes the correct file to be included but the link escapes me at this point.


Rob

By the way, I thought I'd just point out "variadic macros" at this point, which can be very useful.

Variadic macros can have a variable number of arguments, which is great for creating this kind of debug print strategy when the target function can have different numbers of arguments:

#define dprint(...) Serial.print(__VA_ARGS__)
#define dprintln(...) Serial.println(__VA_ARGS__)

The (...) tells the macro preprocessor that this is a place-holder for an unknown number of arguments. All those arguments are then put in wherever the VA_ARGS symbol is found within the macro.

This allows you to use:

dprint("Debug value: ");
dprintln(myVal, HEX);

without having to define options for all the different quantities of arguments.

Does this page help?

westfw:
Does this page help?
http://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html

that's what i need.
Does it mean i need to include according header file?

Graynomad:
Is "AVR_ATmega32" etc defined in the command line with a -D?...no I don't see it, there is a "-mmcu=" switch that I think gets its value from boards.txt. That probably causes the correct file to be included but the link escapes me at this point.

If you use -mmcu=, the compiler will automatically define the appropriate _AVR macro.

MichaelMeissner:

Graynomad:
Is "AVR_ATmega32" etc defined in the command line with a -D?...no I don't see it, there is a "-mmcu=" switch that I think gets its value from boards.txt. That probably causes the correct file to be included but the link escapes me at this point.

If you use -mmcu=, the compiler will automatically define the appropriate _AVR macro.

How does it know what file needs to be included and what macro should be added?

The IDE in boards.txt has a line .build.mcu=. When you select the board type (tools->board), it will look at boards.txt to see what options to pass. The build.mcu option says to add the appropriate -mcu= to the compile line. So for an example, the lines for the Uno are:

uno.build.mcu=atmega328p
uno.build.f_cpu=16000000L
uno.build.core=arduino
uno.build.variant=standard

The uno.build.mcro=atmega328p line says to add the -mcu=atmega328p option to the compiler.

If you look in the compiler source, in /gcc/config/avr/avr-mcus.def, there is the line for atmega328p board:

AVR_MCU ("atmega328p",           ARCH_AVR5, "__AVR_ATmega328P__",        0, 0, 0x0100, 1, "m328p")

The third argument gives the identifier to be defined (AVR_ATmega328P in the case of the Uno).

MichaelMeissner:
The IDE in boards.txt has a line .build.mcu=. When you select the board type (tools->board), it will look at boards.txt to see what options to pass. The build.mcu option says to add the appropriate -mcu= to the compile line. So for an example, the lines for the Uno are:

uno.build.mcu=atmega328p

uno.build.f_cpu=16000000L
uno.build.core=arduino
uno.build.variant=standard




The **uno.build.mcro=atmega328p** line says to add the **-mcu=atmega328p** option to the compiler.

If you look in the compiler source, in *<gcc>***/gcc/config/avr/avr-mcus.def**, there is the line for atmega328p board:



AVR_MCU ("atmega328p",          ARCH_AVR5, "AVR_ATmega328P",        0, 0, 0x0100, 1, "m328p")




The third argument gives the identifier to be defined (**__AVR_ATmega328P__** in the case of the Uno).

I'm getting closer and closer.
So in order to emulate this avr-gcc toolchain -mmcu arg usage i need to define AVR_ATmega328P definition and include file "m328.h" in sketch code and it's path to I:

#define __AVR_ATmega328P__
#include <m328p.h>
#include <Arduino.h>
%sketch_code%

and execute compilation with params:

%sketch_filename%
-I%core_path%
-I%m328p.h_filepath%

All other things wil be done automatically according to definitions from "avr/io.h" which is included by "Arduino.h". Is it correct?