Radio Life - Подключение регистра сдвига к контроллеру

Подключение регистра сдвига к контроллеру

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

Рис. 1.
Подключение регистра сдвига к контроллеру.

В табл. 1 приведена таблица истинности работы регистра в разных режимах работы. При программировании следует учесть, что в процессе установки уровней на управляющих входах /CS и W/R, уровень на входе синхросигнала CLK должен быть высоким. Состояние адресного входа C/D для режима работы регистра безразлично, поэтому в таблице не указано.

Таблица 1.
Таблица истинности для регистра DD2
Режим работы регистра /CS W/R /Z1 S0 S1 D0-D7
Сдвиг вправо H H L H L data
Запись во внешнее устройство L H L L L data
Чтение из внешнего устройства L L H H H Z-состояние

Подпрограмма для сдвига байта в регистре приведена на рис. 2. Написана она в ассемблерном варианте, т.к., естественно, скорость работы ассемблерного варианта примерно на порядок превышает скорость варианта на Си. При тактовой частоте контроллера 20 МГц скорость приема/передачи данных равна примерно 80 кбит.

#define   BYTE            unsigned char
BYTE      ShiftByte(BYTE);         // прием/выдача байта в сдвиговый регистр
...
//   ------------------------------------------------
// BYTE ShiftByte(BYTE)
// ------------------------------------------------
// Прием/передача байта в регистр сдвига
//   ------------------------------------------------
// P24 - /MCS2     - J2.28 - (O10)  - Выход последовательных данных
// P25 - /MCS3     - J2.29 - (O11)  - Выход синхроимпульсов сдвига данных
// P19 - RTS1/PCS3 - J2.25 - (IO8)  - Вход последовательных данных
// P26 - UZI       - J2.30 - (O12)  - Выход сигнала чтения/записи
// P29 - /CLKDIV2  - J2.31 - (O13)  - Выход сигнала выбора внешнего устройства
// ------------------------------------------------
// 1. выводим 8 бит данных в последовательный регистр, одновременно считывая
// из него последовательные данные
//
// 2. перед началом выходы: синхроимпульса (P25), чтения/записи (P26), выбора
// внешнего устройства (P29) должны быть установлены в высокое состояние (H).
//
BYTE
ShiftByte(BYTE d)
{
BYTE   b;

asm   mov   dx, 0xff7a   // загружаем в DX адрес порта (16-32) линий вв/выв.
   // устанавливаем высокие уровни на выходах управления
asm   in    ax, dx
   // Не забываем, что сигналы на выходах должны быть инвертированы!!!
asm   and   ax, 0xd9ff
asm   out   dx, ax
   // готовим данные для цикла чтения
asm   mov   bl, d
asm   mov   bh, 0
asm   mov   cx, 8        // цикл для приема/передачи 8 бит данных
asm cycle:
asm   in    ax, dx
asm   mov   es, ax
   // считываем бит входных данных
asm   and   ax, 0x0008   // считываем бит входных данных
asm   jz    d0
asm   clc                // устанавливаем флаг переноса если бит данных 1
asm   jmp   d1
asm d0:
asm   stc                // сбрасываем бит переноса если бит данных 0
asm d1:
asm   rcl   bh, 1        // сдвигаем перенос в регистр
asm   mov   ax, es       // востанавливаем AX
asm   or    ax, 0x0200   // установим LOW на линии CLK при подготовке бита данных
   // устанавливаем бит выходных данных
   // с учетом инвертора на выходе порта контроллера, выходной
   // бит выдается в обратной полярности к оригинальному!!!
asm   rcl   bl, 1        // сдвигаем влево со старшего разряда
asm   jc    m0
asm   or    ax, 0x0100   // если бит данных 0
asm   jmp   m1
asm m0:
asm   and   ax, 0xfef7   // если бит данных 1
asm m1:
asm   out   dx, ax
   // формируем передний фронт CLK для сдвига данных в регистре
asm   and   ax, 0xfdf7
asm   out   dx, ax
asm   loop  cycle
asm   mov   b, bh

   return b;
}

Рис. 2.
ShiftByte — подпрограмма приема/передачи последовательных данных через регистр сдвига.

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

Подпрограмма записи данных из внешнего устройства в регистр (операция чтения ReadByte) приведена на рис. 3. Нужно учитывать, что после этой операции байт записывается только в регистр, а для его считывания контроллером нужно выполнить функцию ShiftByte. По этой причине функция не возвращает значения, а передается ей только адрес регистра внешнего устройства.


