6.4 Программирование таймера
Микроконтроллер ADuC812 имеет три программируемых 16-битных
таймера/счетчика: Таймер 0, Таймер 1, Таймер 2. Каждый таймер состоит из
двух 8-битных регистров THX и TLX. Все три таймера могут быть настроены
на работу в режимах “таймер” или "счетчик". Организация и принцип работы
Таймера 0 и 1 рассмотрена в подразделе 2.2.6.1.
Чтобы настроить таймер на определенную частоту (работа по
прерыванию) в МК ADuC812 стенда SDK-1.1, необходимо выполнить
следующую последовательность действий:
• Выбрать один из 4-х режимов работы таймера (регистр TMOD);
• Настроить таймер на заданную частоту (инициализировать регистры
THx, TLx);
• Включить таймер (регистр TCON);
252
• Написать обработчик прерывания от таймера и установить вектор
прерывания в пользовательской таблице прерываний (внешняя память
данных начиная с адреса 2003h);
• Разрешить прерывания от выранного таймера (регистр IE);
• Разрешить все прерывания (регистр IE).
В приведенном примере программы реализована анимация на
светодиодных индикаторах. Исходные коды драйвера ПЛИС смотрите в
разделе 6.2.
unsigned long __systime = 0;
///////////////////////////////////////////////////////////////////////////
// Инициализация Таймера 0 (1000Гц)
///////////////////////////////////////////////////////////////////////////
void InitSystimer0( void )
{
TCON = 0x00;
// Выключение таймера 0 (и таймера 1)
TMOD = 0x01;
// Выбор режима работы 16-разрядный таймер
TH0 = 0xFC;
// Инициализация таймера 0:
TL0 = 0x67;
// настройка на частоту работы 1000 Гц (чуть больше)
TCON = 0x10;
// Включение таймера 0
}
///////////////////////////////////////////////////////////////////////////
// Чтение милисекундного счетчика
///////////////////////////////////////////////////////////////////////////
unsigned long GetMsCounter( void )
{
unsigned long res;
ET0 = 0;
res = __systime;
ET0 = 1;
return res;
}
///////////////////////////////////////////////////////////////////////////
// Возвращает прошедшее время (от момента замера)
///////////////////////////////////////////////////////////////////////////
unsigned long DTimeMs( unsigned long t2 )
{
unsigned long t1 = ( unsigned long )GetMsCounter();
return t1 - t2;
}
///////////////////////////////////////////////////////////////////////////
// Задержка в милисекундах
///////////////////////////////////////////////////////////////////////////
void DelayMs( unsigned long ms )
{
unsigned long t1 = ( unsigned long )GetMsCounter();
while ( 1 )
{
if ( DTimeMs( t1 ) > ms ) break;
}
}
253
//////////////////////// T0_ISR //////////////////////////////
// Обработчик прерывания от таймера 0.
//////////////////////////////////////////////////////////////
void T0_ISR( void ) __interrupt ( 1 )
{
// Время в милисекундах
__systime++;
TH0 = 0xFC;
// Инициализация таймера 0:
TL0 = 0x67;
// настройка на частоту работы 1000 Гц (чуть больше)
}
//////////////////////// SetVector //////////////////////////
// Функция, устанавливающая вектор прерывания в пользовательской таблице
// прерываний.
// Вход: Vector - адрес обработчика прерывания,
// Address - вектор пользовательской таблицы прерываний.
// Выход: нет.
// Результат: нет.
//////////////////////////////////////////////////////////////
void SetVector(unsigned char xdata * Address, void * Vector)
{
unsigned char xdata * TmpVector; // Временная переменная
// Первым байтом по указанному адресу записывается
// код команды передачи управления ljmp, равный 02h
*Address = 0x02;
// Далее записывается адрес перехода Vector
TmpVector = (unsigned char xdata *) (Address + 1);
*TmpVector = (unsigned char) ((unsigned short)Vector >> 8);
++TmpVector;
*TmpVector = (unsigned char) Vector;
// Таким образом, по адресу Address теперь
// располагается инструкция ljmp Vector
}
void main( void )
{
unsigned char light = 1;
InitSystimer0();
// Установка вектора в пользовательской таблице
SetVector( 0x200B, (void *)T0_ISR );
// Разрешение прерываний от таймера 0
ET0 = 1; EA = 1;
while( 1 )
{
leds( light );
if( light == 0xFF ) light = 1;
else light |= light << 1;
DelayMs( 300 );
}
}
254
Do'stlaringiz bilan baham: |