Stm32 прерывания по кнопке

Урок 74

Вот наконец-то и настало время нам попробовать поработать с внешними прерываниям. Данный урок, во-первых, был очень востребован, хотя он и кажется на первый взгляд несложным. Очень много было просьб и я не мог не откликнуться. Во-вторых, мы сейчас работаем с модулем LAN ENC28J60, у которго имеется выход, по которому мы можем получить прерывания по окончании определённых операций, которые я и хотел обработать. Также, если у меня получится, я хотел этим поделиться и с вами, но без первоначального представления о внешних прерываниях в контроллере STM32, это понять, я считаю, будет, мягко говоря, нелегко. Вот поэтому и созрел данный урок.

В качестве микроконтроллера мы возьмём тот же самый STM32F103RCT6, расположенный на недорогой плате, с которой мы и занимаемся в процессе программирования модуля LAN, а в качестве программатора также недорогой маленький ST-Link V2.

Кратко о внешних прерываниях. Внешние прерывания — это такие прерывания, которые обрабатываются вследствие возникновения некоторых событий на определённой ножке порта микроконтроллера. Таких событий может быть несколько не смотря на всего 2 логических состояния. Разнообразие данных событий легко увидеть, раскрыв их список в Cube MX в настройке ножек портов

Можно разделить данные типы на 2 группы пополам. первая группа — External Interrupt — это обработка внешних прерываний. А второй — обработка событий. Разница здесь лишь в том, что в первом случае вызывается обработчик прерываний, а во втором только поднимается соответствующий флаг. Каждая группа уже делится на три вида событий:

1. Обнаружен восходящий фронт (изменение уровня 0 на 1),

2. Обнаружен нисходящий фронт (изменение уровня 1 на 0),

3. Обнаружен любой из вышеперечисленных фронтов.

Также ещё есть программные типы прерываний, но нам с вами они точно не понадобятся.

Вот и всё по типам прерываний.

Существует несколько регистров для обработки внешних прерываний:

EXTI_IMR: Регистр масок прерываний,

EXTI_EMR: Регистр масок событий,

EXTI_RTSR: Регистр срабатывания по восходящему фронту,

EXTI_FTSR:Регистр срабатывания по нисходящему фронту,

EXTI_SWIER: Регистр софтверного запуска прерывания,

EXTI_PR: регистр флагов событий, по которым происходят вызовы прерываний.

Подробно все эти регистры расписаны в технической документации Reference Manual ко всем контроллерам STM. Мы их подробно рассматривать не будем, оставим это на совести библиотеки HAL.

Вот логическая схема обработчика прерываний в контроллере

Здесь мы видим наши все регистры и какая между ними логическая связь.

Также можно посмотреть схему организации линии внешних прерываний

Здесь мы видим 16 линий, подключенных через мультиплексоры к одноимённым пинам всех портов. То есть одновременно мы можем обработать 16 ножек контроллера, но, как видно из мультиплексивной организации, что все они должны быть с разными номерами. То есть мы можем обработать одновременно ножки PA1 и PC2, но не можем обработать PA1 и PC1.

Также существуют ещё 4 линии, которые подключены не к портам общего назначения, а к определённым видам периферии

The four other EXTI lines are connected as follows:

• EXTI line 16 is connected to the PVD output

• EXTI line 17 is connected to the RTC Alarm event

• EXTI line 18 is connected to the USB Wakeup event

• EXTI line 19 is connected to the Ethernet Wakeup event (available only in connectivity line devices)

То есть мы можем ещё обработать внешние события от программируемого детектора напряжений, от будильника RTC, от "пробуждений" USB и Ethernet.

Вот сколько всего по прерываниям, и это ещё не всё. На данную тему в технической документации написано целых 18 страниц, так что кому интересно — обязательно почитайте.

Наша задача — грамотно эти прерывания обработать в нашем коде, используя функции библиотеки HAL.

Создадим в генераторе проектов Cube MX новый проект, выбрав наш контроллер

Включим кварцевый резонатор

Выберем программатор по интерфейсу SWD

Задействуем ножку, отвечающую за светодиод

Включим внешние прерывания на ножке PA1

