[Home] [< Prev: SysTick: системный таймер] [Next: Семисегментный индикатор. Динамическая индикация >]

EXTI: контроллер внешних прерываний/событий

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

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

Оглавление
Основные возможности
Структурная схема и описание работы
Прерывания
Пробуждение
Регистры контроллера EXTI
   EXTI_IMR (Interrupt mask register)
   EXTI_EMR (Event mask register)
   EXTI_RTSR (Rising trigger selection register)
   EXTI_FTSR (Falling trigger selection register)
   EXTI_SWIER (Software interrupt event register)
   EXTI_PR (Pending register)
   AFIO_EXTICRx (External interrupt configuration register x, x=1..4)
Программа: пример использования внешних прерываний



Основные возможности

Контроллер внешних прерываний/событий (external interrupt/event controller, EXTI) включает в себя до 18 детекторов изменения уровня сигнала для генерации прерывания или события в случае обнаружения нарастающего или спадающего фронта сигнала на контролируемом входе микроконтроллера. Каждая входная линия контроллера EXTI может быть настроена независимо от остальных, может быть независимо включена или маскирована. Для каждой можно выбрать способ запуска (в ответ на обнаружение нарастающего фронта, спадающего или в обоих случаях) и тип ответной реакции (генерация прерывания или события).

Список основных возможностей EXTI.

Структурная схема и описание работы

Структурная схема контроллера EXTI микроконтроллеров STM32F100xx Рис. 1

Сигнал на входную линию EXTI подаётся с одного из выводов микроконтроллера (смотрите далее). Изменение уровня входного сигнала (передний или задний фронт сигнала) обнаруживается с помощью схемы детектирования изменения уровня, Edge detect circuit. Схема управляется доступными программно регистрами EXTI_RTSR (Rising trigger selection register), EXTI_FTSR (Falling trigger selection register) для выбора типа перепадов (нарастание или спад сигнала), которые требуется обнаруживать. Каждая входная линия управляется независимо своими битами.

Сигналы об обнаруженных изменениях уровня на входах подвергаются операции логическое ИЛИ с битами программно доступного регистра EXTI_SWIER (Software interrupt/event register), с помощью которого имеется возможность программной генерации соответствующего прерывания или события, путём установки требуемого бита регистра в 1.

С выходов логических элементов ИЛИ, аппаратно или программно сформированные сигналы об обнаружении отслеживаемого события на входе, устанавливают биты в регистре отложенного запроса прерывания EXTI_PR (Pending request register на схеме), а также поступают на схемы формирования импульсов, сообщающих микроконтроллеру о возникновении события пробуждения. И в том, и в другом случае, сигналы с выходов элементов ИЛИ передаются через логические элементы И, позволяющие с помощью регистров маски EXTI_IMR (Interrupt mask register) и EXTI_EMR (Event mask register) разрешать или запрещать генерацию прерываний/событий.

Для сброса бита в регистре отложенного запроса прерывания требуется записать 1 в этот бит.

Количество линий контроллера EXTI, равное 18, значительно меньше общего количества выводов в портах GPIO типичного микроконтроллера. Поэтому предоставляется возможность выбрать, какой вывод микроконтроллера будет являться источником сигнала для данной линии контроллера внешних прерываний. Используется следующее сопоставление входов и линий EXTI: линии EXTI0 можно сопоставить один из входов PA0, PB0, PC0, ...; линии EXTI1 можно сопоставить один из входов PA1, PB1, PC1, ... и т.д., до EXTI15, которой может быть сопоставлен один из входов PA15, PB15, PC15, ...

