Введение
Платформа 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 на нечто более продвинутое будет сложно.
Автор: Дмитрий Притыкин