Trouble setting up interrupts in a header file

Here's my code:

color_sensor.ino

#include "TCS3200.h"

void setup() {
    TCS3200_begin();
    Serial.begin(9600);
}

void loop() {
    delay(200);
    Serial.print(frequencyRead());
    Serial.print("kHz");
    Serial.println();
}

TCS3200.h

#ifndef _TCS3200
#define _TCS3200

// PINS
uint8_t
    OUT = 2,
    OE = 3,
    S0 = 4,
    S1 = 5,
    S2 = 6,
    S3 = 7;

// PULSE COUNTING
volatile uint16_t
    pulse_count;
uint32_t
    start_time,
    end_time;

void TCS3200_begin() {
    pinMode(OE, OUTPUT);
    pinMode(S0, OUTPUT);
    pinMode(S1, OUTPUT);
    pinMode(S2, OUTPUT);
    pinMode(S3, OUTPUT);
    
    digitalWrite(OE, LOW);
    
    digitalWrite(S0, HIGH);
    digitalWrite(S1, LOW);
    
    digitalWrite(S2, HIGH);
    digitalWrite(S3, LOW);
}

void ISR_pulseIncrement() {
    pulse_count += 1;
}
attachInterrupt(digitalPinToInterrupt(OUT), ISR_pulseIncrement, RISING);

float frequencyRead() {
    // Returns frequency in kHz
    end_time = micros();
    float frequency = 1000.0 * pulse_count / (end_time - start_time);
    start_time = micros();  
    pulse_count = 0;
    return frequency;
}

#endif // _TCS3200

And the error I'm getting is this:

TCS3200.h:39:16: error: expected constructor, destructor, or type conversion before '(' token
attachInterrupt(digitalPinToInterrupt(OUT), ISR_pulseIncrement, RISING);
^
exit status 1
expected constructor, destructor, or type conversion before '(' token

It seems like the IDE wants me to put the attachInterrupt() inside of a function, but when I do that, the ISR is out of scope, so I'm not sure what to do.

You shouldn't define variables in header files.

You cannot have statements like this outside of a function.

Declare the ISR before you use it:

void ISR_pulseIncrement();

this is not true.
This can be done if the header is included in only one translation unit

But then it shouldn't be a header file. Just because you can use it without errors in some cases doesn't mean you should.

If you want the nuanced guideline, you usually shouldn't define non-const, non-inline variables in header files.
C++ Core Guidelines: SF.2: A .h file must not contain object definitions or non-inline function definitions

You shouldn't define functions in a header file, either.

1 Like

Coming from Python, my understanding of header files is that they can be used to refactor code so that the main file stays more neat. If this was Python, I would make all those functions and data into members of a class. Then, I would use that class to interact with the sensor hardware. I thought I might do this with a struct, but all the sources I read said that that was misguided and not what structs are for.

If there is a better way to structure this code, links to sources where I can learn more would be helpful. I'm trying to refactor in preparation for adding some more functionality.

At any rate, I appreciate all the suggestions for best practices, but none of them seem to answer my question. I want to understand why I'm getting the error I'm getting and how I can fix it. Why am I getting this error, and how can I fix it?

You were already told why:

To fix it, put all executable code inside of a function.

See my Reply #5 in this Thread for some basic guidelines for multi-file projects.

In my initial post, I specifically addressed this suggestion. I tried putting this code into a function, but then I get a new error because the ISR function is out of scope. I tried defining the ISR function within the function in which I called attachInterrupt(), but then I get a third error, because it is not allowed to define a function within a function.

it is common practice to put the attachinterrupt() line within setup() in your main .ino file

Too bad you didn't post the code for that attempt ....

I did that at first, but now that I'm refactoring my code, I don't want to put the interrupt definition right in the main .ino file. That's why I tried putting it in a .h file.

@duwaar0
I am agree with post #11

Here is what my code looks like when I put the attachInterrupt() function inside of another function:

color_sensor.ino

#include "TCS3200.h"

void setup() {
    TCS3200_begin();
    Serial.begin(9600);
}

void loop() {
    delay(200);
    Serial.print(frequencyRead());
    Serial.print("kHz");
    Serial.println();
}

TCS3200.h

#ifndef _TCS3200
#define _TCS3200

