I would like to know if there is a way to call functions that are contained within C files using an Arduino sketch?
My C file declares and defines a function. To save putting the messy function definition into my Arduino sketch, I'd like to call the function straight from the sketch.
Is there a standard way to do this using Arduino and C? Here is the sketch:
#include "crc16.h";
void setup(){
}
void loop(){
CalculateCRC16("<09M", 4);
}
and this is the trimmed down C file:
#include <stdio.h>
#include <stdint.h>
uint16_t crctable[256] =
{
0x0000, 0x1189,.....
uint16_t // Returns Calculated CRC value
CalculateCRC16( // Call example CalculateCRC16("<09M", 4);
const void *c_ptr, // Pointer to byte array to perform CRC on
size_t len) // Number of bytes to CRC
{
uint16_t crc = 0xFFFF // Seed for CRC calculation
const uint8_t *c = c_ptr;
while (len--)
crc = (crc << 8) ^ crctable[((crc >> 8) ^ *c++)];
return crc;
}
3 Answers 3
You can extern "C" #include like the following:
extern "C"{
#include "crc16.h"
};
void setup(){
}
void loop(){
CalculateCRC16("<09M", 4);
}
And the crc16.h file could be (some minor fixes, the #pragma once, a cast):
#pragma once
#include <stdio.h>
#include <stdint.h>
uint16_t crctable[2] ={ 0x0000, 0x1189};
uint16_t CalculateCRC16( // Call example CalculateCRC16("<09M", 4);
const void *c_ptr, // Pointer to byte array to perform CRC on
size_t len) // Number of bytes to CRC
{
uint16_t crc = 0xFFFF; // Seed for CRC calculation
const uint8_t *c = (const uint8_t *)c_ptr;
while (len--)
crc = (crc << 8) ^ crctable[((crc >> 8) ^ *c++)];
return crc;
}
-
Thanks, it works just fine now. Could you please explain the need of the pragma?user_name– user_name2014年03月27日 14:44:37 +00:00Commented Mar 27, 2014 at 14:44
-
1Sure, it is a good practice, though it is not needed in your example. It avoids the same header file to be included twice in a compilation file. Imagine a.cpp->(b.h and c.h) and b.h->c.h. That will duplicate the contents of c.h while compiling a.cpp. The #pragma once avoid this. Also guard directives #ifndef _MY_FILE_H_INCLUDED #define _MY_FILE_H_INCLUDED are common for this. Note, however, that as Peter R. Bloomfield points out, it might be better to put the implementation of CalculateCRC16 in a cpp file, and leave just the declaration in the header file.drodri– drodri2014年03月27日 15:45:59 +00:00Commented Mar 27, 2014 at 15:45
-
Ok, I can see that becoming an issue when the code gets more and more complicated. Thanks for the advice.user_name– user_name2014年03月27日 15:52:22 +00:00Commented Mar 27, 2014 at 15:52
Your CRC function can easily be converted to C++ so that it can go into a *.cpp file. All you need to do is use an explicit cast when you initialise your c
pointer. Here's the 'proper' C++ way to do it:
const uint8_t *c = static_cast<const uint8_t*>(c_ptr);
However, an old C-style cast would also work:
const uint8_t *c = (const uint8_t*)c_ptr;
The problem is basically that C can be a little more permissive about letting you convert pointers implicitly between types. To do it in C++, you need to tell the compiler explicitly that the conversion is intentional.
Yes, just copy its declaration line in your sketch:
extern "C" {
void myfunction(int arg);
}
const void *c_ptr
andconst uint8_t *c = c_ptr;
. The error message mentions an invalid conversion between types.In function uint16_t CalculateCRC16(uint16_t, const void*, size_t)': 46 invalid conversion from
const void*' toconst uint8_t*' In function int main()': 57 system' undeclared (first use this function) (Each undeclared identifier is reported only once for each function it appears in.)