Ардуино нано тестовый скетч

Содержание

Урок 1 — Мигаем встроенным на плату Arduino светодиодом

На плату Arduino UNO (Nano, Mega, micro и пр.) установлен светодиод который соединен с 13 pin платы. На плате он обозначается буквой L.

Для того чтобы заставить мигать встроенный светодиод на плату Arduino. Достаточно загрузить не большую программу.

Для урока нам понадобиться:

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

pinMode(13, OUTPUT); Инициализируем цифровой вход/выход в режиме выхода. Этого можно не делать так как цифровые выходы Ардуины по умолчанию настроенные на режим выход.

После вызова функции setup(), которая инициализирует и устанавливает первоначальные значения, функция loop() делает точь-в-точь то, что означает её название, и крутится в цикле, позволяя вашей программе совершать вычисления и реагировать на них. Использовать её нужно для активного управления платой Arduino.

DigitalWrite() — Так как у нас пин настроен как выход (pinMode(13, OUTPUT);), то для значение HIGH напряжение на соответствующем вход/выходе (pin) будет 5В (3.3В для 3.3V плат), и 0В(земля) для LOW.

Т.е. digitalWrite(13, HIGH); — На пин 13 подается 5 вольт.

digitalWrite(13, LOW); — На пин 13 подается 0В.

delay() — Останавливает выполнение программы на заданное в параметре количество миллисекунд (1000 миллисекунд в 1 секунде).

Следующий урок: Мигаем светодиодом подключенным к 2 pin Arduino

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

Понравилась статья? Поделитесь ею с друзьями:

Источник

Arduino.ru

Скетч для проверки работоспособности портов и EEPROM

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Написал универсальный скетч для проверки работоспособности портов и EEPROM памяти. Ищутся добровольцы для проверки в железе и доработки тестовой программы. Мой код проверен на ATmega128A, ATmega8A при этом никаких правок в коде делать не нужно. Количество цифровых и аналоговых выводов определяется автоматически.

Что еще нужно сделать:

1. Проверка аппаратных прерываний, таймеров, прерываний по переполнению таймера.

2. Прошивка на асме для проверки RAM, Stack Pointer Register, Status Register, регистров R0-R25, X,Y,Z

Что уже было сделано: Мой код при запуске ничего не делает, он ждет команду по UART. В терминал нужно отправить одну английскую букву для запуска нужного теста. Когда какой то тест был запушен, ч тобы его прервать нажмите кнопку ресет. Список комманд :

v — Выводит версию программы и краткое описание доступных тестов.

a — АЦП тест . Выводит значения всех аналоговых входов. Для этого вы подключаете переменный резистор поочередно к каждому аналоговому входу и смотрите как меняются значения.
i — Inputs test . В этом тесте включена подтяжка всех входов (INPUT_PULLUP). Тест в ыводит значения всех входов с низким уровнем на них. Вы берете провод подключенный на землю и через резистор 1КОм по очереди качаетесь каждого входа, в терминале должна появиться только одна надпись LOW с номером вывода. Этот тест позволяет найти замкнутые между собой пины или дорожки с обрывом (а также выводы со сгоревшими внутренними PULLUP резисторами )
o — Outputs test . Устанавливает все порты как выход с 1 на них. Вы берете тестер или светодиод с резистором и проверяете наличие высокого уровня на каждом выходе.
b — Blink . Тест наплатного светодиода.
0 — ZEROFILL встроенного EEPROM (тоесть заполнение нулями 0x00 во все ячейки ). Тест закончится, когда будет выведено «Done» в консоль. После этого запустите комманду » e » для вывода содержимого EEPROM в консоль и проверьте нет ли бытых ячеек
1 — 0xFF заполнение встроенного EEPROM. Тест закончится, когда будет выведено «Done» в консоль. После этого запустите комманду » e » для вывода содержимого EEPROM в консоль и проверьте нет ли бытых ячеек
p — Тест ШИМ на наплатном светодиод е . Тест надо полностью переписать, текущая реализация мне не нравится.

e — Выводит все содержимое EEPROM в терминал.

Цифровые порты 0 и 1 не тестируются. Этот тест предполагает, что выводы 0 ( RX ) и передачи данных 1 ( TX ) данных в порядке , раз у вас получилось загрузить скетч .

Код состоит из двух файлов. Последняя версия всегда доступна по ссылке

Источник

Мигающий светодиод Ардуино Нано, Уно

Мигание светодиодом Ардуино, встроенного в плату — один из первых примеров скетчей, для начинающих изучать программирование микроконтроллера Arduino Uno или Arduino Nano. Разберем несколько примеров — мигание встроенным светодиодом, мигание без delay, мигание несколькими светодиодами. Прочитав статью до конца, вы поймете, как управлять миганием светодиодов, подключенных к Ардуино.

Мигание светодиодом на Ардуино Нано, Уно

Для этого занятия потребуется:

  • Arduino Uno / Arduino Nano / Arduino Mega;
  • светодиоды и резисторы;
  • макетная плата;
  • провода «папа-папа».

Платы данного семейства имеют встроенный светодиод на плате, подключенный к пину 13 через резистор. Этот светодиод мигает при включении или перезагрузке микроконтроллера. Можно с помощью программы управлять включением и выключением (миганием) светодиодом, который «висит» на 13 пине Arduino Uno и Nano. При этом не потребуется даже собирать на макетной плате электрическую схему.

Мигание встроенным светодиодом на плате

Для первого примера не потребуется собирать принципиальную схему. Код программы, используется из примера «Подключение светодиода к Ардуино». Встроенный светодиод подключается через резистор, поэтому к 13 пину можно подключать внешний светодиод без резистора. Это самый простой скетч, с которого начинают знакомство с Ардуино, скопируйте код и загрузите его в микроконтроллер через Arduino IDE.

Скетч. Мигание встроенным светодиодом Ардуино

Пояснения к коду:

  1. delay(); останавливает программу на заданное количество микросекунд;
  2. данный код подойдет к плате Arduino Nano и Arduino Mega.

Мигание светодиода на Ардуино без delay

В коде используется функция millis, которая возвращает количество миллисекунд с момента начала программы. Благодаря этой функции можно организовать многозадачность микроконтроллера. В отличии от функции delay(); , программа не останавливает выполнение команд в скетче, а считает когда пройдет заданное количество миллисекунд и может выполнять параллельные задачи.

Схема для мигания светодиодом на Ардуино без delay

Скетч. Мигание светодиода на Arduino Uno без delay

Пояснения к коду:

  1. каждые 500 миллисекунд состояние переменной boolean меняется на противоположное с помощью команды ledState=!ledState .

Мигание двух светодиодов на Ардуино Уно

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

Мигание несколькими светодиодами на Ардуино одновременно

Скетч. Мигание несколькими светодиодами одновременно

Пояснения к коду:

  1. включение/выключение светодиодов происходит поочередно;
  2. одновременное включение можно сделать, поменяв местами строчки в коде.

Заключение. В этом обзоре мы рассмотрели, как сделать мигающий светодиод на Arduino Nano или Uno. Заставить светодиод мигать можно с помощью задержки delay или через millis. Если у вас остались вопросы по данной теме, то можете их смело оставлять в комментариях к этой записи. Мы постараемся ответить на все вопросы по мере поступления. Желаем успехов в освоении программирования Arduino.

Источник

Модульные тесты для проектов Ардуино

«Серьезные» разработчики встраиваемых систем (читай: стмщики) время от времени любят шпынять голозадых «ардуинщиков», у которых среда разработки, помимо всего прочего, не поддерживает даже аппаратные отладчики с точками останова и просмотром значений переменных под курсором мышки или в специальной табличке в реальном времени. Что ж, обвинение вполне справедливо, окошко Монитора последовательного порта (Serial Monitor) плюс Serial.println — не самый лучший инструмент отладки. Однако грамотный ардуинщик сможет с легкостью парировать атаку и поставить зарвавшегося стмщика на место в том случае, если он (ардуинщик) использует модульные тесты.

Итак, модульные тесты (unit tests, юнит-тесты) облегчают жизнь при поиске проблемных мест приложения, предотвращают повторение уже найденных проблем (регрессий), дают измеримую уверенность в надежности написанного кода. Это тем более важно при разработке встраиваемых приложений и всевозможных мобильных роботов, для которых процесс отладки, отлова и воспроизведения (особенно, воспроизведения) ошибок особенно затруднителен по сравнению с классическими настольными, серверными или мобильными приложениями.

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