Настроим делители и умножители на максимальную производительность в разделе "Clock Configuration" (нажмите на картинку для увеличения изображения)

Перейдём в "Configuration" и в разделе GPIO настроим ножку PC13 на среднюю скорость

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

Применим настройки портов и перейдём в настройки глобальных прерываний по кнопке "NVIC", включим там прерывания EXTI1

Также применим данные настройки.

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

Настроим проект, присвоив имя EXTI01 и выбрав среду разработки SW4STM32

Сгенерируем проект, откроем его в System Workbench, как всегда и удалим в настройках отладчика файл отладки.

Соберём проект, попытаемся его запустить, но скорей всего у нас ничего не получится и мы увидим в консоли вот такое сообщение, что прошить контроллер не удалось из-за того, что его не удалось перезагрузить

Конечно, можно вовремя держать и отпускать на плате кнопку RESEТ. Но мы пойдём другим путём. Я почитал некоторое количество форумов и ничего там не нашёл, за исключением правки конфигурационных файлов. Откроем наш файл отладки в свойствах проекта

В открывшемся диалоге зайдём в закладку "Debugger" и нажмём там кнопку "Show generator options"

В открывшемся внизу поле "Reset mode" выберем пункт "Software System reset"

Сохраним настройки, теперь должно всё прошиться.

Откроем main.c и отключим наш светодиод в функции main(), так как мы знаем, что он подключен инверсно (можно конечно это сделать и в Cube MX, но так нагляднее)

/* USER CODE BEGIN 2 */

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);

/* USER CODE END 2 */

Далее в main.c добавим обработчик внешних прерываний

/* USER CODE BEGIN 4 */

void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin)

/* USER CODE END 4 */

Затем мы здесь отследим прерывание именно от 1 линии и зажжем светодиод

void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin)

if (GPIO_Pin== GPIO_PIN_1) <

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET );

__NOP();

/* USER CODE END 4 */

Подключим кнопку между PA1 и проводом питания (нажмите на картинку для увеличения изображения)

Соберём проект, прошьём контроллер. Затем нажмём на кнопку — светодиод должен будет засветиться (нажмите на картинку для увеличения изображения)

Давайте разнообразим немного наш проект, чтобы он не был таким скучным. Для этого зайдём в Cube MX, и, так как у нас не Keil, проект закрывать не надо, и включим внешние прерывания ещё и на ножке PA2

Причем включим мы уже другой тип — срабатывание прерывания по низходящему фронту, а резистор мы уже наоборот подтянем к источнику напряжения. Для этого внесём следующие настройки в "Configuration" в GPIO для ножки PA2

Применим настройки, сгенерируем проект, вернёмся в System Workbench и сделаем проекту Refresh.

Допишем следующим образом наш обработчик, чтобы по прерыванию на ножке PA1 наш светодиод зажигался, а в случае PA2 — потухал

void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin)

if (GPIO_Pin== GPIO_PIN_1) <

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET );

> else if (GPIO_Pin== GPIO_PIN_2) <

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET );

Подключем ещё одну кнопку, но уже к PA2, причём вторым выводом уже к общему проводу (нажмите на картинку для увеличения изображения)

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

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

Всем спасибо за внимание!

Отладочную плату можно приобрести здесь STM32F103C8T6

Смотреть ВИДЕОУРОК (нажмите на картинку)

Урок 74

Вот наконец-то и настало время нам попробовать поработать с внешними прерываниям. Данный урок, во-первых, был очень востребован, хотя он и кажется на первый взгляд несложным. Очень много было просьб и я не мог не откликнуться. Во-вторых, мы сейчас работаем с модулем LAN ENC28J60, у которго имеется выход, по которому мы можем получить прерывания по окончании определённых операций, которые я и хотел обработать. Также, если у меня получится, я хотел этим поделиться и с вами, но без первоначального представления о внешних прерываниях в контроллере STM32, это понять, я считаю, будет, мягко говоря, нелегко. Вот поэтому и созрел данный урок.

В качестве микроконтроллера мы возьмём тот же самый STM32F103RCT6, расположенный на недорогой плате, с которой мы и занимаемся в процессе программирования модуля LAN, а в качестве программатора также недорогой маленький ST-Link V2.

