PROGCONT.RU

Форма входа







Регистрпция Вход/

STM32F INTERRUPT или как настроить прерывание.

 Назначение прерываний уйти от выполнения основного кода программы что бы выполнить другую более важную часть кода по определенному событию. Прерывания могут происходить как от внешних источников( появление или спад сигнала на выводе) так и от собственной периферии контроллера например переполнения таймера.
 За контроль и выполнение прерываний отвечает специальной модуль под название NVIC( вложенный векторный контроллер прерываний), он должен после возникновение включенного прерывания перейти по нужному адресу к нашей функции обработчик, адрес которой хранится в таблице векторов данного прерывания, туда его вписывает компилятор. Еще в обязанности NVIC входит контроль важности всех включенных прерываний например при возникновений одновременно двух прерываний ядро контроллера уйдет на выполнение обработчика прерывания с более высоким приоритетом и еще каждый приоритет может содержать под приоритет зависит от выбранной группы.
 Перед подробным изучением нужно разобраться где находятся три нужных нам файла для работы с NVIC для примера буду использовать контроллер STM32F105RB и программную среду IAR.
Файлы:
misc.h-виды груп и функции для настройки, работы с NVIC;

нет рисунка

 startup_stm32f10x_cl.s-обработчики прерываний, название зависит от контроллера этот для STM32F105RB;

нет рисунка

 stm32f10x.h-тут перечислены все прерывания которые можно использовать, тоже зависит от контроллера.

нет рисунка


Описание функций NVIC в SPL.

NVIC_PriorityGroupConfig( NVIC_PriorityGroup)-выбор группы для установки и порядка выполнения приоритета прерываний, для этого контроллера возможно пять вариантов для NVIC_PriorityGroup которые находятся в файле misc.h в виде таблицы.

нет рисунка

 Группами выбирают сколько будет основных приоритетов и их под приоритетов, если у одновременно срабатываемых прерываний совпадают приоритеты ядро выберет для выполнения то прерывание у которого выше под приоритет. Если установить NVIC_PriorityGroup_0 то для всех прерываний будет только самый высокий приоритет но 0-15 под приоритетов, для NVIC_PriorityGroup_4 все наоборот 0-15 приоритетов а вот под приоритет только 0 самый высокий.

NVIC_PriorityGroup:
NVIC_PriorityGroup_0
NVIC_PriorityGroup_1
NVIC_PriorityGroup_2
NVIC_PriorityGroup_3
NVIC_PriorityGroup_4


 Внимание! Самый высокий приоритет равен значению 0 самый низкий 15, по умолчанию у всех прерываний самый высокий.


NVIC_InitTypeDef Nvic_str-Nvic_str произвольное имя вашей структуры которая будет создана для настройки NVIC.
Nvic_str.NVIC_IRQChannel-настраиваемое прерывание выбранное из файла stm32f10x.h.
Nvic_str.NVIC_IRQChannelPreemptionPriority-назначает приоритет от 0 до 15 в зависимости установленной группы.
Nvic_str.NVIC_IRQChannelSubPriority-назначает под приоритет от 0 до 15 в зависимости установленной группы.
Nvic_str.NVIC_IRQChannelCmd-тут два параметра ENABLE включает прерывание, DISABLE отключает.


NVIC_Init( NVIC_InitStruct)-функция принимает выше описанную структуру настроек и применяет ее для нужного прерывания.

NVIC_SetVectorTable( NVIC_VectTab, Offset)-функция применяется если была перемещена таблица векторов из начального положения в другу часть памяти( SRAM), функцией будет установлено смещение в памяти указывающее на новое положение таблицы.
Где:
NVIC_VectTab-выбор области памяти:
NVIC_VectTab_RAM-SRAM адрес 0x20000000 плюс Offset указывает на новый адрес.
NVIC_VectTab_FLASH-FLASH память адрес 0x08000000 Offset равен нулю, туда устанавливается таблица векторов после прошивки контроллера.
Offset-32 битовое значение для смещения.