// PINS
uint8_t
    OUT = 2,
    OE = 3,
    S0 = 4,
    S1 = 5,
    S2 = 6,
    S3 = 7;

// PULSE COUNTING
volatile uint16_t
    pulse_count;
uint32_t
    start_time,
    end_time;

void TCS3200_begin() {
    pinMode(OE, OUTPUT);
    pinMode(S0, OUTPUT);
    pinMode(S1, OUTPUT);
    pinMode(S2, OUTPUT);
    pinMode(S3, OUTPUT);
    
    digitalWrite(OE, LOW);
    
    digitalWrite(S0, HIGH);
    digitalWrite(S1, LOW);
    
    digitalWrite(S2, HIGH);
    digitalWrite(S3, LOW);
    
    attachInterrupt(digitalPinToInterrupt(OUT), ISR_pulseIncrement, RISING);
}

void ISR_pulseIncrement() {
    pulse_count += 1;
}

float frequencyRead() {
    // Returns frequency in kHz
    end_time = micros();
    float frequency = 1000.0 * pulse_count / (end_time - start_time);
    start_time = micros();  
    pulse_count = 0;
    return frequency;
}

#endif // _TCS3200

Error message:

TCS3200.h:35:49: error: 'ISR_pulseIncrement' was not declared in this scope
attachInterrupt(digitalPinToInterrupt(OUT), ISR_pulseIncrement, RISING);
^~~~~~~~~~~~~~~~~~
exit status 1
'ISR_pulseIncrement' was not declared in this scope

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Here is what the code looks like when I put the ISR function definition in side the same function as the attachInterrupt() function call in an attempt to have them both in the same scope:

color_sensor.ino

#include "TCS3200.h"

void setup() {
    TCS3200_begin();
    Serial.begin(9600);
}

void loop() {
    delay(200);
    Serial.print(frequencyRead());
    Serial.print("kHz");
    Serial.println();
}

TCS3200.h

#ifndef _TCS3200
#define _TCS3200

// PINS
uint8_t
    OUT = 2,
    OE = 3,
    S0 = 4,
    S1 = 5,
    S2 = 6,
    S3 = 7;

// PULSE COUNTING
volatile uint16_t
    pulse_count;
uint32_t
    start_time,
    end_time;

void TCS3200_begin() {
    pinMode(OE, OUTPUT);
    pinMode(S0, OUTPUT);
    pinMode(S1, OUTPUT);
    pinMode(S2, OUTPUT);
    pinMode(S3, OUTPUT);
    
    digitalWrite(OE, LOW);
    
    digitalWrite(S0, HIGH);
    digitalWrite(S1, LOW);
    
    digitalWrite(S2, HIGH);
    digitalWrite(S3, LOW);
    
    void ISR_pulseIncrement() {
    pulse_count += 1;
    }

    attachInterrupt(digitalPinToInterrupt(OUT), ISR_pulseIncrement, RISING);
}

float frequencyRead() {
    // Returns frequency in kHz
    end_time = micros();
    float frequency = 1000.0 * pulse_count / (end_time - start_time);
    start_time = micros();  
    pulse_count = 0;
    return frequency;
}

#endif // _TCS3200

Error message:

TCS3200.h:35:31: error: a function-definition is not allowed here before '{' token
void ISR_pulseIncrement() {
^
TCS3200.h:39:49: error: 'ISR_pulseIncrement' was not declared in this scope
attachInterrupt(digitalPinToInterrupt(OUT), ISR_pulseIncrement, RISING);
^~~~~~~~~~~~~~~~~~
exit status 1
a function-definition is not allowed here before '{' token

Is that helpful? Sorry about the formatting of the error message. I couldn't figure out how to get the "^" characters in the right place, but hopefully that's enough information.

The problem with this attempt may be due to lack of a function prototype. The Arduino auto-prototype generator may be failing because of the way you're trying to #include excusable code in a .h file.

As you already noted, a function definition is not allowed inside of another function.

Actually, all three of your attempts are fundamentally misguided. See:

In the first code try to move

ISR_pulseIncrement()

function above the

TCS3200_begin()

one

But in general I agree with @gfvalvo

Also, in C, you can't define a function (ISR_pulseincrement) inside of another function (TCS3200_begin) - the definition needs to be at global scope, but the USE has to be inside another function.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.