Arduino в Linux: настраиваем Qt Creator в качестве среды разработки

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

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

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

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

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

nzum6m6rpcsv4l5izgncuqe528y.png

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

jkm_akr6uwywb4whvqwbolina7g.png

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

ci2c2v8nbynsag3lmijyfuqh6yg.png

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

9ab2qpaz4pdz8oq9geu4kqsmkpa.png

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

zly6tdyneajhywibopatkr-3bfs.png

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

oixzvuontcomii78urykevl1nkm.png

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

nollestvtwrb2g5bx5vxjbwp-8q.png

Теперь ручками начинаем писать текст в *.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++

6kla0qpfzoqfsc9fopgiuqemgp0.png

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

m7irkmvajjuso6zf907z5vttot8.png

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

m_dcaifkzi5on256d51fghsmev0.png

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

e-zjywi7fu13rxcozoeor8tf5mo.png

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

yi--gr36m4qeisoz4ltnt8fy8yg.png

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 нам никогда не обеспечит: добавим к скетчу заголовочный файл, проделав действия аналогичные вышеописанным

jqqi6rurkb3sxnc5rgqcxc0becs.png

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

#ifndef LED_BLINK_H
#define LED_BLINK_H

#include    

#endif // LED_BLINK_H

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

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

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

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

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

#include    "led-blink.h"

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

}

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

}

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

tzoukybm5989venm11vkijatfrc.png

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

gf6yd-r8ddnpboia1j5jzh86x4c.png

Всё ок, присутствует 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 = 0×1e950f (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. Для этого делаем настройки запуска такими

aswufovej_kbodu76teq4fnnxvi.png

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

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

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

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

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

© Geektimes