Attempt to make library from sketch generates errors

I wrote some working code to operate the cheap 74HC595 7 segment modules. It was a neat diversion, and I found better ways to do it with display ICs. However, I came across the Multifunction board here:

I wanted to create a custom library to control the shield. I’m aware that there is already a library written by the above people, but it’s just not what I need. So I set about to create a class to do this. I quickly got into trouble, when I tried to code the ISR. Basically, the problem has been that the ISR can not seem to access the data items that it uses, which are declared as static members of the class. I also tried making the ISR static. I had so much trouble that I decided to try coding it without any class container. I was quite flummoxed to see that it didn’t change anything, I get the same errors.

So, I stripped the thing down to as small as I can make it, so I could post it here. All the files are in the project folder.

Here is the sketch:

// MultiFunction_Shield_SevenSegment 1.06 minimal example
//
#include "MultiFunctionShield.h"

// count variables:

unsigned long previousCountUp = 0;        // will store last time of count
const long intervalCountUp = 200;  // interval at which to count (milliseconds)

long charCount = 0xff00;  // initial demo counter value

void setup () {
  mfsBegin();
}

void loop()
{
  unsigned long currentMillis = millis();

  if (currentMillis - previousCountUp >= intervalCountUp)
  {
    previousCountUp = currentMillis;

    if (++charCount > 10100) {
      charCount = -1010;
    }

    mfsPrint(charCount, DEC);
  }
}

The .h file:

#include "Arduino.h"
#include "TM16xxFonts.h"

const uint8_t LATCH_PIN  =   4;
const uint8_t CLK_PIN    =   7;
const uint8_t DATA_PIN   =   8;

const byte numDigits = 4;
byte displayBuffer[numDigits] = {0};

enum displayBrightness {DIM, MEDIUM, BRIGHT};
displayBrightness displayBright;

void mfsBegin();
void mfsClearDisplay();
void mfsUpdate();
void mfsInitDisplay();

void TIMER_COMPA_ISR();
void mfsTimerInit();

void mfsPrint(long val, byte base);

The error message:

Arduino: 1.8.13 (Linux), Board: “Arduino Uno”

sketch/Multifunction_Shield_SevenSegment_106_minimal.ino.cpp.o (symbol from plugin): In function charCount': (.text+0x0): multiple definition of displayBright’
sketch/MultifunctionShield.cpp.o (symbol from plugin):(.text+0x0): first defined here
sketch/Multifunction_Shield_SevenSegment_106_minimal.ino.cpp.o (symbol from plugin): In function charCount': (.text+0x0): multiple definition of displayBuffer’
sketch/MultifunctionShield.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
exit status 1
Error compiling for board Arduino Uno.

This report would have more information with
“Show verbose output during compilation”
option enabled in File → Preferences.

(compiler warnings are set to “ALL”), IDE version 1.8.13 running on Linux Mint.

It’s very strange that it thinks ‘charCount’ is a function, as it is declared as a long int! It says “multiple definition” of the 2 variables, but a text search finds only one instance of each definition in all the files.

I did do some research into this, but I couldn’t find anything specific enough here or via Google, or anything that helped me understand what I’m doing wrong… can anyone help? I’m on about day 5 on this one.

The .cpp file and font file are too big, so I’m attaching them:

MultifunctionShield.cpp (7.04 KB)

TM16xxFonts.h (3.87 KB)

I forget the shenanigans the IDE pulls to deal with multiple tabs, but I don’t think it applies to files with a cpp extension. That being so, the main program and MultifunctionShield.cpp both include MultiFunctionShield.h which contains these declarations which the linker doesn’t like:

const byte numDigits = 4;
byte displayBuffer[numDigits] = {0};

enum displayBrightness {DIM, MEDIUM, BRIGHT};

This compiles and links:

// MultiFunction_Shield_SevenSegment 1.06 minimal example
//
//#include "MultiFunctionShield.h"

// count variables:

unsigned long previousCountUp = 0;        // will store last time of count
const long intervalCountUp = 200;  // interval at which to count (milliseconds)

//long charCount = 0xff00;  // initial demo counter value
void mfsBegin();
void mfsPrint(long val, byte base);

void setup ()
{
  mfsBegin();
}

void loop()
{
static long charCount = 0xff00;  // initial demo counter value
  unsigned long currentMillis = millis();
  if (currentMillis - previousCountUp >= intervalCountUp)
  {
    previousCountUp = currentMillis;
    if (++charCount > 10100)
    {
      charCount = -1010;
    }
    mfsPrint(charCount, DEC);
  }
}

Variable definitions don't belong in .h files. If those variables are only needed in the .cpp, take them out of the .h and put them there. If they are needed in multiple .cpp files or the .ino, DECLARE them extern in the .h and define them in a single .cpp.

Change the two variables declared in the .h file to extern references:

const byte numDigits = 4;
extern byte displayBuffer[numDigits];


enum displayBrightness {DIM, MEDIUM, BRIGHT};
extern displayBrightness displayBright;

Then add the declarations in the .cpp so they are only declared once.

const byte numDigits = 4;
extern byte displayBuffer[numDigits];

It does compile now... (after simply moving the declarations to the .cpp file as @gfvalvo suggested) doing further testing. Thanks! I'm still digesting the other answers...