цифровая электроника
вычислительная техника
встраиваемые системы

 

Микроконтроллеры семейства PIC32. Работа с таймерами.

Автор: Mike(admin) от 29-08-2013, 13:08

В этой статье пойдет речь о таймерах – очень важном элементе в любой микроконтроллерной системе. С помощью них можно реализовать отсчет времени, организовывать прерывания, формировать сигналы с широтно-импульсной модуляцией и т.д.


Таймеры


В PIC32 имеется два типа таймеров – таймеры A (по сути, он один – TMR1) и таймеры B (TMR2, TMR3, TMR4, TMR5). Все они 16-разрядные, могут тактироваться от внешнего или внутреннего источника и вызывать прерывания. Но таймер A может работать в качестве асинхронного таймера/счетчика, тактируемого от отдельного осциллятора, функционировать в спящем режиме микроконтроллера и иметь предделитель со значениями 1:1, 1:8, 1:64, 1:256. Таймеры B могут формировать в паре один 32-разрядный таймер, иметь предделитель со значениями 1:1, 1:2, 1:4, 1:8, 1:16, 1:32, 1:64, 1:256, влиять на срабатывание триггера события.


Итак, для начала рассмотрим работу TMR1. Сконфигурируем его с помощью функции OpenTimer1 из библиотеки plib следующим образом:



OpenTimer1(T1_OFF | T1_SOURCE_INT | T1_PS_1_256, 0xFFFF);

Что это значит? T1_SOURCE_INT означает, что в качестве источника (SOURCE) тактирования выступает внутренний (INT) источник, для внешнего было бы T1_SOURCE_EXT. T1_PS_1_256 – предделитель взят с коэффициентом 1:256, то есть регистр данных таймера будет увеличиваться на единицу при каждом 256-ом «приходе» сигнала от тактового генератора. T1_OFF свидетельствует о том, что таймер на данный момент отключен, если хотим его включить в работу сразу, то указываем T1_ON. 0xFFFF означает, что выбран максимально возможный потолок, до которого досчитает таймер, обнулит свой регистр TMR1 и начнет отсчет заново.


Вообще, библиотека plib предоставляет более наглядную работу со служебными регистрами микроконтроллера. То же самое без нее выглядело бы так:



T1CON = 0x0070;
PR1 = 0xFFFF;

Отдельные биты регистра конфигурации пришлось бы смотреть в даташите или помнить наизусть. Хотя обычная запись в регистры в определенных случаях может смотреться куда лаконичнее и удобнее. Впрочем, стилистика написания программы не главный элемент в процессе творения, главное, чтобы работало!


Таймеры являются источником для генерации прерываний, но мы не будем пока использовать прерывание от таймера (про прерывания поговорим отдельно), поэтому с помощью функции ConfigIntTimer1(T1_INT_OFF) его можно отключить, если оно было включено. Если же хочется прерываться по таймеру, то можно сделать так:



ConfigIntTimer1(T1_INT_ON|Tx_INT_PRIOR_5|Tx_INT_SUB_PRIOR_1);

Так мы разрешили прерывания при равенстве данных регистра TMR1 значению, записанному в PR1 (сейчас оно 0xFFFF), установили приоритет (5) и субприоритет (1) прерывания.


С помощью функции WriteTimer1() можно записать в регистр TMR1 определенное значение, например, можно обнулить его WriteTimer1(0). По сути, это эквивалент команды TMR1=0;.


Функция ReadTimer1() считывает данные из этого регистра.


Давайте по нажатию одной из кнопок из этого примера будем запускать таймер TMR1:



if (PORTG & 0x40)
{
WriteTimer1(0); // или можно просто TMR1=0;
T1CONSET = 0x8000; //15-й бит регистра конфигурации запускает таймер, аналог функции OpenTimer1(T1_ON)
}

По второй кнопке будем его останавливать



if (PORTG & 0x80)
{
WriteTimer1(0);//TMR1=0;
T1CONCLR = 0x8000; // аналог функции OpenTimer1(T1_OFF)
}

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



tmrcount1=ReadTimer1(); // tmrcount1=TMR1;
if (tmrcount1>0x1FFF) PORTDSET=0x0040; else PORTDCLR=0x0040;

В итоге светодиод будет мигать с определенной постоянной частотой, которая в первую очередь будет зависеть от частоты тактового генератора.


В некоторых задачах 16-разрядного таймера с максимально допустимым предделителем 1:256 может не хватать для реализации большего периода счета. Тогда на помощь приходят пары таймеров группы B (TMR2 и TMR3, TMR4 и TMR5) . Пара из двух 16-битных таймеров образует один 32-битный. Естественно период такого таймера увеличивается с 0xFFFF до 0xFFFFFFFF, а это уже существенная разница. Управляющим или основным таймером в паре является младший – TMR2 или TMR4. Сконфигурируем один такой супер-таймер:



OpenTimer23(T2_OFF | T2_SOURCE_INT | T2_PS_1_256 | T2_32BIT_MODE_ON, 0x1FFFF);

