Аппаратное обеспечение IBM PC

       

Программирование таймера на уровне портов


Таймеру соответствуют четыре порта ввода/вывода со следующими адресами:

  • 40h - канал 0;
  • 41h - канал 1;
  • 42h - канал 2;
  • 43h - управляющий регистр.
  • Приведем формат управляющего регистра:

    7 6 5 4 3 2 1 0 T-T-T-T-T-T-T-¬ ¦ ¦ ¦ ¦ ¦ LT+T+T+T+T+-+T+T- LT- LT- L=T=- L= BCD: 0 - двоичный счет; ¦ ¦ ¦ 1 - двоично-десятичный счет. ¦ ¦ ¦ ¦ ¦ L===== M: 000 - режим 0; ¦ ¦ 001 - режим 1; ¦ ¦ X10 - режим 2; ¦ ¦ X11 - режим 3; ¦ ¦ 100 - режим 4; ¦ ¦ 101 - режим 5. ¦ ¦ ¦ L========== RW: 00 - код команды CLC (запомнить CE); ¦ 01 - чтение/запись старшего байта; ¦ 10 - чтение/запись младшего байта; ¦ 11 - чтение/запись младшего, затем ¦ старшего байта. ¦ L============== SC: 00 - канал 0; 01 - канал 1; 10 - канал 2; 11 - код команды RBC (чтение состояния канала).

    Поле BCD определяет формат константы, использующейся для счета - двоичный или двоично-десятичный. В двоично-десятичном режиме константа задается в диапазоне 1-9999.

    Поле M определяет режимы работы микросхемы 8254:

  • 0 - прерывание от таймера;
  • 1 - программируемый ждущий мультивибратор;
  • 2 - программируемый генератор импульсов;
  • 3 - генератор меандра;


  • 4 - программно-запускаемый одновибратор;
  • 5 - аппаратно-запускаемый одновибратор.
  • Мы будем рассматривать только режим 3, так как именно он используется в каналах 0 и 2.

    Поле RW определяет способ загрузки констант через однобайтовый порт. Если в этом поле задано значение 00, это управляющее слово будет использоваться для фиксации текущего содержимого регистров счетчика CE в буферном регистре OL с целью чтения программой. Это код команды CLC - фиксация регистров. Код канала, для которого будет выполняться фиксация, должен быть указан в поле SC. Поля M и BCD при этом не используются.

    Поле SC определяет номер канала, для которого предназначено управляющее слово. Если в этом поле задано значение 11, будет выполняться чтение состояния канала.

    Приведем формат команды RBC чтения слова состояния канала:

    7 6 5 4 3 2 1 0 T-T-T-T-T-T-T-¬ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ LT+T+T+T+T+T+T+T- LT- ¦ ¦ ¦ ¦ ¦ L= равно 0. ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ L=== 1 - выбор канала 0. ¦ ¦ ¦ ¦ L===== 1 - выбор канала 1. ¦ ¦ ¦ L======= 1 - выбор канала 2. ¦ ¦ ¦ ¦ ¦ L========= STAT: 0 - читать состояние каналов; ¦ ¦ 1 - не читать состояние каналов. ¦ ¦ ¦ L=========== CNT: 0 - запомнить текущее содержимое CE; ¦ 1 - не запоминать содержимое CE. ¦ L============== код команды RBC - 11.


    С помощью этой команды вы можете выполнять операции чтения состояния каналов либо запоминание регистра счетчика CE каналов. Можно выполнять эти операции как для отдельных каналов, так и для всех каналов одновременно, если установить соответствующие биты (1, 2, 3) в 1.

    Формат слова состояния канала напоминает формат регистра управляющего слова, за исключением двух старших разрядов 7 и 6:

    7 6 5 4 3 2 1 0 T-T-T-T-T-T-T-¬ ¦ ¦ ¦ ¦ ¦ ¦ LT+T+T+T+T+-+T+T- ¦ ¦ LT- L=T=- L= BCD: 0 - двоичный счет; ¦ ¦ ¦ ¦ 1 - двоично-десятичный счет. ¦ ¦ ¦ ¦ ¦ ¦ ¦ L===== M: 000 - режим 0; ¦ ¦ ¦ 001 - режим 1; ¦ ¦ ¦ X10 - режим 2; ¦ ¦ ¦ X11 - режим 3; ¦ ¦ ¦ 100 - режим 4; ¦ ¦ ¦ 101 - режим 5. ¦ ¦ ¦ ¦ ¦ L========== RW: 00 - код команды CLC (запомнить CE); ¦ ¦ 01 - чтение/запись старшего байта; ¦ ¦ 10 - чтение/запись младшего байта; ¦ ¦ 11 - чтение/запись младшего, затем ¦ ¦ старшего байта. ¦ ¦ ¦ L============= FN: флаг перезагрузки констант; L=============== OUT: состояние выхода OUT.

    Разряд FN используется, в основном, в режимах 1 и 5 для определения, произошла ли загрузка константы из регистра CR в регистр счетчика CE.

    Разряд OUT позволяет определить состояние выходной линии канала OUT в момент выполнения команды RBC.

    Для программирования канала таймера необходимо выполнить следующую последовательность действий:

  • вывести в порт управляющего регистра с адресом 43h управляющее слово;


  • требуемое значение счетчика посылается в порт канала (адреса 40h...42h), причем вначале выводится младший, а затем старший байты значения счетчика.


  • Сразу после этого канал таймера начнет выполнять требуемую функцию.

    Для чтения текущего содержимого счетчика CE необходимо выполнить следующее:

  • вывести в порт управляющего регистра код команды CLC (команда запоминания содержимого регистра CE);


  • вывести в порт управляющего регистра код команды запроса на чтение/запись в регистры канала (поле RW должно содержать 11);


  • двумя последовательными командами ввода из порта нужного канала ввести младший и старший байты текущего сосотояния счетчика CE.




  • Для чего вам может понадобиться перепрограммирование каналов таймера?

    Если вам надо повысить точность измерения времени, выполняемого с помощью канала 0 таймера, вы можете увеличить частоту генерируемых этим каналом импульсов (стандартно 18,2 Гц). По окончании измерений режим работы канала необходимо восстановить для правильного функционирования системы.

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

    Приведем пример программы, отображающей слово состояния и содержимое счетчика для всех трех каналов таймера:

    #include <stdio.h> #include <conio.h>

    main() {

    unsigned i;

    printf("\n\nКанал 0" "\n-------" "\n");

    // Читаем слово состояния канала, // команда 0xe2 = 11100010B

    outp(0x43, 0xe2);

    printf("\nСлово состояния канала: %02.2X", inp(0x40));

    // Читаем текущее состояние регистра счетчика // канала. Для этого вначале выдаем команду CLC // для канала 0. Код этой команды - 0x00

    outp(0x43, 0x00);

    // Вводим младший и старший байты счетчика // и отображаем его.

    i = inp(0x40); i = (inp(0x40) << 8) + i;

    printf("\nРегистр счетчика: %04.4X",i);

    // Повторяем те же действия для 1 и 2 каналов.

    printf("\n\nКанал 1" "\n-------" "\n");

    outp(0x43, 0xe4); printf("\nСлово состояния канала: %02.2X",inp(0x41));

    outp(0x43, 0x40);

    i = inp(0x41); i = (inp(0x41) << 8) + i;

    printf("\nРегистр счетчика: %04.4X",i);

    printf("\n\nКанал 2" "\n-------");

    outp(0x43, 0xe8); printf("\nСлово состояния канала: %02.2X",inp(0x42));

    outp(0x43, 0x80);

    i = inp(0x42); i = (inp(0x42) << 8) + i;

    printf("\nРегистр счетчика: %04.4X",i);

    exit(0);

    }


    Содержание раздела