На примере микроконтроллера К1986ВЕ92QI (MDR32F9Q2I) и отладочной платы LDM-K1986BE92QI рассмотрим применение прерываний и системного таймера, описанных в пунктах 12, 29 и 30 спецификации на МК.
В предыдущих примерах мы моргали светодиодом делая задержку пустым вращением цикла for. Это не есть хорошо, так как ресурсы процессора можно и нужно использовать для более полезных вещей.
Тут нам на помощь приходят прерывания - механизм вызова функции, которая вызывается по каким-то внешним или внутренним событиям. Таким образом, до прихода события, процессор может заниматься выполнением полезной работы, как только событие произойдет, процессор сохраняет свой контекст (значения) и выполняет функцию прерывания. По завершении выполнения функции прерывания, процессор продолжает выполнять свою полезную работу, как будто ничего его и не прерывало (ну кроме задержки на выполнения функции прерывания).
Для включения механизма прерываний нужно:
1) Вызывать функцию NVIC_EnableIRQ(), в качестве единственного параметра которой передать ей одно из предопределенных макроопределений с индексом прерывания.
2) Определить функцию предопределенного обработчика прерываний.
3) Настроить периферию МК, в приведенном ниже коде примера, это делается в функции init_SysTick() и там же выполняется пункт 1 - вызов NVIC_EnableIRQ().
Алгоритм поиска нужных наименований:
1) Вариант 1. В IDE Keil нажать Ctrl + F и в появившемся диалоговом окне поиска в поле "Find what:" вставить SysTick_IRQn, а в поле "Look in" выбрать в списке "Current Project" и нажимая кнопку "Find Next" поискать рядом подходящие прерывания и обработчики. Повторить поиск для "SysTick_Handler".
2) Вариант2. Воспользоваться таблицей ниже.
Таблица 1. Наименования для вызова всех имеющихся прерываний МК К1986ВЕ92QI (MDR32F9Q2I).
id | Макроопределение прерывания параметр NVIC_EnableIRQ() | Функция обработчика прерывания |
---|---|---|
__initial_sp | ||
Reset_Handler | ||
-14 | NonMaskableInt_IRQn | NMI_Handler |
-13 | HardFault_IRQn | HardFault_Handler |
-12 | MemoryManagement_IRQn | MemManage_Handler |
-11 | BusFault_IRQn | BusFault_Handler |
-9 (-10?) | UsageFault_IRQn | UsageFault_Handler |
-5 | SVCall_IRQn | SVC_Handler |
-4 | DebugMon_Handler | |
-2 | PendSV_IRQn | PendSV_Handler |
-1 | SysTick_IRQn | SysTick_Handler |
0 | CAN1_IRQn | CAN1_IRQHandler |
1 | CAN2_IRQn | CAN2_IRQHandler |
2 | USB_IRQn | USB_IRQHandler |
5 | DMA_IRQn | DMA_IRQHandler |
6 | UART1_IRQn | UART1_IRQHandler |
7 | UART2_IRQn | UART2_IRQHandler |
8 | SSP1_IRQn | SSP1_IRQHandler |
10 | I2C_IRQn | I2C_IRQHandler |
11 | POWER_IRQn | POWER_IRQHandler |
12 | WWDG_IRQn | WWDG_IRQHandler |
14 | Timer1_IRQn | Timer1_IRQHandler |
15 | Timer2_IRQn | Timer2_IRQHandler |
16 | Timer3_IRQn | Timer3_IRQHandler |
17 | ADC_IRQn | ADC_IRQHandler |
19 | COMPARATOR_IRQn | COMPARATOR_IRQHandler |
20 | SSP2_IRQn | SSP2_IRQHandler |
27 | BACKUP_IRQn | BACKUP_IRQHandler |
28 | EXT_INT1_IRQn | EXT_INT1_IRQHandler |
29 | EXT_INT2_IRQn | EXT_INT2_IRQHandler |
30 | EXT_INT3_IRQHandler | |
31 | EXT_INT4_IRQn | EXT_INT4_IRQHandler |
Пример программы использующей прерывание по системному таймеру для моргания светодиодом.
На практике, в программе, требуются множество различных временных отсчетов, а таймеров в МК не так много. Один из подходов это настроить таймер на достаточно маленький отсчет времени, например 1 мс, а в обработчике прерывания таймера проверять требуемые отсчеты времени использую счетчики или операцию деления по модулю.
В программе ниже я приведу оба этих метода. Следует помнить что в часе 3600 секунд, а в сутках 3600 * 24 = 86 400 секунд (или 86 400 000 миллисекунд). Максимальное значение счетчика типа unsigned int 4 294 967 295 и примерно через 49 суток непрерывной работы ПО возникнет переполнение счетчика - переход через максимальное значение и опять счет от нуля, в этот момент времени могут возникать неправильные интервалы времени. А при использовании в ПО значений счетчика, с последующим их вычитанием для получения интервала времени и более грубые ошибки.