При подготовке к внедрению в проект модульных тестов следует иметь ввиду:

  • Тесты требуют дополнительного времени для написания кода (на самом деле, нет: время, потраченное на автоматические тесты, вполне сравнимо со временем, потраченным на ручную отладку того же участка, а на долгой дистанции оно еще многократно окупится), при этом код теста может превышать по размеру код тестируемого участка.
  • В покрытом тестами проекте может быть сложно проводить глобальную реорганизацию кода (рефакторинг) — особенно актуально на начальном этапе разработки, когда кодовая база и внутренний API еще не достаточно устаканились (с другой стороны, рефактор проекта, не покрытого тестами, повлечет все те же регрессии, просто вы про них не узнаете)
  • Нужно писать модули приложения так, чтобы их можно было запускать как в рамках приложения, так и внутри отдельных тестов
  • Необходимо проработать структуру и связи внутри проекта так, чтобы в нем нашлось место коду основного приложения, исполняемой прошивке основного приложения, коду тестов, исполняемой прошивке («запускальщик»/ланчер) для запуска тестов.

Я более не буду распространяться про философию модульного тестирования, а просто покажу, как технически внедрить простые модульные тесты в ваш проект на Ардуино.

  • Несколько стратегий организации рабочего пространства проекта с модульными тестами с учетом особенностей платформы Ардуино.
  • Вариант «все в одном» (и код и тесты в одном файле скетча),
  • вынесение тестов в отдельный модуль в каталоге скетча,
  • вынесение тестов в отдельный проект.
  • Запуск тестов на устройстве,
  • запуск этих же тестов на настольном компьютере без загрузки на устройство, заглушки для API Ардуино

Выбор библиотеки для модульного тестирования

Нам нужен фреймворк модульного тестирования:

  • Для Си/С++
  • Должен работать на устройствах семейства Ардуино
  • Должен работать на настольных системах
  • Люблю легковесные библиотеки (моё персональное предпочтение)

Для программирования Ардуино используется язык С++ вперемешку с Си, поэтому, теоретически, пойдет любой фреймворк модульного тестирования для С++, но мы хотим запускать тесты и на настольном компьютере и на устройстве. Дело в том, что для Ардуино реализованы кое-какие вызовы стандартной библиотеки libc, но далеко не все, поэтому не каждый фреймворк, работающий с libc, скомпилируется для Ардуино. Верно и в обратную сторону: если фреймворк сделан специально для Ардуино, то он может не заработать на настольной системе с libc.

Я просмотрел несколько фреймворков и остановился на 2х:

  • ArduinoUnit: https://github.com/mmurdoch/arduinounit. В общем, он удовлетворяет ключевым исходным требованиям: работает как на Ардуино (очевидно из названия), так и на настольных системах (см раздел «En Vitro Testing» на сайте проекта), но на беглый взгляд показался тяжеловатым и я решил посмотреть другие варианты.
  • Библиотека Sput (Sput Unit Testing Framework for C/C++) https://www.use-strict.de/sput-unit-testing/. Это библиотека легкая настолько, насколько это возможно: всего один заголовочный файл, даже без пары с исходником «.cpp» (все сделано на нескольких макросах). Однако вывод сообщений идет через std::out (что совершенно естественно для libc), который на Ардуино как раз не реализован.

И все-таки мои симпатии перевесили в пользу sput, а проблему с std::out удалось решить несколькими исправлениями (заменой printf на sprintf+Serial.print).

В итоге получился проект sput-ino — порт библиотеки sput на платформу Ардуино с сохранением совместимости с настольными системами с libc

— пример с разделением основного кода и тестов на модули
sput-ino/examples/sput-ino-modules/

— запуск тестов на настольной системе
sput-ino/example-desktop/

— пример с разделением основного кода и тестов на разные проекты — в отдельном репозитории
https://github.com/sadr0b0t/sput-ino-demo

Установим библиотеку

Просто клонируйте репозиторий git https://github.com/sadr0b0t/sput-ino.git в каталог $HOME/Arduino/libraries:

и перезапустите среду Ардуино IDE.

Или на странице проекта github https://github.com/sadr0b0t/sput-ino/ нажмите кнопку Клонировать или скачать > Скачать ZIP (Clone or download > Download ZIP), после этого установите архив sput-ino-master.zip через меню установки библиотек Ардуино: Скетч > Подключить библиотеку > Добавить .ZIP библиотеку. .

Примеры появятся в меню Файл > Примеры > sput-ino (File > Examples > sput-ino)

Простой вариант: однофайловый скетч с кодом и тестами

При внедрении тестов в проект Ардуино придется учитывать некоторые особенности её сборочной системы. В простейшем случае проект (скетч) состоит из одного файла с расширением «.ino». При сборке файл «.ino» с незначительными изменениями конвертируется в «.cpp» (подключается заголовок Arduino.h и еще кое-чего по мелочи), сгенерированный файл компилируется в прошивку.

добавляем какой-то полезный код:

Комплектуем наборы тестов (тест-сьюты).

Все тесты в одном наборе:

и по одному набору на каждый тест:

Здесь я делаю по одному набору на каждый тест плюс один набор на все тесты вместе. На устройстве ограничен ресурс флеш-памяти, все тесты могут не уместиться разом в одну прошивку, поэтому одиночные наборы можно включать/выключать, комментируя отдельные вызовы в главном скетче. Всеобщий набор удобно пускать одной строчкой на настольном компьютере (ну, и на устройстве тоже, если он там все-таки уместится).

Запускаем тесты здесь:

Добавляем обычные setup/loop, запускаем тесты с run_tests в setup в самом начале, предварительно инициировав последовательный порт Serial.begin, чтобы тесты могли печатать сообщения:

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

Компилируем, загружаем на устройство, смотрим результат в окошке монитора последовательного порта (Инструменты > Монитор порта / Tools > Serial monitor)

Результат выполнения на плате ChipKIT Uno32 (клон Ардуино с 32-битным чипом PIC32):

запуск на обычной Arduino Uno (чип AVR 16 бит):

Обратим внимание на пару моментов:

— На PIC32 все тесты завершились успешно, а на AVR один тест со сложением провалился. 34000 + 34000 == 68000 только на 32-битном контроллере PIC32, на AVR размер int = 2 байта (16 бит), максимальное число, которое можно в него положить = 2^16-1=65536-1=65535 (в беззнаковом режиме unsigned). На AVR с 16-битным int происходит переполнение, а на 32-битном PIC32 (и на 64-битном десктопе с x86_64) все ок. Такие особенности платформы стоит учитывать там, где они могут себя проявить, и добавлять в тесты.

— Тест test_led_on_even (включить лампочку, если передано четное число) успешно проходит на обоих контроллерах, но, вообще говоря, использовать чтение digitalRead для проверки успешности записи digitalWrite на реальном железе — не самая хорошая идея.

Во-первых, digitalRead (прочитать значение GPIO в режиме ввода pinMode INPUT) совершенно не обязан выдавать значение, которое было отправлено в порт GPIO с digitalWrite в режиме вывода pinMode OUTPUT: в официальной документации на digitalRead про такое использование метода ничего не говорится, хотя на железке это и срабатывает.

Во-вторых, полагаясь на то, что digitalRead вернет нужное значение после вызова digitalWrite, мы встаем на скользкую дорожку тестирования не своего, но чужого кода. Успешность прохождения теста зависит не только от тестируемого кода, но и от того, как именно реализована связка digitalWrite/digitalRead на конкретном контроллере и нет ли в ней ошибок (кстати, на Arduino UNO с AVR тест провалится, если убрать строку перевода ножки в режим вывода pinMode(13, OUTPUT), на ChipKIT Uno32 с PIC32 тест проходит в любом случае).

Здесь мы не должны проверять, что digitalWrite ЗАПИСАЛ значение в порт GPIO так, что digitalRead смог его прочитать. Здесь мы проверяем, что digitalWriite БЫЛ ВЫЗВАН с нужными нам параметрами. При запуске тестов на реальном железе мы навряд ли сможем это сделать без построения каких-то некрасивых вспомогательных конструкций, но в режиме тестирования на настольной системе это будет легко реализовано при помощи заглушек (см ниже).

Тестируемый код и тесты в отдельные модули

Хранить тесты и весь код в одном большом файле — не самое удобное решение, если проект начинает жить и вырастает чуть дальше чернового наброска.

Теперь мы хотим вынести тесты в отдельный модуль. Модуль тестов должен вызывать тестируемые функции, для этого он должен подключить заголовочный файл с их объявлениями, а значит весь тестируемый код тоже идет в свой отдельный модуль. Здесь мы видим, как внедрение тестов с первых шагов волей-неволей принуждает нас к красоте и порядку внутри проектного дерева.

