Как прерывания работают на arduino uno и аналогичных платах?

Резюме

Платформа Arduino предоставляет нам несколько способов выполнения задержки в своем проекте. С помощью delay вы можете быстро поставить на паузу выполнение скетча, но при этом заблокируете работу микроконтроллера. Использование команды millis позволяет обойтись в ардуино без delay, но для этого потребуется чуть больше программировать. Выбирайте лучший способ в зависимости от сложности вашего проекта. Как правило, в простых скетчах и при задержке меньше 10 секунд используют delay. Если логика работы сложнее и требуется большая задержка, то вместо delay лучше использовать millis.

Толстовка с капюшоном Allen — White Girl Problems LYRICS

Пожалуйста, объясните, как работают прерывания на Arduino Uno и связанных платах, использующих процессор ATmega328P. Платы, такие как:

  • Уно
  • Мини
  • Нано
  • Pro Mini
  • Кувшинок

В частности, обсудите:

  • Для чего использовать прерывания
  • Как написать программу обслуживания прерывания (ISR)
  • Проблемы с синхронизацией
  • Критические разделы
  • Атомарный доступ к данным

Примечание: это справочный вопрос.

TL; DR:

При написании процедуры обслуживания прерывания (ISR):

  • Оставь это короткая
  • Не использовать
  • Не делайте серийных отпечатков
  • Делайте переменные общими с основным кодом летучий
  • Переменные, используемые совместно с основным кодом, могут нуждаться в защите «критических разделов» (см. Ниже).
  • Не пытайтесь включить или выключить прерывания

Что такое прерывания?

У большинства процессоров есть прерывания. Прерывания позволяют вам реагировать на «внешние» события, делая что-то еще. Например, если вы готовите ужин, вы можете положить картофель на 20 минут. Вместо того, чтобы смотреть на часы в течение 20 минут, вы можете установить таймер, а затем пойти смотреть телевизор. Когда зазвонит таймер, вы «прерываете» просмотр телевизора, чтобы что-то сделать с картошкой.

Пример прерываний

В этом примере показано, как, даже если основной цикл ничего не делает, вы можете включить или выключить светодиод на контакте 13, если нажат переключатель на контакте D2.

Чтобы проверить это, просто подключите провод (или переключатель) между D2 и землей. Внутренняя подтяжка (активирована в настройке) обычно устанавливает ВЫСОКИЙ уровень на выводе. При заземлении он становится НИЗКИМ. Изменение вывода обнаруживается прерыванием CHANGE, которое вызывает процедуру обработки прерывания (ISR).

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

Преобразование номеров контактов в номера прерываний

Чтобы упростить преобразование номеров векторов прерываний в номера контактов, вы можете вызвать функцию , передав пин-код. Возвращает соответствующий номер прерывания, или (-1).

Например, на Uno вывод D2 на плате — это прерывание 0 (INT0_vect из таблицы ниже).

Таким образом, эти две строки имеют одинаковый эффект:

Однако второй легче читать и переносить на разные типы Arduino.

Доступные прерывания

Ниже приведен список прерываний в порядке приоритета для Atmega328:

Внутренние имена (которые вы можете использовать для настройки обратных вызовов ISR) указаны в скобках.

Предупреждение: если вы неправильно написали имя вектора прерывания, даже если неправильно написали заглавные буквы (что легко сделать), подпрограмма прерывания не будет называться, и вы не получите ошибку компилятора.

Причины использования прерываний

Основные причины, по которым вы можете использовать прерывания:

  • Для обнаружения изменений штифта (например, поворотных энкодеров, нажатия кнопок)
  • Сторожевой таймер (например, если ничего не происходит через 8 секунд, прервите меня)
  • Прерывания таймера — используются для сравнения / переполнения таймеров
  • Передача данных SPI
  • Передача данных I2C
  • Передача данных USART
  • Преобразования АЦП (аналого-цифровой)
  • EEPROM готов к использованию
  • Флэш-память готова

«Передача данных» может использоваться, чтобы позволить программе делать что-то еще, пока данные отправляются или принимаются через последовательный порт, порт SPI или порт I2C.

Программирование Arduino Uno с помощью PlatformIO

Мы рассмотрим программирование платы Arduino Uno с помощью PlatformIO на примере простой программы мигания светодиодом. Для этого выполните следующую последовательность шагов.

Выберите в PlatformIO вкладку “New Project” (новый проект) из меню быстрого доступа.

