Какая функция возвращает время работы платы arduino

Arduino.ru

Часто при работе с проектами на микроконтроллерах требуется запускать фоновую функцию через равные промежутки времени. Это часто реализуется установкой аппаратного таймера для выработки прерывания. Это прерывание запускает программу обработки прерываний (Interrupt Service Routine, ISR) для управления периодическим прерыванием. В настоящей статье я описываю установку 8-битного таймера 2 для выработки прерываний на микроконтроллере ATMega168 Arduino. Я пройдусь по этапам, требуемым для установки программы обработки прерываний и внутри нее самой.

Arduino подразумевает процессор ATMega168 (ссылка на спецификацию). Этот микроконтроллер имеет несколько систем ввода-вывода, которые доступны каждому пользователю Arduino, поскольку библиотека Arduino облегчает их использование. К примеру, цифровой ввод-вывод, ШИМ, аналого-цифровые входы и последовательный порт. ATMega168 также имеет три внутренних аппаратных таймера. Хотя библиотека Arduino позволяет использовать некоторые свойства таймеров, нельзя напрямую использовать таймер для выработки периодических прерываний.

Прерывания?

Как подсказывает название, прерывания – это сигналы, прерывающие нормальное течение программы. Прерывания обычно используются для аппаратных устройств, требующих немедленной реакции на появление событий. Например, система последовательного порта или UART (универсальный асинхронный приемопередатчик) микроконтроллера должен быть обслужен при получении нового символа. Если этого не сделать быстро, новый символ может быть потерян.

При поступлении нового символа UART генерирует прерывание. Микроконтроллер останавливает выполнение основной программы (вашего приложения) и перескакивает на программу обработки прерываний (ISR), предназначенную для данного прерывания. В данном случае это прерывание по полученному символу. Эта ISR захватывает новый символ из UART, помещает в буфер, затем очищает прерывание и выполняет возврат. Когда ISR выполняет возврат, микроконтроллер возвращается в основную программу и продолжает её с точки вызова. Все это происходит в фоновом режиме и не влияет напрямую на основной код вашего приложения.

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

Вы можете задуматься, почему бы не просто проверять новый символ время от времени, вместо использования такого сложного процесса прерывания. Давайте вычислим пример, чтобы увидеть, насколько важны процессы прерывания. Скажем, у вас есть последовательный порт со скоростью передачи данных 9600 бод. Это означает, что каждый бит символа посылается с частотой 9600 Гц или около 10 кГц. На каждый бит уходит 100 мкс. Около 10 бит требуется, чтобы послать один символ, так что мы получаем один полный символ каждую миллисекунду или около того. Если наш UART буферизован, мы должны извлечь последний символ до завершения приема следующего, это дает нам на всю работу 1 мс. Если наш UART не буферизован, мы должны избавиться от символа за 1 бит или 1 мкс. Рассмотрим для начала буферизованный пример.

Мы должны проверять получение байта быстрее, чем каждую миллисекунду, чтобы предотвратить потерю данных. Применительно к Arduino это означает, что наша функция цикла должна обращаться для чтения статуса UART и возможно, байта данных, 1000 раз в секунду. Это легко выполнимо, но сильно усложнит код, который вам нужно написать. До тех пор, пока ваша функция цикла не требует больше 1 мс до завершения, вам это может сойти с рук. Но представьте, что вам нужно обслуживать несколько устройств ввода-вывода, или что необходимо работать на гораздо большей скорости передачи. Видите, какие неприятности это вскоре может принести.

С прерываниями вам не нужно отслеживать поступление символа. Аппаратура подает сигнал с помощью прерывания, и процессор быстро вызовет ISR, чтобы вовремя захватить символ. Вместо выделения огромной доли процессорного времени на проверку статуса UART, вы никогда не должны проверять статус, вы просто устанавливаете аппаратное прерывание и выполняете необходимые действия в ISR. Ваша главная программа напрямую не затрагивается, и от аппаратного устройства не требуется особых возможностей.