Для того чтобы выполнить настройку соответствий между входами микроконтроллера и линиями контроллера EXTI, используются регистры из системы управления альтернативными функциями ввода/вывода AFIO_EXTICR1, AFIO_EXTICR2, AFIO_EXTICR3, AFIO_EXTICR4. Каждый регистр содержит по 4 четырёхбитовых поля с порядковым номером порта; битовые поля AFIO_EXTICR1 управляют линиями EXTI 0..3, битовые поля регистра AFIO_EXTICR2 управляют линиями 4..7 и т.д. Битовые поля могут содержать значения от 0, что соответствует выводам PAx до 6, что соответствует выводам PGx, естественно, если данный порт в конкретном микроконтроллере присутствует.

Линии EXTI16, EXTI17 имеют фиксированное подключение к внутренним источникам сигнала.
EXTI16 подключена к выходу PVD (программируемый датчик напряжения питания).
EXTI17 подключена к RTC Alarm event ("будильник" в часах реального времени RTC).

Отображение линий портов ввода/вывода на линии контроллера EXTI Рис. 2

Итак, для обработки прерываний или событий от EXTI, необходимо:

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

Прерывание/событие будет сгенерировано не только в ответ на сигнал на внешнем выводе микроконтроллера, но и в случае программного запуска с помощью регистра EXTI_SWIER (для этого нужно записать 1 в бит регистра, соответствующей линии, в которой будет сгенерировано прерывание/событие; сброс бита происходит путём сброса соответствующего бита в регистре EXTI_PR, который, в свою очередь, сбрасывается записью в него 1).

Прерывания

Для первых пяти линий контроллера, EXTI0..EXTI4, выделены индивидуальные номера прерываний, и они могут обслуживаться отдельными обработчиками. Следующие пять линий, EXTI5..EXTI9, имеют общий номер прерывания и обслуживаются одним обработчиком, внутри которого потребуются дополнительные действия по выявлению причины прерывания, если генерация прерываний разрешена одновременно для нескольких линий из данной группы. Ещё один вектор прерывания выделяется для группы из 6 следующих линий EXTI10..EXTI15. Ещё по одному вектору выделено для двух последних линий, получающих сигнал от PVD и от RTC соответственно.

Имя обработчика Обрабатываемое прерывание
PVD_IRQHandler Прерывание от EXTI16 (линия получает сигнал от программируемого датчика напряжения питания, PVD)
RTC_IRQHandler Прерывание от EXTI17 (на линию подаётся сигнал пробуждения от часов реального времени, RTC)
EXTI0_IRQHandler Прерывание от линии 0 EXTI
EXTI1_IRQHandler Прерывание от линии 1 EXTI
EXTI2_IRQHandler Прерывание от линии 2 EXTI
EXTI3_IRQHandler Прерывание от линии 3 EXTI
EXTI4_IRQHandler Прерывание от линии 4 EXTI
EXTI9_5_IRQHandler Прерывание от линий [9:5] EXTI
EXTI15_10_IRQHandler Прерывание от линий [15:10] EXTI

Пробуждение

Если микроконтроллер выполнил текущие задачи и далее некоторое время не потребуется выполнять какой-либо код, то с целью экономии электроэнергии, он может быть переведён в один из доступных режимов пониженного потребления. Это можно сделать с помощью инструкций wfi или wfe (WFI, Wait For Interrupt - ждать прерывания; WFE, Wait for Event - ждать события). Выход из режима пониженного энергопотребления произойдёт, соответственно, в случае возникновения прерывания (если используется инструкция wfi), в частности, в случае прерывания от контроллера EXTI, или в случае возникновения события пробуждения, wakeup event (если используется инструкция wfe). Источником событий пробуждения является настроенный соответствующим образом контроллер EXTI.

Событие пробуждения от внешнего сигнала может генерироваться двумя способами.

Регистры контроллера EXTI

Доступ к регистрам периферийного устройства EXTI осуществляется как к словам (32 бита).


EXTI_IMR (Interrupt mask register)
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16  
Reserved MR17 MR16  
rw rw  
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0  
MR15 MR14 MR13 MR12 MR11 MR10 MR9 MR8 MR7 MR6 MR5 MR4 MR3 MR2 MR1 MR0  
rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw  

