I am trying to split up my arduino code base from a single 'ino' file into a proper-ish c++ program by creating classes which have both .h & .cpp files. I am running into a few errors that I just haven't been able to solve. I hope I am missing something simple.
When compiling in visual studio running the "Arduino IDE for Visual Studio" plugin, I get the following errors:
7:8: error: 'class MPU6050' has no member named 'timer
30:5: error: prototype for 'int MPU6050::MPU6050_read(int, uint8_t*, int)' does not match any in class 'MPU6050
What am I missing here?
.h
#ifndef MPU6050_H
#define MPU6050_H
class MPU6050
{
private: // Vars
uint32_t timer; // Hold the value of the timer used for the complementary filter
int error;
public: // Methods
MPU6050();
~MPU6050();
void read_acc_gyr();
float const * const getXa();
float const * const getYa();
float const * const getXvel();
float const * const getYvel();
float const * const getZvel();
float const * const getZang();
double const * const getDt();
private:
void test_gyr_acc();
void MPU6050_init();
void printGyroValues();
void calibrateGyro();
int MPU6050_write(int start, const uint8_t *pData, int size);
int MPU6050_read(int start, uint8_t *buffer, int size);
int MPU6050_write_reg(int reg, uint8_t data);
};
#endif
.cpp
#include "MPU6050.h"
#include "Arduino.h"
#include "MPU6050Definitions.h"
MPU6050::MPU6050()
{
timer = 0; // Always start the timer at 0
error = 1;
Serial.println("Testing Gyro");
test_gyr_acc();
}
MPU6050::~MPU6050()
{
}
int MPU6050::MPU6050_read(int start, uint8_t *buffer, int size)
{
int i, n, error;
Wire.beginTransmission(MPU6050_I2C_ADDRESS);
n = Wire.write(start);
if (n != 1)
return (-10);
n = Wire.endTransmission(false); // hold the I2C-bus
if (n != 0)
return (n);
// Third parameter is true: relase I2C-bus after data is read.
Wire.requestFrom(MPU6050_I2C_ADDRESS, size, true);
i = 0;
while (Wire.available() && i<size)
{
buffer[i++] = Wire.read();
}
if (i != size)
return (-11);
return (0); // return : no error
}
void MPU6050::test_gyr_acc()
{
uint8_t c = 0;
error = MPU6050_read(MPU6050_WHO_AM_I, &c, 1);
if (error != 0) {
while (true) {
digitalWrite(13, HIGH);
delay(300);
digitalWrite(13, LOW);
delay(300);
}
}
}
MPUT6050Definitions.h includes all of my constants and looks like the following: (many more #defines which I don't think are relevant to include)
#pragma once
//All the values to setup the MPU6050 gyro/accelermeter
#define MPU6050_AUX_VDDIO 0x01 // R/W
#define MPU6050_SMPLRT_DIV 0x19 // R/W
#define MPU6050_CONFIG 0x1A // R/W
#define MPU6050_GYRO_CONFIG 0x1B // R/W
It looks like I made a simple mistake.
A few more errors down the list was an unknown declaration of type uint_32 which propagated itself causing the errors I was seeing before. I included the Arduino.h header which resolved the uint_32 problem causing the rest of the code to compile as expected.
Moral of the story is don't try to fix your errors from the top down.
Related
I am working with GNU AVR GCC version 5.4.0 and Atmelstudio 7.0.2397 and I have the following problem.
Problem Description
In the following Image, ye can see that up to line 13, the program has stored the address of function usart_send into the transmitter variable which is member of SimpleClass object sc.
The prototype of the transmitter function is void (*transmitter)(uint8_t * txbuff, uint8_t len); and usart_send function prototype definition is void usart_send(uint8_t *, uint8_t);.
Now when I step into the foo function, notice that when inside the member function of the class's object, the address of transmitter is now 0.
Similarly inside the function flush, its value is still 0. So I cannot call the desired function. And this is what disassembly is showing and so is my MCU.
Cause of this problem
So I have the following code for SimpleClass.h
#pragma once
typedef unsigned char uint8_t;
#ifndef rxBufferLen
#define rxBufferLen 30
#endif
#ifndef txBufferLen
#define txBufferLen 30
#endif
class SimpleClass{
uint8_t rxbuffer[rxBufferLen]; ///< receiver buffer
uint8_t txBuffer[txBufferLen]; ///< transmitter buffer
uint8_t rxbuff_index, ///< rxbuffer index. Indicates where to put new data
txbuff_index; ///< txBuffer index. Indicates where to put new data
public:
void (*transmitter)(uint8_t * txbuff, uint8_t len);
void pushtx(uint8_t byte);
void pushrx(uint8_t byte);
void flush();
void foo();
};
Notice that have the length of txBuffer and rxBuffer defined using define. And in incfile1.h I have the following code.
#pragma once
#define rxBufferLen 50
#define txBufferLen 50
#include <avr/io.h>
#include "simpleClass.h"
#define TIMER0_CLOCK_PRESCALAR (3)
#define TIMER0_CLOCK_COUNT (0xff - 50)
void usart_init();
void timer0_init();
void serial_send_ln(const char *);
void usart_send(uint8_t *, uint8_t);
void usart_send_ln(uint32_t num);
In here I have redefined rxBufferLen and txBufferLen. This definition of define causes the above problem. If I remove these two lines, this code is working fine.
Question
So you can see that by defining the buffer length for a buffer which is inside a class, causes its member function to loose the value the class's function pointer (which is a member variable). And I want to know why?
Code
Here are many un used functions and this is because I was isolating bug(if it is a bug!) from my project.
main.cpp
#include "IncFile1.h"
SimpleClass sc;
int main(void)
{
usart_init();
timer0_init();
sc.transmitter = &usart_send;
sc.foo();
while (1)
{
}
}
IncFile.h
#pragma once
#define rxBufferLen 50
#define txBufferLen 50
#include <avr/io.h>
#include "simpleClass.h"
#define TIMER0_CLOCK_PRESCALAR (3)
#define TIMER0_CLOCK_COUNT (0xff - 50)
void usart_init();
void timer0_init();
void serial_send_ln(const char *);
void usart_send(uint8_t *, uint8_t);
void usart_send_ln(uint32_t num);
SimpleClass.h
#pragma once
typedef unsigned char uint8_t;
#ifndef rxBufferLen
#define rxBufferLen 30
#endif
#ifndef txBufferLen
#define txBufferLen 30
#endif
class SimpleClass{
uint8_t rxbuffer[rxBufferLen]; ///< receiver buffer
uint8_t txBuffer[txBufferLen]; ///< transmitter buffer
uint8_t rxbuff_index, ///< rxbuffer index. Indicates where to put new data
txbuff_index; ///< txBuffer index. Indicates where to put new data
public:
void (*transmitter)(uint8_t * txbuff, uint8_t len);
void pushtx(uint8_t byte);
void pushrx(uint8_t byte);
void flush();
void foo();
};
SimpleClass.cpp
#include "simpleClass.h"
void SimpleClass::flush(){
transmitter(txBuffer, txbuff_index);
}
void SimpleClass::pushtx(uint8_t byte){
txBuffer[txbuff_index++] = byte;
}
void SimpleClass::pushrx(uint8_t byte){
rxbuffer[rxbuff_index++] = byte;
}
void SimpleClass::foo(){
uint8_t dv = 0;
dv ++ ;
pushtx(0x01);
pushtx(0x02);
pushtx(0x03);
pushtx(0x04);
pushtx(0x05);
flush();
}
CPPFile1.cpp
#include "IncFile1.h"
void usart_init(){
unsigned int ubrr = 51;
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, stop bit */
UCSR0C = (3<<UCSZ00);
}
void timer0_init(){
TCCR0B = TIMER0_CLOCK_PRESCALAR;
TIMSK0 = 1; // enable timer overflow interrupt
TCNT0 = TIMER0_CLOCK_COUNT;
}
void serial_send(const char * c){
for(uint8_t i=0 ; c[i] != '\0';i++){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = c[i];
}
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = 0x0a;
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = 0x0d;
}
void usart_send(uint8_t *buff, uint8_t len){
for(uint8_t i = 0; i < len; i++){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = buff[i];
}
}
void usart_send_ln(uint32_t num){
for(uint8_t i =0;i < 4; i++){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = num >> (8*(3-i));
}
}
Edits
You are violating the One Definition Rule - linking C++ program where the same class is defined twice and these definitions are not identical is undefined behaviour. The compiler/linker is not required to check or report these errors.
You are doing just that:
CPPFile1.cpp includes IncFile1.h which creates SimpleClass definition with buffers[50],
SimpleClass.cpp includes SimpleClass.h with buffers[30].
PROBLEM
I'm starting to play with Arduino IoT (ESP32). I read the GPIO configuration from a file on the SD card. I have a problem with external interrupts. I need to count the number of interrupts on a given GPIO.
I wrote a class that stores the GPIO configuration, and put the objects of this class in a global array. How can I count interrupts on a given pin, so that the result is available by using the appropriate object method?
I tried different solutions, but the problem lies in the ISR method, which must be static. This method has no access to object fields, so I do not know where and how to increment the counter of interrupts.
I divided the code into several files. I attach only the necessary to solve this problem.
This holds up my project. Please help.
Main file:
#define GPIO_CONFIG_FILE "cfg/gpio.txt"
#define WIFI_AP_CONFIG_FILE "cfg/ap.txt"
#define WIFI_STA_CONFIG_FILE "cfg/sta.txt"
#define AVAILABLE_GPIO_CNT 7
#define LED_BUILTIN_OLIMEX 33
#define BTN_BUILTIN_OLIMEX 34
#include "FS.h"
#include "SD_MMC.h"
#include "GPIO_CONFIG.h"
GPIO_CONFIG gpio[AVAILABLE_GPIO_CNT];
uint32_t gpio_int_cnt[AVAILABLE_GPIO_CNT] = {0};
void setup() {
if (checkSdCard()) {
setUpPinsFromFile(GPIO_CONFIG_FILE);
}
}
void loop() {
}
GPIO_CONFIG.h
#ifndef GPIO_CONFIG_h
#define GPIO_CONFIG_h
#include "Arduino.h"
#define ID_LENGTH 7
class GPIO_CONFIG {
public:
GPIO_CONFIG();
void setUp(const char * key);
void printConfig();
uint8_t number();
uint8_t mode();
uint16_t multiplier();
bool inversion();
char * id();
static void isr();
static uint32_t int_cnt();
private:
uint8_t gp_number;
uint8_t gp_mode;
uint16_t gp_multiplier;
uint32_t gp_init_value;
bool gp_inversion;
char gp_id[ID_LENGTH];
// const uint8_t gp_mode_array[4] = {INPUT, OUTPUT, INPUT_PULLUP};
};
#endif
GPIO_CONFIG.cpp
#include "GPIO_CONFIG.h"
GPIO_CONFIG::GPIO_CONFIG() {
gp_number = 0;
gp_multiplier = 1;
gp_inversion = false;
gp_init_value = 0;
}
void GPIO_CONFIG::setUp(const char * key) {
//nr|id|name|mode|multi|inv|init
char cfg[sizeof(key)];
for (uint8_t b = 0; b < sizeof(key); ++b) {
cfg[b] = key[b];
}
//PIN_NUMBER
char * tok = strtok(cfg, "|");
gp_number = atoi(tok);
//ID
tok = strtok(NULL, "|");
for (int b = 0; b < sizeof(tok); b++) {
if (b < ID_LENGTH) {
gp_id[b] = tok[b];
} else {
break;
}
}
gp_id[ID_LENGTH - 1] = '\0';
//NAME
strtok(NULL, "|");
//MODE
tok = strtok(NULL, "|");
gp_mode = atoi(tok);
//MULTIPLIER
tok = strtok(NULL, "|");
gp_multiplier = atoi(tok);
//INVERSION
tok = strtok(NULL, "|");
gp_inversion = (atoi(tok) > 0);
//INITIAL VALUE
tok = strtok(NULL, "|");
gp_init_value = atoi(tok);
//0-in; 1-out; 2-int
if (gp_mode != 1) {
if (gp_inversion) { //sterowanie podstawowe przez vcc
pinMode(gp_number, INPUT_PULLUP);
} else {
pinMode(gp_number, INPUT);
}
if (gp_mode > 2) {
attachInterrupt(digitalPinToInterrupt(gp_number), isr, FALLING);
}
} else {
pinMode(gp_number, OUTPUT);
}
}
void GPIO_CONFIG::printConfig() {
#ifdef DEBUG
Serial.print("GPIO_CONFIG:");
Serial.print(" -no:");
Serial.print(gp_number);
Serial.print(" -id:");
Serial.print(gp_id);
Serial.print(" -mode:");
Serial.print(gp_mode);
Serial.print(" -multi:");
Serial.print(gp_multiplier);
Serial.print(" -inv:");
Serial.print(gp_inversion);
Serial.println("");
#endif
}
uint8_t GPIO_CONFIG::number() {
return gp_number;
}
uint8_t GPIO_CONFIG::mode() {
return gp_mode;
}
uint16_t GPIO_CONFIG::multiplier() {
return gp_multiplier;
}
bool GPIO_CONFIG::inversion() {
return gp_inversion;
}
char * GPIO_CONFIG::id() {
return gp_id;
}
void GPIO_CONFIG::isr() {
// gpio_int_cnt[0]++;
}
uint32_t GPIO_CONFIG::int_cnt() {
// return gpio_int_cnt[0];
}
#EDIT 2018/01/04 08:10
I add some changes to files:
Main .ino file
isr_ptr isrptr[AVAILABLE_GPIO_CNT];
GPIO_CONFIG.h
#define AVAILABLE_GPIO_CNT 7
class GPIO_CONFIG;
typedef /*static*/ void (*isr_ptr)();
extern isr_ptr isrptr[AVAILABLE_GPIO_CNT];
extern GPIO_CONFIG gpio[AVAILABLE_GPIO_CNT];
(...)
public:
void setIndex(const uint8_t * i);
uint8_t index();
(...)
private:
uint8_t gp_index;
uint32_t gp_cnt_value;
GPIO_CONFIG.cpp
void GPIO_CONFIG::setIndex(const uint8_t * i){
gp_index = *i;
isrptr[gp_index] = &isr;
}
uint8_t GPIO_CONFIG::index(){
return gp_index;
}
void GPIO_CONFIG::setUp(const char * key) {
(...)
attachInterrupt(digitalPinToInterrupt(gp_number), isrptr[gp_index], FALLING);
(...)
}
void GPIO_CONFIG::isr() {
for(uint8_t i=0; i<AVAILABLE_GPIO_CNT; ++i){
if(&isrptr[i] == &gpio[i].isr()){ //here is my actualy problem. how can i compare this?
gpio[i].increment_cnt_value();
break;
}
}
}
uint32_t GPIO_CONFIG::int_cnt() {
return gp_cnt_value;
}
SOLUTION
Here I place short fragments which have to be modified:
GPIO_CONFIG.cpp
From isrptr[gp_index] = &isr; to isrptr[gp_index] = isr;
From if(&isrptr[i] == &gpio[i].isr){ to if(isrptr[i] == gpio[i].isr){
I've looked over your code several times and can't find your ISR(s). I know how to handle this sort of problem in simple C code: You just define an array with one element for each interrupt pin, and increment that element from its respective ISR. I don't know how to relate that to what you've shown.
The part that often causes trouble is that you usually need to define variables shared between the main code and ISR as volatile. Failing to do this can cause problems that are really hard to find, due to the compiler optimizing away things that it decides aren't changed (in the ISR or the main code).
Best regards,
I see there are a couple of Q&A in this topic but I still can't find the clue to my issue. I must admit I am pretty new to c++, so this might be the root cause.
Ok, so I am trying to declare a new type like :
struct measurement_t
{
int sensorID;
int sensorData;
measurement_t(int ID, int Data)
{
sensorID = ID;
sensorData = Data;
}
};
and my project contains a method, that should return this type of data:
measurement_t getLightSensorData()
{
...
}
when I try to compile the code I got error : error: 'measurement_t' does not name a type
What I also find very strange is that the error line the compiler reports is the line number of the first #define statement at the very beginning of the code :
#define CE_PIN 7
If I simply change the method to void, the the project compiles (useless, though).
I also tried returning pointer by specifying measurement_t * as return type but the result is the same. Tried remove constructor from struct, same result again.
Can someone please help me to understand what the problem is here ?
The minimal version of the code that reproducing the same issue is:
struct measurement_t
{
int sensorID;
int sensorData;
measurement_t(int ID, int Data)
{
sensorID = ID;
sensorData = Data;
}
};
measurement_t getLightSensorData()
{
int sensorValue = 1;
measurement_t m(1, sensorValue);
return m;
}
For reference, this is intended to be an arduino sketch, and the full code is as below:
#include "RF24.h"
#include <SPI.h>
#include "printf.h"
#define CE_PIN 7
#define CS_PIN 8
#define LIGHTSENSOR_PIN A0
RF24 myRadio(CE_PIN, CS_PIN);
byte rxAddr[6] = { 0x0, 0x0, 0x0, 0x0, 0x0F };
unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 3000; // send once per second
unsigned long loopSleepMillis = 200;
struct measurement_t
{
int sensorID;
int sensorData;
measurement_t(int ID, int Data)
{
sensorID = ID;
sensorData = Data;
}
};
// the setup routine runs once when you press reset:
void setup()
{
Serial.println(">>> Initializing...");
Serial.begin(115200);
printf_begin();
bool radioOk = myRadio.begin(); // Start up the physical nRF24L01 Radio
if (radioOk) Serial.println(" Radio initialized");
else Serial.println(" ERROR initializing radio !");
myRadio.setChannel(120); // Above most Wifi Channels
myRadio.setPALevel(RF24_PA_HIGH);
myRadio.setRetries(15, 15);
myRadio.openWritingPipe(rxAddr); // Use the first entry in array 'addresses' (Only 1 right now)
Serial.println("<<< Done initialization");
}
// the loop routine runs over and over again forever:
void loop()
{
currentMillis = millis();
if (currentMillis - prevMillis >= txIntervalMillis)
{
transmitData(getLightSensorData());
prevMillis = millis();
}
delay(loopSleepMillis);
}
measurement_t getLightSensorData()
{
int sensorValue = analogRead(LIGHTSENSOR_PIN);
measurement_t m(1, sensorValue);
return m;
}
void transmitData(measurement_t data)
{
myRadio.stopListening();
Serial.print("Transmitting data...");
bool writeOK = myRadio.write(&data, sizeof(data));
if (writeOK)
{
Serial.println("OK");
}
else
{
Serial.println(F("no response"));
//myRadio.printDetails();
}
}
You had to use
struct measurement_t getLightSensorData()
{
int sensorValue = analogRead(LIGHTSENSOR_PIN);
measurement_t m(1, sensorValue);
return m;
}
You might have outdated version of Arduino IDE because on my IDE it compiled without the use of struct keyword.
I'm trying to write an arduino library. I've written a few classes before but nothing for arduino. I'm running into one error pretty consistently. First let me show you the code:
Code
Main.ino (The arduino project)
#include <Wire.h>
#include "Mobility.h"
Mobility mol = new Mobility();
void setup() {
Serial.begin(9600);
Wire.begin();
}
void loop() {
Serial.println("loop");
mol.move(true, 125, false, 125, 10);
delay(2000);
}
Mobility.h
#ifndef MOBILITY_H
#define MOBILITY_H
#if (ARDUINO >= 100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
const int DEFAULT_MOBILITY_ADD = 4;
class Mobility
{
public:
void begin();
void begin(int address);
int i2cAdd;
int move(bool lPos, unsigned char leftPower, bool rPos, unsigned char rightPower, unsigned char msec);
private:
};
/**/
#endif
Mobility.cpp
#if (ARDUINO >= 100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "Mobility.h"
#include "Wire.h"
void Mobility::begin(){
Wire.begin();
this.i2cAdd = DEFAULT_MOBILITY_ADD;
}
void Mobility::begin(int address){
Wire.begin();
this.i2cAdd = address;
}
int Mobility::move(bool lPos, unsigned char leftPower,bool rPos, unsigned char rightPower, unsigned char msec){
if (leftPower < -255 || leftPower > 255){
return -1;
}
if (rightPower < -255 || rightPower > 255){
return -2;
}
if(msec <= 0){
return -3;
}
Wire.beginTransmission(this.i2cAdd);
Wire.write(lPos);
Wire.write(leftPower);
Wire.write(rPos);
Wire.write(rightPower);
Wire.write(msec);
Wire.endTransmission();
return 0;
}
ERRORS
I've been getting two big errors while I've been trying to fix the code. The first is:
error: conversion from 'Mobility*' to non-scalar type 'Mobility' requested
Mobility mol = new Mobility();
The problem is caused by this line:
Mobility mol = new Mobility();
the first part is static memory allocation:Mobility mol - statically allocates memory for the object mol.
the second part uses dynamic memory allocation: new - dynamically allocates memory.
So you can do :
Mobility mol;// static allocation
or
Mobility *mol = new Mobility(); //dynamic allcocation
But not a mix of the two. Either way the constructor will be called when creating the object.
I'm attempting to break out a previously working sketch I created into a class and sketch, and I'm having some trouble. I'm extending the functionality of a keyboard class designed for the board I'm working on, but the compiler keeps complaining about multiple definitions of functions.
here is my sketch, my .h, and my .cpp:
sketch
#include <DigiKeyboard.h>
#include "MacroKeyboard.h"
//constants
#define LED 1
#define SWITCH 0
//configuration
#define PAUSE_ON_ENTER true
const char command[] PROGMEM = "test string";
MacroKeyboard kb(command, SWITCH);
void setup() {
//tie switch to high
pinMode(SWITCH, OUTPUT);
digitalWrite(SWITCH, HIGH);
// set pins to correct uh whatever
pinMode(LED, OUTPUT);
pinMode(SWITCH, INPUT);
}
void loop() {
DigiKeyboard.update();
kb.update();
}
.h:
#ifndef MacroKeyboard_h
#define MacroKeyboard_h
#include "Arduino.h"
#define ON LOW
#define OFF HIGH
#define SCANCODE_DIFF 8
class MacroKeyboard {
const char* command;
int pin;
bool isPressed = false;
public:
MacroKeyboard(const char*, int);
void parseLetter(int);
void update();
};
#endif
.cpp:
#include <DigiKeyboard.h>
#include "MacroKeyboard.h"
MacroKeyboard::MacroKeyboard(const char* macro_position, int pin_number){
command = macro_position;
pin = pin_number;
}
void MacroKeyboard::parseLetter(int letter){
unsigned int scancode = pgm_read_byte_near(ascii_to_scan_code_table + letter - SCANCODE_DIFF);
unsigned int keycode = scancode & ((1 << 7) - 1); // masking off shift bit
unsigned int mods = 0;
unsigned int shift = (scancode & (1 << 7)) >> 7;
mods |= (shift == 1) ? MOD_SHIFT_LEFT : 0;
DigiKeyboard.sendKeyStroke(keycode, mods);
}
void MacroKeyboard::update(){
if(digitalRead(pin) == ON && !isPressed){
isPressed = true;
for (int i = 0; i < strlen(command); i++){
char letter = pgm_read_byte_near(command + i);
parseLetter(letter);
}
}
if (digitalRead(pin) == OFF && isPressed){
isPressed = false; // debounce
}
}
the errors I'm getting are this:
MacroKeyboard\MacroKeyboard.cpp.o: In function `usbFunctionSetup':
C:\Program Files (x86)\Digistump_Arduino\hardware\digistump\avr\libraries\DigisparkKeyboard/DigiKeyboard.h:216: multiple definition of `usbFunctionSetup'
MacroKeyboardTest.cpp.o:C:\Program Files (x86)\Digistump_Arduino\hardware\digistump\avr\libraries\DigisparkKeyboard/DigiKeyboard.h:216: first defined here
MacroKeyboard\MacroKeyboard.cpp.o: In function `MacroKeyboard::MacroKeyboard(char const*, int)':
C:\Program Files (x86)\Digistump_Arduino\hardware\digistump\avr\libraries\DigisparkKeyboard/DigiKeyboard.h:170: multiple definition of `DigiKeyboard'
MacroKeyboardTest.cpp.o:C:\Program Files (x86)\Digistump_Arduino\hardware\digistump\avr\libraries\DigisparkKeyboard/DigiKeyboard.h:199: first defined here
MacroKeyboard\MacroKeyboard.cpp.o:(.progmem.data.usbDescriptorHidReport+0x0): multiple definition of `usbDescriptorHidReport'
MacroKeyboardTest.cpp.o:(.progmem.data.usbDescriptorHidReport+0x0): first defined here
collect2: error: ld returned 1 exit status
Error compiling.
what am I doing wrong?
The library you use is written in a strange way. In the file DigiKeyboard.h there are such definitions as (comments mine):
// Declares a global variable.
// If you include this file in more than one cpp file it will cause linker error.
DigiKeyboardDevice DigiKeyboard = DigiKeyboardDevice();
// Defines a non-inline function
// Again, multiple definitions error if the file is included in several source files.
uchar usbFunctionSetup(uchar data[8]) {
// code
}
So you have to use it by including this .h file into only one of .cpp files.