Система сборки Ардуино позволяет дробить проект на модули: в каталоге со скетчем (.ino) можно размещать дополнительные заголовочные файлы (*.h), файлы с исходниками Си (.c) и C++ (.cpp). Заголовочные файлы будут подключаться как обычно директивой #include, файлы с исходниками C/C++ будут автоматически компилироваться и собираться в единую исполняемую прошивку. Среда разработки Arduino IDE показывает все исходные файлы проекта на вкладках.

Модуль с тестируемым кодом: mylib.h+mylib.cpp

Исходный код модуля. Если хотите здесь взаимодействовать с железом и использовать API Arduino, просто подключайте Arduino.h.

Модуль с тестами: mylib-test.h+mylib-test.cpp

Заголовочный файл — объявления наборов тестов (тест-сьютов), сами тесты объявлять на публику не обязательно:
sput-ino/examples/sput-ino-modules/mylib-test.h

Тесты и наборы тестов: все тоже без изменений, только теперь подключаем mylib.h и Arduino.h вручную.

Главный скетч для исполняемой прошивки: здесь остались только обращения к модулю приложения mylib.h и модулю с тестами mylib-test.h.

Прошиваем, открываем монитор последовательного порта, результат идентичен предыдущему.

Итого, структура проекта:
sput-ino-modules/

— исполняемая прошивка для основного приложения и тестов:
sput-ino-modules/sput-ino-modules.ino

В целом, с такими установками уже можно жить вполне комфортно. Однако не всем может понравится, что тесты и исходники хранятся вперемешку в одном и том же каталоге, а так же то, что для переключения режимов тест/приложение нужно что-то комментировать/раскомментировать в одной и той же исполняемой прошивке, поэтому

Выносим тесты в отдельный проект