void   ReadByte(char);   // чтение байта из внешнего устр. в регистр.
...
//
// ------------------------------------------------
// void ReadByte(char addr)
// addr - адрес регистра внешнего устройства (0 или 1)
// ------------------------------------------------
// чтение байта из внешнего устройства в регистр сдвига
// ------------------------------------------------
// P24 - /MCS2     - J2.28 - (O10)  - Выход последовательных данных
// P25 - /MCS3     - J2.29 - (O11)  - Выход синхроимпульсов сдвига данных
// P19 - RTS1/PCS3 - J2.25 - (IO8)  - Вход последовательных данных
// P26 - UZI       - J2.30 - (O12)  - Выход сигнала чтения/записи
// P29 - /CLKDIV2  - J2.31 - (O13)  - Выход сигнала выбора внешнего устройства
//       T7        - J2.32 - (O14)  - Выход выбора регистра внешнего устройства
// ------------------------------------------------
// 1. перед началом выходы: синхроимпульса (P25), чтения/записи (P26), выбора
// внешнего устройства (P29) должны быть установлены в высокое состояние (H).
//
// 2. параметр addr указывает на адрес опрашиваемого регистра внешнего
// устройства. В данном варианте можно опрашивать устройство, имеющее
// ТОЛЬКО ДВА РЕГИСТРА, поэтому параметр addr может быть только 0 или 1.
//
// 3. следует учесть, что считанный байт находится в регистре, и для его
// считывания контроллером следует использовать функцию ShiftByte
//
void
ReadByte(char addr)
{
   // устанавливаем адрес регистра внешнего устройства
   // не забываем о наличии инвертора на выходе контроллера!!!!
asm   mov   dx, 0x0007
asm   mov   al, addr
asm   xor   al, 0x1      // инвертируем адрес регистра
asm   out   dx, al
   // устанавливаем сигнал чтения на шине P26 (LOW), тем самым переводя
   // выходы регистра в третье состояние
asm   mov   dx, 0xff7a
asm   in    ax, dx
asm   or    ax, 0x0400
asm   out   dx, ax
   // устанавливаем сигналы выбора устройства (P29) и синхроимпульса (P25)
   // в состояние LOW, подготавливая регистр и внешнее устройство к чтению
asm   in    ax, dx
asm   or    ax, 0x2200
asm   out   dx, ax
   // формируем передний фронт синхроимпульса (P25) для записи в регистр
asm   and   ax, 0xfdff
asm   out   dx, ax
   // перед завершением функции устанавливаем высокие уровни для всех
   // управляющих сигналов
asm   in    ax, dx
   // Не забываем, что сигналы на выходах должны быть инвертированы!!!
asm   and   ax, 0xd9ff
asm   out   dx, ax
}

Рис. 3.
ReadByte — подпрограмма чтения байта из внешнего устройства в регистр сдвига.

Подпрограмма записи байта из регистра сдвига во внешнее устройство (WriteByte) приведена на рис. 4. Так же, как и при работе с ReadByte следует учесть, что перед обращением к данной функции необходимо с помощью ShiftByte "сдвинуть" записываемый байт из контроллера в регистр. По этой причине (как и при работе с ReadByte) функции передается только адрес регистра внешнего устройства.


void  WriteByte(char);   // запись байта во внешнее устр. из регистр.
...
//   ------------------------------------------------
// void WriteByte(char addr)
// addr   - адрес регистра внешнего устройства (0 или 1)
// ------------------------------------------------
// запись байта во внешнее устр. из регистра сдвига
//   ------------------------------------------------
// P24 - /MCS2     - J2.28 - (O10)  - Выход последовательных данных
// P25 - /MCS3     - J2.29 - (O11)  - Выход синхроимпульсов сдвига данных
// P19 - RTS1/PCS3 - J2.25 - (IO8)  - Вход последовательных данных
// P26 - UZI       - J2.30 - (O12)  - Выход сигнала чтения/записи
// P29 - /CLKDIV2  - J2.31 - (O13)  - Выход сигнала выбора внешнего устройства
//       T7        - J2.32 - (O14)  - Выход выбора регистра внешнего устройства
// ------------------------------------------------
// 1. перед началом выходы: синхроимпульса (P25), чтения/записи (P26), выбора
// внешнего устройства (P29) должны быть установлены в высокое состояние (H).
//
// 2. параметр addr указывает на адрес опрашиваемого регистра внешнего
// устройства. В данном варианте можно опрашивать устройство, имеющее
// ТОЛЬКО ДВА РЕГИСТРА, поэтому параметр addr может быть только 0 или 1.
//
// 3. следует учесть, что записываемый байт должен находиться в регистре, и для его
// занесения в регистр следует использовать функцию ShiftByte
//
void
WriteByte(char addr)
{
   // устанавливаем адрес регистра внешнего устройства
   // не забываем о наличии инвертора на выходе контроллера!!!!
asm   mov   dx, 0x0007
asm   mov   al, addr
asm   xor   al, 0x1         // инвертируем адрес регистра
asm   out   dx, al
   // устанавливаем сигнал записи на шине P26 (HIGH)
asm   mov   dx, 0xff7a
asm   in    ax, dx
asm   out   dx, ax
   // устанавливаем сигналы выбора устройства (P29) и синхроимпульса (P25)
   // в состояние LOW, подготавливая регистр и внешнее устройство к записи
asm   in    ax, dx
asm   or    ax, 0x2200
asm   out   dx, ax
   // формируем передний фронт синхроимпульса (P25) для чтения из регистра
asm   and   ax, 0xfdff
asm   out   dx, ax
   // перед завершением функции устанавливаем высокие уровни для всех
   // управляющих сигналов
asm   in    ax, dx
   // Не забываем, что сигналы на выходах должны быть инвертированы!!!
asm   and   ax, 0xd9ff
asm   out   dx, ax
}

Рис. 4.
WriteByte — подпрограмма записи байта из регистра сдвига во внешнее устройство.

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

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