Прерывания – это механизм, при котором устройства ввода/вывода или некоторые команды могут приостанавливать «нормальную» работу процессора и переключаться на выполнение другой задачи, поскольку в данном случае она будет иметь наивысший приоритет. К примеру, если процессор мониторит поступление какого-либо события и в это время поступает прерывание от внешнего датчика, то процессор приостанавливает свое нормальное функционирование и переключается на процедуру обслуживания прерывания, после завершения которого он возвращается к своему нормальному функционированию.
В данной статье мы рассмотрим основы использования прерываний в плате STM32F103C8, которая также известна под именем STM32 Blue Pill («синяя таблетка»). В качестве внешнего источника прерывания мы будем использовать обычную кнопку. Всегда при нажатии кнопки мы будем зажигать светодиод и выводить на экран ЖК дисплея слово INTERRUPT (в переводе означает прерывание). При отпускании кнопки мы будем выключать светодиод.
Ранее на нашем сайте мы рассматривали работу с прерываниями в плате Arduino. Также вы можете посмотреть на нашем сайте все проекты с использованием прерываний.
Необходимые компоненты
- Плата разработки STM32F103C8 (STM32 Blue Pill) (купить на AliExpress).
- Кнопка.
- Светодиод (купить на AliExpress).
- Резистор 10 кОм (купить на AliExpress).
- ЖК дисплей 16×2 (купить на AliExpress).
- Макетная плата.
- Соединительные провода.
Типы прерываний и их обработчиков
Прерывания можно разделить на два больших типа: аппаратные прерывания и программные прерывания.
Аппаратные прерывания возникают когда процессор получает сигнал от какого либо внешнего устройства (кнопка, датчик и т.д.) и переключается на обработку этого события.
Программные прерывания генерируются инструкциями, присутствующими в коде программы.
Программа обработки прерываний (Interrupt Service Routine, ISR) или обработчик прерывания (Interrupt handler) – это функция, содержащая обычно небольшое число инструкций. Когда происходит прерывание, процессор первым делом исполняет код этой функции обработчика прерывания и лишь затем возвращается к выполнению задачи, которую он исполнял до возникновения прерывания.
Синтаксис прерываний в плате STM32
В платах Arduino функция обработки прерывания (ISR) имеет синтаксис attachInterrupt (digitalPinToInterrupt(pin), ISR, mode) – его мы можем использовать и в нашей плате STM32 поскольку мы используем для ее программирования среду Arduino IDE.
digitalPinToInterrupt(pin) – цифровой контакт, на котором мы будем обнаруживать прерывание. В платах Arduino Uno для этой цели можно использовать контакты 2 и 3, а в платах Arduino Mega – контакты 2, 3, 18, 19, 20, 21. В плате STM32F103C8 для этой цели можно использовать любые цифровые контакты ввода/вывода (GPIO pins). Нам необходимо просто указать контакт, который мы будем использовать для работы с прерываниями.
ISR – это название функции обработчика прерывания, которая будет вызываться каждый раз при обнаружении внешнего прерывания. Она не содержит аргументов и не должна ничего возвращать (void return type).
Mode – режим срабатывания (обнаружения) прерывания. Может принимать одно из следующих назначений:
— RISING – прерывание срабатывает когда уровень напряжения на контакте изменяется с LOW на HIGH;
— FALLING – прерывание срабатывает когда уровень напряжения на контакте изменяется с HIGH на LOW;
CHANGE – прерывание срабатывает когда уровень напряжения на контакте изменяется (с LOW на HIGH или с HIGH на LOW).
Требования, накладываемые на функцию обработчика прерывания (ISR):
- код этой функции должен быть настолько коротким, насколько это возможно;
- функция Delay() не работает внутри функции обработчика прерывания и следует избегать ее использования в этой функции.
Схема проекта
Схема для демонстрации возможностей использования прерываний в плате STM32F103C8 (Blue Pill) представлена на следующем рисунке.
Подтягивающий резистор (Pull Down resistor) необходим для того, чтобы на контакте платы STM32 были только два возможных значения напряжения – HIGH или LOW (при нажатии или отпускании кнопки). А если данный резистор не использовать, то на контакте платы могут появляться некоторые «плавающие» значения напряжения вследствие воздействия различного вида помех.
Принцип работы подтягивающего резистора показан на следующем рисунке.
Необходимые соединения между платой STM32F103C8 и ЖК дисплеем представлены в следующей таблице.
Плата STM32F103C8 | ЖК дисплей |
GND | VSS |
+5V | VDD |
средний контакт потенциометра | V0 |
PB0 | RS |
GND | RW |
PB1 | E |
PB10 | D4 |
PB11 | D5 |
PC13 | D6 |
PC14 | D7 |
+5V | A |
GND | K |
Внешний вид собранной конструкции проекта показан на следующем рисунке.
Объяснение программы для платы STM32
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Программировать плату STM32F103C8 мы будем с помощью Arduino IDE через USB порт, без использования внешнего FTDI программатора.
В нашей программе мы будем использовать переменную, значение которой мы будем инкрементировать каждую секунду. Значение этой переменной мы будем выводить на экран ЖК дисплея 16×2, также при обнаружении прерывания мы будем выводить на экран дисплея слово ‘INTERRUPT’.
Первым делом в программе укажем контакты платы STM32, к которым подключен ЖК дисплей.
1 |
const int rs= PB10,en= PB11,d4= PB0,d5= PB1,d6= PC13,d7= PC14; |
Далее подключим заголовочный файл библиотеки для работы с ЖК дисплеем и создадим объект для работы с ЖК дисплеем с помощью функции LiquidCrystal.
1 2 |
include<LiquidCrystal.h> LiquidCrystal lcd (rs,en,d4,d5,d6,d7); |
Для обмена данными между функцией обработки прерывания и основной программой можно использовать глобальные переменные. В нашей программе мы объявим переменную ledOn как volatile. Она будет логического типа, то есть будет способна принимать значения True или False.
1 |
volatile boolean ledOn = false; |
Внутри функции void setup() мы укажем тип ЖК дисплея (16х2), покажем на нем приветственное сообщение и через 2 секунды очистим его экран.
1 2 3 4 |
lcd.begin(16,2); lcd.print("CIRCUIT DIGEST"); delay(2000); lcd.clear(); |
Также в функции void setup() мы укажем режимы работы используемых контактов – на ввод или вывод данных.
1 2 |
pinMode(PA1,OUTPUT) pinMode(PA0,INPUT) |
Далее переменную, которую будем инкрементировать в нашей программе. Вначале присвоим ей значение 0.
1 |
int i = 0; |
Одним из основных элементов кода нашей программы будет функция attachInterrupt() – с помощью нее мы будем задавать правила обработки прерываний.
1 |
attachInterrupt(digitalPinToInterrupt(PA0),buttonPressed,CHANGE) |
Обработку (обнаружение) внешнего прерывания мы будем производить на контакте PA0 платы STM32, для обработки прерывания будет вызываться функция buttonPressed. Прерывание будет срабатывать при любом изменении состоянии контакта PA0 – с LOW на HIGH или с HIGH на LOW.
Внутри функции loop() мы будем инкрементировать переменную i и выводить ее значение на экран ЖК дисплея 16х2.
1 2 3 4 5 |
lcd.clear(); lcd.print("NUMBER:"); lcd.print(i); ++i; delay(1000); |
Далее запрограммируем функцию обработчика прерывания void buttonPressed() – она также будет играть одну из главных ролей в нашей программе.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void buttonPressed() { if(ledOn) { ledOn=false; digitalWrite(PA1,LOW); } else { ledOn = true; digitalWrite(PA1,HIGH); lcd.setCursor(0,1); lcd.print("Interrupt"); } } |
В зависимости от значения переменной ledOn светодиод будет включаться (ON) или выключаться (OFF) как показано в следующей таблице.
Состояние кнопки | Значение переменной ledOn | Светодиод | ЖК дисплей 16х2 |
отжата | False | OFF | — |
нажата | True | ON | показывает ‘’INTERRUPT’ |
Примечание: у кнопки может присутствовать эффект «дребезга контактов», который будет приводить к тому, что одиночное нажатие кнопки будет восприниматься нашей платой STM32 как несколько нажатий. Снизить влияние этого эффекта можно с помощью RC фильтра.
Исходный код программы (скетча)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
const int rs= PB10,en= PB11,d4= PB0,d5= PB1,d6= PC13,d7= PC14; // контакты, к которым подключен ЖК дисплей #include<LiquidCrystal.h> // библиотека для работы с ЖК дисплеем LiquidCrystal lcd (rs,en,d4,d5,d6,d7); // создание объекта для работы с ЖК дисплеем volatile boolean ledOn = false; // глобальная логическая переменная void setup() { lcd.begin(16,2); // устанавливаем тип ЖК дисплея16x2 lcd.print("CIRCUIT DIGEST"); // puts CIRCUIT DIGEST IN LCD delay(2000); // задержка 2 секунды lcd.clear(); // очищаем экран ЖК дисплея pinMode(PA1,OUTPUT); // режим работы контакта PA1 – на вывод данных pinMode(PA0,INPUT); // режим работы контакта PA0 – на ввод данных int i = 0; // объявляем переменную i и записываем в нее 0 attachInterrupt(PA0,buttonPressed,CHANGE); // функция для обработки внешних прерываний } void loop() // void loops runs continuously { lcd.clear(); // очищаем экран ЖК дисплея lcd.print("NUMBER:"); // puts NUMBER: in LCD display lcd.print(i); // выводим значение i на экран ЖК дисплея ++i; // инкрементируем значение i delay(1000); // задержка на 1 с } void buttonPressed() // { if(ledOn) // if statement depends on LedOn value { ledOn=false; // Makes ledOn false if it is True digitalWrite(PA1,LOW); // digital writs the low vale to PA1 pin makes led OFF (выключаем светодиод) } else { ledOn = true; // Makes ledOn True if it is False digitalWrite(PA1,HIGH); // digital writs the HIGH vale to PA1 pin makes led ON (включаем светодиод) lcd.setCursor(0,1); // устанавливаем курсор в 1-й столбец 2-й строки lcd.print("Interrupt"); // выводим слово INTERRUPT на экран ЖК дисплея } } |
2 ответа к “Использование прерываний в плате STM32F103C8 (Blue Pill)”
Доброго времени суток. STM32 на просторах инета фигурирует в связке с повышенным порогом входа по сравнению с ардуино. Но благодаря Arduino IDE программировать STM ничуть не сложнее Ардуино. Или все же есть какие моменты? То что простейший скетч занимает тонну памяти, это понятно что Arduino IDE добавляет свой багаж библиотек. Я бы сказал что около 13-14кб. Дальше с ростом скетча уже нет такого роста веса.
Добрый день. Да, благодаря Arduino IDE программирование STM32 становится достаточно простым занятием, поэтому я и решил добавить цикл подобных статей на свой сайт. Каких то особых моментов по сравнению с Ардуино не заметил, разницу в их конструкциях и архитектуре Arduino IDE сводит практически на нет