Pull to refresh

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

Reading time 7 min
Views 25K
Платформа 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 на нечто более продвинутое будет сложно.
Tags:
Hubs:
+11
Comments 21
Comments Comments 21

Articles