Прерывание по таймеру

В настоящей статье я сосредоточусь на использовании программного таймера 2 для периодических прерываний. Исходная идея состояла в использовании этого таймера для генерации частоты биений в звуковых проектах Arduino. Чтобы выводить тон или частоту нам нужно переключать порт ввода-вывода на согласованной частоте. Это можно делать с использованием циклов задержки. Это просто, но означает, что наш процессор будет занят, ничего не выполняя, но ожидая точного времени переключения вывода. С использованием прерывания по таймеру мы можем заняться другими делами, а вывод пусть переключает ISR, когда таймер подаст сигнал, что время пришло.

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

Я опишу в ISR в общем только то, что касается прерываний таймера 2. Более подробно об об использовании прерываний в процессорах AVR можно прочитать в руководстве пользователя avr-libc(англ). На данном этапе не требуется полного понимания, но, в конечном счете, вы можете захотеть получить возможность ускорить использование прерываний, раз это важный инструмент для приложений на микроконтроллерах.

Работа с последовательным портом UART (serial) на Arduino

Последовательный интерфейс (serial) предназначен передачи данных через универсальный асинхронный порт UART. Порт UART очень часто используется для передачи данных с Ардуино на компьютер, и обратно, а также для связи нескольких плат ардуин между собой.

Для многопортовых DUE/MEGA см. здесь.

Основные функций для работы с последовательным портом (Serial)

Serial.begin(rate) — Открывает последовательный порт и задаёт скорость для последовательной передачи данных. Типичная скорость обмена для компьютерной коммуникации — 9600.

Очевидно, когда задействован последовательный порт, выводы 0 (RX) и 1 (TX) не могут использоваться для других целей.

Serial.println(data) — Передаёт данные в последовательный порт, сопровождая автоматическим возвратом каретки и переходом на новую строку.

Serial.print(data) — тоже самое без возврата каретки и перехода на новую строку.

Serial.begin(скорость_передачи); — Инициализация порта. Задает скорость передачи в битах в секунду. Нормированные скорости: 300, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, или 115200.

count = Serial.available(); — Принимаемые по последовательному порту байты попадают в буфер микроконтроллера, откуда Ваша программа может их считать. Функция возвращает количество накопленных в буфере байт. Последовательный буфер может хранить до 128 байт.

char = Serial.read(); — Считывает следующий байт из буфера последовательного порта. возвращает -1 если нет входящих данных

Serial.flush(); — Ожидает окончания передачи исходящих данных (до версии Arduino 1.0 функция очищала буфер последовательного соединения)..

Разные варианты функции print:

Serial.print(b, DEC); — выводит ASCII-строку — десятичное представление числа b.

Serial.print(b, BYTE) — выводит младший байт числа b.

(аналогично HEX, OCT, BIN).

Serial.print(str) // если str — строка или массив символов, побайтно передает str на COM-порт.

Serial.println(); — отличие заключается в том, что после данных дополнительно выводятся два символа – символ возврата каретки (ASCII 13, или ‘\r’) и символ новой линии (ASCII 10, или ‘\n’).

Функция write:

Serial.write(uint8_t c); — Записывает данные в последовательный порт. Данные посылаются как байт или последовательность байт.

Serial.write(val); // где val — переменная для передачи, как единственный байт

Serial.write(str); // где str — строка для передачи, как последовательность байт

Serial.write(buf, len); // где buf — массив для передачи, как последовательность байт; len — длина массива.

Пример 1. Передача данных по Serial-порту с Arduino на компьютер

Инициализация порта со скоростью 9600 бот и передача данных (от Arduino на внешние устройства, например на компьютер):

Пример 2. Передача данных по Serial-порту с компьютера на Arduino

serialEvent() — функция вызывается автоматически, когда поступают данные.

Serial.setTimeout() — задает максимальное время (в мс) для работы Serial.readBytesUntil();

Возможные проблемы