Поскольку основным таймером является TMR2, то обращаемся только к нему. T2_32BIT_MODE_ON активирует 32-разрядный режим, а период теперь можно увеличить, поставим 0x1FFFF.


Теперь по нажатию третьей кнопки будем активировать таймер:



if (PORTG & 0x0100)
{
WriteTimer23(0);
T2CONSET = 0x8000;
}

Вторую кнопку дополним строками деактивации этого таймера, то есть:



if (PORTG & 0x80)
{
WriteTimer1(0); //TMR1=0;
WriteTimer23(0);
T1CONCLR = 0x8000;
T2CONCLR = 0x8000;
}

Индикацию работы супер-таймера повесим на второй диод:



tmrcount2=ReadTimer23();
if (tmrcount2>0xFFFF) PORTDSET=0x0080; else PORTDCLR=0x0080;

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


В рассказе о таймерах PIC32 также стоит упомянуть о возможности активации таймера A по внешнему сигналу (режим Gatedmode). То есть при подаче логической единицы на ножку TxCK (в нашем случае T1CK) TMR1 начнет отсчет, а при снятии сигнала немедленно прекратит. Активируется этот режим установкой 7-го бита в регистре T1CON или директивой T5_GATE_ON в функции OpenTimer1.


Попрактикуемся с этим режимом. Пусть по первой кнопке таймер начинает работать в нормальном режиме, а при нажатии четвертой он начнет отсчет только при наличии сигнала на контакте T1CK:



if (PORTG & 0x0200)
{
WriteTimer1(0);
T1CONCLR = 0x8000;
T1CONSET = 0x0080;
T1CONSET = 0x8000;
}

Также немного изменим обработчик первой кнопки:



if (PORTG & 0x40)
{
WriteTimer1(0);
T1CONCLR = 0x8000;
T1CONCLR = 0x0080;
T1CONSET = 0x8000;
}

Всё! Теперь после нажатия четвертой кнопки второй светодиод начнет свое бодрое мигание.


Вот весь код:



#include <p32xxxx.h>
#include <plib.h>

// настраиваем частоту
#pragma config FNOSC=XTPLL
#pragma config FPLLIDIV=DIV_2, FPLLMUL=MUL_20, FPLLODIV=DIV_1
#pragma config FWDTEN=OFF // отключаем сторожевой таймер

//основная функция
main ()
{

unsigned int tmrcount1=0;
unsigned long tmrcount2=0;

//настройка кэша
mCheConfigure(CHE_CONF_WS2 | CHE_CONF_PF_ALL | CHE_CONF_COH_INVUNL | CHE_CONF_DC_NONE);

CheKseg0CacheOn();
mBMXDisableDRMWaitState();


//Настройка портов

TRISD=0x0000;
PORTD=0x0000;

TRISG=0x03C0;
PORTG=0x0000;

//настройка таймеров
OpenTimer1(T1_OFF | T1_SOURCE_INT | T1_PS_1_256, 0xFFFF);
ConfigIntTimer1(T1_INT_OFF);

OpenTimer23(T2_OFF | T2_SOURCE_INT | T2_PS_1_256 | T2_32BIT_MODE_ON, 0x1FFFF);
ConfigIntTimer23(T23_INT_OFF);

//------------------------------------------------
//бесконечный цикл
do
{

if (PORTG & 0x40)
{
WriteTimer1(0);//очистка регистра счета TMR1=0;
T1CONCLR = 0x8000; //выключаем TMR1
T1CONCLR = 0x0080; // убираем Gated mode
T1CONSET = 0x8000; //включаем TMR1
}

if (PORTG & 0x80)
{
WriteTimer1(0);
WriteTimer23(0); //очистка регистра счета TMR2+ TMR3
T1CONCLR = 0x8000; //включаем TMR1
T2CONCLR = 0x8000; //включаем TMR2+ TMR3
}

tmrcount1=ReadTimer1(); //считываем значение TMR1
// если TMR1 насчитал больше 0x1FFF, то включаем СД1, иначе отключаем его
if (tmrcount1>0x1FFF) PORTDSET=0x0040; else PORTDCLR=0x0040;

if (PORTG & 0x0100)
{
WriteTimer23(0);
T2CONSET = 0x8000;
}

tmrcount2=ReadTimer23();//считываем значение TMR2+ TMR3
// если TMR2+ TMR3 насчитал больше 0xFFFF, то включаем СД2, иначе отключаем его
if (tmrcount2>0xFFFF) PORTDSET=0x0080; else PORTDCLR=0x0080;

if (PORTG & 0x0200)
{
WriteTimer1(0);
T1CONCLR = 0x8000;
T1CONSET = 0x0080;
T1CONSET = 0x8000;
}

}
while(1); // закрытие бесконечного цикла

} // закрытие функции main


© digitrode.ru


Теги: PIC32, таймеры



   Благодарим Вас за интерес к информационному проекту digitrode.ru.
   Если Вы хотите, чтобы интересные и полезные материалы выходили чаще, и было меньше рекламы,
   Вы можее поддержать наш проект, пожертвовав любую сумму на его развитие.


Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Комментарии:

Оставить комментарий