Arduino: как получить тип платы в коде
Я хочу написать скетч, который можно будет скомпилировать на разных платах Arduino. Я хочу отобразить на ПК, какая плата подключена в данный момент.
Это означает, что пользователь подключает ПК через USB-кабель к плате Arduino/Teensy, на которой запускается мой скетч, и мой скетч сообщает ПК через последовательный порт, какая плата подключена. На ПК работает мое приложение C#, которое получает эти данные и отображает их.
Поэтому мне нужна плата, которая была выбрана при компиляции скетча:
Я нашел код на https://github.com/backupbrain/ArduinoBoardManager. но это не дает правильных результатов (кроме того, что не хватает нескольких плат).
Вот фрагмент кода:
static const uint8_t BOARD_MICRO= 0x04;
....
#elif defined(__AVR_Atmega32U4__) // Yun 16Mhz, Micro, Leonardo, Esplora
static const uint8_t BOARD = 0x04;
static const uint8_t NUM_BITS = 8;
static const uint16_t CPU = __AVR_Atmega32U4__;
static const unsigned long SRAM_SIZE = 2500;
static const unsigned long EEPROM_SIZE = 1000;
static const unsigned long FLASH_SIZE = 32000;
#elif defined(.....
Таким образом, этот код дает тот же результат (BOARD = 0x04 = Micro) для Yun 16MHz, Micro, Leonardo y Esplora.
Есть ли способ получить в моем коде C именно ту строку, которую пользователь выбрал в меню компилятора Arduino?
@Elmue, 👍16
Обсуждение6 ответов
Лучший ответ:
Благодаря помощи Чарли Хэнсона и Янтье я нашел универсальное решение!
Поскольку жаль, что каждый программист Arduino должен пройти через ту же боль, чтобы выяснить, как получить имя платы, я предложу свой код общественности, чтобы каждый мог просто скопировать и вставить его.
Вот оно:
#if defined(TEENSYDUINO)
// --------------- Тинси ------------------
#if defined(__AVR_ATmega32U4__)
#define BOARD "Teensy 2.0"
#elif defined(__AVR_AT90USB1286__)
#define BOARD "Teensy++ 2.0"
#elif defined(__MK20DX128__)
#define BOARD "Teensy 3.0"
#elif defined(__MK20DX256__)
#define BOARD "Teensy 3.2" // и Teensy 3.1 (устарело)
#elif defined(__MKL26Z64__)
#define BOARD "Teensy LC"
#elif defined(__MK64FX512__)
#define BOARD "Teensy 3.5"
#elif defined(__MK66FX1M0__)
#define BOARD "Teensy 3.6"
#else
#error "Unknown board"
#endif
#else // ----------------------------- Ардуино ------------------
#if defined(ARDUINO_AVR_ADK)
#define BOARD "Mega Adk"
#elif defined(ARDUINO_AVR_BT) // Bluetooth
#define BOARD "Bt"
#elif defined(ARDUINO_AVR_DUEMILANOVE)
#define BOARD "Duemilanove"
#elif defined(ARDUINO_AVR_ESPLORA)
#define BOARD "Esplora"
#elif defined(ARDUINO_AVR_ETHERNET)
#define BOARD "Ethernet"
#elif defined(ARDUINO_AVR_FIO)
#define BOARD "Fio"
#elif defined(ARDUINO_AVR_GEMMA)
#define BOARD "Gemma"
#elif defined(ARDUINO_AVR_LEONARDO)
#define BOARD "Leonardo"
#elif defined(ARDUINO_AVR_LILYPAD)
#define BOARD "Lilypad"
#elif defined(ARDUINO_AVR_LILYPAD_USB)
#define BOARD "Lilypad Usb"
#elif defined(ARDUINO_AVR_MEGA)
#define BOARD "Mega"
#elif defined(ARDUINO_AVR_MEGA2560)
#define BOARD "Mega 2560"
#elif defined(ARDUINO_AVR_MICRO)
#define BOARD "Micro"
#elif defined(ARDUINO_AVR_MINI)
#define BOARD "Mini"
#elif defined(ARDUINO_AVR_NANO)
#define BOARD "Nano"
#elif defined(ARDUINO_AVR_NG)
#define BOARD "NG"
#elif defined(ARDUINO_AVR_PRO)
#define BOARD "Pro"
#elif defined(ARDUINO_AVR_ROBOT_CONTROL)
#define BOARD "Robot Ctrl"
#elif defined(ARDUINO_AVR_ROBOT_MOTOR)
#define BOARD "Robot Motor"
#elif defined(ARDUINO_AVR_UNO)
#define BOARD "Uno"
#elif defined(ARDUINO_AVR_YUN)
#define BOARD "Yun"
// Эти платы должны быть установлены отдельно:
#elif defined(ARDUINO_SAM_DUE)
#define BOARD "Due"
#elif defined(ARDUINO_SAMD_ZERO)
#define BOARD "Zero"
#elif defined(ARDUINO_ARC32_TOOLS)
#define BOARD "101"
#else
#error "Unknown board"
#endif
#endif
Вы даже можете поместить этот код в новый заголовочный файл и включить его в свой проект.
PD Если вы хотите узнать дополнительно к плате еще и модель процессора, ищите файл avr_cpunames.h
еще одна вещь. вместо использования "return "?";" когда вы не знаете, используйте имя платы предупреждений #pragma неизвестно, @jantje
1.) Я заменил "?" с #ошибкой. 2.) Я не думаю, что струны действительно проблема. Вы поняли, что в конце будет скомпилирована только ОДНА строка? См. мое обновление, которое объясняет это выше. Самая длинная строка составляет 11 байт. Если вам нужно оптимизировать свой код настолько, что вам нужны 11 байтов, я рекомендую определить перечисление и вернуть его вместо строки. Тогда ваша функция вернет один байт вместо 11., @Elmue
3.) А что касается ремонтопригодности: Печально, что приходится писать такую функцию. Это уже должно быть частью файлов заголовков, которые устанавливаются вместе с компилятором, и должны поддерживаться разработчиками и обновляться с каждой новой версией., @Elmue
2) Ошибся при написании примечания по размеру. Я сделал замечание по этому поводу 5 часов назад. Простите за это. 3) Ремонтопригодность - проблема. Я писал очень похожий код в прошлом. Я уверен, что многие другие тоже. Именно удобство сопровождения, почему я предпочитаю «лучшее решение IDE». Я почти уверен, что все «лучшие IDE» будут иметь решение, подобное тому, которое я упомянул в своем ответе. Воспринимайте это как дополнение: вы перерастаете Arduino IDE., @jantje
Если вы написали неправильный комментарий, лучше всего будет его удалить., @Elmue
Мне нравится это решение. Вот предлагаемое дополнение для ESP8266. #elif определено (ESP8266) #define ПЛАТА "ESP8266", @Doug Johnson
Точные названия в меню взяты из файла boards.txt в Arduino IDE (Arduino\hardware\arduino\avr\boards.txt). Я думаю, вам придется самостоятельно разобрать файл и найти там обнаруженную плату.
Разобрать файл ?? И как мне узнать, какой из них выбран в меню?, @Elmue
Обратите внимание, что это мод для Windows, что-то подобное должно существовать в Linux.
Первый быстрый и простой. Просто измените файлы platform.txt, которые вы используете, как описано ниже. Недостатком этого является то, что вам нужно будет изменять файлы platform.txt с каждым выпуском.
добавьте -DBOARD=\"${build.board}\" к рецепту. Это позволит
const char boardName[]=BOARD;
Что дает вам строку "ARDUINO_AVR_LEONARDO" (для leonardo) в boardName.
Второй способ — перейти на лучшую IDE (как уже предлагалось другими). Как создатель плагина arduino eclipse, я бы посоветовал использовать плагин arduino eclipse. В плагине arduino eclipse вы делаете это следующим образом: Правой кнопкой по проекту->свойства->arduino->вкладка "параметры компиляции" поставить
-DBOARD=\"${A.BUILD.BOARD}\"
в поле добавления к C и C++.
Это заставит приведенный выше код скомпилироваться
Приложение
Я не знал, что вам нужно "красивое имя". Я не уверен, что это можно исправить в файле platform.txt в Arduino IDE. В плагине arduino eclipse измените исправление выше в
-DBOARD=\"${A.NAME}\"
чтобы получить красивое имя (для leonardo "Arduino Leonardo") в плате определения.
Не могли бы сторонник понижения голоса или кто-либо еще указать, почему этот ответ нуждается в голосовании?, @jantje
1.) Да, StackExchange должен заставить всех, кто проголосовал против, написать объяснение. (Это был не мой отрицательный голос) 2.) Нет необходимости использовать Eclipse для решения этой проблемы. 3.) Смотрите мой ответ здесь., @Elmue
Elmue, 1) спасибо за согласие :-). 2) Я согласен. Первая часть ответа заключается в том, как вы можете исправить это, изменив txt платформы, чтобы он работал в Arduino IDE. В вашем ответе более подробно рассказывается, как это исправить. Для этого не нужно иметь eclipse или какую-либо лучшую IDE. Лучшее решение ide упоминается, потому что IDE Arduino должен анализировать boards.txt, поэтому он, вероятно, где-то хранит эту информацию и имеет возможность работать без необходимости изменения platform.txt. Поскольку я очень хорошо знаю плагин arduino eclipse, я приведу пример того, как это сделать с помощью этого инструмента. 3) Смотрите мою правку, @jantje
Eclise также работает с Teensy? Какие еще преимущества есть у Exclipse?, @Elmue
Да, teensy поддерживается плагином arduino eclipse, но вам придется модифицировать файл platform.txt (должен быть исправлен в teensyduino 1.28), @jantje
Достоинства: Трудно сказать, так как их очень много. Мне лично нравится, когда вы щелкаете, чтобы увидеть код (когда вы щелкаете по методу, вы переходите к реализации/объявлению этой функции/переменной, даже если это основной код arduino). Дерево вызовов (где это используется?) — действительно мощное представление. Автодополнение, объем, несколько проектов(=скетчей) в одном месте, встроенный контроль версий..., @jantje
Некоторое время назад я задал связанный вопрос.
Существует внутренний файл *.h, который создается IDE и содержит выбранный тип платы. Список возможных вариантов приведен в связанном вопросе, но только для плат AVR . Я считаю, что список не-AVR намного короче.
Это просто вопрос добавления некоторых условных операторов, чтобы отправить ПК правильную информацию. Простой пример:
//...в вашем коде, возможно, во время setup()...
#ifdef ARDUINO_AVR_UNO
serial.println("UNO");
#endif
#ifdef ARDUINO_AVR_LEONARDO
serial.println("LEONARDO");
#endif
// и т. д...
Если вам нужно указать тип платы в скетче более одного раза, используйте следующий формат:
//...ДО setup() или иначе в глобальном пространстве имен...
#ifdef ARDUINO_AVR_UNO
#define __BOARD_TYPE "UNO"
#endif
#ifdef ARDUINO_AVR_LEONARDO
#define __BOARD_TYPE "LEONARDO"
#endif
// и т. д...
// внутри вашего кода, где это необходимо:
serial.println(__BOARD_TYPE);
Последний намного аккуратнее, даже если вам нужен __BOARD_TYPE
только один раз, так как он удаляет громоздкий фрагмент #ifdef
из ваших функций.
Конечно, вам придется написать по одному для каждой платы, которая, как вы ожидаете, может быть у вашего конечного пользователя, и вам, возможно, потребуется обновить этот список по мере появления новых моделей .
Спасибо за Ваш ответ. Мне очень помогло. (См. мой ответ здесь) Но в вашем коде есть ошибка. Вместо AVR_UNO должно быть ARDUINO_AVR_UNO., @Elmue
Возможно, вы захотите удалить точки с запятой в конце вашего #define; они не являются операторами C и не нуждаются в разделителях; на самом деле разделители будут вставлены там, где используются макросы, ссылка внутри скобок функции println(). (Если убрать точки с запятой, этот комментарий не будет иметь смысла для последующих читателей)., @Zeph
Исходный ответ устарел, так как были добавлены новые платы. Базовый тест правильный, но непонятно, откуда берется список плат.
Если вы найдете файл boards.txt
и просмотрите его (например, ~\Library\Arduino\hardware\arduino\avr\boards.txt
на Mac ), каждая плата будет иметь запись в виде строк <BOARD>.build.board=<NAME>
, поэтому, например, для MKR1000 будет строка:
mkr1000.build.board=SAMD_MKR1000
Соответствующий #define может быть сгенерирован путем добавления к <NAME>
префикса ARDUINO_
, поэтому в этом примере следующий код выдаст ошибку для платы MKR1000...
#if определено(ARDUINO_SAMD_MKR1000)
#ошибка
Этот ответ просто бла-бла. Почему бы вам просто не опубликовать полный список всех новых плат со всеми определениями?, @Elmue
Для плат Adafruit, в частности Feather M4, у меня сработало следующее.
#ifdef _VARIANT_FEATHER_M4_
serial.println("Feather M4");
#endif
- устаревшее преобразование из строковой константы в 'char*'
- Как запрограммировать ардуино на чистом C/C++?
- Количество элементов в массиве char
- Регистры ввода-вывода SAM3X8E (Arduino Due)
- как быстро loop() работает в Arduino
- Как вызвать функции C из скетча ардуино?
- Как преобразовать полезную нагрузку byte* в строку
- "EVERY_N_MILLISECONDS"
Если вы используете arduino IDE для сборки прошивки, нет возможности передать компилятору #define на уровне проекта, кроме F_CPU ARDUINO и __AVR_whatever__. Возможно, вам придется использовать make-файл для сборки вместо arduinio IDE. Посетите сайт arduino.SE, у Ника и Игнатио есть несколько хороших примеров., @MarkU
Я не могу найти ничего интересного на Arduino.SE. (Это шведский?), @Elmue
@Elmue arduino.StackExchange.com — это Arduino SE., @Avamander
Аааа. ХОРОШО. Но arduino.se существует!, @Elmue
Под «Я хочу отобразить на ПК, какая плата в данный момент подключена» вы имеете в виду отображать ее при запуске скомпилированного и загруженного скетча, или отображать ее во время компиляции скетча, или пока IDE просто сидит там с определенным плата прилагается? (В последних двух случаях выбор платы отображается в нижней строке IDE 1.6.3, но если у вас более старая или другая IDE, возможно, нет.) (Если применим первый случай, хотите ли вы, чтобы он отображался в последовательном мониторе? ?), @James Waldby - jwpat7
Я обновил свой вопрос, чтобы сделать его более понятным. Я хочу без IDE и без последовательного монитора. Просто мой скетч сообщает ПК через Serial: «Кто я»., @Elmue