Дайте имя проекту (в нашем случае мы назвали его ‘Blink’). Выберите тип платы, с которой будете работать – в нашем случае это Arduino Uno. Поскольку мы собираемся работать во фреймворке Arduino, то в поле фреймворк (framework) необходимо выбрать Arduino. После заполнения всех полей нажмите Finish.

Подождите некоторое время пока ваш новый проект создастся и “подтянет” к себе необходимые ресурсы и расширения.

Когда проект успешно создастся вы увидите всплывающее сообщение “Project has been successfully initialized” как показано на следующем рисунке.

Чтобы открыть созданный проект пролистайте вниз Home Menu (главное меню) PlatformIO и вы увидите список всех созданных проектов. В правой стороне напротив интересующего вас проекта нажмите ссылку ‘Open’ чтобы перейти к редактированию проекта.

Когда проект будет открыт первоначально он будет отображаться как скрытый, но не беспокойтесь, PlatformIO имеет весьма продвинутые опции для работы с файлами, поэтому вы без труда найдете все файлы проекта. Просто идите в левый верхний угол и нажмите там ‘Untitled (Workplace)’. Когда вы нажмете эту ссылку, все файлы проекта появятся в выпадающем меню. Чтобы открыть окно редактирования кода, выберите в выпавшем списке ‘src’ и затем ‘main.cpp’. Окно редактора кода появится в главном экране (Home Screen) с открытием новой вкладки (Tab). После этого вы сможете писать/редактировать код вашей программы.

Напишите код программы для простого мигания светодиодом в плате Arduino Uno. Следует отметить, что PlatformIO по умолчанию не имеет прямого доступа к библиотекам Arduino, поэтому для написания даже самой простой программы (не требующей никаких библиотек) всегда добавляйте строку “#include <Arduino.h>” в самом начале программы.

Следующим шагом будет компиляция и загрузка кода программы в плату Arduino Uno. PlatformIO изначально выбирает тот COM порт, который стоит в системе по умолчанию. Но если это не тот COM порт, который вам нужен, то его можно изменить – это будет объяснено далее в статье. PlatformIO имеет такие функции для работы с кодом программы как Build, Upload, Upload to Remote Device (загрузка в удаленное устройство), Clean, Test, Run Task, Serial Monitor, New Terminal. Все эти функции доступны в левом нижнем углу редактора как показано на следующем рисунке. Когда вы будете наводить мышкой на иконки этих функций, то будет показываться их описание.

Чтобы скомпилировать скетч нажмите на ‘Build’, а чтобы загрузить его в плату Arduino – нажмите на ‘Upload’. Когда загрузка кода в плату будет закончена вы сможете увидеть время, которое потребовалось для загрузки кода, и другие параметры загрузки. Также появится сообщение “Success” (успех). Когда загрузка кода программы в плату будет закончена вы сможете увидеть результат работы программы.

Чтобы выбрать или изменить COM порт, перейдите на главный экран (Home Screen) PlatformIO, выберите там пункт меню Devices (устройства) как показано на следующем рисунке. После этого вы увидите все доступные (подключенные) устройства. Выберите нужный вам COM порт.

Программирование Arduino Shield

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

Чтение или запись сигналов шилдов производится тоже обычным методом: с помощью функций analogRead (), digitalRead (), digitalWrite () и других, привычных любому ардуинщику команд. В некоторых случаях возможны коллизии, когда вы привыкли к оной схеме соединения, а производитель выбрал другую (например, вы подтягивали кнопку к земле, а на шилде – к питанию). Тут нужно быть просто внимательным.

Скетч

После подготовки и сборки компонентов, мы готовы программировать наши платы. Для этого проекта обе платы будут иметь одинаковые скетчи.

Сначала, мы устанавливаем режим контакта 8 (кнопка) в , режим контакта 13 (светодиод) в и устанавливаем начальное состояние контакта 13 в состояние (светодиод выключен).

Как всегда, Arduino позволяет нам легко использовать встроенное оборудование UART с помощью объекта serial. Последовательный serial объект имеет необходимые функции для простого использования UART-интерфейса Arduino.

Serial.begin()

Для связи через UART-интерфейс необходимо сначала его настроить. Самый простой способ настроить UART Arduino — это использовать функцию . Параметр («Скорость») — это скорость передачи данных, с которой мы хотим запустить UART. С помощью этой функции остальные параметры UART будут установлены на значения по умолчанию:

  • Data length = 8 (длина данных)
  • Parity bit = 1 (бит четности)
  • Number of Stop Bits = None (количество стоп-битов = нет)

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