Чтобы понять, зачем нам нужно делать дальнейшие не совсем очевидные телодвижения, сначала стоит пояснить в общих чертах, как работает система сборки проектовав Ардуино:

  • В простейшем случае проект состоит из одного файла с расширением «.ino» (скетч), который должен храниться в каталоге с таким же именем (например: «myproj1/myproj1.ino»).
  • В этом же каталоге могут находиться другие исходники — заголовочные файлы «.h», модули на Си «.c», модули на С++ «.cpp», но не другие файлы «.ino».
  • В начале процедуры компиляции все содержимое каталога проекта копируется в другой временный каталог (что-то вроде /tmp/build2b91b1aecd83593cdd811791fcf30e97.tmp/), там файл «.ino» превращается в «.cpp», потом все файлы «.cpp» и «.c» компилятор gcc превращает в объектные файлы «.o», потом все объектные файлы «.o» линкер превращает в единый файл с исполняемой прошивкой «.hex» и (если был выбран вариант «скомпилировать и прошить») программный программатор avrdude отправляет её на устройство (совет: откройте меню Файл > Настройки, включите галочки Показывать подробный вывод для компиляции и загрузки).
  • Общие библиотеки устанавливают в каталог $HOME/Arduino/libraries/ — они будут доступны при компиляции и сборке любых проектов на этом компьютере.

  • Один проект Ардуино может содержать только один исполняемый файл «.ino». Если мы хотим иметь два разных исполняемых файла «.ino», нам нужно сделать два разных проекта в разных каталогах файловой системы.
  • Мы можем разбивать исходный код на модули и подключать их один к другому с помощью директивы #include (например: #include «mylib.h») внутри каталога одного проекта.
  • Мы НЕ можем из одного проекта напрямую ссылаться на модули из других проектов через относительные ссылки, полагаясь на взаимное положение проектов в файловой системе (например: #include «../proj2/proj2lib.h»), т.к. перед сборкой каждый из проектов будет скопирован во временный каталог и эти связи будут нарушены.
  • Даже если мы решим подключить заголовочные файлы «.h» второго проекта не через относительные, а абсолютные ссылки (а мы это делать, конечно, не будем), система сборки все равно не подцепит исходные файлы «.cpp» и «.c», так тоже не получится.
  • Если мы хотим сделать так, чтобы модули одного нашего проекта были доступны для использования внутри другого нашего проекта, мы должны оформить первый проект в виде библиотеки Ардуино.

Значит, теперь такой план:

  • Конвертировать исходный проект в библиотеку Ардуино и разместить её в $HOME/Arduino/libraries/
  • Вынести тесты в отдельный проект, который будет обращаться к исходному проекту как к общедоступной библиотеке

Пример такого проекта (его можно использовать, как шаблон для ваших новых проектов) я вынес в отдельный репозиторий:
https://github.com/sadr0b0t/sput-ino-demo

Скачайте демо-проект себе на компьютер.

Первым делом в каталоге $HOME/Arduino/libraries нужно создать символьную ссылку на каталог проекта

или, если ваша операционная система не умеет в символьные ссылки, просто скопировать туда весь проект и дальше вести работу прямо в библиотеках.

Структура этого проекта — структура библиотеки Ардуино.

Мы сможем подключать заголовочные файлы этой библиотеки из любого проекта Ардуино на текущем компьютере обычным:

Но чтобы это работало, в корень библиотеки нужно положить еще файл с информацией о библиотеке library.properties:
sput-ino-demo/library.properties

(Кстати, можно обойтись без library.properties, если положить все исходники .h, .c, .cpp не в src/, а в корень библиотеки sput-ino-demo/. Они так же будут подключаться/компилироваться с прошивками ссылающихся на них проектов, но мы так делать не будем, т.к. с src/, конечно, аккуратнее.)

Кстати-2, после установки проекта-библиотеки и перезапуска среды Ардуино этот скетч появится в меню Файл > Примеры > sput-ino-demo/sput-ino-demo, но он оттуда откроется только для чтения. Чтобы открыть скетч для редактирования, воспользуйтесь обычным Файл > Открыть и найдите его в файловой системе.

Кстати-3, файлы проекта-библиотеки mylib.h и mylib.cpp теперь не будут появляться в окне среды Arduino IDE (т.к. они находятся за пределами каталога скетча sput-ino-demo/), вам придется редактировать их в вашем любимом текстовом редакторе. Придется это принять как данность, кому к сожалению, а кому и к счастью.

Кстати-4, теперь у вас в проекте может быть более одного скетча «.ino».

Итак, с библиотекой и запускаемым скетчем разобрались, теперь к тестам.

Тесты мы разместим теперь в отдельном каталоге:
sput-ino-demo/test/

Тесты для настольной системы обсуждаем далее.

Запуск тестов на настольном компьютере

Итак, с запуском тестов на устройстве в целом разобрались. Теперь посмотрим, получится ли запустить эти же тесты на настольном компьютере. Для чего вообще запускать тесты на настольном компьютере? Во-первых, это удобно и быстро: поменяли в исходниках пару строк, быстро пересобрали, запустили тесты, здесь же в консольке посмотрели результат; в случае с устройством одна процедура прошивки может занять больше времени, чем все описанные выше действия. Во-вторых, некоторые ситуации, которые можно легко отработать в настольной симуляции (или, точнее, на макете, mock), на железке будет воспроизвести проблематичнее (например, отработать получение значения с одного или нескольких датчиков, отследить правильность ответной реакции). Так же существует мнение, что запускать тесты на микроконтроллерах вообще не правильно, а правильно их запускать только на настольных системах.

В общем, мы хотим:

  • запускать тесты на настольной системе без прошивки в устройство,
  • это должны быть те же самые тесты и те же самые тестируемые участки приложения, которые мы запускаем на устройстве.

Для того, чтобы решить эту задачу, во-первых, у нас должна быть библиотека для модульного тестирования, которая запустится одновременно и на железке с Ардуино и на настольной системе. Как было сказано в начале статьи, библиотека sput-ino по этому условию проходит: исходная библиотека sput работает на настольных системах с libc, sput-ino — порт библиотеки sput на платформу Ардуино с полным сохранением совместимости API, а также с поддержкой обеих платформ в одной библиотеке. Короче, тесты, использующие библиотеку sput-ino, можно компилировать как для настольных систем с libc, так и для платформы Ардуино.

Далее, условно разделим исходники на две части:

  • части приложения, которые не взаимодействуют с железом, не используют API Ардуино.
  • части приложения, которые взаимодействуют с железом, используют API Ардуино.

Части приложения НЕ используют API Ардуино

В первом случае (у нас это a_plus_b и a_minis_b) всё ясно — это части приложения, написанные на чистом Си/С++. Скорее всего это какие-то математические, алгоритмические или структурные блоки. Как они компилировались и запускались на Ардуино, точно так же они скомпилируются и запустятся с тестами на настольной системе без дополнительных телодвижений. Однако даже с ними не стоит забывать о различиях между платформами (выше мы уже рассмотрели случай с тестом, провалившимся из-за переполнения 16-битного int на чипе AVR, когда на 32-битном PIC32 и 64-битном настольном Intel/AMD все проходит). Такие отличия стоит учитывать при написании тестов и время от времени гонять тесты на целевом устройстве.

Части приложения используют API Ардуино

Во втором случае (у нас это led_on_even) ситуация кажется еще интереснее. Допустим, мы хотим протестировать функцию, которая помимо других действий обращается к железу контроллера через родные ардуинные digitalRead или digitalWrite. Совершенно очевидно, что никаких digitalRead и digitalWrite в стандартных библиотеках libc на настольной системе нет, этот блок приложения просто так не скомпилируется, тем более не запустится (и где у ноутбука пины GPIO?). Что делать? Неужели искать эмулятор или симулятор плат Ардуино и каким-то образом тащить все это счастье к себе в проект? Компилировать исходники Ардуино под x86? Писать симулятор чипа AVR со всей его внутренней регистровой кухней и драйверами самому?

Примерно такие мысли пронеслись у меня в голове, когда я первый раз подумал о том, что нужно каким-то образом запустить значительную часть приложения, написанного специально для Ардуно, на обычном десктопе. Однако первые практические шаги решения почти сразу показали, что масштаб проблемы весьма преувеличен. Я бы сказал, что никакой проблемы вообще нет.

Да, для каждого используемого вызова API Ардуино мы добавляем в проект собственную заглушку: объявляем функцию с таким же именем и сигнатурой (тип возвращаемого значения и аргументы), добавляем ей собственную реализацию. Нет, реализация заглушки не будет иметь никакого отношения к дереву исходников или к железу оригинальной Ардуино. В некоторых случаях заглушка может представлять пустую функцию вообще без кода.

Здесь далеко не все вызовы API Ардуино, мы добавили только те функции и константы, которые необходимы для компиляции и запуска приведенных выше тестов (плюс еще парочка лишних вызовов для примера). Заглушки для остальных функций можно добавлять по мере необходимости.

В общем, этого уже достаточно, чтобы скомпилировать и запустить наши тесты на настольном компьютере. Добавляем главный исполняемый файл с main:
sput-ino/example-desktop/mylib-test-main.cpp

(видим тесты из модульной версии проекта Ардуино)

здесь же в консольке:

Саксэс, саксэс, саксэс. На этой оптимистической ноте можно было бы закончить статью, но лучше разберем еще один обещанный выше случай.

Расширение API макета; тесты, которые получится запускать только на настольной системе

Выше мы отметили, что мы не должны проверять, что digitalWrite ЗАПИСАЛ значение в порт GPIO так, что digitalRead смог его прочитать. Мы проверяем, что digitalWriite БЫЛ ВЫЗВАН с нужными нам параметрами. Другими словами, мы хотим проверить, что digitalWrite был вызван с определенными параметрами, но мы не хотим использовать для этого digitalRead. Да, если говорить конкретно про пару digitalWrite/digitalRead, еще можно как-то рассуждать о целесообразности такого желания (ведь при запуске тестов на настольной системе digitalRead все равно является заглушкой и мы можем вставлять в нее любой удовлетворяющий нас код), но мы вполне можем захотеть проверить обращения и к другим вызовам API Ардуино, у которых нет даже такой пары (например, pinMode).

Короче, давайте добавим к заглушкам API Ардуино еще несколько расширенных вызовов и посмотрим, как будут выглядеть с ними наши старые тесты.

Для порядка объявим дополнительные вызовы для макета в отдельном заголовочном файле, я назвал его _Arduino.h (в начале нижнее подчеркивание):
sput-ino/example-desktop/_Arduino.h

Как видим, реализация _get_pin_value идентична заглушке для digitalRead, но _get_pin_mode уже не имеет прямого аналога в API Ардуино.

Далее пишем новую версию теста test_led_on_eventest_led_on_even_desktoponly, использующую новый вызов _get_pin_value вместо digitalRead. Этот тест уже не скомпилируется и не запустится на устройстве, поэтому мы его размещаем в отдельном модуле за пределами проекта Ардуино — в каталоге с исходными файлами для тестирования на настольном компьютере sput-ino/example-desktop/

Немного поправим исполняемый файл — теперь у нас два набора тестов: кросс-платформенные тесты и тесты, которые запускаем только на десктопе.

чуть правим сборочный скрипт (добавляем mylib-test-desktoponly.cpp)

Хороший пример: потестируем обработчик прерываний

Допустим, у нас есть небольшой проект с модулем управления шаговым мотором:

  • Мотор шагает на фронте HIGH > LOW,
  • модуль проверяет выход за границы с концевых датчиков и
  • программно считает сделанные шаги.

Мотор шагает в фоне по сигналам из программного обработчика прерываний от таймера, несколько тысяч (или десятков тысяч) раз в секунду. Один шаг — 3 тика таймера: тик 1 — проверяем границы (концевые датчики), тик 2 — взводим ножку STEP в HIGH, тик 3 — делаем шаг: сбрасываем STEP в LOW, увеличиваем счетчик.

Код управления мотором может выглядеть примерно так:

Вызов timer_handle_interrupts — обработчик прерывания от таймера, вызывается на каждый тик таймера определенное заранее количество раз в секунду (как запустить таймер на Ардуино: arduino-timer-api).

Теперь представьте, что код загружен на контроллер, мотор подключен, крутится, но что-то не в порядке: может вращается слишком быстро, может не докручивает часть предполагаемого пути, может что-то еще. Подключение электроники в порядке, проверено на простых тестах, проблема явно в программе. Как бы вы стали отлавливать ошибку? Допустим, у вас есть полноценный аппаратный отладчик с просмотром памяти и переменных, точками останова и красивой поддержкой в IDE. Будем ставить брейкпоинт в обработчик прерывания и проверять значения переменных все 100500 тиков? Ставить точку останова с динамическим условием в надежде поймать проблему в середине цикла? Возможно какой-то из этих или других приемов поможет отловить и исправить проблему.

Но посмотрим, как будет выглядеть процедура отладки этого участка при помощи автоматических тестов:

Прерывания от таймера мы симулируем элементарным ручным вызовом обработчика test_timer_handle_interrupts. Как видим, таким образом можно легко контролировать каждый тик: 1й, 2й, 3й, 103й, предпоследний, последний, — и после каждого тика спокойно делать любые нужные проверки.

Источник

Arduino nano тестовый скетч

Содержание

This example shows the simplest thing you can do with an Arduino to see physical output: it blinks the on-board LED.

Hardware Required

220 ohm resistor

Circuit

This example uses the built-in LED that most Arduino boards have. This LED is connected to a digital pin and its number may vary from board type to board type. To make your life easier, we have a constant that is specified in every board descriptor file. This constant is LED_BUILTIN and allows you to control the built-in LED easily. Here is the correspondence between the constant and the digital pin.

D13 — Intel Edison

D13 — Intel Galileo Gen2

D13 — Leonardo and Micro

D13 — LilyPad USB

If you want to lit an external LED with this sketch, you need to build this circuit, where you connect one end of the resistor to the digital pin correspondent to the LED_BUILTIN constant. Connect the long leg of the LED (the positive leg, called the anode) to the other end of the resistor. Connect the short leg of the LED (the negative leg, called the cathode) to the GND. In the diagram below we show an UNO board that has D13 as the LED_BUILTIN value.

The value of the resistor in series with the LED may be of a different value than 220 ohm; the LED will lit up also with values up to 1K ohm.

Schematic

After you build the circuit plug your Arduino board into your computer, start the Arduino Software (IDE) and enter the code below. You may also load it from the menu File/Examples/01.Basics/Blink . The first thing you do is to initialize LED_BUILTIN pin as an output pin with the line

In the main loop, you turn the LED on with the line:

This supplies 5 volts to the LED anode. That creates a voltage difference across the pins of the LED, and lights it up. Then you turn it off with the line:

That takes the LED_BUILTIN pin back to 0 volts, and turns the LED off. In between the on and the off, you want enough time for a person to see the change, so the delay() commands tell the board to do nothing for 1000 milliseconds, or one second. When you use the delay() command, nothing else happens for that amount of time. Once you’ve understood the basic examples, check out the BlinkWithoutDelay example to learn how to create a delay while doing other things.

Once you’ve understood this example, check out the DigitalReadSerial example to learn how read a switch connected to the board.

See Also

AnalogReadSerial — Read a potentiometer, print its state out to the Arduino Serial Monitor.

BareMinimum — The bare minimum of code needed to start an Arduino sketch.

DigitalReadSerial — Read a switch, print the state out to the Arduino Serial Monitor.

Fade — Demonstrates the use of analog output to fade an LED.

ReadAnalogVoltage — Reads an analog input and prints the voltage to the serial monitor.

Источник

Arduino.ru

Скетч для проверки работоспособности портов и EEPROM

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Написал универсальный скетч для проверки работоспособности портов и EEPROM памяти. Ищутся добровольцы для проверки в железе и доработки тестовой программы. Мой код проверен на ATmega128A, ATmega8A при этом никаких правок в коде делать не нужно. Количество цифровых и аналоговых выводов определяется автоматически.

Что еще нужно сделать:

1. Проверка аппаратных прерываний, таймеров, прерываний по переполнению таймера.

2. Прошивка на асме для проверки RAM, Stack Pointer Register, Status Register, регистров R0-R25, X,Y,Z

Что уже было сделано: Мой код при запуске ничего не делает, он ждет команду по UART. В терминал нужно отправить одну английскую букву для запуска нужного теста. Когда какой то тест был запушен, ч тобы его прервать нажмите кнопку ресет. Список комманд :

v — Выводит версию программы и краткое описание доступных тестов.

a — АЦП тест . Выводит значения всех аналоговых входов. Для этого вы подключаете переменный резистор поочередно к каждому аналоговому входу и смотрите как меняются значения.
i — Inputs test . В этом тесте включена подтяжка всех входов (INPUT_PULLUP). Тест в ыводит значения всех входов с низким уровнем на них. Вы берете провод подключенный на землю и через резистор 1КОм по очереди качаетесь каждого входа, в терминале должна появиться только одна надпись LOW с номером вывода. Этот тест позволяет найти замкнутые между собой пины или дорожки с обрывом (а также выводы со сгоревшими внутренними PULLUP резисторами )
o — Outputs test . Устанавливает все порты как выход с 1 на них. Вы берете тестер или светодиод с резистором и проверяете наличие высокого уровня на каждом выходе.
b — Blink . Тест наплатного светодиода.
0 — ZEROFILL встроенного EEPROM (тоесть заполнение нулями 0x00 во все ячейки ). Тест закончится, когда будет выведено «Done» в консоль. После этого запустите комманду » e » для вывода содержимого EEPROM в консоль и проверьте нет ли бытых ячеек
1 — 0xFF заполнение встроенного EEPROM. Тест закончится, когда будет выведено «Done» в консоль. После этого запустите комманду » e » для вывода содержимого EEPROM в консоль и проверьте нет ли бытых ячеек
p — Тест ШИМ на наплатном светодиод е . Тест надо полностью переписать, текущая реализация мне не нравится.

e — Выводит все содержимое EEPROM в терминал.

Цифровые порты 0 и 1 не тестируются. Этот тест предполагает, что выводы 0 ( RX ) и передачи данных 1 ( TX ) данных в порядке , раз у вас получилось загрузить скетч .

Код состоит из двух файлов. Последняя версия всегда доступна по ссылке

Источник

Мигающий светодиод Ардуино Нано, Уно

Мигание светодиодом Ардуино, встроенного в плату — один из первых примеров скетчей, для начинающих изучать программирование микроконтроллера Arduino Uno или Arduino Nano. Разберем несколько примеров — мигание встроенным светодиодом, мигание без delay, мигание несколькими светодиодами. Прочитав статью до конца, вы поймете, как управлять миганием светодиодов, подключенных к Ардуино.

Мигание светодиодом на Ардуино Нано, Уно

Для этого занятия потребуется:

  • Arduino Uno / Arduino Nano / Arduino Mega;
  • светодиоды и резисторы;
  • макетная плата;
  • провода «папа-папа».

Платы данного семейства имеют встроенный светодиод на плате, подключенный к пину 13 через резистор. Этот светодиод мигает при включении или перезагрузке микроконтроллера. Можно с помощью программы управлять включением и выключением (миганием) светодиодом, который «висит» на 13 пине Arduino Uno и Nano. При этом не потребуется даже собирать на макетной плате электрическую схему.

Мигание встроенным светодиодом на плате

Для первого примера не потребуется собирать принципиальную схему. Код программы, используется из примера «Подключение светодиода к Ардуино». Встроенный светодиод подключается через резистор, поэтому к 13 пину можно подключать внешний светодиод без резистора. Это самый простой скетч, с которого начинают знакомство с Ардуино, скопируйте код и загрузите его в микроконтроллер через Arduino IDE.

Скетч. Мигание встроенным светодиодом Ардуино

Пояснения к коду:

  1. delay(); останавливает программу на заданное количество микросекунд;
  2. данный код подойдет к плате Arduino Nano и Arduino Mega.

Мигание светодиода на Ардуино без delay

В коде используется функция millis, которая возвращает количество миллисекунд с момента начала программы. Благодаря этой функции можно организовать многозадачность микроконтроллера. В отличии от функции delay(); , программа не останавливает выполнение команд в скетче, а считает когда пройдет заданное количество миллисекунд и может выполнять параллельные задачи.

Схема для мигания светодиодом на Ардуино без delay

Скетч. Мигание светодиода на Arduino Uno без delay

Пояснения к коду:

  1. каждые 500 миллисекунд состояние переменной boolean меняется на противоположное с помощью команды ledState=!ledState .

Мигание двух светодиодов на Ардуино Уно

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

Мигание несколькими светодиодами на Ардуино одновременно

Скетч. Мигание несколькими светодиодами одновременно

Пояснения к коду:

  1. включение/выключение светодиодов происходит поочередно;
  2. одновременное включение можно сделать, поменяв местами строчки в коде.

Заключение. В этом обзоре мы рассмотрели, как сделать мигающий светодиод на Arduino Nano или Uno. Заставить светодиод мигать можно с помощью задержки delay или через millis. Если у вас остались вопросы по данной теме, то можете их смело оставлять в комментариях к этой записи. Мы постараемся ответить на все вопросы по мере поступления. Желаем успехов в освоении программирования Arduino.

Источник

Arduino Nano и LCD-дисплей 1602A — хеловордим — шпаргалка

Гугл помог, рассказал, что это символьный дисплей; если не извращаться, то доступны скорее всего символы ASCII — цифры, латиница, что-то из базовых символов.

Дисплей достаточно распространенный, и для него уже понапридумывали шилдов — есть варианты с SPI вроде, и/или с I2C, и интернет полон рецептами для этих случаев. Но у меня был в наличии только оригинальный дисплей 16×2, и ардуинка, к которой хотелось его прицепить.

У дисплея есть режим работы и передачи данных полубайтами, по 4 бита, при этом младшие разряды шины не используются. Подключение только половины шины данных много где описано, и я не стал разбираться, как подключить дисплей и работать с ним по 8ми линиям. Меня вполне устроило, что и так работает.

Подключение

У меня дисплей поставлялся с нераспаянными контактами. С начала хотел припаять шлейф, обрезал 16 проводов с дюпонами, зачистил. А потом покопался в ките, и нашел гребенку дюпонов для пайки на плату. Оттуда и отломал 16 контактов и припаял их.
Выглядел (до пайки контактов) мой дисплей примерно так:

Сперва я подключил контакт 15 (A) на +5В, 16 (K) на землю, и убедился, что подсветка работает. Вообще, правильно подключать катод на землю через резистор 220Ом, что я потом и сделал.

Затем подключил землю (1) и питание (2). Arduino может питаться от USB, от стабилизированного напряжения 5В и от нестабилизированного 6-12В, автоматически выбирается наибольшее напряжение. Сейчас ардуинка запитана от USB, и я думал, где там вытащить 5 Вольт. Оказалось, что 5В есть на контакте ардуины, куда подключаются внешние стабилизированные 5В. Вернее, там оказалось 4.7В, но мне хватило.

После подключения питания, если всё хорошо, то верхний ряд загорается сплошными прямоугольниками знакомест.

Затем подключаем потенциометр контраста (пин 3 V0). Один из крайних выводов потенциометра бросаем на землю, второй — на +5В, средний — на пин 3 дисплея. Рекомендуется потенциометр 10К. У меня был 50К из кита, сначала я использовал его. Регулировка была только на одном краю, весьма тонко приходилось ловить нужный контраст. Затем в другом ките нашел аналогичный на 5К, и поставил его. Настройка растянулась от одного края до половины оборота. Видимо, можно и еще меньше взять потенциометр. 10К наверно рекомендуют, чтобы схема поменьше потребляла. Да, пришлось немного попаять, припаял к выводам потенциометров проводки с дюпонами.

Далее подключаем сигнальные линии RS (на D7 Ардуино), R/W (на землю), E (на D6 Ардуино), и линии D4-D7 (на D5-D2 Ардуино). Линии дисплея D0-D3 оставляем неподключенными.

Тестовый скетч

Тестовый скетч берем в примерах от Ардуино студии — «C:\Program Files (x86)\Arduino\libraries\LiquidCrystal\ex amples\HelloWorld\HelloWorld.ino», только нужно поменять контакты на наши — LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

В принципе, в этом скетче есть и описание, что куда подключать. Можно подключить, как там указано, тогда менять вообще ничего не нужно.

Получается что-то вроде этого:

Кстати, дисплей, который попал ко мне в руки, без подсветки не работает. В смысле, работает, но практически ничего не видно.

Источник

Модульные тесты для проектов Ардуино

«Серьезные» разработчики встраиваемых систем (читай: стмщики) время от времени любят шпынять голозадых «ардуинщиков», у которых среда разработки, помимо всего прочего, не поддерживает даже аппаратные отладчики с точками останова и просмотром значений переменных под курсором мышки или в специальной табличке в реальном времени. Что ж, обвинение вполне справедливо, окошко Монитора последовательного порта (Serial Monitor) плюс Serial.println — не самый лучший инструмент отладки. Однако грамотный ардуинщик сможет с легкостью парировать атаку и поставить зарвавшегося стмщика на место в том случае, если он (ардуинщик) использует модульные тесты.

Итак, модульные тесты (unit tests, юнит-тесты) облегчают жизнь при поиске проблемных мест приложения, предотвращают повторение уже найденных проблем (регрессий), дают измеримую уверенность в надежности написанного кода. Это тем более важно при разработке встраиваемых приложений и всевозможных мобильных роботов, для которых процесс отладки, отлова и воспроизведения (особенно, воспроизведения) ошибок особенно затруднителен по сравнению с классическими настольными, серверными или мобильными приложениями.

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

При подготовке к внедрению в проект модульных тестов следует иметь ввиду:

  • Тесты требуют дополнительного времени для написания кода (на самом деле, нет: время, потраченное на автоматические тесты, вполне сравнимо со временем, потраченным на ручную отладку того же участка, а на долгой дистанции оно еще многократно окупится), при этом код теста может превышать по размеру код тестируемого участка.
  • В покрытом тестами проекте может быть сложно проводить глобальную реорганизацию кода (рефакторинг) — особенно актуально на начальном этапе разработки, когда кодовая база и внутренний API еще не достаточно устаканились (с другой стороны, рефактор проекта, не покрытого тестами, повлечет все те же регрессии, просто вы про них не узнаете)
  • Нужно писать модули приложения так, чтобы их можно было запускать как в рамках приложения, так и внутри отдельных тестов
  • Необходимо проработать структуру и связи внутри проекта так, чтобы в нем нашлось место коду основного приложения, исполняемой прошивке основного приложения, коду тестов, исполняемой прошивке («запускальщик»/ланчер) для запуска тестов.

Я более не буду распространяться про философию модульного тестирования, а просто покажу, как технически внедрить простые модульные тесты в ваш проект на Ардуино.

  • Несколько стратегий организации рабочего пространства проекта с модульными тестами с учетом особенностей платформы Ардуино.
  • Вариант «все в одном» (и код и тесты в одном файле скетча),
  • вынесение тестов в отдельный модуль в каталоге скетча,
  • вынесение тестов в отдельный проект.
  • Запуск тестов на устройстве,
  • запуск этих же тестов на настольном компьютере без загрузки на устройство, заглушки для API Ардуино

Выбор библиотеки для модульного тестирования

Нам нужен фреймворк модульного тестирования:

  • Для Си/С++
  • Должен работать на устройствах семейства Ардуино
  • Должен работать на настольных системах
  • Люблю легковесные библиотеки (моё персональное предпочтение)

Для программирования Ардуино используется язык С++ вперемешку с Си, поэтому, теоретически, пойдет любой фреймворк модульного тестирования для С++, но мы хотим запускать тесты и на настольном компьютере и на устройстве. Дело в том, что для Ардуино реализованы кое-какие вызовы стандартной библиотеки libc, но далеко не все, поэтому не каждый фреймворк, работающий с libc, скомпилируется для Ардуино. Верно и в обратную сторону: если фреймворк сделан специально для Ардуино, то он может не заработать на настольной системе с libc.

Я просмотрел несколько фреймворков и остановился на 2х:

  • ArduinoUnit: https://github.com/mmurdoch/arduinounit. В общем, он удовлетворяет ключевым исходным требованиям: работает как на Ардуино (очевидно из названия), так и на настольных системах (см раздел «En Vitro Testing» на сайте проекта), но на беглый взгляд показался тяжеловатым и я решил посмотреть другие варианты.
  • Библиотека Sput (Sput Unit Testing Framework for C/C++) https://www.use-strict.de/sput-unit-testing/. Это библиотека легкая настолько, насколько это возможно: всего один заголовочный файл, даже без пары с исходником «.cpp» (все сделано на нескольких макросах). Однако вывод сообщений идет через std::out (что совершенно естественно для libc), который на Ардуино как раз не реализован.

И все-таки мои симпатии перевесили в пользу sput, а проблему с std::out удалось решить несколькими исправлениями (заменой printf на sprintf+Serial.print).

В итоге получился проект sput-ino — порт библиотеки sput на платформу Ардуино с сохранением совместимости с настольными системами с libc

— пример с разделением основного кода и тестов на модули
sput-ino/examples/sput-ino-modules/

— запуск тестов на настольной системе
sput-ino/example-desktop/

— пример с разделением основного кода и тестов на разные проекты — в отдельном репозитории
https://github.com/sadr0b0t/sput-ino-demo

Установим библиотеку

Просто клонируйте репозиторий git https://github.com/sadr0b0t/sput-ino.git в каталог $HOME/Arduino/libraries:

и перезапустите среду Ардуино IDE.

Или на странице проекта github https://github.com/sadr0b0t/sput-ino/ нажмите кнопку Клонировать или скачать > Скачать ZIP (Clone or download > Download ZIP), после этого установите архив sput-ino-master.zip через меню установки библиотек Ардуино: Скетч > Подключить библиотеку > Добавить .ZIP библиотеку. .

Примеры появятся в меню Файл > Примеры > sput-ino (File > Examples > sput-ino)

Простой вариант: однофайловый скетч с кодом и тестами

При внедрении тестов в проект Ардуино придется учитывать некоторые особенности её сборочной системы. В простейшем случае проект (скетч) состоит из одного файла с расширением «.ino». При сборке файл «.ino» с незначительными изменениями конвертируется в «.cpp» (подключается заголовок Arduino.h и еще кое-чего по мелочи), сгенерированный файл компилируется в прошивку.

добавляем какой-то полезный код:

Комплектуем наборы тестов (тест-сьюты).

Все тесты в одном наборе:

и по одному набору на каждый тест:

Здесь я делаю по одному набору на каждый тест плюс один набор на все тесты вместе. На устройстве ограничен ресурс флеш-памяти, все тесты могут не уместиться разом в одну прошивку, поэтому одиночные наборы можно включать/выключать, комментируя отдельные вызовы в главном скетче. Всеобщий набор удобно пускать одной строчкой на настольном компьютере (ну, и на устройстве тоже, если он там все-таки уместится).

Запускаем тесты здесь:

Добавляем обычные setup/loop, запускаем тесты с run_tests в setup в самом начале, предварительно инициировав последовательный порт Serial.begin, чтобы тесты могли печатать сообщения:

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

Компилируем, загружаем на устройство, смотрим результат в окошке монитора последовательного порта (Инструменты > Монитор порта / Tools > Serial monitor)

Результат выполнения на плате ChipKIT Uno32 (клон Ардуино с 32-битным чипом PIC32):

запуск на обычной Arduino Uno (чип AVR 16 бит):

Обратим внимание на пару моментов:

— На PIC32 все тесты завершились успешно, а на AVR один тест со сложением провалился. 34000 + 34000 == 68000 только на 32-битном контроллере PIC32, на AVR размер int = 2 байта (16 бит), максимальное число, которое можно в него положить = 2^16-1=65536-1=65535 (в беззнаковом режиме unsigned). На AVR с 16-битным int происходит переполнение, а на 32-битном PIC32 (и на 64-битном десктопе с x86_64) все ок. Такие особенности платформы стоит учитывать там, где они могут себя проявить, и добавлять в тесты.

— Тест test_led_on_even (включить лампочку, если передано четное число) успешно проходит на обоих контроллерах, но, вообще говоря, использовать чтение digitalRead для проверки успешности записи digitalWrite на реальном железе — не самая хорошая идея.

Во-первых, digitalRead (прочитать значение GPIO в режиме ввода pinMode INPUT) совершенно не обязан выдавать значение, которое было отправлено в порт GPIO с digitalWrite в режиме вывода pinMode OUTPUT: в официальной документации на digitalRead про такое использование метода ничего не говорится, хотя на железке это и срабатывает.

Во-вторых, полагаясь на то, что digitalRead вернет нужное значение после вызова digitalWrite, мы встаем на скользкую дорожку тестирования не своего, но чужого кода. Успешность прохождения теста зависит не только от тестируемого кода, но и от того, как именно реализована связка digitalWrite/digitalRead на конкретном контроллере и нет ли в ней ошибок (кстати, на Arduino UNO с AVR тест провалится, если убрать строку перевода ножки в режим вывода pinMode(13, OUTPUT), на ChipKIT Uno32 с PIC32 тест проходит в любом случае).

Здесь мы не должны проверять, что digitalWrite ЗАПИСАЛ значение в порт GPIO так, что digitalRead смог его прочитать. Здесь мы проверяем, что digitalWriite БЫЛ ВЫЗВАН с нужными нам параметрами. При запуске тестов на реальном железе мы навряд ли сможем это сделать без построения каких-то некрасивых вспомогательных конструкций, но в режиме тестирования на настольной системе это будет легко реализовано при помощи заглушек (см ниже).

Тестируемый код и тесты в отдельные модули

Хранить тесты и весь код в одном большом файле — не самое удобное решение, если проект начинает жить и вырастает чуть дальше чернового наброска.

Теперь мы хотим вынести тесты в отдельный модуль. Модуль тестов должен вызывать тестируемые функции, для этого он должен подключить заголовочный файл с их объявлениями, а значит весь тестируемый код тоже идет в свой отдельный модуль. Здесь мы видим, как внедрение тестов с первых шагов волей-неволей принуждает нас к красоте и порядку внутри проектного дерева.

Система сборки Ардуино позволяет дробить проект на модули: в каталоге со скетчем (.ino) можно размещать дополнительные заголовочные файлы (*.h), файлы с исходниками Си (.c) и C++ (.cpp). Заголовочные файлы будут подключаться как обычно директивой #include, файлы с исходниками C/C++ будут автоматически компилироваться и собираться в единую исполняемую прошивку. Среда разработки Arduino IDE показывает все исходные файлы проекта на вкладках.

Модуль с тестируемым кодом: mylib.h+mylib.cpp

Исходный код модуля. Если хотите здесь взаимодействовать с железом и использовать API Arduino, просто подключайте Arduino.h.

Модуль с тестами: mylib-test.h+mylib-test.cpp

Заголовочный файл — объявления наборов тестов (тест-сьютов), сами тесты объявлять на публику не обязательно:
sput-ino/examples/sput-ino-modules/mylib-test.h

Тесты и наборы тестов: все тоже без изменений, только теперь подключаем mylib.h и Arduino.h вручную.

Главный скетч для исполняемой прошивки: здесь остались только обращения к модулю приложения mylib.h и модулю с тестами mylib-test.h.

Прошиваем, открываем монитор последовательного порта, результат идентичен предыдущему.

Итого, структура проекта:
sput-ino-modules/

— исполняемая прошивка для основного приложения и тестов:
sput-ino-modules/sput-ino-modules.ino

В целом, с такими установками уже можно жить вполне комфортно. Однако не всем может понравится, что тесты и исходники хранятся вперемешку в одном и том же каталоге, а так же то, что для переключения режимов тест/приложение нужно что-то комментировать/раскомментировать в одной и той же исполняемой прошивке, поэтому

Выносим тесты в отдельный проект

Чтобы понять, зачем нам нужно делать дальнейшие не совсем очевидные телодвижения, сначала стоит пояснить в общих чертах, как работает система сборки проектовав Ардуино:

  • В простейшем случае проект состоит из одного файла с расширением «.ino» (скетч), который должен храниться в каталоге с таким же именем (например: «myproj1/myproj1.ino»).
  • В этом же каталоге могут находиться другие исходники — заголовочные файлы «.h», модули на Си «.c», модули на С++ «.cpp», но не другие файлы «.ino».
  • В начале процедуры компиляции все содержимое каталога проекта копируется в другой временный каталог (что-то вроде /tmp/build2b91b1aecd83593cdd811791fcf30e97.tmp/), там файл «.ino» превращается в «.cpp», потом все файлы «.cpp» и «.c» компилятор gcc превращает в объектные файлы «.o», потом все объектные файлы «.o» линкер превращает в единый файл с исполняемой прошивкой «.hex» и (если был выбран вариант «скомпилировать и прошить») программный программатор avrdude отправляет её на устройство (совет: откройте меню Файл > Настройки, включите галочки Показывать подробный вывод для компиляции и загрузки).
  • Общие библиотеки устанавливают в каталог $HOME/Arduino/libraries/ — они будут доступны при компиляции и сборке любых проектов на этом компьютере.

  • Один проект Ардуино может содержать только один исполняемый файл «.ino». Если мы хотим иметь два разных исполняемых файла «.ino», нам нужно сделать два разных проекта в разных каталогах файловой системы.
  • Мы можем разбивать исходный код на модули и подключать их один к другому с помощью директивы #include (например: #include «mylib.h») внутри каталога одного проекта.
  • Мы НЕ можем из одного проекта напрямую ссылаться на модули из других проектов через относительные ссылки, полагаясь на взаимное положение проектов в файловой системе (например: #include «../proj2/proj2lib.h»), т.к. перед сборкой каждый из проектов будет скопирован во временный каталог и эти связи будут нарушены.
  • Даже если мы решим подключить заголовочные файлы «.h» второго проекта не через относительные, а абсолютные ссылки (а мы это делать, конечно, не будем), система сборки все равно не подцепит исходные файлы «.cpp» и «.c», так тоже не получится.
  • Если мы хотим сделать так, чтобы модули одного нашего проекта были доступны для использования внутри другого нашего проекта, мы должны оформить первый проект в виде библиотеки Ардуино.

Значит, теперь такой план:

  • Конвертировать исходный проект в библиотеку Ардуино и разместить её в $HOME/Arduino/libraries/
  • Вынести тесты в отдельный проект, который будет обращаться к исходному проекту как к общедоступной библиотеке

Пример такого проекта (его можно использовать, как шаблон для ваших новых проектов) я вынес в отдельный репозиторий:
https://github.com/sadr0b0t/sput-ino-demo

Скачайте демо-проект себе на компьютер.

Первым делом в каталоге $HOME/Arduino/libraries нужно создать символьную ссылку на каталог проекта

или, если ваша операционная система не умеет в символьные ссылки, просто скопировать туда весь проект и дальше вести работу прямо в библиотеках.

Структура этого проекта — структура библиотеки Ардуино.

Мы сможем подключать заголовочные файлы этой библиотеки из любого проекта Ардуино на текущем компьютере обычным:

Но чтобы это работало, в корень библиотеки нужно положить еще файл с информацией о библиотеке library.properties:
sput-ino-demo/library.properties

(Кстати, можно обойтись без library.properties, если положить все исходники .h, .c, .cpp не в src/, а в корень библиотеки sput-ino-demo/. Они так же будут подключаться/компилироваться с прошивками ссылающихся на них проектов, но мы так делать не будем, т.к. с src/, конечно, аккуратнее.)

Кстати-2, после установки проекта-библиотеки и перезапуска среды Ардуино этот скетч появится в меню Файл > Примеры > sput-ino-demo/sput-ino-demo, но он оттуда откроется только для чтения. Чтобы открыть скетч для редактирования, воспользуйтесь обычным Файл > Открыть и найдите его в файловой системе.

Кстати-3, файлы проекта-библиотеки mylib.h и mylib.cpp теперь не будут появляться в окне среды Arduino IDE (т.к. они находятся за пределами каталога скетча sput-ino-demo/), вам придется редактировать их в вашем любимом текстовом редакторе. Придется это принять как данность, кому к сожалению, а кому и к счастью.

Кстати-4, теперь у вас в проекте может быть более одного скетча «.ino».

Итак, с библиотекой и запускаемым скетчем разобрались, теперь к тестам.

Тесты мы разместим теперь в отдельном каталоге:
sput-ino-demo/test/

Тесты для настольной системы обсуждаем далее.

Запуск тестов на настольном компьютере

Итак, с запуском тестов на устройстве в целом разобрались. Теперь посмотрим, получится ли запустить эти же тесты на настольном компьютере. Для чего вообще запускать тесты на настольном компьютере? Во-первых, это удобно и быстро: поменяли в исходниках пару строк, быстро пересобрали, запустили тесты, здесь же в консольке посмотрели результат; в случае с устройством одна процедура прошивки может занять больше времени, чем все описанные выше действия. Во-вторых, некоторые ситуации, которые можно легко отработать в настольной симуляции (или, точнее, на макете, mock), на железке будет воспроизвести проблематичнее (например, отработать получение значения с одного или нескольких датчиков, отследить правильность ответной реакции). Так же существует мнение, что запускать тесты на микроконтроллерах вообще не правильно, а правильно их запускать только на настольных системах.

В общем, мы хотим:

  • запускать тесты на настольной системе без прошивки в устройство,
  • это должны быть те же самые тесты и те же самые тестируемые участки приложения, которые мы запускаем на устройстве.

Для того, чтобы решить эту задачу, во-первых, у нас должна быть библиотека для модульного тестирования, которая запустится одновременно и на железке с Ардуино и на настольной системе. Как было сказано в начале статьи, библиотека sput-ino по этому условию проходит: исходная библиотека sput работает на настольных системах с libc, sput-ino — порт библиотеки sput на платформу Ардуино с полным сохранением совместимости API, а также с поддержкой обеих платформ в одной библиотеке. Короче, тесты, использующие библиотеку sput-ino, можно компилировать как для настольных систем с libc, так и для платформы Ардуино.

Далее, условно разделим исходники на две части:

  • части приложения, которые не взаимодействуют с железом, не используют API Ардуино.
  • части приложения, которые взаимодействуют с железом, используют API Ардуино.

Части приложения НЕ используют API Ардуино

В первом случае (у нас это a_plus_b и a_minis_b) всё ясно — это части приложения, написанные на чистом Си/С++. Скорее всего это какие-то математические, алгоритмические или структурные блоки. Как они компилировались и запускались на Ардуино, точно так же они скомпилируются и запустятся с тестами на настольной системе без дополнительных телодвижений. Однако даже с ними не стоит забывать о различиях между платформами (выше мы уже рассмотрели случай с тестом, провалившимся из-за переполнения 16-битного int на чипе AVR, когда на 32-битном PIC32 и 64-битном настольном Intel/AMD все проходит). Такие отличия стоит учитывать при написании тестов и время от времени гонять тесты на целевом устройстве.

Части приложения используют API Ардуино

Во втором случае (у нас это led_on_even) ситуация кажется еще интереснее. Допустим, мы хотим протестировать функцию, которая помимо других действий обращается к железу контроллера через родные ардуинные digitalRead или digitalWrite. Совершенно очевидно, что никаких digitalRead и digitalWrite в стандартных библиотеках libc на настольной системе нет, этот блок приложения просто так не скомпилируется, тем более не запустится (и где у ноутбука пины GPIO?). Что делать? Неужели искать эмулятор или симулятор плат Ардуино и каким-то образом тащить все это счастье к себе в проект? Компилировать исходники Ардуино под x86? Писать симулятор чипа AVR со всей его внутренней регистровой кухней и драйверами самому?

Примерно такие мысли пронеслись у меня в голове, когда я первый раз подумал о том, что нужно каким-то образом запустить значительную часть приложения, написанного специально для Ардуно, на обычном десктопе. Однако первые практические шаги решения почти сразу показали, что масштаб проблемы весьма преувеличен. Я бы сказал, что никакой проблемы вообще нет.

Да, для каждого используемого вызова API Ардуино мы добавляем в проект собственную заглушку: объявляем функцию с таким же именем и сигнатурой (тип возвращаемого значения и аргументы), добавляем ей собственную реализацию. Нет, реализация заглушки не будет иметь никакого отношения к дереву исходников или к железу оригинальной Ардуино. В некоторых случаях заглушка может представлять пустую функцию вообще без кода.

Здесь далеко не все вызовы API Ардуино, мы добавили только те функции и константы, которые необходимы для компиляции и запуска приведенных выше тестов (плюс еще парочка лишних вызовов для примера). Заглушки для остальных функций можно добавлять по мере необходимости.

В общем, этого уже достаточно, чтобы скомпилировать и запустить наши тесты на настольном компьютере. Добавляем главный исполняемый файл с main:
sput-ino/example-desktop/mylib-test-main.cpp

(видим тесты из модульной версии проекта Ардуино)

здесь же в консольке:

Саксэс, саксэс, саксэс. На этой оптимистической ноте можно было бы закончить статью, но лучше разберем еще один обещанный выше случай.

Расширение API макета; тесты, которые получится запускать только на настольной системе

Выше мы отметили, что мы не должны проверять, что digitalWrite ЗАПИСАЛ значение в порт GPIO так, что digitalRead смог его прочитать. Мы проверяем, что digitalWriite БЫЛ ВЫЗВАН с нужными нам параметрами. Другими словами, мы хотим проверить, что digitalWrite был вызван с определенными параметрами, но мы не хотим использовать для этого digitalRead. Да, если говорить конкретно про пару digitalWrite/digitalRead, еще можно как-то рассуждать о целесообразности такого желания (ведь при запуске тестов на настольной системе digitalRead все равно является заглушкой и мы можем вставлять в нее любой удовлетворяющий нас код), но мы вполне можем захотеть проверить обращения и к другим вызовам API Ардуино, у которых нет даже такой пары (например, pinMode).

Короче, давайте добавим к заглушкам API Ардуино еще несколько расширенных вызовов и посмотрим, как будут выглядеть с ними наши старые тесты.

Для порядка объявим дополнительные вызовы для макета в отдельном заголовочном файле, я назвал его _Arduino.h (в начале нижнее подчеркивание):
sput-ino/example-desktop/_Arduino.h

Как видим, реализация _get_pin_value идентична заглушке для digitalRead, но _get_pin_mode уже не имеет прямого аналога в API Ардуино.

Далее пишем новую версию теста test_led_on_eventest_led_on_even_desktoponly, использующую новый вызов _get_pin_value вместо digitalRead. Этот тест уже не скомпилируется и не запустится на устройстве, поэтому мы его размещаем в отдельном модуле за пределами проекта Ардуино — в каталоге с исходными файлами для тестирования на настольном компьютере sput-ino/example-desktop/

Немного поправим исполняемый файл — теперь у нас два набора тестов: кросс-платформенные тесты и тесты, которые запускаем только на десктопе.

чуть правим сборочный скрипт (добавляем mylib-test-desktoponly.cpp)

Хороший пример: потестируем обработчик прерываний

Допустим, у нас есть небольшой проект с модулем управления шаговым мотором:

  • Мотор шагает на фронте HIGH > LOW,
  • модуль проверяет выход за границы с концевых датчиков и
  • программно считает сделанные шаги.

Мотор шагает в фоне по сигналам из программного обработчика прерываний от таймера, несколько тысяч (или десятков тысяч) раз в секунду. Один шаг — 3 тика таймера: тик 1 — проверяем границы (концевые датчики), тик 2 — взводим ножку STEP в HIGH, тик 3 — делаем шаг: сбрасываем STEP в LOW, увеличиваем счетчик.

Код управления мотором может выглядеть примерно так:

Вызов timer_handle_interrupts — обработчик прерывания от таймера, вызывается на каждый тик таймера определенное заранее количество раз в секунду (как запустить таймер на Ардуино: arduino-timer-api).

Теперь представьте, что код загружен на контроллер, мотор подключен, крутится, но что-то не в порядке: может вращается слишком быстро, может не докручивает часть предполагаемого пути, может что-то еще. Подключение электроники в порядке, проверено на простых тестах, проблема явно в программе. Как бы вы стали отлавливать ошибку? Допустим, у вас есть полноценный аппаратный отладчик с просмотром памяти и переменных, точками останова и красивой поддержкой в IDE. Будем ставить брейкпоинт в обработчик прерывания и проверять значения переменных все 100500 тиков? Ставить точку останова с динамическим условием в надежде поймать проблему в середине цикла? Возможно какой-то из этих или других приемов поможет отловить и исправить проблему.

Но посмотрим, как будет выглядеть процедура отладки этого участка при помощи автоматических тестов:

Прерывания от таймера мы симулируем элементарным ручным вызовом обработчика test_timer_handle_interrupts. Как видим, таким образом можно легко контролировать каждый тик: 1й, 2й, 3й, 103й, предпоследний, последний, — и после каждого тика спокойно делать любые нужные проверки.

Источник

Adblock
detector