NVIC_SystemLPConfig( LowPowerMode, NewState)-с помощью функции настраивает работа контроллера в состоянии пониженного энергопотребления где LowPowerMode может быть:
NVIC_LP_SLEEPDEEP-если NewState DISABLE то контроллер после команд __WFI() и __WFЕ() уйдет в сон где будет отключено тактирование ядра( программа не будет выполнятся) но периферия будет работать. NewState ENABLE контроллер уйде в глубокий сон, отключаются HSI и HSE генераторы, ядро и периферия тоже отключены.
NVIC_LP_SEVONPEND-NewState ENABLE контроллер выйдет из сна если будет установлен флаг( interrupt pending bits) от срабатывания любого прерывания которое может быть даже не настроено, NewState DISABLE отключает данный выход из сна.
NVIC_LP_SLEEPONEXIT-NewState DISABLE контроллер сможет войти в сон с помощью команд __WFI() и __WFЕ(), если NewState ENABLE то в сон будет входить дополнительно после выхода из обработчика любого прерывания.


 Внимание! В самом начале программы используйте функцию RCC_DeInit() которая возвращает тактирование контроллера в начальное состояние, если этого не сделать возможно тактирование будет настроено одновременно от HSI и HSE что приведет не корректной работе программы.


Pending bit или interrupt flags.

 Многие опрометчиво думают что pending bit и interrupt flags это одно и тоже но это совсем не так. Самая большая разница в том что pending bit это собственность NVIC модуля а interrupt flags периферии где используется прерывание. Pending bit указывает ядру на какой общей линии произошло прерывание и с помощью его отслеживает отработку обработчика где он должен быть сброшен. Если произойдут несколько прерываний именно по pending bit ядро будет знать сколько прерываний надо обработать, обрабатывать будет в соответствии очереди которая будет зависеть от приоритетов.
 Все функции NVIC по работе с Pending bit возможны только с внешними прерываниями EXTI потому что у них отсутствуют interrupt flags событие прерывания идет напрямую в NVIC, у других прерываний работа с pending bit не предусмотрено а сброс его осуществляется параллельно сбросом interrupt flags.
 Если интересно смотрите как происходит сброс pending bit в прерывании, первый вариант как должно быть второй без сброса interrupt flags происходит зависание программы.

нет рисунка


Внешние прерывания EXTI.

 Внизу два рисунка, первый показывает как устроены внешние прерывания и что у них отсутствуют флаги прерываний, на втором показано что каждая линия прерывания соответствует выводу порта например GPIOC Pin0 будет линия 0( EXTI_Line0), GPIOC Pin1 линия 1( EXTI_Line1) и так далее.

нет рисунка

 Функции SPL для EXTI( внешние прерывания).

EXTI_DeInit()-функция сбрасывает все настройки EXTI и Pending bit у всех прерываний.

EXTI_InitTypeDef ext_intr-ext_intr ваше название структуры для инициализации и включения линии прерывания.
Где ext_intr принимает следующие параметры:
ext_intr.EXTI_Line-выбираем линию прерываний для настройки которые могут быть EXTI_Line0 . . . . . . . . . . EXTI_Line18.
ext_intr.EXTI_Mode-тут могут быть только два варианта это EXTI_Mode_Interrupt произойдет на линии прерывание или EXTI_Mode_Event просто событие.
ext_intr.EXTI_Trigger-на что должна реагировать линия:
EXTI_Trigger_Rising-на подъем напряжения на выводе.
EXTI_Trigger_Falling-на спад напряжения на выводе.
EXTI_Trigger_Rising_Falling-на подъем и спад напряжения на выводе.
ext_intr.EXTI_LineCmd-ENABLE включает линию, DISABLE отключает.

EXTI_Init( EXTI_InitStruct)-принимает выше описанной адрес структуры для применения к EXTI.

EXTI_StructInit( EXTI_InitStruct)-принимает адрес структуры для сброса ее настроек.

EXTI_GenerateSWInterrupt( EXTI_Line)-программный вызов прерывания на линии( EXTI_Line) который произойдет после выполнения этой функции.

EXTI_GetFlagStatus( EXTI_Line)-проверяет состояние прерывания( Pending bit) на линии( EXTI_Line), если было вернет true иначе false.

EXTI_ClearFlag( EXTI_Line) и EXTI_ClearITPendingBit( EXTI_Line)-это две одинаковые функции которые сбрасывают Pending bit указывающий что произошло прерывание которое нужно обработать.

