Проектирование устройств сопряжения (1083567), страница 21
Текст из файла (страница 21)
void Cent_Control_drv (unsigned char control)
// Запись в регистр управления Centronics
{
outportb (Cent_Base+2, (control ^ 0х0В) ^ 0х0Е );
}
unsigned char Cent_Status_drv (void)
// Чтение из регистра управления Centronics
{
return ( ( inportb (Cent_Base+1) >> 3 ) ^ 0x10 );
}
Что касается регистра данных, то запись в него производится командой вида:
outportb (Cent_Base, data);
3.2.2. Программирование на верхнем уровне
Программное прерывание 17Н предоставляет некоторые возможности по работе с параллельным портом принтера. Однако сразу же следует отметить, что этих возможностей недостаточно для полноценного программирования подключенных к этому порту внешних устройств. Тем не менее некоторые функции этого прерывания могут оказаться полезными.
Имеется три функции прерывания 17Н, выбираемые значением регистра АН:
Функция №0 — печать символа.
Вход: АН = 0, AL — символ, DX — номер порта (0, 1 или 2)
Выход: АН — статус порта (см. функцию №2). Функция №1 — инициализация порта.
Вход: АН = 1, DX — номер порта (0, 1 или 2).
Выход: АН — статус порта (см. функцию №2). Функция №2 — определение статуса порта.
Вход: АН = 2, DX — номер порта (0, 1 или 2).
Выход: АН — статус порта:
Значения "1" в битах: 0 — тайм-аут,
3 — ошибка,
4 — принтер выбран,
5 — конец бумаги,
6 — подтверждение,
7 — принтер не занят.
Легко видеть, что устанавливаемые всеми функциями биты статуса соответствуют сигналам шины состояния интерфейса Centronics. Поэтому функцию №2 можно использовать для чтения данных с этой шины. Однако, как и в других случаях, использование прерывания существенно замедляет работу программы, поэтому рекомендуется непосредственно считывать данные по соответствующему адресу.
Действительно полезной оказывается функция №1 — инициализация порта. Дело в том, что эту процедуру необходимо выполнять после окончания работы с портами, иначе возможны конфликты с принтером. Поэтому рекомендуется вызывать функцию №1 прерывания 17Н при выходе из программы.
3.3. Примеры программирования
В данном параграфе приведены примеры драйверов устройств, показанных на рис. 3.2, 3.5 и 3.6.
3.3.1. Драйверы устройства "набор лампочек и кнопочек"
Для показанного на рис. 3.2 устройства необходимо реализовать следующие процедуры:
- инициализация,
- запись в порт светодиодов,
- чтение состояния переключателей.
//*** Драйверы устройства "набор лампочек и кнопочек" ***
// Глобальная переменная — базовый адрес порта int Cent_Base;
// Прототипы функций нижнего уровня (см. п.3.2.1)
// Запись в регистр управления Centronics
extern void Cent_Control_drv (unsigned char control);
// Чтение из регистра управления Centronics
extern unsigned char Cent_Status_drv (void);
// Прототипы функций
// функция инициализации.
int lnit_SP (void);
// Функция записи в регистр светодиодов
void Write_SP (unsigned char data);
// Функция чтения состояния переключателей
unsigned char Read_SP (void);
// Маски битов регистров управления и состояния
// Регистр управления
#define STROBE 0x01
#define AUTOFD 0x02
#define INIT 0x04
#define SLCTIN 0x08 // Регистр состояния
#define BUSY 0x10
#define STATUS_DATA 0x0F
// Функция инициализации.
// Определяет адрес порта.
// к которому подключено устройство
// (по сигналу наличия внешнего питания).
// Гасит все светодиоды.
// Возвращает: 1 — устройство подключено,
// 0 — не подключено
int init_SP (void)
{
int *b;
b = (int *) MK_FP (0, 0x408); // Указатель на ячейку 0:408
while ( *b != 0 ) // Если порт установлен
{
Cent_Base = *b; // Считываем его базовый
// адрес
if (Cent_Status_drv() & BUSY != 0) continue;
// Устройство не подключено
// к этому порту
Cent_Control_drv (0); // Сброс регистра светодиодов
Cent_Control_drv (INIT); // Разрешение записи
// в регистр
// светодиодов return 1
}
// Устройство
// подключено
return 0; // Устройство не подключено
}
// функция записи в регистр светодиодов.
// Вход: data — байт данных, в котором каждый бит
// соответствует светодиоду: 0 — не горит, 1 — горит
void Write_SP (unsigned char data)
{
outportb (Cent_Base, data); // Установка данных
Cent_Control_drv (STROBE | INIT); // Строб записи = 1
Cent_Control_drv (INIT); // Строб записи = 0
}
//Функция чтения состояния переключателей.
// Возвращает: байт данных, в котором каждый бит
// соответствует переключателю:
// 0 — замкнут, 1 — разомкнут
unsigned char Read_SP (void)
{
unsigned char data;
data = Cent_Status_drv() & STATUS_DATA; // Чтение
// младшей
// тетрады
Cent_Control_drv (SLCTIN | INIT); // Выбор старшей
// тетрады
data += (Cent_Status_drv() & STATUS_DATA) << 4;
// Чтение
// старшей тетрады
Cent_Control_drv (INIT); // Исходное состояние
return data;
}
// Конец драйверов
Ниже приводится текст простейшей программы, зажигающей светодиоды при замыкании соответствующих переключателей.
#define ESC 0x1В // Код клавиши ESC
#include <CONIO.H>
// Выход из программы — по клавише Esc
void main (void)
{
char key = 0;
if (lnit_SP() == 0) // Инициализация
exit (1); // He подключено
while (key != ESC) // Выход по Esc
{
while (! kbhit()) // Проверка нажатия клавиши
Write_SP ( Read_SP() ); // Чтение состояния
// переключателей и
// запись в регистр
// светодиодов
key = getch(); // Чтение кода клавиши
}
}
3.3.2. Драйверы модуля ОЗУ
Драйверы показанного на рис. 3.5 модуля ОЗУ емкостью 16 Кбайт реализуют функции инициализации, чтения и записи данных по произвольному адресу.
//***** Драйверы модуля ОЗУ *****
// Глобальная переменная — базовый адрес порта
int Cent_Base;
// Прототипы функций нижнего уровня (см. п.3.2.1)
// Запись в регистр управления Centronics
extern void Cent_Control_drv (unsigned char control);
// Чтение из регистра управления Centronics
extern unsigned char Cent_Status_drv (void);
// Прототипы функций
// Функция инициализации.
int lnit_RAM (void);
// Функция записи данных
void Write_RAM (unsigned addr, unsigned char data);
// функция чтения данных
unsigned char Read_RAM (unsigned addr);
// Маски битов регистров данных, управления и состояния
// регистр данных
#define T1_T2 0x80
#define RE 0x40
// Регистр управления
#define AL_W 0x00
#define AH_W 0x01
#define RAM_W 0x02
#define SLCTIN 0x08
// Регистр состояния
#define BUSY 0x10
#define STATUS_DATA 0x0F
//функция инициализации.
// Определяет адрес порта, к которому подключен модуль
// (по сигналу BUSY).
// Возвращает: 1 — модуль подключен, 0 — не подключен
int lnit_RAM (void)
{
int *b;
b = (int *) MK_FP (0, 0x408); // Указатель на ячейку 0:408
while ( *b != 0 ) // Если порт установлен
{
Cent_Base = *b; // Считываем
// его базовый адрес
if (Cent_Status_drv() & BUSY != 0) continue;
// Модуль не подключен
// к этому порту
Cent_Control_drv (0); // Строб записи = 0
return 1; // Модуль подключен
}
return 0; // Модуль не подключен
}
// Функция записи данных в ОЗУ.
// Вход: data — байт данных, addr — адрес
void Write_RAM (unsigned addr, unsigned char data)
{
// Младший байт адреса ОЗУ
outportb (Cent_Base, addr); // Установка младшего
// байта адреса
Cent_Control_drv (AL_W); // Адрес регистра младшего
// байта адреса
Cent_Control_drv (AL_W | SLCTIN); // Строб записи = 1
Cent_Control_drv (0); // Строб записи = 0
// Старший байт адреса ОЗУ
outportb (Cent_Base, (addr>>8) | RE ); // Установка старшего
// байта адреса
// и режима записи
Cent_Control_drv (AH_W); // Адрес регистра
//старшего байта адреса
Cent_Control_drv (AH_W | SLCTIN); // Строб записи = 1
Cent_Control_drv (0); // Строб записи = 0
// Байт данных
outportb (Cent_Base, data); // Установка байта данных
Cent_Control_drv (RAM_W); // Адрес данных
Cent_Control_drv (RAM_W | SLCTIN); // Строб записи = 1
Cent_Control_drv (0); // Строб записи = 0
}
// Функция чтения данных из ОЗУ
// Вход: addr — адрес.
// Возвращает: байт данных
unsigned char Read_RAM (unsigned addr)
{
unsigned char data;
// Младший байт адреса ОЗУ
outportb (Cent_Base, addr); // Установка младшего
// байта адреса
Cent_Control_drv (AL_W); // Адрес регистра младшего
// байта адреса
Cent_Control_drv (AL_W | SLCTIN); // Строб записи = 1
Cent_Control_drv (0); // Строб записи = 0
// Старший байт адреса ОЗУ и чтение младшей тетрады данных
outportb (Cent_Base, (addr»8)); // Установка старшего
// байта адреса и
// режима чтения
// младшей тетрады данных
Cent Control_drv (AH_W); // Адрес регистра старшего
// байта адреса
Cent_Control_drv (AH_W | SLCTIN); // Строб записи = 1
Cent_Control_drv (0); // Строб записи = 0
data^ Cent_Status_drv() & STATUS_DATA;
// Чтение младшей
// тетрады
// Старший байт адреса ОЗУ и чтение старшей тетрады данных
outportb (Cent_Base, (addr>>8) | T1_T2); // Установка
// старшего байта
// адреса и
// режима чтения
// старшей тетрады
// данных
Cent_Control_drv (AH_W); // Адрес регистра старшего
// байта адреса
Cent_Control_drv (AH_W | SLCTIN); // Строб записи = 1
Cent_Control_drv (0); // Строб записи = 0
data += (Cent_Status_drv() & STATUS_DATA) << 4;
// Чтение старшей
// тетрады
Cent_Control_drv (0); // Исходное состояние
return data;
}
// Конец драйверов
Ниже приведен текст программы, реализующей функциональный тест "Поле нулей" модуля ОЗУ.
#define RAM_SIZE 16384
#include <STDIO.H>
// Программа выводит на экран сообщение
// о результатах теста — ОК или количество ошибок
void main (void)
{
unsigned i;
unsigned char data = 0; // Поле нулей
unsigned err; // Счетчик ошибок
if (init_RAM() == 0) // Инициализация
exit(1); //He подключено
// Запись поля нулей
for (i=0;i<RAM_SIZE;i++)
Write_RAM (i, data);
// Чтение и сравнение с полем нулей
for (i=0,err=0;i<RAM_SIZE;i++)
if ( Read_RAM (i) != data )
err++;
// Вывод на экран результатов теста
if (err = 0)
printf ("Нет ошибок.");
else
printf ("Ошибок — %u", err);
}
3.3.3. Драйверы универсального параллельного адаптера
Драйверы УПА реализуют функции инициализации, записи управляющего слова, записи данных в порт и чтения данных из порта.
//***** Драйверы УПА *****
// Глобальные переменные
int Cent_Base; // Базовый адрес порта
unsigned char CW; // Управляющее слово
// Прототипы функций нижнего уровня (см. п.3.2.1)
// Запись в регистр управления Centronics
extern void Cent_Control_drv (unsigned char control);
// Чтение из регистра управления Centronics
extern unsigned char Cent_Status_drv (void);
// Прототипы функций
// Функция инициализации.
int lnit_UPA (void);
// функция записи управляющего слова
void WriteCW_UPA (void);
// функция записи данных в порт
void WriteP_UPA (unsigned port, unsigned char data);
// функция чтения данных из порта
unsigned char ReadP_UPA (unsigned port);
// Маски битов регистров данных, управления и состояния
// регистр данных — бит переключения тетрад при чтении
#define T1_T2 0x80 // Регистр управления
#define SLCTIN 0x08 // Регистр состояния
#define BUSY 0x10
#define STATUS_DATA 0x0F