Кратко о внешних прерываниях. Внешние прерывания — это такие прерывания, которые обрабатываются вследствие возникновения некоторых событий на определённой ножке порта микроконтроллера. Таких событий может быть несколько не смотря на всего 2 логических состояния. Разнообразие данных событий легко увидеть, раскрыв их список в Cube MX в настройке ножек портов

Можно разделить данные типы на 2 группы пополам. первая группа — External Interrupt — это обработка внешних прерываний. А второй — обработка событий. Разница здесь лишь в том, что в первом случае вызывается обработчик прерываний, а во втором только поднимается соответствующий флаг. Каждая группа уже делится на три вида событий:

1. Обнаружен восходящий фронт (изменение уровня 0 на 1),

2. Обнаружен нисходящий фронт (изменение уровня 1 на 0),

3. Обнаружен любой из вышеперечисленных фронтов.

Также ещё есть программные типы прерываний, но нам с вами они точно не понадобятся.

Вот и всё по типам прерываний.

Существует несколько регистров для обработки внешних прерываний:

EXTI_IMR: Регистр масок прерываний,

EXTI_EMR: Регистр масок событий,

EXTI_RTSR: Регистр срабатывания по восходящему фронту,

EXTI_FTSR:Регистр срабатывания по нисходящему фронту,

EXTI_SWIER: Регистр софтверного запуска прерывания,

EXTI_PR: регистр флагов событий, по которым происходят вызовы прерываний.

Подробно все эти регистры расписаны в технической документации Reference Manual ко всем контроллерам STM. Мы их подробно рассматривать не будем, оставим это на совести библиотеки HAL.

Вот логическая схема обработчика прерываний в контроллере

Здесь мы видим наши все регистры и какая между ними логическая связь.

Также можно посмотреть схему организации линии внешних прерываний

Здесь мы видим 16 линий, подключенных через мультиплексоры к одноимённым пинам всех портов. То есть одновременно мы можем обработать 16 ножек контроллера, но, как видно из мультиплексивной организации, что все они должны быть с разными номерами. То есть мы можем обработать одновременно ножки PA1 и PC2, но не можем обработать PA1 и PC1.

Также существуют ещё 4 линии, которые подключены не к портам общего назначения, а к определённым видам периферии

The four other EXTI lines are connected as follows:

• EXTI line 16 is connected to the PVD output

• EXTI line 17 is connected to the RTC Alarm event

• EXTI line 18 is connected to the USB Wakeup event

• EXTI line 19 is connected to the Ethernet Wakeup event (available only in connectivity line devices)

То есть мы можем ещё обработать внешние события от программируемого детектора напряжений, от будильника RTC, от "пробуждений" USB и Ethernet.

Вот сколько всего по прерываниям, и это ещё не всё. На данную тему в технической документации написано целых 18 страниц, так что кому интересно — обязательно почитайте.

Наша задача — грамотно эти прерывания обработать в нашем коде, используя функции библиотеки HAL.

Создадим в генераторе проектов Cube MX новый проект, выбрав наш контроллер

Включим кварцевый резонатор

Выберем программатор по интерфейсу SWD

Задействуем ножку, отвечающую за светодиод

Включим внешние прерывания на ножке PA1

Настроим делители и умножители на максимальную производительность в разделе "Clock Configuration" (нажмите на картинку для увеличения изображения)

Перейдём в "Configuration" и в разделе GPIO настроим ножку PC13 на среднюю скорость

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

Применим настройки портов и перейдём в настройки глобальных прерываний по кнопке "NVIC", включим там прерывания EXTI1

Также применим данные настройки.

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

Настроим проект, присвоив имя EXTI01 и выбрав среду разработки SW4STM32

Сгенерируем проект, откроем его в System Workbench, как всегда и удалим в настройках отладчика файл отладки.

Соберём проект, попытаемся его запустить, но скорей всего у нас ничего не получится и мы увидим в консоли вот такое сообщение, что прошить контроллер не удалось из-за того, что его не удалось перезагрузить