Нижеприведенный код добавляет внутри для инициализации Arduino Uno UART со скоростью 9600 бит/с и другими параметрами, установленными по умолчанию.

Следующая часть кода — это чтение и сохранение значения, полученного из последовательного интерфейса. Для этого мы будем использовать функцию вместе с оператором , чтобы проверить, не получены ли данные. Затем мы вызовем для получения одного байта полученных данных и сохраним значение в переменную . Значение управляет включением/выключением встроенного светодиода.

Serial.available()

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

Serial.read()

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

Serial.write()

Для отправки данных через контакты Arduino TX0 мы будем использовать функцию . Параметр — это байт (или серия байтов), который будет отправлен.

В нашем скетче мы будем посылать значение в зависимости от состояния контакта 8. Мы отправим значение char ‘1’, если пин 8 HIGH, или значение char ‘0’, если пин 8 LOW.

Схема Arduino Nano ISCP

Наконец, надо сказать о подключении программатора. Для программирования контроллеров Atmel, на котором собран модуль Arduino, используется интерфейс ICSP. Для Arduino Nano icsp распиновка выглядит выглядит следующим образом (см. верхнюю часть предыдущего рисунка):

  1. MISO (ведущий принимает от ведомого);
  2. +5V (питание);
  3. SCK (тактовый импульс);
  4. MOSI (ведущий передает ведомому);
  5. RESET (сброс);
  6. GND (земля).

Первый пин 6-контактного разъема имеет в основании форму квадратика и нумеруется по часовой стрелке, если смотреть сверху. Чтобы не возникало сомнений по порядку нумерации выводов коннектора, ниже приводится фрагмент принципиальной схемы платы Ардуино:

Этот разъем подключается к программатору с интерфейсом SPI (интерфейс последовательного программирования контроллеров Atmel). Кроме того, прошивка контроллера может меняться из среды программирования через кабель USB, так что приобретать программатор становится необязательным (он нужен только в том случае, если отсутствует программа загрузчика).

Номера прерываний

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

Однако более старые скетчи часто используют прямые номера прерываний. Часто использовались 0 (для цифрового вывода 2) или 1 (для цифрвого вывода 3). В приведенной ниже таблице показаны доступные выводы прерывний на различных платах.

Обратите внимание, что в приведенной ниже таблице номера прерываний это числа, которые должны быть переданы. По историческим причинам эта нумерация не всегда соответствует прерываниям на чипе ATmega (например, int.0 соответствует INT4 на чипе ATmega2560)

Соответствие номеров выводов номерам прерываний на платах Arduino
Плата INT.0 INT.1 INT.2 INT.3 INT.4 INT.5
Uno, Ethernet 2 3        
Mega2560 2 3 21 20 19 18
На базе 32u4 (например, Leonardo, Micro) 3 2 1 7  

Для плата Uno WiFiRev.2, Due, Zero, семейства MKR и 101 номер прерывания = номер вывода.

Разбудить процессор

Внешние прерывания, прерывания при смене вывода и прерывание сторожевого таймера также могут использоваться для пробуждения процессора. Это может быть очень удобно, так как в спящем режиме процессор может быть настроен на использование гораздо меньшей мощности (например, около 10 мкА). Прерывание нарастания, спада или низкого уровня может использоваться для пробуждения гаджета (например, если вы нажмете на нем кнопку), или прерывание «сторожевого таймера» может периодически пробуждать его (например, для проверки времени или температура).

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

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

Включение / отключение прерываний

Прерывание «сброса» нельзя отключить. Однако другие прерывания можно временно отключить, сбросив глобальный флаг прерывания.

Программирование STM32 с помощью PlatformIO

Для поклонников микроконтроллеров, построенных на основе платформы STM32, мы в данной статье рассмотрим их программирование с помощью PlatformIO. Процесс программирования STM32 будет практически таким же, как и рассмотренная процедура программирования Arduino UNO с помощью PlatformIO. Различие будет состоять в том, что необходимо будет выбрать соответствующую плату STM32 когда будете создавать новый проект для STM32. Достоинством PlatformIO в данном случае является то, что при работе в ней нет необходимости отдельно скачивать какие либо внешние пакеты для работы с любой платой, PlatformIO скачивает все необходимые пакеты автоматически, поэтому нам необходимо просто выбрать плату и затем можно переходить к редактору. Мы будем использовать внешний JLink/ JTAG/ STLink/ Serial Programmer чтобы загружать скетч в STM32. Также следует отметить, что STM32 можно программировать и с помощью Arduino IDE.

