Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
9 years ago.
Multiply defined symbol despite #ifndef
Hi,
I've run into an annoying problem. I've split my program into several files, and made a library folder for my oPPM.cpp and its header oPPM.h. My include structure works like this oPPM.h -> core.h -> main.cpp. But I get the following error for all lines in my file oPPM.h: Error: Symbol PPMChannels multiply defined (by oPPM.LPC1768.o and main.LPC1768.o).
And I cannot understand why, in my mind #ifndef should make sure I get no duplicate definitions right?
oPPM.h
#ifndef oPPM_H
#define oPPM_H
#include "mbed.h"
#define PPMPulseLength 300 //high pulse length in uS
#define PPMFrameLength 20 //total frame length in mS
DigitalOut PPM_output(p21);
DigitalOut PPM_sync(p22);
/**
* variables
*/
int PPMChannels[16];
unsigned int activeChannels;
unsigned int currentChannel;
bool PPMActive;
bool PPMFrameStarted;
Ticker FrameTicker;
Timeout ChannelTimer;
void PPM_Init(unsigned int numberOfChannels);
void PPM_start(void);
void PPM_stop(void);
void PPM_PulseHandler(void);
void PPM_PulseTimeout(void);
void PPM_Inactive(void);
#endif /* oPPM_H */
My common.h
core.h
#include "stdio.h" #include "mbed.h" #include "SPI_TFT_ILI9341.h" #include "string" #include "Arial12x12.h" #include "Arial24x23.h" #include "QEI.h" #include "oPPM.h" #include "TFTBattery.h"
My code in oPPM.cpp:
oPPM.cpp
/**
* @author Olle Sköld
*
* @section LICENSE
*
*/
#include "oPPM.h"
void PPM_init(unsigned int numberOfChannels){
activeChannels = numberOfChannels;
currentChannel = 0;
PPMActive = false;
PPMFrameStarted = false;
}
void PPM_start(void) {
PPMActive = true;
FrameTicker.attach_us(&PPM_PulseHandler, PPMFrameLength);
}
void PPM_stop(void) {
PPMActive = false;
FrameTicker.attach_us(&PPM_Inactive, PPMFrameLength);
}
void PPM_PulseHandler(void){
PPM_output = 1;
//start first pulse
ChannelTimer.attach_us(&PPM_PulseTimeout, PPMPulseLength);
if(currentChannel == 0){
PPM_sync = 1; //if this is the start pulse, switch sync pin high
}
}
void PPM_PulseTimeout(void){
PPM_output = 0;
//Load current channel and start timer for low part
//First, check if this was the stop pulse
if(currentChannel == activeChannels){
PPM_sync = 0; //swtich sync pin low after stop bit
return;
} else {
//if it wasn't the stop pulse
ChannelTimer.attach_us(&PPM_PulseHandler, PPMChannels[currentChannel]);
}
}
//function will be called by frame ticker if PPM is inactivated after it has been started
void PPM_Inactive(void){
PPM_sync = !PPM_sync; //toggle sync output when inactive
}
My main.cpp only includes core.h
Thanks in advance! I have a feeling I'm missing something simple.. :S
1 Answer
9 years ago.
Hi Olle,
In your header file (oPPM.h), you are defining variables in the global scope instead of declaring them. As a result, every source file which include oPPM.h will define contain a definition for those variables. During the link, the linker see a variable with the same identifier, the result is an error. The C++ mandate that in any translation unit, a template, type, function, or object can have no more than one definition. Hence the error.
What you can do is just declare those variables in the header file and provide a definition in your cpp file.
aPPM.h
#ifndef oPPM_H
#define oPPM_H
#include "mbed.h"
#define PPMPulseLength 300 //high pulse length in uS
#define PPMFrameLength 20 //total frame length in mS
/**
* variables
*/
// Note the use of the extern keyword which indicate to the compiler that the variable is defined somewhere else.
extern DigitalOut PPM_output;
extern DigitalOut PPM_sync;
extern int PPMChannels[16];
extern unsigned int activeChannels;
extern unsigned int currentChannel;
extern bool PPMActive;
extern bool PPMFrameStarted;
extern Ticker FrameTicker;
extern Timeout ChannelTimer;
void PPM_Init(unsigned int numberOfChannels);
void PPM_start(void);
void PPM_stop(void);
void PPM_PulseHandler(void);
void PPM_PulseTimeout(void);
void PPM_Inactive(void);
#endif /* oPPM_H */
aPPM.cpp
/**
* @author Olle Sköld
*
* @section LICENSE
*
*/
#include "oPPM.h"
/**
* variables
*/
// global definitions goes here
DigitalOut PPM_output(p21);
DigitalOut PPM_sync(p22);
int PPMChannels[16];
unsigned int activeChannels;
unsigned int currentChannel;
bool PPMActive;
bool PPMFrameStarted;
Ticker FrameTicker;
Timeout ChannelTimer;
void PPM_init(unsigned int numberOfChannels){
activeChannels = numberOfChannels;
currentChannel = 0;
PPMActive = false;
PPMFrameStarted = false;
}
void PPM_start(void) {
PPMActive = true;
FrameTicker.attach_us(&PPM_PulseHandler, PPMFrameLength);
}
void PPM_stop(void) {
PPMActive = false;
FrameTicker.attach_us(&PPM_Inactive, PPMFrameLength);
}
void PPM_PulseHandler(void){
PPM_output = 1;
//start first pulse
ChannelTimer.attach_us(&PPM_PulseTimeout, PPMPulseLength);
if(currentChannel == 0){
PPM_sync = 1; //if this is the start pulse, switch sync pin high
}
}
void PPM_PulseTimeout(void){
PPM_output = 0;
//Load current channel and start timer for low part
//First, check if this was the stop pulse
if(currentChannel == activeChannels){
PPM_sync = 0; //swtich sync pin low after stop bit
return;
} else {
//if it wasn't the stop pulse
ChannelTimer.attach_us(&PPM_PulseHandler, PPMChannels[currentChannel]);
}
}
//function will be called by frame ticker if PPM is inactivated after it has been started
void PPM_Inactive(void){
PPM_sync = !PPM_sync; //toggle sync output when inactive
}