EXTI_GetITStatus( EXTI_Line)-возвращает состояние прерывания на линии включено или выключено.


 Теперь практика ниже два примера первый для GPIOA Pin0 и второй для GPIOB Pin9, различие в том что для второго нужно использовать AFIO( альтернативная функция вывода). Программа работает следующим образом, если GPIOA Pin0 и GPIOB Pin9 подключит к земле произойдут прерывания и выполнение программы уйдет в соответствующие обработчики.

//Для GPIOA Pin0.
#include "stm32f10x.h"
int main()
{
RCC_DeInit();
//Настройка вывода как вход подтянутый к питанию.
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef PIN_interrupt;
PIN_interrupt.GPIO_Pin = GPIO_Pin_0;
PIN_interrupt.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &PIN_interrupt);

//Настройка и подключение линии прерываний.
EXTI_InitTypeDef ext_intr;
ext_intr.EXTI_Line =EXTI_Line0;
ext_intr.EXTI_Mode =EXTI_Mode_Interrupt;
ext_intr.EXTI_Trigger =EXTI_Trigger_Falling;
ext_intr.EXTI_LineCmd =ENABLE;
EXTI_Init( &ext_intr);

//Настройка группы приоритетов и сам приоритет будет самый низкий.
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4);
NVIC_InitTypeDef nvic_str;
nvic_str.NVIC_IRQChannel =EXTI0_IRQn;
nvic_str.NVIC_IRQChannelPreemptionPriority =15;
nvic_str.NVIC_IRQChannelSubPriority =0;
nvic_str.NVIC_IRQChannelCmd =ENABLE;
NVIC_Init( &nvic_str);

while(1){
//Тут ваша программа.
}
return 0;
}

void EXTI0_IRQHandler( void){
EXTI_ClearITPendingBit( EXTI_Line0);
//Ваш код для обработчика прерывания.
}
//Для GPIOB Pin9.
#include "stm32f10x.h"
int main()
{
RCC_DeInit();
//Перенаправление вывода на прерывание.
RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig( GPIO_PortSourceGPIOB, GPIO_PinSource9);

//Настройка вывода как вход подтянутый к питанию.
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef PIN_interrupt;
PIN_interrupt.GPIO_Pin = GPIO_Pin_9;
PIN_interrupt.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &PIN_interrupt);

//Настройка и подключение линии прерываний.
EXTI_InitTypeDef ext_intr;
ext_intr.EXTI_Line =EXTI_Line9;
ext_intr.EXTI_Mode =EXTI_Mode_Interrupt;
ext_intr.EXTI_Trigger =EXTI_Trigger_Falling;
ext_intr.EXTI_LineCmd =ENABLE;
EXTI_Init( &ext_intr);

//Простое включение прерывание через CMSIS.
NVIC_EnableIRQ( EXTI9_5_IRQn);

while(1){
//Тут ваша программа.
}
return 0;
}

void EXTI9_5_IRQHandler( void){
EXTI_ClearITPendingBit( EXTI_Line9);
//Ваш код для обработчика прерывания.
}



 Во втором примере используется для включения прерывания NVIC_EnableIRQ( EXTI9_5_IRQn) и обработчик EXTI9_5_IRQHandler цифры в них указывают что прерывание будет включены с 9 по 5 линии и один общий обработчик для них, для определения на каком выводе произошло прерывание используйте функции GPIO определяющие его состояние.


Прерывания от внутренних источников на примере TIM1.

 Тут настраиваем TIM1 что бы у того каждую секунду переполнялся счетчик и генерировалось прерывание.

#include "stm32f10x.h"
int main()
{
RCC_DeInit();

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
TIM_TimeBaseInitTypeDef TIM1_InitStructure;
TIM1_InitStructure.TIM_Period = 40000;
TIM1_InitStructure.TIM_Prescaler = 200-1;
TIM1_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM1_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM1_InitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit( TIM1, &TIM1_InitStructure);
TIM_ClearFlag( TIM1, TIM_FLAG_Update);
TIM_ITConfig( TIM1, TIM_IT_Update, ENABLE);
NVIC_EnableIRQ( TIM1_UP_IRQn);
TIM_Cmd( TIM1, ENABLE);

while(1){
//Тут ваша программа.
}
return 0;
}
void TIM1_UP_IRQHandler( void){
TIM_ClearFlag( TIM1, TIM_FLAG_Update);
//Ваш код для обработчика прерывания.
}

Комментариев нет  Только зарегистрированные пользователи могут оставлять комментарии!