Продолжаем знакомиться с stm32f4 discovery.
На этот раз речь пойдёт о прерываниях.
Создадим программу которая будет зажигать диоды «по кругу» т.е. при нажатии на кнопку срабатывает прерывание и зажигается следующий диод..
Как и раньше я использую eclipse + arm plugin + st-util
Первым делом инклуды:
#include <stm32f4xx.h> #include <stm32f4xx_rcc.h> // для настройки тактирования #include <stm32f4xx_gpio.h> // для работы с периферией #include <misc.h> // всё необходимое для обработки прерываний #include <stm32f4xx_syscfg.h> #include <stm32f4xx_exti.h>
Первым делом необходимо инициализировать и настроить необходимую периферию.
Функция настройки кнопки:
void ButtonInit() {
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // разрешаем тактирование порта A
GPIO_InitTypeDef gpio_b; /// структура для инициализации кнопки
GPIO_StructInit(&gpio_b); // заполняем структуру стандартными параметрами
gpio_b.GPIO_Mode = GPIO_Mode_IN; // это кнопка - порт работает как вход
GPIO_Init(GPIOA, &gpio_b); // инициализируем порт А
}
Как вы наверное догадались из комментариев к коду, сначала мы разрешаем тактирование порта А, после чего заполняем настроечную структуру стандартными данными, а изменяем только параметр mode.
Глобальная константа для обозначения всех диодов:
const uint16_t LEDS = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
Глобальный массив с диодами:
const uint16_t LED[] = {GPIO_Pin_12, GPIO_Pin_13, GPIO_Pin_14, GPIO_Pin_15};
Инициализируем порт D для работы с диодами:
void leds_init() {
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); // разрешаем тактирование
GPIO_InitTypeDef gpio; // структура
GPIO_StructInit(&gpio);
gpio.GPIO_OType = GPIO_OType_PP; // подтяжка резисторами
gpio.GPIO_Mode = GPIO_Mode_OUT; // работаем как выход
gpio.GPIO_Pin = LEDS; // все пины диодов
GPIO_Init(GPIOD, &gpio);
}
А теперь время пришло для самых вкусностей.
Настроим прерывание по нажатии кнопки.
Вот функция настройки:
void it_init() {
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
EXTI_InitTypeDef exti; // структура для настроки
exti.EXTI_Line = EXTI_Line0; /// кнопка на линии 0
exti.EXTI_Mode = EXTI_Mode_Interrupt; // прерывание (а не событие)
exti.EXTI_Trigger = EXTI_Trigger_Rising; // срабатываем по переднему фронту импульса
exti.EXTI_LineCmd = ENABLE; /// вкл
EXTI_Init(&exti);
NVIC_InitTypeDef nvic;
nvic.NVIC_IRQChannel = EXTI0_IRQn; // указываем канал IRQ
nvic.NVIC_IRQChannelPreemptionPriority = 2; // приоритет канала ( 0 (самый приоритетный) - 15)
nvic.NVIC_IRQChannelSubPriority = 2; // приоритет подгруппы
nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic);
}
Поясню.
Сначала мы выбираем A порт как линию прерывания EXTI. Затем при помощи известной структуры настраиваем его. После чего переходим к настройке NVIC.
Глобальная переменная — флаг горящего диода:
u16 flag = 0;
Обработчик прерывания:
void EXTI0_IRQHandler(void){
/* нужно проверять состояние линии прерывания */
if (EXTI_GetITStatus(EXTI_Line0) != RESET){
flag += 1; // увеличиваем флаг - следующий диод
if (flag >= 4) flag = 0; // у нас 4 диода. Обнуляем
EXTI_ClearITPendingBit(EXTI_Line0); // сбрасываем флаг прерывания
}
}
!!! Обращаем внимание на выделенные жирным участки кода.
Функция main:
int main(){
ButtonInit();
it_init();
leds_init();
do {
GPIO_Write(GPIOD, LED[flag]); // зажигаем диод по флагу. по сути флаг - номер диода (от 0 до 3)
} while(1);
}
Теперь при нажатии кнопки будет включатся следующий диод. Изначально горит зелёный.
Против дребезга контактов я ничего не применял, так что кнопка иногда может срабатывать не совсем правильно.
!!! Обратите внимание. После прошивки такого проекта вам придётся держать reset для соединения с st-util
Скачать проект.






