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

 



Микроконтроллеры семейства 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, таймеры




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

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

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