Address offset: 0x00
Reset value: 0x0000 0000

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

MRx: Interrupt Mask on line x, x=0..17
Бит, разрешающей генерацию прерываний от соответствующей линии EXTI:
0: не формируются запросы на прерывание от соответствующей линии EXTIx;
1: разрешается формировать запросы на прерывание от соответствующей линии EXTIx.


EXTI_EMR (Event mask register)
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16  
Reserved MR17 MR16  
rw rw  
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0  
MR15 MR14 MR13 MR12 MR11 MR10 MR9 MR8 MR7 MR6 MR5 MR4 MR3 MR2 MR1 MR0  
rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw  

Address offset: 0x04
Reset value: 0x0000 0000

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

MRx: Event mask on line x, x=0..17
Бит, разрешающей генерацию событий от соответствующей линии EXTI:
0: не формируются сигналы события от соответствующей линии EXTIx;
1: разрешается формировать сигналы события от соответствующей линии EXTIx.


EXTI_RTSR (Rising trigger selection register)
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16  
Reserved TR17 TR16  
rw rw  
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0  
TR15 TR14 TR13 TR12 TR11 TR10 TR9 TR8 TR7 TR6 TR5 TR4 TR3 TR2 TR1 TR0  
rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw  

Address offset: 0x08
Reset value: 0x0000 0000

Регистр для выбора линий контроллера EXTI, запускаемых нарастающим входным сигналом.

TRx: Rising trigger event configuration bit of line x=0..17
Бит определяет, что на входной линии x контроллера EXTI требуется обнаруживать нарастающий фронт сигнала:
0: отключён запуск нарастающим фронтом (как для прерываний, так и для событий) для данной линии;
1: включён запуск нарастающим фронтом (как для прерываний, так и для событий) для данной линии.

Примечание. На внешних выводах, подключаемых к линиям контроллера EXTI, не должно быть паразитных выбросов, так как возможно ложное срабатывание схемы, чувствительной к фронту сигнала.
Если нарастающий фронт на внешней линии приходится на момент записи в регистр EXTI_RTSR, установки бита отложенного прерывания не происходит.
Можно установить одновременно для одной линии биты запуска как нарастающим фронтом внешнего сигнала, так и спадающим; тогда срабатывание детектора фронта сигнала в данной линии будет происходить в обоих случаях.


EXTI_FTSR (Falling trigger selection register)
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16  
Reserved TR17 TR16  
rw rw  
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0  
TR15 TR14 TR13 TR12 TR11 TR10 TR9 TR8 TR7 TR6 TR5 TR4 TR3 TR2 TR1 TR0  
rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw  

Address offset: 0x0C
Reset value: 0x0000 0000

Регистр для выбора линий контроллера EXTI, запускаемых спадающим входным сигналом.

TRx: Falling trigger event configuration bit of line x, x=0..17
Бит определяет, что на входной линии x контроллера EXTI требуется обнаруживать спадающий фронт сигнала:
0: отключён запуск спадающим фронтом (как для прерываний, так и для событий) для данной линии;
1: включён запуск спадающим фронтом (как для прерываний, так и для событий) для данной линии.

Примечание. На внешних выводах, подключаемых к линиям контроллера EXTI, не должно быть паразитных выбросов, так как возможно ложное срабатывание схемы, чувствительной к фронту сигнала.
Если спадающий фронт на внешней линии приходится на момент записи в регистр EXTI_FTSR, установки бита отложенного прерывания не происходит.
Можно установить одновременно для одной линии биты запуска как нарастающим фронтом внешнего сигнала, так и спадающим; тогда срабатывание детектора фронта сигнала в данной линии будет происходить в обоих случаях.


EXTI_SWIER (Software interrupt event register)
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16  
Reserved SWIER
17
SWIER
16
 
