An area that is still misunderstood about the MikroE. IDEs are the ability for a project level pre-processor define. Several reasons for project level defines exist. We can change the behavior of an application, we can define a constant across the entire application, or even change the definition of a function or variable.
In normal development flow, we have features, functions, or variables that are only used in particular instances. An example of this are radio libraries. Radios can be both a transmitter and a receiver, or possibly one or the other. You wouldn't want to write a library for client and one for server and you wouldn't want to include both libraries in the case where it is only going to be a client. How can a single library be used for such dynamic behavior? The answer, PLD or project level defines. A definition that resides over the entire project across all modules.
How common is this practice? Very. If you are attempting to port an manufacturers library to your own purposes, you will find that a project level define is almost required to bend the source code to your own compiler. Learning this practice will save you both time and frustration.
Behavior Changes
You can get away with a single define in a single module:
wireless.h
#define CLIENT #if defined( CLIENT ) int connect_to_server( uint32_t address ); #elif defined( SERVER ) uint32_t wait_for_client_to_connect( void ); #endif
But... what happens in other modules:
socket.c
#if defined( CLIENT ) socket_t *create_client_socket( void ); #elif defined( SERVER ) socket_t* create_server_socket( void ); #endif
error! No function create_client_socket defined
Defining a Constant
#define NUM_OF_CONNECTIONS 10
app.c
uint8_t connection_max = NUM_OF_CONNECTIONS;
Changing a Variable Name
If you are using an off the shelf library, sometimes they use variables in their code that end up being reserved or keywords in another compiler. For example: the word data is used in all MikroE. compilers as a storage modifier. People like using the word data for defining... data. So instead of having to modify someones' code, we can re-name all their variables without have to modify a single line of code.
#define data _data
Now the pre-processor will replace all the data keywords with _data without permanent change and you can go on with compiling without errors.
Changing the Definition of a Function
One thing programmers can be are short-cut takers. If the universe would let us, our variables would all be a single character as to save us the typing. One thing I use alot in debugging are serial output statements but dislike the having to type in the entire UART_Write_Text( "Blah" ); . What I do is define a definition #define MSG( stuff ) UART_Write_Text( stuff ) so that my output statements are MSG( "All tests successful" ); .
Entire Project?
The problem with all of these is that they are local level or module level defines that have a limited scope. What we need is a pre-processor directive that spans the entire project. Here is how it is done.
The How
Here is the easiest way to do this.
- Alternate click on the Project Manager / Project Level Defines folder in the right pane of the IDE and select "Add New File".
- When you add a new file, the file will be blank. You will need to save the file first.
What is important about is step is that in the "Files of type" NEEDS to be *.* and not *.c or *.h. If you don't, your file will be recognized as a source or header file and not a project level define. Save the file with the extension xxxxxxx.pld. When you get it correct the background of the editor will change color.You will also notice the file listed in the Project Manager under the folder "Project Level Defines".
- Add some new defines. There are some specific rules that needs to be followed:
A file must contain one definition per line in the following form :symbol=value
Define a macro
=
. To specify a value, use=
. If=
is omitted, 1 is assumed. Do not enter white-space characters immediately before the "=
". If a white-space character is entered immediately after the "=
", the macro is defined as zero token. This option can be specified repeatedly. Each appearance of symbol will be replaced by the value before compilation.Example:
data=_data
or
const=
The last one eliminates all the keywords const from the entire project.
Enjoy your new super powers.
NOTE*
Some caution and words of warning need to be addressed. Macros and pre-processor directives are not easily debugged. They do not show up in the normal debugging routines and can lead to loss of hair. Before you start adding mountains of defines in your pld, you need to be sure they are correct for the application and operate the way you intended. Without doing this, you may be causing more problems than you solved.