Multiple files - What am I doing wrong?

Okay, I’ve combed over this for a while now and can’t see where I’m going wrong.

I thought I’d try breaking up my project into multiple files to manage it a little better, and wanted to keep some things separated for reuse later on. After a lot of trial and mostly error, I am at a loss as to what I’m doing wrong.

Here’s a stripped down example of what I’m trying to do.

file: cycle.pde

#include "cycle_timing.h"

unsigned int ledCycle = 60;
unsigned long ledLastMillis = 0;
boolean ledState = false;

#define LED_PIN 13


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

void loop()
{
  if(cycleCheck(&ledLastMillis, ledCycle))
    digitalWrite(LED_PIN, ledState = !ledState);
}

file: cycle_timing.h

boolean cycleCheck(unsigned long *, unsigned int);

file: cycle_timing.c

#include <WProgram.h>
#include "cycle_timing.h"

boolean cycleCheck(unsigned long *lastMillis, unsigned int cycle)
{
  if(millis() - *lastMillis >= cycle)
  {
    *lastMillis = millis();
    return true;
  }
  else
    return false;
}

When I compile this (and many different variation of it) I get “ In function 'void loop()':” for an error. Yup. That’s it. Not real helpful, is it? If I put everything back in one file it compiles and runs just fine. So I’m doing something wrong when I split it and might be overlooking something about the preprocessor behavior.

Just plain stumped… Any tips would be greatly appreciated.

Two things:

  1. Put the following line at the start of ‘cycle.pde’ :
    #include <WProgram.h>
    How else are you getting ‘boolean’ defined?

  2. Rename ‘cycle_timing.c’ to ‘cycle_timing.pde’

and then startup the Arduino IDE. This is what worked for me.

-Rusty-

  1. That gets included automatically for the main file of the sketch so should be unnecessary.

  2. According to the documentation, secondary files should be named with the .h extension for headers and .c or .cpp for source.

Those changes made no difference.

Well, under Linux and arduino-0012, I removed the include of
WProgram.h from the cycle.pde file and the 'boolean' in
cycle_timing.h got flagged as an error.

And if what you say is true, why the include of WProgram.h in the
cycle_timing.c file?

And I couldn't get everything to link together without changing
the .c extension to .pde.

Maybe it has to do with 0012?

Here's where I got the file extensions from, as well as the information regarding WProgram.h. Redirecting

Unless I'm reading it wrong, which is entirely possible, the .c extension should be correct for a supplemental file.

Seems like it should work, but obviously it doesn't. The odd error throws me, too. It seems like it's an error reporting problem in the preprocessor, maybe.

dmesser--

I'm pretty sure your problem is the result of a mixed linkage problem (although I don't understand why your error message is so cryptic).

Try changing the header file to:

#ifdef __cplusplus
extern "C" 
#endif
boolean cycleCheck(unsigned long *, unsigned int);

and I think that should fix your problem.

When you moved cycleCheck() from the main file to the .c file you actually changed it subtly from a function with "C++ linkage" to a function with "C linkage". Because the loop() function is written in C++, it assumes cycleCheck is also, but can't find any such function that has C++ linkage. Hence the failure.

By adding the 'extern "C"' business, you are informing the C++ compiler to look for a C linkage.

Mikal

That makes some sense. I'll try it first chance I get. Thanks.

Or just give your file a .cpp extension.

In a similar situation to the OP (dmesser); Fascinating:

#ifdef __cplusplus
extern "C"
#endif

and all about the linkage theory.

Where is a definitve guide on multi file sketches? I am still looking, and by experiment I've found several ways. ANd none of them work well (missing "byte" as datatype or static does not limit global variables to the module.)

Until multi-file sketches issues are fixed, a workaround is to create a library.

The following files must be copied in sketchbook/libraries/CycleTiming folder:

CycleTiming.h

/*

 * CycleTiming.h

 *

 */



#ifndef CYCLETIMING_H

#define CYCLETIMING_H



#include <WProgram.h>



class CycleTiming {



public:
    CycleTiming(int cycleTime);

    boolean check();


private:
    int cycleTimeMillis;

    unsigned long lastCheckMillis;
};



#endif

CycleTiming.cpp

#include "CycleTiming.h"


CycleTiming::CycleTiming(int cycleTime) {
    cycleTimeMillis = cycleTime;
    lastCheckMillis = 0;
}


boolean CycleTiming::check() {
    if (lastCheckMillis == 0) {
        lastCheckMillis = millis();
        return true;
    }
    else if ((millis() - lastCheckMillis) > cycleTimeMillis) {
        lastCheckMillis = millis();
        return true;
    }
    else {
        return false;
    }
}

This is a sketch that makes use of the library:

#include "CycleTiming.h"

#define LED_PIN 13

boolean ledState = false;
CycleTiming timer(500);


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


void loop() {
  if (timer.check()) {
    ledState = !ledState;
    digitalWrite(LED_PIN, ledState);
  }
}

Hope this helps.