Чтобы произвести программирование STM32 с помощью PlatformIO выполните следующую последовательность шагов.

Дайте имя новому проекту – мы его назвали ‘Blink STM32’. Затем выберите необходимую плату STM32 – в нашем случае это ‘BluePill F103C8(Generic)’. Выберите фреймворк для Arduino. После заполнения всех полей нажмите на Finish и подождите некоторое время пока проект создастся и загрузит все необходимые пакеты для работы с STM32.

Повторное создание проекта для работы с STM32 произойдет гораздо быстрее потому что все необходимые пакеты будут уже загружены при создании первого проекта. Теперь перейдите в пункт меню Untitled(Workspace) -> src -> main.cpp как мы это уже рассматривали ранее в статье при работе с платой Arduino.

Следующим шагом идет выбор программатора – он весьма важный. Для программирования плат STM32 могут быть использованы такие программаторы как JTAG, STLink, JLink, Serial и т.п. Все они рабочие, но вам необходимо соответствующим образом сконфигурировать страницу конфигурации ‘platformio.ini’

В этом проекте мы используем программатор Serial Programmer CP210x USB to UART Bridge. Подсоедините этот последовательный программатор к плате STM32 (как показано в следующей таблице) и к вашему компьютеру.

USB to Serial Programmer STM32 Board
5V 5V
Gnd Gnd
Rx A9
Tx A10

