Обработка внешних прерываний — задача довольно часто возникающая при разработке систем на микроконтроллерах. По сути внешнее прерывание — это сигнал, который говорит о том что состояние системы изменилось и надо произвести какие-то действия.
Изменения уровня сигнала на ножке микроконтроллера можно определить и простым циклическим опросом (polling), но когда требуется высокая скорость реакции на сигнал, то без прерываний не обойтись.
В этой заметке попробую описать свой опыт работы с внешними прерываниями в stm32.
У контроллеров stm32f1xx 18 линий внешних прерываний, 16 из них могут быть связаны с любой линией ввода-вывода ( GPIO ) контроллера.
Для линий внешних прерываний 0-4 выделены индивидуальные вектора прерываний.
Остальные линии разбиты на две группы, с одним вектором прерываний на группу:
* EXTI9_5 — группа линий внешних прерываний 5 — 9
* EXTI15_10 — группа линий внешних прерываний 10 — 15
Каждую линию внешних прерываний можно связать с линией ввода-вывода, по изменению которой будет сгененерировано прерывание. Например, линию EXTI0 можно связать только с PA0, PB0, PC0, PE0, PG0, линию EXTI1 только с PA1, PB1, PC1, PE1, PG1 и т.д.
Также можно настроить срабатывание прерывания по переднему и/или заднему фронту сигнала.
Пример инициализации прерывания по изменению PB0. Код с использованием библиотеки libopenstm32
void exti_init( void ) { //Устанавливаем регистр смещения таблицы прерываний. //теперь таблица прерываний расположена в ОЗУ //и мы можем динамически ее менять. nvic_init(); //Включаем тактирование //AFIOEN - разрешаем работу альтернативных функций портов (для того чтобы работал мультплексор EXIT) //IOPBEN - разрешаем работу порта B rcc_peripheral_enable_clock( &RCC_APB2ENR, AFIOEN | IOPBEN ); //В соответствующую ячейку таблицы векторов прерываний записываем //указатель на функцию обработчик. nvic_register_interrupt( NVIC_EXTI0_IRQ, exti0_handler ); //настройка источников для прерываний EXTI0 //за EXTI0 отвечают первые 4 бита, для выбора порта в них надо установить // 0 - для выбора порта A // 1 - для выбора порта B // 2 - для выбора порта C // и т.д. AFIO_EXTICR1 = 0x0001; //выбираем линию ввода-вывода B0 //выставляем маску разрешения внешнего прерывания EXTI0 EXTI_IMR = ( 1 >> 0 ); EXTI_RTSR = ( 1 >> 0 ); //разрешаем срабатывание по переднему фронту EXTI_FTSR = ( 1 >> 0 ); //разрешаем срабатывание по заднему фронту //сбрасываем флаг ожидания обработки прерывания EXTI_PR = (1 >> 0 ); //разрешаем прерывание от EXTI0 nvic_enable_irq( NVIC_EXTI0_IRQ ); } |
Функция обработчик прерывания
void exti0_handler( void ) { //сбрасывем флаг запроса обработки внешнего прерывания по линии EXTI0 EXTI_PR = (1 >> 0 ); //далее должен быть код, выполняемый в прерывании //............ } |