LaunchPad от TI. Реализация ШИМ на таймере Timer_A

После того, как мы поморгали светодиодами, разобрались с тактированием и источниками прерываний, пришло время освоить таймер контроллера MSP430G2553.
Таймер – это счетный механизм, привязанный к импульсам сигнала тактового генератора. Таймер Timer_A , является 16-ти битным таймером. Это означает, что он считает от нуля до двоичного 0b1111111111111111, или шестнадцатеричного 0xFFFF, или десятеричного 65535. Таймер является периферийным устройством и так же имеет собственные прерывания.
Таймер Timer_A имеет три режима работы.

непрерывный счет

Режим непрерывного счёта, в нём таймер просто считает от 0 до 0xFFFF, потом начинает с начала, и так до бесконечности.

режим прямого счета

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

реверсивный счет

Режим реверсивного счёта, похож на режим прямого счёта тем, что в нём вы можете выбрать максимальное значение таймера. Отличие его в том, что достигнув максимума, таймер начинает считать вниз, потом, достигнув 0, опять вверх и т.д.
На графиках есть обозначение TACCR0 – это регистр захвата сравнения. Их может быть два (TACCR0 и TACCR1), может быть три (TACCR0, TACCR1 и TACCR2) в зависимости от модели. В этот регистр можно записывать так называемые ключевые точки, по достижению которых таймер будет вызывать прерывание.

Ниже подробно описаны регистры Таймера А
TACTL – Timer_A Control Register, Регистр управления Таймера А. Используется для связи таймера с тактовыми сигналами и выбора режимов работы.
TASSELx, биты 8 и 9, указывают таймеру, какой из тактовых сигналов использовать.
IDx, биты 6 и 7, указывают, какой делитель частоты тактового сигнала использовать, 2, 4 или 8. Делится частота, полученная уже после применения делителя в самом генераторе тактового сигнала.
MCx, биты 4 и 5, указывают на режим работы таймера. Если они равны 0 (стоит по умолчанию) таймер полностью остановлен.
TACLR, бит 2. Если в него вписать 1, это приведет к сбросу таймера. Микроконтроллер автоматически вписывает в этот бит 0, после перезапуска таймера.
TAIE и TAIFG, биты 0 и 1, соответственно. Контролируют прерывание таймера, об этом чуть ниже.
TAR – Timer_A Register, Регистр счётчика Таймера А, в нём содержится текущее значение таймера.
TACCRx – Timer_A Capture/Compare Registers, Регистры захвата/сравнения Таймера А. Их может быть два (TACCR0 и TACCR1), может быть три (TACCR0, TACCR1 и TACCR2) в зависимости от модели микроконтроллера. В режиме сравнения, мы вписываем в них значения, по достижении которых, таймер должен подать нам сигнал. TACCR0 зачастую используется для указания верхней границы счёта. В режиме захвата, процессор записывает в них текущее значение TAR, по сигналу на входе.
TACCTLx – Timer_A Capture/Compare Control Registers, Регистр управления блоком захвата/сравнения Таймера А. От его значения, зависят режимы работы регистров захвата/сравнения.
CMx, биты 14 и 15, определяют тип сигнала, по которому происходит захват. (По нарастающему, спадающему, обоим фронтам. – Прим. пер.)
CCISx, биты 12 и 13, выбирают, откуда берется сигнал захвата.
SCS и SCCI, биты 11 и 10 соответственно, синхронизация сигнала захвата с тактовым сигналом таймера. Обычно, таймер работает независимо, асинхронно, от внешних сигналов. (Я сам до конца не разобрался в этой функции, напишу подробней в следующих уроках)
CAP, бит 8, выбор режима работы, 1 – режим захвата, 0 – режим сравнения.
OUTMODx, биты 5-7, выбор режима работы модуля вывода, т.е. тип реакции на событие захвата или сравнения.
CCIE и CCIFG, биты 4 и 0 соответственно, обработка прерываний по захвату/сравнению.
CCI и OUT, биты 3 и 2 соответственно, вход и выход захвата/сравнения.
COV, бит 1, переполнение захвата. Устанавливается в 1, если произошел второй захват, а первый еще не был считан. Должен сбрасываться программно.
TAIV – Taimer_A Interrupt Vector Register, регистр вектора прерывания Таймера А. Так как прерывание таймера, может быть вызвано по нескольким разным причинам, содержимое этого регистра, указывает на причину вызова прерывания.
TAIVx, биты 1-3, содержат тип случившегося прерывания, что позволяет нам, совершить разные действия для обработки разных причин прерываний.

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

TACCR0 = 62499; // период 62,500 циклов 

TACCTL0 = CCIE; // Разрешаем прерывание таймера  по  достижению значения CCR0. 


TACTL = TASSEL_2 + ID_3 + MC_1 + TACLR;  //Настройка режима работы Timer_A:

// TASSEL_2 - источник так тов SMCLK (SubMainCLocK),

// по умолчанию настроенны х на работу от DCO

// ID_3 - делитель частоты на 8, от 1MHz это будет 125kHz

// MC_1 - режим прямого счёта (до TACCR0)

// TACLR - начальное обнуление таймера

Но давайте немного усложним задачу и сделаем плавное зажигание и затухание светодиода. Для этого нам необходимо применить ШИМ. Принцип ШИМ заключается в подаче напряжения импульсами с фиксированной частотой и переменным коэффициентом заполнения. ШИМ характеризуется таким параметром как коэффициент заполнения — это величина обратная скважности и равна отношению длительности импульса к его периоду.

Чтобы было понятнее, на рисунке ниже приведены сигналы ШИМ для коэффициента заполнения: а – 25%; б – 50 %; в – 75 %; г – 100 %.

ШИМ

t0– время импульса;
T – период;
Изменяя t0, можно получать различные средние значения напряжения на нагрузке, таким образом, изменяя яркость свечения светодиода.
Период широтно-импульсной модуляции должен быть постоянным и больше чем время импульса. Поэтому запишем TACCR0 = 600; // период 600 циклов . Это число я подобрал экспериментальным путём, чтобы работу таймера было видно невооруженным глазом.
Так как светодиод должен медленно начать светиться, то начальное время импульса должно быть очень маленьким например TACCR1 = 10; // время импульса 10 циклов . TACCR1 – это второй регистр захвата\сравнения Таймера А. Итак, получается, что при достижении значения TACCR0 = 600 таймер будет генерировать прерывание, в котором мы будем устанавливать выход микроконтроллера в единицу, что будет началом импульса. При это таймер обнуляется и начинает считать заново с нуля пока не дойдёт до TACCR1 = 10, тогда будет сгенерировано прерывание по второму регистру захвата\сравнения, в котором мы установим выход микроконтроллера в ноль. Таким образом длительность импульса t0 будет длиться 5 тактов.
Для того, чтобы светодиод увеличивал интенсивность свечения, необходимо увеличивать время импульса. Для этого после каждого прерывания от TACCR0 будем прибавлять к текущему значению TACCR1 какое-то значение. При этом максимально значения, которое может иметь TACCR1 будет равно периоду, то есть 600. В зависимости о значения, которое мы будем прибавлять, будет зависеть плавность и скорость изменения интенсивности свечения.

TACCR0 = 600; // Период

TACCR1 = 5;  //Время импульса

TACCTL0 = CCIE; // Разрешаем прерывание таймера по достижению CCR0.

TACCTL1 = CCIE; // Разрешаем прерывание таймера по достижению CCR1.

TACTL = TASSEL_2 + ID_3 + MC_1 + TACLR; //Настройка режима работы Timer_A

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

#pragma vector = TIMER0_A0_VECTOR 

