Pull to refresh

MSP430, учимся программировать и отлаживать железо (часть 2)

Reading time 4 min
Views 48K

Здравствуй, уважаемый хабрапользователь.
В предыдущей статье мы начали рассматривать программирование под MSP430.
Материал, описанный в данной статье, позволит в общих чертах ознакомиться с прерываниями и понять некоторые тонкости MSP430.


Введение


Прерывание (англ. interrupt) — сигнал, сообщающий процессору о наступлении какого-либо события. При этом выполнение текущей последовательности команд приостанавливается и управление передаётся обработчику прерывания, который реагирует на событие и обслуживает его, после чего возвращает управление в прерванный код.
Механизм прерываний создан для обеспечения максимально оперативной реакции программы на определенные события. Это очень важная часть знакомства с любым микроконтроллером.

Прерывания


Начнём с небольшого примера.
  1. #include "msp430f2274.h"
  2.  
  3. void main()
  4. {
  5.   WDTCTL = WDTPW + WDTHOLD;
  6.  
  7.   P1DIR &= ~BIT2;
  8.   P1REN |= BIT2;
  9.  
  10.   P1IE |= BIT2; // Разрешение прерываний на P1.2
  11.   P1IES |= BIT2; // Прерывание происходит по 1/0 (отпусканию/нажатию)
  12.   P1IFG &= ~BIT2; // Очистка флага прерываний для P1.2
  13.  
  14.   P1DIR |= BIT0 + BIT1;
  15.   P1OUT |= BIT0;
  16.   P1OUT &= ~BIT1;
  17.   __bis_SR_register(GIE); // Установка флага глобального разрешения прерываний
  18.  
  19.   while(true);
  20. }
  21.  
  22. #pragma vector=PORT1_VECTOR
  23. __interrupt void P1INT() // Обработчик прерывания
  24. {
  25.   P1IE &= ~BIT2; // Запрет прерываний на P1.2
  26.  
  27.   P1OUT ^= BIT0; // P1.0 меняет своё состояние
  28.   P1OUT ^= BIT1; // P1.1 меняет своё состояние
  29.  
  30.   for(volatile unsigned int i = 30000; i != 0; i--); // Задержка
  31.   P1IE |= BIT2; // Разрешение прерываний на P1.2
  32.   P1IFG &= ~BIT2; // Очистка флага прерываний для P1.2
  33. }
  34.  

В данном примере по нажатию на кнопку (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.

Дребезг контактов


Про это явление можно подробно прочитать в википедии. Дребезг контактов возникает при нажатии кнопки, благодаря чему обработчик прерываний будет вызван многократно. В данном примере этого удалось избежать следующим образом:
  1. Сразу после вызова обработчика устанавливается запрет прерываний (строка 25);
  2. после переключения состояний светодиодов делается задержка (строка 30);
  3. снова устанавливается разрешение прерываний (строка 31).

Директива volatile в 30 строке кода означает, что переменная i не будет оптимизироваться при компиляции. Если её убрать, то задержки не будет.

Заключение


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

Я надеюсь, что эта статья оказалась полезна тебе, читатель.
Tags:
Hubs:
+21
Comments 32
Comments Comments 32

Articles