rw rw  
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0  
SWIER
15
SWIER
14
SWIER
13
SWIER
12
SWIER
11
SWIER
10
SWIER
9
SWIER
8
SWIER
7
SWIER
6
SWIER
5
SWIER
4
SWIER
3
SWIER
2
SWIER
1
SWIER
0
 
rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw  

Address offset: 0x10
Reset value: 0x0000 0000

Регистр для программной генерации прерываний и событий контроллера EXTI.

SWIERx: Software interrupt on line x, x=0..17
Запись 1 в этот бит, когда он содержит 0, приводит к установке соответствующего отложенного бита в регистре EXTI_PR (если разрешено регистром маски EXTI_IMR). Если прерывания для данной линии разрешены, генерируется запрос на прерывание.
Бит сбрасывается при сбросе соответствующего бита в регистре EXTI_PR, который, в свою очередь, сбрасывается записью 1 в этот бит.


EXTI_PR (Pending register)
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16  
Reserved PR17 PR16  
rc_w1 rc_w1  
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0  
PR15 PR14 PR13 PR12 PR11 PR10 PR9 PR8 PR7 PR6 PR5 PR4 PR3 PR2 PR1 PR0  
rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1 rc_w1  

Address offset: 0x14
Reset value: undefined

Регистр отложенных прерываний

PRx: Pending bit
Бит отложенного прерывания:
0: не генерировалось запросов на прерывание;
1: произошла генерация запроса на прерывание.
Этот бит устанавливается при обнаружении отслеживаемого фронта входного сигнала на внешней линии. Бит сбрасывается путём записи 1 в этот бит.



Регистры AFIO_EXTICRx

Эти регистры не входят в состав периферийного устройства EXTI, но они очень важны для работы с внешними прерываниями, поэтому их описание приводится здесь.

Регистры настройки внешних прерываний AFIO_EXTICR1, AFIO_EXTICR2, AFIO_EXTICR3, AFIO_EXTICR4:
AFIO_EXTICR1 (Address offset: 0x08, Reset value: 0x0000);
AFIO_EXTICR2 (Address offset: 0x0C, Reset value: 0x0000);
AFIO_EXTICR3 (Address offset: 0x10, Reset value: 0x0000);
AFIO_EXTICR4 (Address offset: 0x14, Reset value: 0x0000).

В CMSIS доступ к данным регистрам осуществляется как к элементам массива:

AFIO->EXTICR[n];

где n=0..3. Это даёт возможность модифицировать требуемое битовое поле с помощью одного C/C++ выражения. Допустим, если мы хотим поставить в соответствие линии внешнего прерывания x (EXTIx) внешний вывод микроконтроллера PY[x], где Y определяет порт ввода-вывода (обозначается буквами A, B, C, ..., которым соответствуют в данном случае индексы 0, 1, 2, ...), а x определяет разряд в пределах порта, x=0..15 (например, PC10; в связи с особенностями реализации контроллера внешних прерываний, требуется, чтобы номер отображаемого разряда порта совпадал с номером линии внешнего прерывания, на которую происходит отображение, т.е. вывод PC10 обязательно должен отображаться на линию EXTI10). Тогда можно использовать следующий код:

    const unsigned int Y=2; // 0 - A, 1 - B, 2 - C, ...
    const unsigned int X=10;
    // (Сбрасываем битовое поле по маске и устанавливаем новое значение,
    // равное порядковому номеру порта, A - 0, B - 1, ...)
    AFIO->EXTICR[X/4]=AFIO->EXTICR[X/4]&~(0xF<<X%4*4)|
        (Y<<X%4*4);
    // или
    // AFIO->EXTICR[X>>2]=AFIO->EXTICR[X>>2]&~(0xF<<((X&3)<<2))|(Y<<((X&3)<<2));
AFIO_EXTICR1 (External interrupt configuration register 1)
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16  
Reserved  
 
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0  
EXTI3[3:0] EXTI2[3:0] EXTI1[3:0] EXTI0[3:0]  
rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw  