1) auto-reboot DTR : возможна автоперезагрузка МК при передаче на него данных по serial-пору. Чтобы отключить это, надо поставить конденсатор 10мкФ между RES и GND. Я ставил электролитический кондер (естественно, + на RES).

Как соединить две ардуины по UART (serial) порту

Схема соединения двух ардуин:

Длина провода и скорость: RS-232 (англ. Recommended Standard 232) — стандарт физического уровня для асинхронного интерфейса (UART).

Расстояние связи по RS232 максимум 15 метров.

Но всё зависит от скорости.

Работа Arduino MEGA/DUE с несколькими последовательными serial портами

Многопортовые ардуино.

Как вы уже заметили, на ардуиновских платах Mega и Due имеется по 4 последовательных порта, а именно:

Serial — выводы 0 (RX) and 1 (TX);

Serial1 — выводы 19 (RX) and 18 (TX);

Serial2 — выводы 17 (RX) and 16 (TX);

Serial3 — выводы 15 (RX) and 14 (TX).

Естественно, что на Due используется напряжение 3.3 В (на MEGA как обычно 5 В).

Как с ними работать?

Здесь синим цветом выделены собственно имена объектов ( Serial , Serial1 , Serial2 , Serial3 ), которые используются в коде программы для работы с их методами. Всё просто! Например,

Пример вывода на дисплей LCD1602 через последовательный порт UART Arduino из-под Linux средствами языка Python

Короче говоря, есть комп с линуксом, к которому подключена Arduino через USB, а к арудине подключен дисплей LCD1602, и мы хотим на него выводить инфу.

Сначала привожу полный код программы для Arduino UNO, к которой подключен дисплей LCD1602:

Я сделал здесь решетку ‘#’ в качестве символа завершения передачи пакета данных. Как только в потоке данных встречается символ #, данные выводятся на дисплей, и буфер обнуляется, при этом сам символ ‘#’ не выводится. Конечно, можно было бы использовать ‘\n’ или др.

Далее мы напишем скрипт на Python, который будет выводить инфу на дисплей. Я выбрал Python, потому что это прикладной язык и он лучше всего подходит для подобных задач. С такими языками как C++/C# и т.п. больше возни с библиотеками, а здесь всё просто, особенно если это дело происходит под линуксом.

Первым делом устанавливаем необходимые библиотеки (для 2-ой или 3-ей версии python)

$sudo apt-get install python-serial

$sudo apt-get install python3-serial

Далее в интерпретаторе python пишем:

Здесь ардуина у меня подключена к порту /dev/ttyUSB0 — это я узнавал из Arduino IDE. Обычно она всегда на этом порту сидит, если других устройств на последовательный порт не подключено.

Как вы уже догадались, и в первой, и во второй программы должна быть указано одинаковая скорость в бодах. В моем случае это 9600 — стандартная, хотя и маленькая скрость. Может быть и больше (читай выше).

Arduino

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

Синтаксис
Параметры
Возвращаемое значение

Количество миллисекунд, прошедших с момента запуска программы

Пример

Выводим значение, возвращаемое функцией millis() и ждем 1 секунду:

Функция micros()
Описание

Возвращает время в микросекундах, прошедшее с начала выполнения программы на плате Arduino. Это число будет переполнено и сброситься до 0 примерно через 70 минут выполнения.

Синтаксис
Параметры
Возвращаемое значение

Количество микросекунд, прошедших с момента запуска программы

Пример

Выводим значение, возвращаемое функцией micros() и ждем 1 секунду:

Примечания

На платах Arduino 16 МГц (например Uno и Nano) эта функция имеет разрешение в четыре микросекунды, поэтому значение всегда кратно четырем. На платах Arduino 8 МГц (например, LilyPad) эта функция имеет разрешение восемь микросекунд.

Функция delay()
Описание

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

Синтаксис
Параметры

ms — время в миллисекундах, на которое нужно приостановить программу

Возвращаемое значение
Пример

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

Примечания

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

Однако некоторые функции во вовремя выполнение delay() все же продолжают работать. Например, прерывания.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *