Здравствуй, уважаемый хабрапользователь.
В предыдущей статье мы начали рассматривать программирование под MSP430.
Материал, описанный в данной статье, позволит в общих чертах ознакомиться с прерываниями и понять некоторые тонкости MSP430.
Введение
Прерывание (англ. interrupt) — сигнал, сообщающий процессору о наступлении какого-либо события. При этом выполнение текущей последовательности команд приостанавливается и управление передаётся обработчику прерывания, который реагирует на событие и обслуживает его, после чего возвращает управление в прерванный код.
Механизм прерываний создан для обеспечения максимально оперативной реакции программы на определенные события. Это очень важная часть знакомства с любым микроконтроллером.
Прерывания
Начнём с небольшого примера.
#include "msp430f2274.h"
void main()
{
WDTCTL = WDTPW + WDTHOLD;
P1DIR &= ~BIT2;
P1REN |= BIT2;
P1IE |= BIT2; // Разрешение прерываний на P1.2
P1IES |= BIT2; // Прерывание происходит по 1/0 (отпусканию/нажатию)
P1IFG &= ~BIT2; // Очистка флага прерываний для P1.2
P1DIR |= BIT0 + BIT1;
P1OUT |= BIT0;
P1OUT &= ~BIT1;
__bis_SR_register(GIE); // Установка флага глобального разрешения прерываний
while(true);
}
#pragma vector=PORT1_VECTOR
__interrupt void P1INT() // Обработчик прерывания
{
P1IE &= ~BIT2; // Запрет прерываний на P1.2
P1OUT ^= BIT0; // P1.0 меняет своё состояние
P1OUT ^= BIT1; // P1.1 меняет своё состояние
for(volatile unsigned int i = 30000; i != 0; i--); // Задержка
P1IE |= BIT2; // Разрешение прерываний на P1.2
P1IFG &= ~BIT2; // Очистка флага прерываний для P1.2
}
В данном примере по нажатию на кнопку (P1.2) происходит прерывание, которое меняет состояние двух светодиодов (P1.0 и P1.1). Давайте разберёмся как же это происходит.PxIE разрешает прерывания для пинов порта Px. Значение «1», записанное в определенный разряд позволяет получать прерывания от определенного пина.PxIES определяет по какому уровню сигнала будет происходить прерывание. В нашем случае это означает, что единица, помещенная в конкретный разряд данного регистра, позволит получать событие нажатия кнопки. И наоборот, ноль позволит получать событие отпускания кнопки.Напомню, что кнопка в данном примере «подтянута» до единицы, это означает что нажатая кнопка имеет значение ноль.
На схеме подключения резистор R1 нарисован показательно, на самом деле он находится внутри микроконтроллера и включается регистром P1REN.PxIFG и есть флаг прерывания. В случае возникновения события нажатия кнопки он будет установлен в единицу, что и вызовет обработчик прерывания (__interrupt void P1INT()). Соответственно, сразу после обработки события флаг необходимо сбросить.Попробуйте убрать из примера строчку 32 в конце обработчика, и тогда, сразу после первого нажатия кнопки, лампочки будут переключаться так, как будто вы постоянно нажимаете на кнопку.__bis_SR_register(GIE) устанавливает флаг глобального разрешения прерываний (Global Interrupt Enable) в status register. Фактически это эквивалентно записи SR |= GIE, но мы можем обращаться к регистру SR только по средствам функций __bis_SR_register и __get_SR_register.
Ниже приведена схема битов в SR регистре.0, 1, 2 и 8 биты — это биты математических операций.4, 5, 6, 7 — биты управления уровнями энергопотребления, за счёт уменьшения частоты или отключения АЛУ.
Ну и собственно бит 3 — это глобальное разрешение прерываний. Пока этот бит не установлен в единицу, никакие прерывания обрабатываться не будут.#pragma vector — директива, которая определяет что нижеследующая функция является обработчиком указанного прерывания.Список всех доступных векторов прерываний можно посмотреть в заголовочном файле для Вашего контроллера. В данном случае это msp430f2274.h.
Дребезг контактов
Про это явление можно подробно прочитать в википедии. Дребезг контактов возникает при нажатии кнопки, благодаря чему обработчик прерываний будет вызван многократно. В данном примере этого удалось избежать следующим образом:Сразу после вызова обработчика устанавливается запрет прерываний (строка 25);
после переключения состояний светодиодов делается задержка (строка 30);
снова устанавливается разрешение прерываний (строка 31).
Директива volatile в 30 строке кода означает, что переменная i не будет оптимизироваться при компиляции. Если её убрать, то задержки не будет.
Заключение
После прочтения предыдущей статьи, коллеги и друзья упрекнули меня в том, что я не уделяю достаточно внимания мелочам. В этот раз я постарался исправить этот недостаток и сделать материал статьи ещё более доступным. Однако это значительно увеличило объем информации.
В следующий раз я постараюсь рассмотреть передачу данных с контроллера на персональный компьютер по средствам программатора и, в зависимости от полученного объема, watchdog.
Я надеюсь, что эта статья оказалась полезна тебе, читатель.