Difficulties with included C files

I created a test application to familiarize myself with the Leonardo board.
The project functions correctly as long as I keep all of the code in the project ino file.
When I attempt to split the code into modules, I get compile errors indicating that the compiler cannot find the function.
The additional module is included in the project folder (comms.c) and a header (comms.h) is included in the same folder. The header included the prototype.
The additional file is compiled (errors are reported) and I can use a string declared in the comms.c file in the main ino file using extern, indicating that the compiling is done correctly.
The included library for the timer interrupts also functions properly.
However, I get two errors when using a function in the additional module:

  1. The complier reports that it cannot find the function.
  2. The function makes use of Serial.print() and the compiler reports that it cannot find "Serial".

I can't seem to find a header that should be included to support the "Serial::function" library.
I have included a pic of the tabs within the project.

Code for project .ino:

/** Files Included *******************************************************/
#include "Defines.h"
#include <TimeInterrupt.h>
#include <avr/wdt.h>
#include "Comms.h"

/** Definitions **********************************************************/
#define WatchdogLed 13
#define WatchdogTimingHi 60
#define WatchdogTimingLo 20

/** Global variables and Arrays ******************************************/
bool LedChange = 0;   
uint8_t LedTmr = 0;

extern const uint8_t Version[];
extern const uint8_t Product[];

//---------------------------------------------------------------------------------------
// Initialization
//---------------------------------------------------------------------------------------
void setup()
{
  Serial.begin(9600);
  while (!Serial) {}

  pinMode(WatchdogLed,OUTPUT);
  TimeInterrupt.begin(PRECISION);                     //Initialize the interrupt with high precision timing
  TimeInterrupt.addInterrupt(TimerHandler, 10);       //Call 'TimerHandler' every 10mS
  Serial.println(F("Timers Started"));
  PrtCrLf();
  PrintId();
//  PrintId2();
}

//#######################################################################################
// Main Loop
//#######################################################################################
void loop() 
{
  if(LedChange)
  {
    digitalWrite(WatchdogLed, !digitalRead(WatchdogLed));
    LedChange = 0;
    if(digitalRead(WatchdogLed)) LedTmr = WatchdogTimingHi;
    else LedTmr = WatchdogTimingLo;
  }
}

//---------------------------------------------------------------------------------------
// Timer Tick (10mS)
//---------------------------------------------------------------------------------------
void TimerHandler()
{
  if(LedTmr)LedTmr--;
  else
  {
    LedChange = 1;
  }
}

//########################################################################################
// Comms routines
//########################################################################################

//______________________________________________________________________________________
// Print a String of Text - not Formatted
//______________________________________________________________________________________

void PrtString(const char *str)
{
  uint8_t idx = 0;

  while(str[idx] !=0)
  {
    Serial.print(str[idx]);
    idx ++;
  }
}

//___________________________________________________________________________________________
// Print Version of Hardware and Software
//___________________________________________________________________________________________
void PrintId()
{
  Serial.println("Leonardo Tester");
  Serial.print("Revision: ");
  PrtString(Version);
  PrtCrLf();
}

void PrtCrLf()
{
  Serial.write(Cr);
  Serial.write(Lf);
}

Comms.c file:

*************************************************************************
 * Leonardo Tester
 ************************************************************************/
 
/** Files Included *******************************************************/
#include <Arduino.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <avr/io.h>
#include <avr/wdt.h>
#include "Defines.h"
#include "Comms.h"

/** Global variables and Arrays ******************************************/
const uint8_t Version[] = "0.01";
const uint8_t Product[] = "Leo Tester> ";

void PrintId2()
{
//  Serial.print("Revision");
//  Serial.println(Version);
//  Serial.println("Leonardo Tester");
}

Comms.h file:

#ifndef comms_h
#define comms_h

void PrintId2();

#endif

The error report when un-commenting "PrintId2":

Arduino: 1.8.13 (Windows 10), Board: "Arduino Leonardo"
C:\Users\danie\AppData\Local\Temp\ccAfhuos.ltrans0.ltrans.o: In function setup': C:\Arduino\Projects\LeoTest/LeoTest.ino:37: undefined reference to PrintId2()'
collect2.exe: error: ld returned 1 exit status
exit status 1
Error compiling for board Arduino Leonardo.

If a Serial.print() line is un-commented in the "Comms.c" file:

Arduino: 1.8.13 (Windows 10), Board: "Arduino Leonardo"
"C:\Users\danie\AppData\Local\Temp\arduino_build_111200\sketch\Comms.c" -o "C:\Users\danie\AppData\Local\Temp\arduino_build_111200\sketch\Comms.c.o"
C:\Users\danie\AppData\Local\Temp\arduino_build_111200\sketch\Comms.c: In function 'PrintId2':
Comms.c:24:3: error: 'Serial' undeclared (first use in this function); did you mean 'ceil'?
Serial.print("Revision");
^~~~~~
ceil
C:\Users\danie\AppData\Local\Temp\arduino_build_111200\sketch\Comms.c:24:3: note: each undeclared identifier is reported only once for each function it appears in
exit status 1
'Serial' undeclared (first use in this function); did you mean 'ceil'?

Can anyone tell me what I am doing wrong?

Project Pic.png

Project Pic.png

extern "C"

Or use the C++ compiler.

Arduino uses C++, not C.

Rename your files to .cpp, not .c. If you really want to use C, you'll have to find alternatives to things like Serial.print, and you'll have to declare the C functions as extern "C" when calling them from your C++ code or from the main .ino file (which is compiled as C++).

Pieter

Thanks for the replies - searching on the forum seemed to indicate that either C or C++ was ok

daveve:
Thanks for the replies - searching on the forum seemed to indicate that either C or C++ was ok

You can use C to program the microcontrollers, but then you cannot use the Arduino libraries, which are written in C++.

@PieterP replied much the same while I was typing this, but I'll post it anyway;

It is OK. C is fully supported. You just need to understand the implications of using C code in a C++ program. If you're not set on using C, it's easier to just use C++ for everything, but if you're into C, or even assembly, you can do that. Important components of the Arduino core library are written in C and assembly, but some are also C++ as you discovered.

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