Как IDE организует вещи
Во-первых, вот как IDE организует ваш «эскиз»:
- Основной
.inoфайл является одним из того же имени, что и папки он находится в Итак, для. foobar.inoВ foobarпапке - основной файл foobar.ino.
- Любые другие
.inoфайлы в этой папке объединяются вместе в алфавитном порядке в конце основного файла (независимо от того, где находится основной файл в алфавитном порядке).
- Этот объединенный файл становится
.cppфайлом (например, foobar.cpp) - он помещается во временную папку компиляции.
- Препроцессор «услужливо» генерирует прототипы функций для функций, которые он находит в этом файле.
- Основной файл проверяется на наличие
#include <libraryname>директив. Это запускает среду IDE, чтобы также скопировать все соответствующие файлы из каждой (упомянутой) библиотеки во временную папку и сгенерировать инструкции для их компиляции.
- Любые
.c, .cppили .asmфайлы в папке эскиза добавляются в процессе сборки в виде отдельных единиц компиляции (то есть, они составлены обычным способом в виде отдельных файлов)
- Любые
.hфайлы также копируются во временную папку компиляции, поэтому к ним могут обращаться ваши файлы .c или .cpp.
- Компилятор добавляет в процесс сборки стандартные файлы (вроде
main.cpp)
- Затем процесс сборки компилирует все вышеуказанные файлы в объектные файлы.
- Если фаза компиляции проходит успешно, они связаны вместе со стандартными библиотеками AVR (например, предоставление вам
strcpyи т. Д.)
Побочным эффектом всего этого является то, что вы можете рассматривать основной эскиз (файлы .ino) как C ++ для всех намерений и целей. Однако создание прототипа функции может привести к неясным сообщениям об ошибках, если вы не будете осторожны.
Избежание причуд препроцессора
Самый простой способ избежать этих идиосинкразий - оставить основной эскиз пустым (и не использовать другие .inoфайлы). Затем создайте еще одну вкладку ( .cppфайл) и поместите в нее свои вещи так:
#include <Arduino.h>
// put your sketch here ...
void setup ()
{
} // end of setup
void loop ()
{
} // end of loop
Обратите внимание, что вам нужно включить Arduino.h. Среда IDE делает это автоматически для основного эскиза, но для других модулей компиляции это необходимо сделать. В противном случае он не будет знать о таких вещах, как String, аппаратные регистры и т. Д.
Как избежать установки / основной парадигмы
Вам не нужно работать с концепцией настройки / цикла. Например, ваш файл .cpp может быть:
#include <Arduino.h>
int main ()
{
init (); // initialize timers
Serial.begin (115200);
Serial.println ("Hello, world");
Serial.flush (); // let serial printing finish
} // end of main
Принудительное включение библиотеки
Если вы работаете с концепцией «пустой эскиз», вам все равно нужно включить библиотеки, используемые в других местах проекта, например, в ваш основной .inoфайл:
#include <Wire.h>
#include <SPI.h>
#include <EEPROM.h>
Это связано с тем, что среда IDE сканирует только основной файл на предмет использования библиотеки. По сути, вы можете рассматривать основной файл как файл проекта, который указывает, какие внешние библиотеки используются.
Проблемы с именами
Не называйте ваш главный набросок "main.cpp" - в среде IDE есть собственный main.cpp, поэтому у вас будет дубликат, если вы это сделаете.
Не называйте ваш .cpp файл тем же именем, что и ваш основной .ino файл. Поскольку файл .ino фактически превращается в файл .cpp, это также даст вам конфликт имен.
Объявление класса в стиле C ++ в одном и том же файле .ino (слышал, но никогда не видел работающим - это вообще возможно?);
Да, это компилируется нормально:
class foo {
public:
};
foo bar;
void setup () { }
void loop () { }
Однако вам, вероятно, лучше всего следовать обычной практике: поместите ваши декларации в .hфайлы, а ваши определения (реализации) в .cpp(или .c) файлы.
Почему "наверное"?
Как показывает мой пример, вы можете собрать все в один файл. Для более крупных проектов лучше быть более организованным. В конце концов вы попадаете на сцену в средне-крупномасштабном проекте, где вы хотите разделить вещи на «черные ящики», то есть класс, который делает одно, делает это хорошо, тестируется и самодостаточен ( настолько далеко, насколько возможно).
Если этот класс затем используется в нескольких других файлах в вашем проекте, то здесь отдельные .hи .cppфайлы вступают в игру.
.hФайл объявляет класс - то есть, он обеспечивает достаточно деталей для других файлов , чтобы знать , что он делает, какие функции у него есть, и как они называются.
В .cppфайл определяет (реализует) класс - то есть, он на самом деле обеспечивает функции и статические члены класса, которые делают класс делать свое дело. Поскольку вы хотите реализовать его только один раз, это находится в отдельном файле.
.hФайл , что входит в другие файлы. .cppФайл компилируется один раз в IDE для реализации функций класса.
Библиотеки
Если вы следуете этой парадигме, то вы готовы очень легко переместить весь класс ( файлы .hи .cppфайлы) в библиотеку. Затем его можно разделить между несколькими проектами. Все , что требуется , чтобы сделать папку (например. myLibrary) И поставить .hи .cppфайлы в ней (например, myLibrary.hа myLibrary.cpp) , а затем поместить эту папку внутри librariesпапки в папку , в которой хранятся ваши эскизы (этюдник папку).
Перезапустите IDE, и теперь она знает об этой библиотеке. Это действительно тривиально просто, и теперь вы можете поделиться этой библиотекой с несколькими проектами. Я делаю это много.
Чуть подробнее здесь .