Платформа Arduino популярна, независимо от того, ругают её или хвалят. Её создателям удалось снизить порог вхождения до уровня несколько кликов мышью + пара строк кода и вуаля — вот вам моргающий светодиодик. И вообще, для быстрого прототипирования поделок на AVR, Arduino вещь крайне удобная. Единственное что им не удалось это IDE, которую и IDE-то назвать сложно. Среди функций IDE она обеспечивает только одну — автоматизацию создания и сборки проекта.

Для пользователей Windows существует альтернатива: MS Visual Studio Community + плагин vMicro который позволяет писать скетчи, но уже со всеми вкусностями, предоставляемыми IDE. Плагин без проблем качается в самой студии через меню «Инструменты» и в триале работает сколько угодно. Платная версия в теории поддерживает пошаговую отладку, но меня, как владельца лицензионной копии vMicro они не очень-то и впечатлили.

Для пользователей Linux всё как всегда: хотим хорошую IDE — выбираем «жертву» и пытаемся прикрутить к ней нужный функционал. Существуют решения на базе Eclipse, но я не люблю эклипс, о чём уже однажды писал. Я мирюсь с ним как с неизбежным злом, когда под рукой нет вообще ничего подходящего. Из всех бесплатных IDE я больше всего уважаю мощный и замечательный Qt Creator, в котором я и моя команда работаем уже больше года. Поэтому и рассказывать буду о том, как превратить его в среду разработки для Arduino.

1. Подготовка почвы


Qt Creator имеется в репозиториях любого более-менее уважающего себя дистрибутива Linux. Например в арче его получают так

$ sudo pacman -S qtcreator

Кроме того, нам понадобятся пакеты, касающиеся самой Arduino

$ sudo pacman -S arduino arduino-avr-core

В тот день, когда мы наконец забудем Arduino нам понадобятся ещё компилятор, ассемблер, компоновщик и стандартная библиотека C для AVR, поэтому ставим и их

$ sudo pacman -S avr-gcc avr-binutils avr-libc

Отладчик и эмулятор мы опробуем уже в этой статье, поэтому установим ещё такие пакеты

$ sudo pacman -S avr-gdb simavr

2. Создаем проект в Qt Creator


Запускаем Qt Creator и создаем новый проект без Qt на языке C++



Выбираем расположение проекту и даем ему имя



В качестве системы сборки берем штатный qmake



Рабочий комплект оставляем по-умолчанию, поправим это потом



Под контроль версий добавляем проект по желанию



Получаем стандартный C++ проект



В проекте всего два файла: main.cpp и led-blink.pro. Первый удаляем, второй вычищаем от всего что там написано, получая совершенно пустой проект



Теперь ручками начинаем писать текст в *.pro файл, формируя структуру проекта для Arduino

# Определяем переменные окружения сборки

# Корневой каталог исходников Arduino Core
ARDUINO_DIR=/usr/share/arduino/hardware/archlinux-arduino/avr/
# Выбираем целевой контроллер (Arduino Uno, Nano, Mini)
ARDUINO_MCU=atmega328p
# Частота тактирования контроллера
ARDUINO_FCPU = 16000000L

Исключаем из проекта всё что касается Qt и выбираем шаблон проекта

# Ни гуи, ни ядра Qt нам не надо!
QT -= gui core
CONFIG -= qt

# Шаблон проекта - приложение, будет собираться исполняемый файл формата ELF 
TEMPLATE = app

Задаем каталог для собранного бинарника и его имя

DESTDIR = ../bin
TARGET = led-blink

Дальше подключим директории поиска заголовочных файлов

# Подключаем заголовочные файлы
INCLUDEPATH += $$ARDUINO_DIR/cores/arduino
INCLUDEPATH += $$ARDUINO_DIR/variants/standard
INCLUDEPATH += $$ARDUINO_DIR/libraries
INCLUDEPATH += /usr/avr/include

Задаем компилятор C и его ключи

QMAKE_CC = /usr/bin/avr-gcc
QMAKE_CFLAGS += -c -g -Os -w -ffunction-sections -fdata-sections
QMAKE_CFLAGS += -MMD -mmcu=$$ARDUINO_MCU -DF_CPU=$$ARDUINO_FCPU
QMAKE_CFLAGS += -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR

и компилятор C++ и его ключи