AFIO_EXTICR2 (External interrupt configuration register 2)
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16  
Reserved  
 
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0  
EXTI7[3:0] EXTI6[3:0] EXTI5[3:0] EXTI4[3:0]  
rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw  

AFIO_EXTICR3 (External interrupt configuration register 3)
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16  
Reserved  
 
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0  
EXTI11[3:0] EXTI10[3:0] EXTI9[3:0] EXTI8[3:0]  
rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw  

AFIO_EXTICR4 (External interrupt configuration register 4)
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16  
Reserved  
 
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0  
EXTI15[3:0] EXTI14[3:0] EXTI13[3:0] EXTI12[3:0]  
rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw  

EXTIx[3:0]: EXTI x configuration,
где
x=0..3 для регистра AFIO_EXTICR1;
x=4..7 для регистра AFIO_EXTICR2;
x=8..11 для регистра AFIO_EXTICR3;
x=12..15 для регистра AFIO_EXTICR4.
Биты (битовые поля) модифицируются программно и используются для выбора источника сигнала для линии внешнего прерывания EXTIx, x=0..15. В зависимости от значения битового поля, используется вход одного из портов ввода/вывода микроконтроллера (GPIO):
0000: PA[x] вывод микроконтроллера;
0001: PB[x] вывод микроконтроллера;
0010: PC[x] вывод микроконтроллера;
0011: PD[x] вывод микроконтроллера;
0100: PE[x] вывод микроконтроллера;
0101: PF[x] вывод микроконтроллера;
0110: PG[x] вывод микроконтроллера.
Как можно заметить, в то время как порт для любой линии внешнего прерывания мы можем выбирать произвольно, номер разряда в пределах порта всегда фиксированный и равен номеру используемой линии внешнего прерывания x.

Программа: пример использования внешних прерываний

Рассмотрим простой пример использования внешних прерываний. Будем использовать оценочную плату STM32VLDISCOVERY с микроконтроллером STM32F100RBT6B или плату с аналогичной конфигурацией. Напишем программу, которая при последовательных нажатиях на кнопку будет включать/выключать один из светодиодов, установленных на плате.

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

Однако, возможны ситуации, когда использование внешних прерываний для обработки нажатий на кнопки оказывается полезным или даже неизбежным. Например, если после выполнения своей задачи, микроконтроллер должен переходить в режим сна для экономии электроэнергии. Естественно, во время сна, сканирование клавиш невозможно. Зато за счёт внешнего прерывания, возникающего в ответ на нажатие кнопки, микроконтроллер может выйти из сна и выполнить требуемые действия. Устранение дребезга при этом возможно различными способами. Можно это сделать аппаратно, в простейшем случае - с помощью RC-цепи (растянутый фронт импульсов допустим, так как на входах микроконтроллера установлены триггеры Шмитта) или программно, например, используя гибридный метод обработки нажатий, когда пробуждение происходит по внешнему прерыванию, после чего производится переход в режим сканирования.

На плате STM32VLDISCOVERY кнопка подключена к микроконтроллеру как показано на схеме (рис. 3). При отпущенной кнопке на выводе PA0 формируется уровень лог. 0, при нажатии на кнопку на вывод подаётся уровень лог. 1. Дребезг контактов кнопки устраняется с помощью RC-цепи.

Схема подключения кнопки USER BUTTON к микроконтроллеру в оценочной плате STM32VLDISCOVERY Рис. 3

Далее приведён исходный код программы. Программа крайне проста, в ней выполняется следующие действия.

Скачать исходный код

/**
  *  IMPORTANT NOTE!
  *  Для запуска и отладки кода в RAM, при построении проекта, требуется
  *  определить символ препроцессора VECT_TAB_SRAM, если используются
  *  прерывания. Иначе будет использоваться таблица прерываний,
  *  расположенная во Flash-памяти.
  *  Смотрите файл <system_*.c>, функция SystemInit() обновляет
  *  регистр SCB->VTOR.
  *  Для использования таблицы прерываний в RAM должно быть, например,
  *  SCB->VTOR = 0x20000000;
  */