Конечно, можно вовремя держать и отпускать на плате кнопку RESEТ. Но мы пойдём другим путём. Я почитал некоторое количество форумов и ничего там не нашёл, за исключением правки конфигурационных файлов. Откроем наш файл отладки в свойствах проекта

В открывшемся диалоге зайдём в закладку "Debugger" и нажмём там кнопку "Show generator options"

В открывшемся внизу поле "Reset mode" выберем пункт "Software System reset"

Сохраним настройки, теперь должно всё прошиться.

Откроем main.c и отключим наш светодиод в функции main(), так как мы знаем, что он подключен инверсно (можно конечно это сделать и в Cube MX, но так нагляднее)

/* USER CODE BEGIN 2 */

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);

/* USER CODE END 2 */

Далее в main.c добавим обработчик внешних прерываний

/* USER CODE BEGIN 4 */

void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin)

/* USER CODE END 4 */

Затем мы здесь отследим прерывание именно от 1 линии и зажжем светодиод

void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin)

if (GPIO_Pin== GPIO_PIN_1) <

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET );

__NOP();

/* USER CODE END 4 */

Подключим кнопку между PA1 и проводом питания (нажмите на картинку для увеличения изображения)

Соберём проект, прошьём контроллер. Затем нажмём на кнопку — светодиод должен будет засветиться (нажмите на картинку для увеличения изображения)

Давайте разнообразим немного наш проект, чтобы он не был таким скучным. Для этого зайдём в Cube MX, и, так как у нас не Keil, проект закрывать не надо, и включим внешние прерывания ещё и на ножке PA2

Причем включим мы уже другой тип — срабатывание прерывания по низходящему фронту, а резистор мы уже наоборот подтянем к источнику напряжения. Для этого внесём следующие настройки в "Configuration" в GPIO для ножки PA2

Применим настройки, сгенерируем проект, вернёмся в System Workbench и сделаем проекту Refresh.

Допишем следующим образом наш обработчик, чтобы по прерыванию на ножке PA1 наш светодиод зажигался, а в случае PA2 — потухал

void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin)

if (GPIO_Pin== GPIO_PIN_1) <

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET );

> else if (GPIO_Pin== GPIO_PIN_2) <

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET );

Подключем ещё одну кнопку, но уже к PA2, причём вторым выводом уже к общему проводу (нажмите на картинку для увеличения изображения)

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

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

Всем спасибо за внимание!

Отладочную плату можно приобрести здесь STM32F103C8T6

Смотреть ВИДЕОУРОК (нажмите на картинку)

Доброго всем дня! Продолжаем работать с отладочной платой STM32F3Discovery, и сегодня мы разберемся как настроить и использовать внешние прерывания в микроконтроллерах серии STM32F3.

Что такое вообще внешнее прерывание? Ну тут особо нечего рассказывать – это просто такое прерывание, которое возникает при изменении состояния определенного входа микроконтроллера. То есть хотим мы, например, оперативно реагировать на изменение входного сигнала на выводе PA0. Тут то нам и придут на помощь внешние прерывания. Настраиваем их соответствующим образом, и при изменении сигнала с 0 на 1 (или наоборот, в зависимости от настроек) на интересующей нас ножке контроллера программа ускачет на обработку прерывания. Как видите, все действительно довольно-таки просто, так что перейдем к практической реализации всего этого безобразия 😉

У STM32F3 имеется в наличии целых 36(!) внешних прерываний. Прерывания EXTI0..EXTI15 висят на обработке изменения уровня сигнала на обычных ножках нашего контроллера. То есть прерывание EXTI0 мы можем настроить на работу с ножками PA0, PB0, PC0, PD0, PE0 или PF0, аналогично для EXTI3 – выводы PA3, PB3, PC3, PD3, PE3 или PF3. Вот как это все выглядит:

Возникает вопрос – а остальные 20 прерываний? А вот они:

Вот, например, в статье про будильник (вот она) мы использовали EXTI line 17, для пробуждения по будильнику )

Итак, с теорией мы разобрались немножко, давайте напишем тестовую программку для работы с внешними прерываниями. А заодно, пожалуй, поэкспериментируем-ка с пользовательской кнопкой (синего цвета), установленной на плате STM32F3Discovery 😉 Пусть будет такая задачка:

  1. Опрашиваем состояние кнопки (ножка PA0).
  2. Если кнопка нажата, то выставляем вывод PE2 в 1 (высокий уровень сигнала).
  3. Замыкаем на плате ногу PE2 на вывод PE1.
  4. Настраиваем внешнее прерывание так, чтобы оно возникало при изменении сигнала на PE1 с низкого уровня на высокий.
  5. И в обработчике прерывания меняем состояние какого-нибудь светодиода из установленных на плате – пусть будет синий (PE8).

Что же мы ожидаем увидеть в результате всего этого?) Сейчас разберемся..При нажатии на кнопку сигнал на выводе PE2 меняется с 0 на 1, а, соответственно, аналогичным образом меняется сигнал и на выводе PE1, что приводит к возникновению внешнего прерывания. А в обработчике, как вы помните, мы должны менять состояние светодиода. Таким образом, при нажатиях на кнопку синий светодиод должен то зажигаться, то гаснуть. Немного запутанно, конечно, но для примера пойдет 😉

Переходим к делу..Создаем новый проект, подключаем все нужные файлы и объявляем переменные:

Пора переходить к инициализации) Для того, чтобы настроить правильную работу внешних прерываний нужно сделать следующее:

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

Теперь осталось реализовать все эти шаги в коде 😉

Почти все готово, осталось написать функцию main() и, собственно, обработчик прерывания:

В функции main() опрашиваем нашу кнопку и в зависимости от ее состояния меняем уровень сигнала на выводе PE2, который, как вы помните, у нас замкнут на ножку PE1. При нажатии кнопки должно возникать прерывание EXTI1_IRQ, в обработчике которого меняем состояние вывода PE8, на котором у нас висит светодиод =)

Компилируем, прошиваем микроконтроллер, жмем на кнопку и видим результат – на каждое нажатие кнопки синий светодиод меняет свое состояние. Соответственно, программа работает именно так, как и было первоначально задумано =)

Похожие статьи:

Понравилась статья? Поделись с друзьями!

Хорошая статья, но к сожалению не могу понять как инициализировать внешние прерывания на STM32F10x. Если можно расскажите пожалуйста как инициализируются прерывания на STM32F10x

Ну там в принципе все то же самое по сути

Да по сути то же самое, но в библиотеке отсутствуют подобные файлы “stm32f30x_syscfg.h” “stm32f30x_misc.h”. Я сам перехожу с PIC и асемблера на STM32 поэтому очень сложно дается язык С. Если вам не трудно расскажите хотя бы в крации как подключить прерывания на STM32F10x

Ну вот, что-то вроде такого должно быть:

И обработчик прерывания:

Огромное спасибо за пример. У меня почему то ругается на вот эту строчку timer.c(73): error: #167: argument of type “GPIO_TypeDef *” is incompatible with parameter of type “uint8_t” GPIO_EXTILineConfig(GPIOA, GPIO_Pin_0); аргумент несовместим с типом данных. Подскажите пожалуйста где надо глянуть чтобы исправить эту ошибку?

Это я поспешил ) Вот так надо:
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);

Спасибо большое за ответ буду дальше пробовать.

Еще вопрос а как правильно сбросит флаг прерывания? Попробовал вот так не вышло EXTI_ClearITPendingBit( EXTI0, EXTI_Line)

Что-то залил этот пример и на нажатие на кнопку не реагирует вообще…ошибок при компиляции не было.

Прошил пример, на нажатие на кнопку не реагирует…ошибок при компиляции не было…

Если бы была ошибка в проге из примера, то хотя бы компилятор тогда ругался бы…

Если бы была ошибка в проге из примера, то хотя бы компилятор тогда ругался бы…

P.S. Прошу прощения, что ниже написал комментарий…

Снова прошу прощения, ошибка была с моей стороны.
В проект не добавил startup файл…

Главное, чтобы заработало в итоге)

Заработало 🙂
Только повешал прерывание на прямую на кнопку.

А как можно сделать, чтобы например прерывание срабатывало, например, если загорелся светодиод LD12?

exti.EXTI_Line = EXTI_Line12;
exti.EXTI_Mode = EXTI_Mode_Interrupt;
exti.EXTI_Trigger = EXTI_Trigger_Rising;
exti.EXTI_LineCmd = ENABLE;
EXTI_Init(&exti);

nvic.NVIC_IRQChannel = EXTI15_10_IRQn;
nvic.NVIC_IRQChannelPreemptionPriority = 0x0F;
nvic.NVIC_IRQChannelSubPriority = 0x0F;
nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic);

И функция обработчик EXTI15_10_IRQHandler?
Почему-то так не работает…

Охохох…и снова я сильно поспешил…спутал мягкое с теплым…
Прерывание же и не будет работать на “выход” от ПИНа контроллера…

Здравствуйте. Уже долгое время я бьюсь с установкой приоритета прирываний при помощи SPL, но все четно. Вот программа:
#include “STM32F30x.h” // Device header
#include “stm32f30x_rcc.h”
#include “stm32f30x_gpio.h”
#include “stm32f30x_exti.h”
#include “stm32f30x_misc.h”
#include “stm32f30x_syscfg.h”

EXTI_InitTypeDef exti;
GPIO_InitTypeDef port;
NVIC_InitTypeDef nvic;

int i, j;
uint16_t SostKnopki;

void Inicial(void)
<
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

port.GPIO_Mode = GPIO_Mode_IN;
port.GPIO_Pin = GPIO_Pin_3;
port.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOC, &port);

port.GPIO_Mode = GPIO_Mode_OUT;
port.GPIO_Pin = GPIO_Pin_8;
port.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOE, &port);

port.GPIO_Mode = GPIO_Mode_OUT;
port.GPIO_Pin = GPIO_Pin_11;
port.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOE, &port);

port.GPIO_Mode = GPIO_Mode_IN;
port.GPIO_Pin = GPIO_Pin_1;
port.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOA, &port);

port.GPIO_Mode = GPIO_Mode_OUT;
port.GPIO_Pin = GPIO_Pin_10;
port.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOE, &port);

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource3);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource1);

exti.EXTI_Line = EXTI_Line3;
exti.EXTI_LineCmd = ENABLE;
exti.EXTI_Mode = EXTI_Mode_Interrupt;
exti.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_Init(&exti);

exti.EXTI_Line = EXTI_Line1;
exti.EXTI_LineCmd = ENABLE;
exti.EXTI_Mode = EXTI_Mode_Interrupt;
exti.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_Init(&exti);

nvic.NVIC_IRQChannel = EXTI3_IRQn;
nvic.NVIC_IRQChannelCmd = ENABLE;
nvic.NVIC_IRQChannelSubPriority = 0xF;
NVIC_Init(&nvic);

nvic.NVIC_IRQChannel = EXTI1_IRQn;
nvic.NVIC_IRQChannelCmd = ENABLE;
nvic.NVIC_IRQChannelSubPriority = 0x2;
NVIC_Init(&nvic);
>

Добрый день!
Ваш пример, аккуратно и без ошибок перенесенный,
у меня не работает. Похоже, не вызывается обработчик прерывания. В чем может быть проблема?
Пины соединил. Пробовал переносить прерывание на другие пины, не помогает.
Пробую именно на STM32F3Discovery, среда разработки CodeBlocks 13.12.
Спасибо!

При беглом просмотре Вашей программы я не увидел, где собственно меняется переменная SostKnopki, и где считывается ее состояние.

Я не претендую на истину, сам начинающий, и проблемы с прерываниями, не вызываются! У Вас получилось в итоге?

У меня нет там такой переменной вроде бы. Плата у меня – discovery, ide – Keil 4. Стартап там Кейл сам добавляет в проект при создании проекта.

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

У Вас STM32F3Discovery плата? Какую версию startup файла Вы использовали и в какой среде разработки делали проект? Мучаюсь уже месяц, прерывания не вызываются…

Спасибо! Про переменную я не Вам, видимо, мои комменты в кучу смешались.

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

