Arduino STM32 - внешние прерывания









Эта статья является продолжением описания платы Blue Pill (Arduino STM32). Начало здесь.

Описание сделано предельно упрощённо, и рассчитано на программирование в IDE Arduino.

Если Вас интересует работа на более низком уровне, то вот здесь, всё великолепно объяснено.




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

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

Во время обработки прерывания не работают функции delay() и millis().

Прерывания от таймеров здесь не рассматриваются, про это в следующей части.




Внешние прерывания вызываются при поступлении сигналов от какого-либо устройства, например, изменение состояния на «ножке» МК…

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

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



Любой пин может использоваться для прерываний, но не более 16-ти одновременно. Это определяется количеством EXTI Line — линий внешних прерываний (External Interrupts Lines), к которым подключены пины.

К линии EXTI0 подключены нулевые пины — PB0 и PA0, к линии EXTI1 первые — PA1 и PB1 и т.д. Обращайте внимание на то, что выведено на пины, например РА11 и РА12 это USB, поэтому вряд ли стоит заводить на них внешние сигналы.

Не получится одновременно использовать несколько пинов находящихся на одной линии, можно только какой-то один (это замечание относится к программированию в IDE Arduino). Соответственно если Вам нужно «слушать» прерывания от двух источников, нельзя использовать PB0 и PA0, нужно выбрать пины из разных линий.



Arduino STM32


Еще есть линии внешних прерываний не выведенные непосредственно на «ножки»…

EXTI16 – подключена к PVD (программируемый детектор напряжения).
EXTI17 – RTC Alert event.
EXTI18 – USB Wakeup event.
EXTI19 – Ethernet Wakeup event.

схема из datasheet





Запуск прерывания — attachInterrupt(pin, function, mode);
Отключение — detachInterrupt(pin);

pin — номер пина
function — функция, которая будет вызываться при срабатывании прерывания.
mode — тип сигнала (RISING, FALLING, CHANGE).

RISING — с LOW на HIGH.
FALLING — с HIGH на LOW.
CHANGE — с LOW на HIGH и с HIGH на LOW.

То есть то же самое, что и у Arduino, только нет режима LOW.

Переменные внутри функции прерывания должны иметь модификатор volatile.



Пример прослушивания трёх внешних прерываний:

#define signal1 PA0 // пин на линии EXTI0
#define signal2 PA1 // пин на линии EXTI1
#define signal3 PA2 // пин на линии EXTI2

#define LED1 PB0 
#define LED2 PB1 

volatile int state1 = LOW; 
volatile int state2 = LOW;
volatile int state3 = LOW;

void setup() 
{ 
  Serial.begin(115200);
  pinMode(signal1, INPUT_PULLDOWN);
  pinMode(signal2, INPUT_PULLDOWN);
  pinMode(signal3, INPUT_PULLDOWN);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT); // PC13
  attachInterrupt(signal1, func_interrup_1, RISING); // инициализация первого прерывания
  attachInterrupt(signal2, func_interrup_2, FALLING); // инициализация второго прерывания
  attachInterrupt(signal3, func_interrup_3, CHANGE); // инициализация третьего прерывания
  
}

void loop() 
{
  Serial.println("Hello");
  delay(2000);
}

void func_interrup_1() // обработчик первого прерывания
{
  if(state1 == HIGH) state1 = LOW;
  else state1 = HIGH;
  digitalWrite(LED1, state1);
}

void func_interrup_2() // обработчик второго прерывания
{
  if(state2 == HIGH) state2 = LOW;
  else state2 = HIGH;
  digitalWrite(LED2, state2);
}

void func_interrup_3() // обработчик третьего прерывания
{
  if(state3 == HIGH) state3 = LOW;
  else state3 = HIGH;
  digitalWrite(LED_BUILTIN, state3);
}

Теперь, если подать на пины PA0, PA1, PA2 сигналы (например с ардуины — чередующиеся digitalWrite(5, HIGH); delay(50); и digitalWrite(5, LOW); delay(50);), то светики на пинах PB0, PB1, PC13 будут дружно моргать. PC13 будет мигать в два раза чаще. При этом задержка в цикле void loop() не будет ни на что влиять.


Warning! Пины PA0, PA1, PA2 трехвольтовые, сигнал подавайте через делитель напряжения, либо укажите другие ноги.
картинка




У микроконтроллера stm32 (в отличии от Arduino) у прерываний есть приоритет, высший у линии EXTI0, низший у линии EXTI19. Соответственно если одновременно произойдут два или более прерывания, то приоритет будет у линии с меньшим номером. Прерывания на линии с большим номером будут поставлены в очередь.

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



На этом всё.

Форум (рус.)

Руководство (рус.) по stm32

Телеграм-чат STM32

Следите за обновлениями ядра.


Ссылки:
External Interrupts

attachInterrupt

detachInterrupt


  • 0
  • 2123
Telegram-канал istarik

Известит Вас о новых публикациях...


Комментарии (3)

0
нет ошибки в коде:

if(state1 == HIGH) state1 = LOW;
else state1 = HIGH;
digitalWrite(LED1, state1);

может так:

if(signal1 == HIGH) state1 = LOW;
else state1 = HIGH;
digitalWrite(LED1, state1);
0
тут редактировать можно?
а то вместо "?" поставил ":"
0
Ошибки нет. Проверяется состояние переменной (0 или 1), меняется на противоположное и назначается пину.

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