QMAKE_CXX = /usr/bin/avr-g++
QMAKE_CXXFLAGS += -c -g -Os -w  -ffunction-sections -fdata-sections
QMAKE_CXXFLAGS += -fno-exceptions -fno-threadsafe-statics
QMAKE_CXXFLAGS += -MMD -mmcu=$$ARDUINO_MCU -DF_CPU=$$ARDUINO_FCPU
QMAKE_CXXFLAGS += -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR

задаем компоновщик и его ключи

QMAKE_LINK = /usr/bin/avr-gcc
QMAKE_LFLAGS = -w -Os -Wl,--gc-sections -mmcu=$$ARDUINO_MCU
QMAKE_LIBS = -lm

Настраиваем постобработку ELF-файла, с целью перекрутить его в Intel HEX для последующей прошивки в плату

QMAKE_POST_LINK += /usr/bin/avr-objcopy -O ihex -j .text -j .data -S ${TARGET} ${TARGET}.hex

Указываем, какие заголовочные файлы включаются в проект

HEADERS += $$files($$ARDUINO_DIR/cores/arduino/*.h)
HEADERS += $$files($$ARDUINO_DIR/variants/standard/*.h)

Задаем файлы исходных текстов Arduino Core

SOURCES += $$files($$ARDUINO_DIR/cores/arduino/*.c)
SOURCES += $$files($$ARDUINO_DIR/cores/arduino/*.cpp)

Так, ну а когда мы собственно начнем писать скетч? Сейчас и начнем, но то что мы проделали, благородные доны, это необходимый минимум для того чтобы код скетча заработал.

Теперь добавляем в проект исходник скетча. Правой кнопкой щелкаем по проекту в дереве и выбираем «Добавить новый...» Добавляем файл исходных текстов C++



Чтобы упорядочить исходники внутри проекта, в следующем окне



жмем «Обзор» и создаем папку src для файлов *.cpp



Теперь даем файлу имя



Жмем на следующем окошке «Завершить». Получаем такую картинку



IDE добавит этот файл в скрипт сборки led-blink.pro

HEADERS += $$files($$ARDUINO_DIR/cores/arduino/*.h)
HEADERS += $$files($$ARDUINO_DIR/variants/standard/*.h)

# Исходники Arduino Core
SOURCES += $$files($$ARDUINO_DIR/cores/arduino/*.c)     src/led-blink.cpp
SOURCES += $$files($$ARDUINO_DIR/cores/arduino/*.cpp)

но, чтобы не делать длинных списков исходников, я обычно делаю так

# Заголовки Arduino Core
HEADERS += $$files($$ARDUINO_DIR/cores/arduino/*.h)
HEADERS += $$files($$ARDUINO_DIR/variants/standard/*.h)

# Исходники Arduino Core
SOURCES += $$files($$ARDUINO_DIR/cores/arduino/*.c)
SOURCES += $$files($$ARDUINO_DIR/cores/arduino/*.cpp)

# Исходники проекта
SOURCES += $$files(./src/*.cpp)

Теперь сделаем то, что Arduino IDE нам никогда не обеспечит: добавим к скетчу заголовочный файл, проделав действия аналогичные вышеописанным



В этот файл добавим необходимые проекту заголовки

#ifndef LED_BLINK_H
#define LED_BLINK_H

#include    <Arduino.h>

#endif // LED_BLINK_H

настроим пути к заголовкам и исходникам

#Заголовки проекта

INCLUDEPATH += ./include
HEADERS += $$files(./include/*.h)

# Исходники проекта
SOURCES += $$files(./src/*.cpp)

и вот теперь, наконец, напишем скетч

#include    "led-blink.h"

//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
void setup()
{

}

//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
void loop()
{

}

Теперь щелкаем правой кнопкой по дереву проекта и выбираем «Собрать»



Идем в папку проекта. У нас появился каталог bin/, в котором лежат продукты работы компилятора



Всё ок, присутствует ELF, который пригодится при отладке и hex для прошивки в контроллер. Теперь напишем очередную моргалку светодиодом на пине 13

#include    "led-blink.h"

#define LED_STAND_PIN 13

unsigned long time = 0;
unsigned long DELAY = 500000;
bool on = false;

//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
void setup()
{
    pinMode(LED_STAND_PIN, OUTPUT);
}

//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
void loop()
{
    if ( micros() >= time + DELAY )
    {
        time = micros();
        on = !on;
    }

    uint8_t state = on ? HIGH : LOW;

    digitalWrite(LED_STAND_PIN, state);
}

Собираем проект, заходим в bin/. Втыкаем в усб вашу плату. В моем случае это Uno, в моей системе она выставляет для программирования порт с именем /dev/ttyACM0. Выполняем команду

$ avrdude -c arduino -p m328p -P /dev/ttyACM0 -b 115200 -U flash:w:led-blink.hex:i

Здесь

  • -P /dev/ttyACM0 — порт программатора
  • -p m328p — модель контроллера
  • -c arduino — тип программатора: встроенный в плату Uno
  • -b 115200 — скорость порта
  • -U flash:w:led-blink.hex:i — указываем область прошивки, тип операции (запись) и файл прошивки

Выхлоп, похожий на такой

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "led-blink.hex"
avrdude: writing flash (2838 bytes):

Writing | ################################################## | 100% 0.47s

avrdude: 2838 bytes of flash written
avrdude: verifying flash memory against led-blink.hex:
avrdude: load data flash data from input file led-blink.hex:
avrdude: input file led-blink.hex contains 2838 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.38s

avrdude: verifying ...
avrdude: 2838 bytes of flash verified

avrdude: safemode: Fuses OK (E:00, H:00, L:00)

avrdude done.  Thank you.

сообщает нам, что процесс прошел нормально. Светодиодик будет моргать с частотой 2 Гц.

В принципе, можно настроить прошивку и в IDE. Для этого делаем настройки запуска такими



и, выбрав запуск проекта (нажав Ctrl + R) мы выполним прошивку и запуск так же точно, как это делает Arduino IDE.

Выводы


Описанный процесс настройки — довольно трудоемкая процедура. Но взамен мы получаем всю мощь одной из самых замечательных IDE, существующих в системах на базе ядра Linux (да и Windows это тоже касается). Автодописывание, рефакторинг, удобная навигация по коду — всё это теперь можно с успехом использовать.

Этот пример сделан, что называется, «в лоб». На деле Arduino IDE компонует Arduino Core в отдельную статическую библиотеку core.a и линкует с исполняемым файлом. В итоге прошивки собранные в стандартной среде выходят меньше по размеру, чем в описанном в статье методе. С этими нюансами мне ещё предстоит разобраться. А заодно в следующей заметке на эту тему мы поговорим о:

  • структуре проекта, выясним где находится функция main() и покажем, почему чрезмерное зацикливание на Arduino это плохо
  • пошаговой отладке с использованием эмуляторов
  • разберемся с опциями компилятора, применяемыми при сборке

в общем постараемся прояснить многие вопросы, полезные для понимания происходящих процессов, без которого в будущем перейти с Arduino на нечто более продвинутое будет сложно.

Комментарии (13)


  1. gudvinr
    18.11.2017 04:00

    Но почему qmake, а не cmake, например?
    В сети немало готовых скелетов для ардуино на cmake.
    А конфигураторы проектов cmake поддерживаются чуть ли не всеми IDE.


    1. maisvendoo Автор
      18.11.2017 11:55

      qmake — родная система сборки для Qt Creator (наряду с Qbs). Qt Creator поддерживает и систему cmake, собирает проекты на её основе. Но там есть проблемы с добавление файлов в проект через IDE. В статье акцент смещен на выбор IDE, а не выбор системы сборки.

      Есть и ряд субъективных причин. Мне нравится cmake, но по моему мнению она достаточно многословна, но повторюсь это очень субъективно. Плюс из вменяемых IDE использующих cmake: CLion за деньги, Netbeans больше заточен под java, Eclipse не предлагать.

      Так что да, выбор обусловлен личной привязанность к Qt Creator


      1. Serge78rus
        18.11.2017 15:06

        Не могли бы Вы подробнее объяснить неприятие Eclipse, давно ей широко пользуюсь, в том числе и для C/C++, и из существенных недостатков могу назвать только отсутствие поддержки синтаксиса C++14 и свежее. Так сказать, раскройте мне глаза, может, действительно засиделся я на ней и пора мигрировать на что-то еще. В Qt Creator немного поработал — после Eclipse непривычно, а привычка хоть и дело наживное, но требует времени. Хочется понять — стоит ли игра свеч.

        Личное мнение по поводу Arduino: пока программу называют скетчем, никакая IDE не поможет перейти от «скетчестроения» к нормальному программированию.


        1. maisvendoo Автор
          18.11.2017 20:19
          +1

          Не могли бы Вы подробнее объяснить неприятие Eclipse

          Могу. Среда функционально мощная, но с гадко спроектированным, не очевидным UI. К тому же разработана на java, откуда проистекают неприятные фризы при её работе. Qt Creator для C намного более приятен. Неоспоримый плюс эклипс — это комбайн, который можно настроить под что угодно, в отличие от creator'а, заточенного исключительно под C/C++.


          1. eugenk
            19.11.2017 22:12

            Среда функционально мощная, но с гадко спроектированным, не очевидным UI.

            С UI у меня как раз претензий нет, тут по-моему как раз QT Creator хуже. Впрочем возможно только из-за моей привычки к эклипсу. Претензии у меня в том, что начиная с 4-й ветки, эклипс становится с каждым выпуском всё хуже. Растёт потребление памяти, всё больше тормозит и т.п. Вобщем под эклипсом я если не с самого его начала, то уж со второй ветки это точно. Причем не только пользуюсь, но и пишу для него плагины. Но последнее время усиленно гляжу по сторонам, куда бы с него сбежать. Увы, бежать пока особо некуда. Сейчас например ваяю проектик на верилоге. Выяснилось, что из свободных редакторов для него тоже нет ничего лучшего, чем SVEditor под эклипс. Да, он тоже достаточно безобразен. Но всё остальное ещё хуже.


  1. WebConn
    18.11.2017 15:27

    Разделяю вашу симпатию к Qt Creator и умеренно — к ардуинам, хотя часто это самый простой и быстрый наваять какую-нибудь поделку. Спасибо за материал!

    Вот ещё тема для будущих заметок: сборка для Arduino Leonardo и их производных, у которых на борту atmega32u4. Там с проектом ещё надо хитро слинковать кусок usb-загрузчика (искать Caterina bootloader), который у них не влез в область загрузчика и без которого плату будет проблемно перепрошить.


    1. maisvendoo Автор
      18.11.2017 20:22

      и умеренно — к ардуинам,

      Умеренно — хорошее слово, выражающая и моё отношение. По роду деятельности я не эмбеддер, но приходится вникать в техпроцесс команды электронщиков, которым часто не хватает времени на поддержку наших совместных проектов. А они для прототипирования используют Arduino, отсюда проистекает и мой интерес к данной теме


  1. ploop
    18.11.2017 20:40

    У Qt Creator'а хорошая система плагинов, неужели никто не написал плагин для C/C++ эмбеддед-проектов и Arduino в частности?


  1. Zibx
    19.11.2017 14:10

    Расскажите как настроить в такой связке нормальный дебаггер. Хотелось бы получить обычных брейкпоинтов и возможности оглядеться вокруг. Без этого мы приходим к обычному дебагу принтами.


    1. maisvendoo Автор
      19.11.2017 14:12

      Нормальную отладку с эмулятором настроить очень легко, и об этом я напишу. Что касается отладки внутрисхемной, тут есть сложности


      1. ploop
        20.11.2017 22:28

        Ну я в своё время под саблайм внутрисхемную настраивал (STM32 правда), не думаю, что проблемы будут.


  1. xlop-chik
    20.11.2017 13:52

    автор, а что на GTK ничего нет? мне для того, чтобы попробовать ваш пример нужно пол KDE установить… хотелось бы примеров на GTK+ 3.22.


  1. granindb
    21.11.2017 06:54

    Попытался выполнить это под Windows.
    Получил ошибку
    14:23:12: Запускается: «C:\Qt\Qt5.9.1\Tools\mingw530_32\bin\mingw32-make.exe»
    C:/Qt/Qt5.9.1/Tools/mingw530_32/bin/mingw32-make -f Makefile.Release
    mingw32-make[1]: Entering directory 'Z:/Coding/qt/arduino_template'
    r:/Programs/arduino-1.8.2/hardware/tools/avr/bin/avr-gcc.exe -c -fno-keep-inline-dllexport -pipe -c -g -Os -w -ffunction-sections -fdata-sections -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR -O2 -Wextra -Wall -W -DUNICODE -DQT_NEEDS_QMAIN -I. -Isrc -Ir:\Programs\arduino-1.8.2\hardware\arduino\avr\cores\arduino -Ir:\Programs\arduino-1.8.2\hardware\arduino\avr\variants\standard -Ir:\Programs\arduino-1.8.2\hardware\arduino\avr\libraries -I/usr/avr/include -IC:\Qt\Qt5.9.1\5.9.1\mingw53_32\mkspecs\win32-g++ -o release\hooks.o r:\Programs\arduino-1.8.2\hardware\arduino\avr\cores\arduino\hooks.c
    avr-gcc.exe: error: command line option '-fno-keep-inline-dllexport' is not supported by this configuration


    И по-моему вы пропустили этап

    Рабочий комплект оставляем по-умолчанию, поправим это потом

    Не увидел, как его настраивать.