Arduino IDE - область применения препроцессора "#define"

Я создаю библиотеку Arduino, и у меня есть 3 файла - программа "test.ino" и два файла библиотеки/класса: "testLibrary.h" и "testLibrary.cpp".

Библиотека использует некоторые аппаратные ресурсы, такие как регистры и ISR, которые зависят от того, какой вывод ввода-вывода используется, и это должно быть сделано во время компиляции.

Я хотел бы #определить пин в основной программе, который во время компиляции используется в библиотеке для определения того, какие разделы кода активируются. Поскольку это будет стандартная библиотека Arduino для использования другими, она должна компилироваться и запускаться без необходимости изменения компилятора или #include path, чтобы заставить ее работать.

Но кажется, что область #define в основной программе/скетче не распространяется на библиотеку.

тест.

#define PIN_NUMBER 3
#include "testLibrary.h"
void setup() {}
void loop() {}

testLibrary.h

#ifndef _TESTLIBRARY_h
#define _TESTLIBRARY_h
#ifndef PIN_NUMBER
#error PIN is not defined
#endif
class test {
public:
  test();
  ~test();
};
#endif

testLibrary.cpp

#include "testLibrary.h"
test::test(){}*
test::~test(){}

Компиляция вышеуказанных ветвей в "#error" с помощью Arduino IDE 1.8.13, а также с помощью Visual Studio с Visual Micro.

Есть ли способ для меня, чтобы библиотека Arduino использовала "#define" из основного скетча?

, 👍2

Обсуждение

На самом деле вы не определили " PIN_NUMBER` в своем коде. Или это ошибка копирования и вставки?, @chrisl

У вас есть два #endif, но только один #if в *testLibrary.h*. Это вызовет ошибку компиляции, если вы определите "PIN_NUMBER" в своем основном коде (*test.ino*), когда он пропустит "#error "в *testLibrary.h*. Может быть, вы не заметили ошибку "#endif without #if"? Вы можете исправить это, вставив #define _TESTLIBRARY_h в качестве первой строки *testLibrary.h*. I. o.w. область действия PIN_NUMBER будет глобальной, если вы определите ее в *test.ino*. Попробовать это., @StarCat

Это была действительно ошибка копирования и вставки, я поставил первую строку своего кода на ту же строку, что и теги кода, что означает, что для каждого из моих фрагментов кода первые строки отсутствовали. Я это исправил (@chrisl & StarCat)., @Zanshin

Вы можете использовать заголовочный файл библиотеки в нескольких других библиотеках или приложениях. Таким образом, заголовочные файлы библиотеки не должны зависеть от того, где они были использованы. Даже если бы препроцессор разрешал определенные локальные макросы во включенных (заголовочных) файлах, это был бы очень плохой дизайн. Как вы можете знать, что будет делать основное приложение? Это приводит к ужасным ошибкам для людей, использующих вашу библиотеку. Если вам нужно значение в классе, просто добавьте свойство в класс и установите его в основном коде с помощью вашей константы. Библиотека SoftwareSerial делает это, например, для определения контактов tx и rx., @Peter Paul Kiefer

Есть ли особая причина, по которой вы хотите использовать определение? Соглашение состоит в том, чтобы позволить пользователю предоставлять такую информацию в качестве параметров либо для конструктора класса, либо для метода begin ()., @chrisl

Поскольку любой контакт на Arduino может быть использован, мне нужно было бы определить каждый INT или PCINT "ISR" в библиотеке, даже если нужен только один, и это исключило бы их использование в другом месте. Поэтому я хочу использовать инструкцию precompiler; если это значение передается в качестве параметра во время выполнения для этого приложения, слишком поздно., @Zanshin

работает ли это, если вы избавитесь от cpp-файла (переименуете его в .cpp.old)? Мне пришлось поместить полный код библиотеки в файл H, чтобы заставить его распознавать defines перед тем, как #включить его. Работает отлично, так как заголовочный файл просто буквально вставляется в ino в точке оператора #include. Обычно код в заголовке хмурится, потому что его легко вставить несколько раз, но все файлы ino все равно объединяются вместе, так что шансов на это нет. Используемый таким образом, он точно так же, как вставка дополнительного файла ino поверх вашего скетча, работает довольно интуитивно., @dandavis

иначе говоря: ошибка проистекает из testLibrary.cpp, а не заголовочный файл, потому что как другая единица перевода макрос ino не определен; он должен работать так, как будто ino не существует, а cpp и h-файлы имеют все, что им нужно. afaik, просто нет способа "передать" значение из ino в cpp-файл lib., @dandavis

Спасибо за все ответы. Я этого и боялся, поскольку документация по c++ действительно привела меня к пониманию того, что область действия "#define" ограничена. @dandavis. В конце концов я собираюсь использовать "BADISR_vect" в качестве универсала и предположить, что единственным неопределенным прерыванием является INTx или PCINTx для контакта, который будет передан библиотеке как часть вызова "begin()" во время выполнения. И вместо компактной серии операторов "#define", которые вычисляются во время компиляции, мне придется использовать более длинный оператор "switch(pin)" во время выполнения., @Zanshin


1 ответ


2

Область действия макроса #DEFINE - это единица перевода. Это текущий файл .c или .cpp, который в настоящее время компилируется.

В вашем коде номер PIN_NUMBER определен в test.ino. Макрос #include буквально копирует содержимое testLibrary.h в test.ino. Так что для компилятора это работает идеально, так как определен номер PIN_NUMBER.

Ваш testLibrary.cpp однако не доволен этим. В том числе в testLibrary.h для компиляции отсутствует определение PIN_NUMBER.

Среда IDE Arduino очень ограничена и не предлагает вам способа глобального определения номера ПИН. Обычно это делается с аргументом компилятора-DPIN_NUMBER=3. Все единицы перевода получат этот аргумент, и, таким образом, компиляция будет успешной. Нет необходимости указывать PIN в коде.

,

К сожалению, добавление аргумента компилятора не является решением - вся постановка проблемы была связана с попыткой создать стандартную библиотеку, которую любой пользователь Arduino IDE мог просто загрузить и включить _ без_ внесения каких-либо последующих изменений., @Zanshin

В ответе на аналогичный вопрос предлагается поместить #define в заголовочный файл, который затем включается во все единицы перевода (т. Е. ino, c или cpp-файлы) https://arduinoprosto.ru/q/23681/visibility-of-define-between-sketch-and-library, @RowanP