/**
 * Программа для демонстрации работы с внешними прерываниями.
 * Последовательные нажатия на кнопку USER button приводят к включению/
 * отключению светодиода BLUE LED.
 *
 * Предполагается использование оценочной платы STM32VLDISCOVERY
 * или аналогичной конфигурации:
 *
 * кнопка подключается к PA0, при замыкании формирует лог. 1
 * на входе микроконтроллера, имеется аппаратная защита от дребезга
 * контактов в виде RC-цепи;
 *
 * используемый светодиод подключается к PC8 и зажигается уровнем
 * лог. 1 на выходе микроконтроллера.
 */

// PA0 - USER button;
// PC8 - blue led;
// PC9 - green led.

#include "stm32f10x.h"

// Переключение подключённого к PC8 светодиода (из выключенного
// состояния во включённое и наоборот).
void toggle_blue_led()
{
    GPIOC->ODR^=1<<8;
}

// Обработчик внешнего прерывания от линии EXTI0.
extern "C" void EXTI0_IRQHandler()
{
    // Сбрасываем нулевой бит регистра EXTI->PR записывая в бит 1.
    EXTI->PR=1;

    // Выполняем прочие действия, в данном случае, управляем светодиодом.
    toggle_blue_led();
}



int main(void)
{
    // Настраиваем NVIC - контроллер вложенных векторных прерываний:
    // разрешаем обработку используемых внешних прерываний и задаём
    // уровень приоритета.
    NVIC_SetPriority(EXTI0_IRQn, 0); // делаем прерывание высокоприоритетным.
    NVIC_EnableIRQ(EXTI0_IRQn);

    // Включаем тактовые сигналы используемых периферийных устройств:
    // AFIO (для доступа к регистрам AFIO->EXTICR[]),
    // GPIOA, GPIOC.
    // EXTI не требует включения тактового сигнала.
    RCC->APB2ENR|=
        RCC_APB2ENR_AFIOEN|
        RCC_APB2ENR_IOPAEN|
        RCC_APB2ENR_IOPCEN;

    // Выполняем конфигурирование портов ввода-вывода.
    // 1. PA0: float in; (CNF[1:0], MODE[1:0])=0100 (bin)=0x4
    GPIOA->CRL=GPIOA->CRL&~0xF|0x4;
    // 2. PC8: push-pull out, 2MHz max; (CNF, MODE)=0010 (bin)=0x2
    GPIOC->CRH=GPIOC->CRH&~0xF|0x2;

    // Выполняем назначение внешнего вывода PY[x] внешней
    // линии x контроллера внешних прерываний EXTI;
    // в нашем случае Y=A (индекс 0), x=0, т.е. можем использовать
    // значения регистров AFIO->EXTICR[y] после сброса по умолчанию
    // или выполнить код:
    // AFIO->EXTICR[0]=AFIO->EXTICR[0]&~AFIO_EXTICR1_EXTI0|AFIO_EXTICR1_EXTI0_PA;

    // Разрешаем генерацию прерываний для линии EXTI0, для остальных - запрещаем.
    EXTI->IMR=1;
    // EXTI->IMR|=1; // если не хотим изменять прочие биты.

    // Настраиваем линию 0 на обнаружение нарастающего фронта.
    EXTI->RTSR=1;
    // EXTI->RTSR|=1; // если не хотим изменять прочие биты.

    // Теперь последовательные нажатия на кнопку USER button будут
    // приводить к включению/отключению светодиода BLUE LED.

    int i = 0;
    /* Infinite loop */
    while (1)
    {
        i++;
    }
}
author: hamper; date: 2017-02-15
  @Mail.ru