Создание библиотеки для ардуино

Я нашел действительно хороший 24-битный АЦП I2C, который к тому же был довольно дешевым (ADS1219), но, насколько я мог судить, для него нет библиотек, поэтому я решил сделать свою собственную. Мне удалось написать функции и заставить все работать на самой Arduino, но у меня возникли серьезные проблемы с преобразованием их в библиотеку. Итак, я попробовал сделать очень простой скетч, чтобы посмотреть, смогу ли я сделать что-то простое, например, напечатать hello world, используя библиотеку. Вот мой файл ADS1219.h:

#ifndef ADS1219
#define ADS1219

#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif

class ADS1219{
public:
 ADS1219();
 void begin();
 void printHello();
};

#endif

И ADS1219.cpp:

#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif

#include 

ADS1219::ADS1219{
 Serial.println("New object created!");
}

void ADS1219::begin(){
 Serial.begin(9600);
}

void ADS1219::printHello(){
 Serial.println("Hello World");
}

и мой основной набросок:

#include 

ads = new ADS1219;

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

void loop() {
  ads.printHello();
  delay(2000);
}

но я получаю очень длинную ошибку, которая, по сути, говорит о том, что мне не удалось создать объект a ds. Я попробовал рекламу ADS1219; тоже, но та же ошибка... не знаю, в чем дело, если честно.

Arduino: 1.8.8 (Windows 10), Board: "Arduino Nano, ATmega328P (Old Bootloader)"

In file included from sketchADS1219.cpp:7:0:

ADS1219.h:14:11: error: expected unqualified-id before ')' token

   ADS1219();

           ^

ADS1219.h:12:14: error: an anonymous struct cannot have function members

 class ADS1219{

              ^

ADS1219.h:18:1: error: abstract declarator '' used as declaration

 };

 ^