__interrupt void CCR0_ISR(void) //вектор прерывания для TACCR0, Таймера А
{
P1OUT |= BIT0; // устанавливаем нулевой бит в еденицу

if (TACCR1>=(TACCR0-5)) // если TACCR1 больше TACCR0, то уменьшаем TACCR1
{
indeX=1;
}
if (TACCR1<=5) // если TACCR1 меньше минимального значения, то увеличиваем TACCR1
{
indeX=2;
}
if (indeX == 1)
{
--TACCR1;  // уменьшаем TACCR1 на 1
}
if ((indeX == 2) || (indeX == 0) )
{
++TACCR1; // увеличиваем TACCR1 на 1
}
}

Прерывание для TACCR1 будет выглядеть следующим образом.

#pragma vector=TIMER0_A1_VECTOR  

__interrupt void CCR1_ISR(void) //вектор прерывания для TACCR1, Таймера А
{
P1OUT &= ~BIT0;  // устанавливаем нулевой бит порта Р1 в ноль.

TAIV &= ~TA0IV_TACCR1; //сбрасываем флаг прерывания.
}

Обратите внимание, что в первом случае, в обработчике прерывания от TACCR0 я не сбрасывал флаг прерывания, а для TACCR1 сделал это. Все потому, что флаг прерывания для TACCR0 сбрасывается автоматически при вызове такого прерывания, а для TACCR1 его нужно сбрасывать вручную.

Теперь можно составить полный текст программы.

#include <msp430g2553.h>

/* Глобальные переменные */

unsigned int indeX = 0;

/* Объявление функций */

void main(void) {

WDTCTL = WDTPW + WDTHOLD; // отключаем сторожевой таймер

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

P1OUT = 0x01; // устанавливаем нулевой бит порта Р1 в единицу

BCSCTL1 = CALBC1_1MHZ; // Устанавливаем частоту DCO

DCOCTL = CALDCO_1MHZ;

TACCR0 = 600; // Период

TACCR1 = 10; // Время импульса

TACCTL0 = CCIE; // Разрешаем прерывание таймера по достижению CCR0

TACCTL1 = CCIE; // Разрешаем прерывание таймера по достижению CCR1

TACTL = TASSEL_2 + ID_3 + MC_1 + TACLR; //Настройка режима работы Timer_A:

// TASSEL_2 - источник так тов SMCLK (SubMainCLocK),
// по умолчанию настроенны х на работу от DCO
// ID_3 - делитель частоты на 8, от 1MHz это будет 125kHz
// MC_1 - режим прямого счёта (до TACCR0)
// TACLR - начальное обнуление таймера

_enable_interrupt(); // разрешаем все прерывания
}
#pragma vector = TIMER0_A0_VECTOR 

__interrupt void CCR0_ISR(void) //вектор прерывания для TACCR0, Таймера А
{
P1OUT |= BIT0; // устанавливаем нулевой бит в еденицу

if (TACCR1>=(TACCR0-5)) // если TACCR1 больше TACCR0, то уменьшаем TACCR1
{
indeX=1;
}
if (TACCR1<=5) // если TACCR1 меньше минимального значения, то увеличиваем TACCR1
{
indeX=2;
}
if (indeX == 1)
{
--TACCR1;  // уменьшаем TACCR1 на 1
}
if ((indeX == 2) || (indeX == 0) )
{
++TACCR1; // увеличиваем TACCR1 на 1
}
}
#pragma vector=TIMER0_A1_VECTOR  

__interrupt void CCR1_ISR(void) //вектор прерывания для TACCR1, Таймера А
{
P1OUT &= ~BIT0;  // устанавливаем нулевой бит порта Р1 в ноль.

TAIV &= ~TA0IV_TACCR1; //сбрасываем флаг прерывания.
}

Итак, прошиваем контроллер, запускаем программку и видим, что красный светодиод медленно зажигается и гаснет, зажигается и гаснет.
Данную программку очень удобно применить на практике. Допустим вам необходимо менять яркость свечения диодного светильника или скорость вращения двигателя постоянного тока, все эти вещи прекрасно реализуются с помощью ШИМ, управлять которой можно с помощью таймера, имеющегося в контроллере MSP430G2553. На нашем сайте обязательно появится цикл статей по управлению двигателем постоянного тока с помощью ШИМ, где мы и применим данные навыки на практике.

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>