Да, фронт настраивается. Можно настроить прерывание так, чтобы реагировало на любое изменение фронта, а в самом обработчике просто анализировать сигнал, чтобы понять какой именно фронт пришел.

Здравствуйте. Подскажите пожалуйста, возникла проблема при обработке внешнего прерывания
программа зависает в обработчике прерывания:
void EXTI0_IRQHandler(void)
<
/* USER CODE BEGIN EXTI0_IRQn 0 */

/* USER CODE END EXTI0_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
/* USER CODE BEGIN EXTI0_IRQn 1 */
HAL_GPIO_WritePin( GPIOD,GPIO_PIN_12, GPIO_PIN_SET);
HAL_Delay (100);
/* USER CODE END EXTI0_IRQn 1 */
>
если закоментировать HAL_Delay (100); то всё начинает работать.

Да, я только хотел написать, что причина в задержке, как увидел, что в конце сообщения это уже написано )

Связано это с тем, что функция задержки сама построена на прерывании SysTick’а, поэтому если ее вызвать из другого прерывания, возникает такая вот проблема.

Добрый день ! Хочу повесить прерывания напрямую на кнопку , делаю следующим образом :
void Button_init_Handler()<

GPIO_InitTypeDef GPIO_Button_Ini;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);

GPIO_Button_Ini.GPIO_Pin = GPIO_Pin_0;
GPIO_Button_Ini.GPIO_Mode = GPIO_Mode_IN ;
GPIO_Button_Ini.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_Button_Ini.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Button_Ini.GPIO_OType = GPIO_OType_PP;
GPIO_Init(GPIOA,&GPIO_Button_Ini);

//SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource1);
// GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
//*
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
//NVIC_EnableIRQ(EXTI0_IRQn);//enable IRQ
//*/
//*
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//так программа вылетает в сore_cm3.h , если поставить //DISABLE , все нормально , идет по программе , но не заходит //в EXTIO_IRQHandler
NVIC_Init(&NVIC_InitStructure);
// */

void EXTIO_IRQHandler()
<
EXTI_ClearFlag(EXTI_Line0);
if( BUTTON_READ_USER == 1) <
Led_Green;
>else <
Led_Green_OFF;
>
>
//*/

void led_init() <
//RCC_AHBPeriph_GPIOB
RCC_APB1PeriphClockCmd(RCC_AHBPeriph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_Init_Led_Green;

GPIO_Init_Led_Green.GPIO_Pin = GPIO_Pin_7;
GPIO_Init_Led_Green.GPIO_Mode = GPIO_Mode_OUT;//|GPIO_Mode_AF;
GPIO_Init_Led_Green.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init_Led_Green.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init_Led_Green.GPIO_OType = GPIO_OType_PP;

SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);

task_add(*IWDG_ReloadCounter);
task_add(*tmg_dm);*/
//LED_ON;
// encoder_ini();
led_init();
Button_init_Handler();

// Systick_Enc();//proba
// EXTI15_10_IRQnHandler();
while(1)
<

//*
if ( BUTTON_READ_USER == 1) <
Led_Green;
>else <
Led_Green_OFF;
>
//*/
// UpdateSats();
delay(50);

Что неправильно делаю ?

По тексту создается впечатление, что в “EXTIO_…..” это не ноль, а буква “О”… В коде тоже?

поменял на всякий случай , я думаю там в инцилизации должно быть оба ENABLE , но у меня почему то неправильно работает , если и NVIC и EXTI Enable .Проверьте мою иницилизацию пожалуйста

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

а ок , я тогда проверю с ENABLE )

Инициализация вроде бы в порядке.

спасибо как проверю . отпишу.

Добрый день! подскажите, пожалуйста, как организовать двойное нажатие (например зажечь диод). Всю голову сломал. Заранее спасибо!

Завести переменную-счетчик и инкрементировать при нажатии, когда получили два нажатия, то выполнять действие. И кроме того, после первого нажатия начинать отсчитывать время и по прошествию, к примеру, секунды обнулять счетчик (если нужно именно двойное нажатие, а не два нажатия подряд с любым интервалом).

Оцените статью
ПК Знаток
Добавить комментарий

Adblock
detector