После этого перейдите в менеджер проектов (project explorer), откройте в нем страницу ‘platformio.ini’ и внесите в нее изменения как показано на следующем рисунке. Протокол загрузки кода (upload_protocol) определяет какой программатор следует использовать ((STLink, JLink, Serial и т.д.). В качестве параметра upload_port следует указать используемый вами COM порт. Вы можете изменить/выбрать используемый COM порт в пункте меню ‘Devices’ на главной странице PlatformIO.

После этого перейдите в ‘main.cpp’ и напишите/измените программу мигания светодиодом. Далее загрузите код программы в плату. В случае успешной загрузки кода будут показаны параметры его загрузки. После загрузки кода вы сможете наблюдать мигание светодиода, подключенного к контакту PC13 платы STM32.

Написание ISR

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

Однако, если библиотека еще не предоставила «перехватчик» для ISR, вы можете создать свой собственный, например:

В этом случае вы используете макрос «ISR» и указываете имя соответствующего вектора прерывания (из таблицы ранее). В этом случае ISR обрабатывает завершение передачи SPI

(Обратите внимание, что в некоторых старых кодах используется SIGNAL вместо ISR, однако SIGNAL устарел)

Прерывания в языке Arduino

Теперь давайте перейдем к практике и поговорим о том, как использовать прерывания в своих проектах.

Функция attachInterrupt используется для работы с прерываниями. Она служит для соединения внешнего прерывания с обработчиком.

Синтаксис вызова: attachInterrupt(interrupt, function, mode)

interrupt – номер вызываемого прерывания (стандартно 0 – для 2-го пина, для платы Ардуино Уно 1 – для 3-го пина),
function – название вызываемой функции при прерывании(важно – функция не должна ни принимать, ни возвращать какие-либо значения),
mode – условие срабатывания прерывания.

Возможна установка следующих вариантов условий срабатывания:

  • LOW – выполняется по низкому уровню сигнала, когда на контакте нулевое значение. Прерывание может циклично повторяться – например, при нажатой кнопке.
  • CHANGE – по фронту, прерывание происходит при изменении сигнала с высокого на низкий или наоборот. Выполняется один раз при любой смене сигнала.
  • RISING – выполнение прерывания один раз при изменении сигнала от LOW к HIGH.
  • FALLING – выполнение прерывания один раз при изменении сигнала от HIGH к LOW.4

Важные замечания

При работе с прерываниями нужно обязательно учитывать следующие важные ограничения:

  • Функция – обработчик не должна выполняться слишком долго. Все дело в том, что Ардуино не может обрабатывать несколько прерываний одновременно. Пока выполняется ваша функция-обработчик, все остальные прерывания останутся без внимания и вы можете пропустить важные события. Если надо делать что-то большое – просто передавайте обработку событий в основном цикле loop(). В обработчике вы можете лишь устанавливать флаг события, а в loop – проверять флаг и обрабатывать его.
  • Нужно быть очень аккуратными с переменными. Интеллектуальный компилятор C++ может “пере оптимизировать” вашу программу – убрать не нужные, на его взгляд, переменные. Компилятор просто не увидит, что вы устанавливаете какие-то переменные в одной части, а используете – в другой. Для устранения такой вероятности в случае с базовыми типами данных можно использовать ключевое слово volatile, например так: volatile boolean state = 0. Но этот метод не сработает со сложными структурами данных. Так что надо быть всегда на чеку.
  • Не рекомендуется использовать большое количество прерываний (старайтесь не использовать более 6-8). Большое количество разнообразных событий требует серьезного усложнения кода, а, значит, ведет к ошибкам. К тому же надо понимать, что ни о какой временной точности исполнения в системах с большим количеством прерываний речи быть не может – вы никогда точно не поймете, каков промежуток между вызовами важных для вас команд.
  • В обработчиках категорически нельзя использовать delay(). Механизм определения интервала задержки использует таймеры, а они тоже работают на прерываниях, которые заблокирует ваш обработчик. В итоге все будут ждать всех и программа зависнет. По этой же причине нельзя использовать протоколы связи, основанные на прерываниях (например, i2c).

Распиновка Arduino Nano

У Arduino Nano распиновка выполнена так, как показано на картинке ниже:

1 – TX (передача UART) или порт D0;
2 – RX (прием UART) или порт D1;
3,28 – сброс (RESET);
4,29 – земля;
5…16 – порты D3…D13;
17 – напряжение 3,3 В;
18 – опорное напряжение АЦП;
19…26 – 8 каналов АЦП A0…A7;
27 – напряжение 5,0 В;
30 – плюс питания модуля 2-20 В

Первые два вывода используются либо для связи по классическому последовательному интерфейсу с другим устройством, либо как порты для двоичных данных. В arduino nano распиновка 5…16 выводов, кроме указанных, имеет дополнительные функции:

5 – прерывание INT0;
6 – прерывание INT1 / ШИМ / AIN0;
7 – таймер-счетчик T0 / шина I2C SDA / AIN1;
8 – таймер-счетчик T1 / шина I2C SCL / ШИМ;
9,12,13,14 – ШИМ;
16 – светодиод.

Более подробная схема вводов-выводов на рисунке ниже (нажмите для увеличения):

Распиновка Arduino Nano

AIN0 и AIN1 – это входы быстродействующего аналогового компаратора. Кроме того, имеется 6 каналов с выходом широтно-импульсного модулятора (ШИМ). К тому же имеется большее число пинов, на которые могут быть переведены запросы прерываний.

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

Распиновка Arduino Nano 3.0

У Arduino Nano 3.0 распиновка не отличается от той схемы, что приведена выше, несмотря на другой контроллер. ATmega328 отличается от ATmega168 вдвое большим объемами памяти всех видов:

  • flash,
  • оперативной,
  • EEPROM.

Это позволяет улучшить ПО прошивки и загручика, а также дать пользователю больше возможностей для его прикладной задачи. Arduino nano v 3.0 распиновка может быть использована для программирования, но для этих целей используется отдельный разъем. Об этом ниже.

Расположение выводов, распиновка

Разработчики платы Arduino очень удобно и логично расположили выводы платы. Дело в том, что при разработке на «чистых» МК АВР приходилось обращаться к выводу порта, для этого нужно было запомнить название каждой ножки на чипе. Здесь это гораздо проще. На самой плате указано название каждого из пинов. Удобства добавляет и то, что пины разбиты на 3 группы:

  1. Digital – блок цифровых пинов.
  2. Analog – блок аналоговых пинов.
  3. Power – блок пинов, которые связаны с питанием и работой микросхемы.

Распиновка платы

При этом в разделе Digital пины, которые могут выдавать ШИМ-сигнал (PWM), помечены тильдой «~». Для служебных целей и проверки работоспособности контроллера на плате установлен светодиод, который подключен к 13-му выводу, а из среды разработки Arduino IDE к нему можно обращаться через встроенную директиву LED_BUILTIN. Такие схемы расположения пинов называются «Arduino UNO pinout», при этом, вместо UNO, может быть указано название другой платы, которая вас интересует.

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: