Продолжаем знакомство с LaunchPad от TI. Система прерываний и тактирование от внутреннего генератора.

В предыдущей статье, о знакомстве с LaunchPad от TI, мы рассмотрели первые шаги по его программированию. И как я обещал, в этот раз мы рассмотрим систему прерываний и способы тактирования процессора, попробуем запрограммировать контроллер так, чтобы он реагировал на внешние воздействия.
Встроенный во все MSP430 генератор с цифровым управлением — одно из важнейших, подконтрольных нам, периферийных устройств. Это лёгкий в настройке источник тактового сигнала, для него не нужно никаких внешних элементов, он полностью управляется из программы микроконтроллера. DCO управляется двумя регистрами: DCOCTL и BCSCTL1. Для выбора частоты мы используем биты RSELx регистра BCSCTL1 (таким образом мы выбираем рабочий диапазон от 0 до 15) и биты DCOx регистра DCOCTL (шаг от 0 до 7). Для того, чтобы узнать какую именно пару битов использовать, необходимо воспользоваться спецификацией на ваш контроллер.
Очень точные часы или что-то подобное на этом встроенном генераторе вы врядли сделаете, по тому, что его точность для таких вещей оставляет желать лучшего. Но в тоже время во всех встроенных генераторах есть и откалиброванные частоты. Так, например, в нашем случае это 1, 8, 12, 16 МГц. Поэтому вы можете использовать откалиброванные частоты, правильно используя предделитель. Если же в программе не указать источник тактового сигнала и его настройки, как это было в предыдущей статье, то контроллер работает по умолчанию на мегагерцовой частоте внутреннего источника тактирования.
И так для нашего примера программы возьмём три диапазона частот: (7,3); (9,3); (11,3), что примерно соответствует частотам 1МГц, 2.3МГц, 4.25МГц. Для этого нам необходимо будет создать массивы, в которые мы запишем наши диапазоны.

char bcs_vals[3] = {7,9,11};

char dco_vals[3] = {3,3,3};

Так же, в предыдущей статье, мы рассмотрели настройку порта на выход. В этот раз кроме вывода мы собираемся использовать и ввод. Поэтому необходимо правильным образом настроить порты. Для этого воспользуемся уже знакомой нам командой.

P1DIR |= 0x41; // Настраиваем нулевой и шестой бит порта Р1 на на выход

Так как, при таком способе настройки, все биты кроме нулевого и шестого остаются установленными в ноль, то соответственно они настроены на ввод. Осталось только включить подтягивающие резисторы .
Обратим внимание, что на LaunchPad имеется две кнопки, одна из них это Reset, а вторая может быть запрограммирована так, как вы захотите, и подключена она к третьему биту порта Р1 одним контактом, и к GND вторым контактом. При нажатии кнопки, P1.3 будет «садиться» на землю, поэтому необходимо включить подтягивающий резистор к плюсу питания.

P1REN |= BIT3 ; //разрешаем подтяжку

P1OUT |= BIT3; //подтяжка вывода P1.3 вверх

Так как, благодаря подтяжке вверх, нормальное состояние этого вывода, логическая 1, прерывание должно генерироваться переходом из 1 в 0.

P1IES |= BIT3; // прерывание по переходу 1->0 выбирается битом IESx = 1.

Для того, чтобы после настройки наша программа не выскочила сразу в прерывание, ведь нам не известно в каком состоянии был порт во время пуска программы и, что происходило за время конфигурации, обнулим флаг прерывания для P1.3. И затем разрешим прерывания от порта P1.3.

P1IFG &= ~BIT3; // Для предотвращения немед ленного вызова прерывания,
		            	// обнуляем его флаг для P1.3 до разрешения прерываний

P1IE |= BIT3; // Разрешаем прерывания дляP1.3

Теперь, как только мы нажмём кнопку, программа приостановится и из основного цикла перейдёт в обработчик прерывания, где мы и должны описать, какое действие должно выполниться по нажатию.
Для того, чтобы прерывание было обработано, необходимо создать в нашей программе обработчик прерываний.

/* Обработчики прерываний */

#pragma vector = PORT1_VECTOR

__interrupt void P1_ISR(void) 

Ключевое слово #pragma используется для записи специальных команд конкретного компилятора. Это означает, что в другом компиляторе данная строка будет просто проигнорирована. Напомню, что в наших статьях мы работаем с бесплатной версией CCS, скачивание которой становится доступным при покупке LaunchPad и регистрации на сайте TI. В данном случае, компилятор получает команду прикрепить последующий код к выхову прерывания по имени PORT1_VECTOR . Это имя должно точно повторять то, что прописано в заголовочном файле вашей модели микроконтроллера.
__interrupt означает начало функции обработчика прерывания. Здесь вы можете написать любое имя, в данном случае P1_ISR. Так же, в отличии от ассемблера, в Си не нужна команда возврата из прерывания.
Попробуем написать обработчик прерывания целиком и разобраться в его работе.

/* Обработчики прерываний */

#pragma vector = PORT1_VECTOR

__interrupt void P1_ISR(void) {

switch(P1IFG & BIT3) {

case BIT3:

P1IFG &= ~BIT3; // обнуляем флаг прерывания

BCSCTL1 = bcs_vals[i]; //выбираем частоту тактирования

DCOCTL = dco_vals[i]; //выбираем частоту тактирования

if (++i == 3)

i = 0;

default:

P1IFG = 0; //обнуляем все флаги прерывания порта Р1

}
}

Прерывание порта, может возникнуть от восьми отдельных выводов микроконтроллера, и обработчик прерывания должен выбрать, что делать в каждом из случаев. В этом нам поможет оператор выбора switch() . В скобках укажем флаг прерывания от третьего бита, который и будет проверяться. Если подтвердится, что прерывание пришло именно от этого бита, то будет выполнен следующий за ним участок кода, где мы меняем частоту тактирования при каждом нажатии ++i .
Ну и теперь, когда мы разобрались, как изменить частоту тактирования, настроили порты и написали обработчик прерываний, нам осталось сделать главный цикл в основном теле программы. Не будем слишком заморачиваться и просто скопируем из предыдущей статьи цикл for(;;) , в котором мы поочерёдно мигали диодами.

for(;;) {
 
volatile unsigned int i; // отключаем оптимизации для i
 
P1OUT ^= 0x41; // инвертируем значение нулевого и шестого бита порта Р1
 
i = 20000; // Присваиваем i значение 20000 (интервал задержки)
 
do i--;   // вычитаем из i = 10000 единицу до тех пор пока
 
while(i != 0); // i не станет равным нулю
} 

В итоге программа приобретает следующий вид:

#include <msp430g2553.h>

char i=0; //резервируем память char типа (один байт)

char bcs_vals[3] = {7,9,11}; //создаём массив значений для bcs

char dco_vals[3] = {3,3,3};  //создаём массив значений для dco

void delay(void);

void main(void){

	WDTCTL = WDTPW | WDTHOLD;		// останавливаем сторожевой таймер

	P1DIR |= 0x41;// настраиваем нулевой и шестой биты на выход, остальные на вход

	P1OUT = 0x01; //устанавливаем нулевой бит в единицу, зажигаем один светодиод

	P1REN |= BIT3 ; //разрешаем подтяжку

	P1OUT |= BIT3; //подтяжка вывода P1.3 вверх

	P1IFG &= ~BIT3; // Для предотвращения немед ленного вызова прерывания,
		            	// обнуляем его флаг для P1.3 до разрешения прерываний

	P1IE |= BIT3; // Разрешаем прерывания дляP1.3

	P1IES |= BIT3; // прерывание по переходу 1->0 выбирается битом IESx = 1.

	_enable_interrupt(); //разрешаем все прерывания


	for(;;) {

		volatile unsigned int j;	// отключаем оптимизации для j

		P1OUT ^= 0x41; //Инвертируем значения нулевого и шестого битов	
	
		j = 10000;					// задержка

		do j--;

		while(j != 0);
	}
	}

/* Обработчики прерываний */

#pragma vector = PORT1_VECTOR

__interrupt void P1_ISR(void) {

switch(P1IFG & BIT3) {

case BIT3:

P1IFG &= ~BIT3; // обнуляем флаг прерывания

BCSCTL1 = bcs_vals[i]; //выбираем частоту тактирования

DCOCTL = dco_vals[i]; //выбираем частоту тактирования

if (++i == 3)

i = 0;

default:

P1IFG = 0; //обнуляем все флаги прерывания порта Р1
}
}

Таким образом, при каждом нажатии кнопки, диоды будут менять частоту мерцания, как это показано на видео ниже.

Попробуйте немного изменить программу и сделать так, чтоб диоды меняли частоту мерцания только после нескольких нажатий подряд. двух, трёх и т.д. Для этого в обработчике прерываний используйте счетчик и дополнительную переменную, например К. Подобный счётчик уже есть в обработчике прерываний.

You may also like...

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>