ADS1219.cpp:9:17: error: expected id-expression before '{' token

 ADS1219::ADS1219{

                 ^

ADS1219.cpp:13:21: error: explicit qualification in declaration of 'void begin()'

 void ADS1219::begin(){

                     ^

ADS1219.cpp:17:26: error: explicit qualification in declaration of 'void printHello()'

 void ADS1219::printHello(){

                          ^

In file included from C:UsersOM222ODesktopadslibadslib.ino:1:0:

ADS1219.h:14:11: error: expected unqualified-id before ')' token

   ADS1219();

           ^

ADS1219.h:12:14: error: an anonymous struct cannot have function members

 class ADS1219{

              ^

ADS1219.h:18:1: error: abstract declarator '' used as declaration

 };

 ^

adslib:3:1: error: 'ads' does not name a type

 ads = new ADS1219;

 ^

C:UsersOM222ODesktopadslibadslib.ino: In function 'void setup()':

adslib:7:3: error: 'ads' was not declared in this scope

   ads.begin();

   ^

C:UsersOM222ODesktopadslibadslib.ino: In function 'void loop()':

adslib:11:3: error: 'ads' was not declared in this scope

   ads.printHello();

   ^

exit status 1
expected unqualified-id before ')' token

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

, 👍0

Обсуждение

Извините, я не знал, что такое существует... существует так много разных SE, ха-ха-ха. Я перенесу его туда., @OM222O

Первая ошибка: «#define ADS1219». Вместо этого используйте соглашение «#define ADS1219_H». Пожалуйста, возвращайтесь за дополнительной помощью по C++ :)., @Mikael Patel

Это абсолютно ничего не изменило :D, @OM222O

Я даже пытался загрузить точный код для создания библиотек, который показывали некоторые люди, но мне все равно не удалось! буквально тот же код не хочет работать на моей машине! Есть идеи, что я могу делать неправильно? изменить: вот ссылка, по которой я перешел: https://www.alanzucconi.com/2016/05/11/libraries-for-arduino/, @OM222O

Вам не нужно проверять старую версию Arduino. Это больше не используется. На дворе почти 2019 год. Просто подключите Arduino.h (только в файле ADS1219.h). Что такое #include без указания, какой файл включать? В скетче достаточно «ads ADS1219». В Github полно библиотек Arduino, там можно найти множество примеров, например: https://github.com/Locoduino/SlowMotionServo/tree/master/src и https://github.com/winlinvip/SimpleDHT (всего два случайных выбранные библиотеки, их должно быть сотни)., @Jot

@Jot, это именно то, что я сделал, поэтому у меня даже есть строка для проверки версий Arduino ... Я не знаю, что такое версия 1, но я напрямую скопировал эту часть заголовка из других библиотек. Как я уже сказал, я напрямую копирую чужой код и смотрю, где он ломается, пока не научусь писать все с нуля :D, @OM222O

Я создал здесь точно такой же вопрос... и не могу его удалить... может ли это сделать кто-нибудь другой? Я не хочу спамить вопросами, @OM222O

Кажется, я запутался со слиянием двух вопросов. Теперь это активный вариант., @Nick Gammon

@ OM222O OM222O, ты смотрел эти два случайных примера? Разница между ними и вашим кодом в том, что не так. Мы рассказали вам все, чтобы все заработало. Исправьте определение, исправьте включения, добавьте «()» для конструктора, удалите «= new» для объявления. Вот и все, тогда все будет работать., @Jot


3 ответа


2

Ваша проблема связана с этой строкой:

#define ADS1219

Вы определяете макрос ADS1219 как пустой. С этого момента все ссылки на ADS1219 ничем не заменяются. Например:

class ADS1219{
public:
 ADS1219();
 void begin();
 void printHello();
};

становится:

class {
public:
 ();
 void begin();
 void printHello();
};

И

void ADS1219::begin(){
 Serial.begin(9600);
}

становится:

void ::begin(){
 Serial.begin(9600);
}

Используя в заголовке то же имя, что и имя класса, вы портите все остальное.

Я всегда использую строгие правила для макросов защиты заголовков, чтобы гарантировать, что они никогда не конфликтуют ни с чем другим. Вам следует изменить свое, чтобы прочитать что-то другое. Я бы использовал:

#ifndef _ADS1219_H
#define _ADS1219_H

// ... содержание

#endif

В реализации конструктора также отсутствуют круглые скобки:

ADS1219::ADS1219{
 Serial.println("New object created!");
}

следует читать:

ADS1219::ADS1219(){
 Serial.println("New object created!");
}

И вы не задаете тип переменной ads и не хотите использовать new:

ads = new ADS1219;

следует читать:

ADS1219 ads;
,

Также в файл cpp ему не следует снова включать файл Arduino.h, а включать только файл библиотеки (ADS1219.h). Более того, в свои библиотеки я перестал включать WProgram.h. Вы считаете, что это все еще необходимо?, @frarugi87

Я не включал wprogram.h целую вечность. Не помешает включить файл несколько раз, поскольку заголовки должны включать защиту заголовков., @Majenko

спасибо, это решило мою проблему на данный момент: DI попытаюсь закончить остальное самостоятельно, но мне все равно может понадобиться помощь. Я опубликую ее, как только закончу, @OM222O


1

Вы уверены, что компилируете это для C++, а не C?

В любом случае вы определяете

#define ADS1219

Я не знаю, как это повлияет на имя вашего класса. Вы пробовали

#define ADS1219_H  // <- Стандартное включение защиты

вместо этого? Дает ли это разные результаты?

,

arduino — это сам C, но расширение файла — cpp (c plus plus), поэтому я сам немного запутался. Изменение его на ADS1219_H приводит к тому же сообщению об ошибке., @OM222O

спасибо за указание на это, и да, я использую IDE. Я почти уверен, что он использует компоновщик GCC и уже настроен правильно., @OM222O

Standard include Guard - разве не для этого используется #pragma Once?, @Jaromanda X

Arduino — это C++, а не C., @Majenko


0

Я добился большого прогресса и почти все работает нормально... за исключением того, что я изначально использовал струны в корпусе переключателя для настройки режимов опорного напряжения и преобразования... это совсем не понравилось. Вместо этого я намеревался использовать перечисления для той же цели, но теперь получаю следующую ошибку:

Arduino: 1.8.8 (Windows 10), Board: "Arduino Nano, ATmega328P (Old Bootloader)"

In file included from sketch\LibraryExample1.ino.cpp:1:0:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:81:18: error: expected identifier before numeric constant

 #define INTERNAL 3

                  ^

C:\Users\OM222O\Documents\Arduino\libraries\ADS1219/ADS1219.h:49:3: note: in expansion of macro 'INTERNAL'

   INTERNAL = VREF_INTERNAL,

   ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:81:18: error: expected '}' before numeric constant

 #define INTERNAL 3

                  ^

C:\Users\OM222O\Documents\Arduino\libraries\ADS1219/ADS1219.h:49:3: note: in expansion of macro 'INTERNAL'

   INTERNAL = VREF_INTERNAL,

   ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:81:18: error: expected unqualified-id before numeric constant

 #define INTERNAL 3

                  ^

C:\Users\OM222O\Documents\Arduino\libraries\ADS1219/ADS1219.h:49:3: note: in expansion of macro 'INTERNAL'

   INTERNAL = VREF_INTERNAL,

   ^

In file included from C:\Users\OM222O\Desktop\LibraryExample1\LibraryExample1.ino:2:0:

C:\Users\OM222O\Documents\Arduino\libraries\ADS1219/ADS1219.h:51:1: error: expected declaration before '}' token

 }adsRef_t;

 ^

exit status 1
Error compiling for board Arduino Nano.

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

мой файл ADS1219.h:

#ifndef ADS1219_H
#define ADS1219_H

#if (ARDUINO >=100)
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

#include <Wire.h>

#define CONFIG_REGISTER_ADDRESS 0x20
#define STATUS_REGISTER_ADDRESS 0x24

#define MUX_MASK                0x1F
#define MUX_DIFF_0_1            0x00
#define MUX_DIFF_2_3            0x20
#define MUX_DIFF_1_2            0x40
#define MUX_SINGLE_0            0x60
#define MUX_SINGLE_1            0x80
#define MUX_SINGLE_2            0xA0
#define MUX_SINGLE_3            0xC0
#define MUX_SHORTED             0xE0

#define GAIN_MASK               0xEF
#define GAIN_ONE                0x00
#define GAIN_FOUR               0x10

#define DATA_RATE_MASK          0xF3
#define DATA_RATE_20            0x00
#define DATA_RATE_90            0x04
#define DATA_RATE_330           0x08
#define DATA_RATE_1000          0x0c

#define MODE_MASK               0xFD
#define MODE_SINGLE_SHOT        0x00
#define MODE_CONTINUOUS         0x02

#define VREF_MASK               0xFE
#define VREF_INTERNAL           0x00
#define VREF_EXTERNAL           0x01

typedef enum{
  ONE   = GAIN_ONE,
  FOUR  = GAIN_FOUR
}adsGain_t;

typedef enum{
  INTERNAL  = VREF_INTERNAL,
  EXTERNAL  = VREF_EXTERNAL
}adsRef_t;

typedef enum{
  SINGLE_SHOT   = MODE_SINGLE_SHOT,
  CONTINUOUS    = MODE_CONTINUOUS
}adsMode_t;

class ADS1219  {
  protected:
    uint8_t address;
  public:
    // Constructor 
    ADS1219(int drdy, uint8_t addr = 0x40);

    // Methods
    void begin();
    void resetConfig();
    long readSingleEnded(int channel);
    long readDifferential_0_1();
    long readDifferential_2_3();
    long readDifferential_1_2();
    long readShorted();
    void setGain(adsGain_t gain);
    void setDataRate(int rate);
    void setConversionMode(adsMode_t mode);
    void setVoltageReference(adsRef_t vref);

  private:
    void writeRegister(uint8_t data);
    uint8_t readRegister(uint8_t reg);
    long readConversionResult();
    uint8_t config;
    int data_ready;
};
#endif

и мой файл cpp:

#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif

#include <Wire.h>
#include "ADS1219.h"

static uint8_t i2cRead(void) {
  #if ARDUINO >= 100
  return Wire.read();
  #else
  return Wire.receive();
  #endif
}

static void i2cWrite(uint8_t x) {
  #if ARDUINO >= 100
  Wire.write(x);
  #else
  Wire.send(x);
  #endif
}


ADS1219::ADS1219(int drdy, uint8_t addr) {
  data_ready = drdy;
  address = addr;
  config = 0x00;
}

void ADS1219::begin() {
  Wire.begin();
}

uint8_t ADS1219::readRegister(uint8_t reg){
  Wire.beginTransmission(address);
  i2cWrite(reg);
  Wire.endTransmission();
  Wire.requestFrom((uint8_t)address,(uint8_t)1);
  return i2cRead();
}

void ADS1219::writeRegister(uint8_t data){
  Wire.beginTransmission(address);
  i2cWrite(CONFIG_REGISTER_ADDRESS);
  i2cWrite(data);
  Wire.endTransmission();
}

long ADS1219::readConversionResult(){
  Wire.beginTransmission(address);
  i2cWrite(0x10);
  Wire.endTransmission();
  Wire.requestFrom((uint8_t)address,(uint8_t)3);
  byte dataMSB = i2cRead();
  byte data = i2cRead();
  byte dataLSB = i2cRead();
  long data32 = dataMSB;
  data32 <<= 8;
  data32 |= data;
  data32 <<= 8;
  data32 |= dataLSB;
  return (data32 << 8) >> 8;
}

void ADS1219::resetConfig(){
    writeRegister(0x00);
}

long ADS1219::readSingleEnded(int channel){
    if (channel > 3) return 0;
    config &= MUX_MASK;
    switch (channel){
    case (0):
      config |= MUX_SINGLE_0;
      break;
    case (1):
      config |= MUX_SINGLE_1;
      break;
    case (2):
      config |= MUX_SINGLE_2;
      break;
    case (3):
      config |= MUX_SINGLE_3;
      break;
    default:
      break;
  }
  writeRegister(config);
  while(digitalRead(data_ready)==1);
  return readConversionResult();
}

long ADS1219::readDifferential_0_1(){
  config &= MUX_MASK;
  config |= MUX_DIFF_0_1;
  writeRegister(config);
  while(digitalRead(data_ready)==1);
  return readConversionResult();
}

long ADS1219::readDifferential_2_3(){
  config &= MUX_MASK;
  config |= MUX_DIFF_2_3;
  writeRegister(config);
  while(digitalRead(data_ready)==1);
  return readConversionResult();
}

long ADS1219::readDifferential_1_2(){
  config &= MUX_MASK;
  config |= MUX_DIFF_1_2;
  writeRegister(config);
  while(digitalRead(data_ready)==1);
  return readConversionResult();
}

long ADS1219::readShorted(){
  config &= MUX_MASK;
  config |= MUX_SHORTED;
  writeRegister(config);
  while(digitalRead(data_ready)==1);
  return readConversionResult();
}

void ADS1219::setGain(adsGain_t gain){
    config &= GAIN_MASK;
    config |= gain;
  writeRegister(config);
}

void ADS1219::setDataRate(int rate){
    config &= DATA_RATE_MASK;
    switch (rate){
    case (20):
      config |= DATA_RATE_20;
      break;
    case (90):
      config |= DATA_RATE_90;
      break;
    case (330):
      config |= DATA_RATE_330;
      break;
    case (1000):
      config |= DATA_RATE_1000;
      break;
    default:
      break;
  }
  writeRegister(config);
}

void ADS1219::setConversionMode(adsMode_t mode){
    config &= MODE_MASK;
    config |= mode;
  writeRegister(config);
}

void ADS1219::setVoltageReference(adsRef_t vref){
    config &= VREF_MASK;
    config |= vref;
  writeRegister(config);
}

Кажется, он передает Gain (или, возможно, еще не скомпилировал его), но не может выбрать ссылку... Я не знаю, что мне следует изменить, чтобы решить проблему.

Редактировать: я очень надеюсь, что это не очередное соглашение об именах... если это так, то извините, но C++, похоже, слишком требователен к именам в целом

,

Подсказка: используйте частное перечисление для всех управляющих кодов и т. д. Использование #define — это старая школа, которая на самом деле является основной причиной многих проблем. C++ допускает пространства имен, частные, константные и т. д., что гораздо более семантически богато. Вот пример, который поможет вам в этом; https://github.com/mikaelpatel/Cosa/blob/master/libraries/ADXL345/ADXL345.hh, @Mikael Patel

Подсказка: чтобы избежать использования некоторых констант, масок и т. д., в структурах можно использовать битовые поля. Вот пример: https://github.com/mikaelpatel/Cosa/blob/master/libraries/DS2482/DS2482.hh, @Mikael Patel

большое спасибо! Я посмотрю. Я почти закончил программу :D, @OM222O