
- •Тверской государственный технический университет
- •Периферийные устройства эвм
- •Введение
- •1. Интерфейс rs-232c
- •1.1. Интерфейс rs-232c – cом-порт
- •1.1.1. Протокол rs-232c
- •Управление потоком данных
- •Системная поддержка Com-портов
- •Использование cом-портов
- •1.1.5. Непосредственное подключение устройств
- •1.2. Программируемый последовательный интерфейс
- •Связь компьютера с микроконтроллером
- •1.3.1. Протокол обмена
- •Работа с com-портом на низком уровне
- •Микросхемы асинхронных приемопередатчиков и особенности работы с ними
- •1.4.2. Структура регистров уапп 16550a
- •1.4.3. Описание регистров уапп 16550a
- •1.4.4. Примеры работы с последовательным портом на низком уровне
- •1.4.5. Аппаратное подтверждение связи
- •1.4.6. Проблемы передачи данных
- •1.4.7. Переполнение регистра-приемника
- •1.4.8. Использование функций bios
- •1.4.9. Использование функций Windows api
- •2.1. Классификация модемов
- •2.2. Устройство модемов
- •2.3. Подключение модема через интерфейс rs-232
- •Модемные протоколы и стандарты. Виды протоколов. Протоколы взаимодействия и модуляции
- •Команды управления модемами (ат-язык). Наборы ат-команд
- •2.5.1. Основные команды модема
- •2.5.2. Стандартный набор ответов модема
- •2.6.1. Локальный аналоговый тест
- •2.6.2. Локальный аналоговый тест с самодиагностикой
- •2.6.3. Локальный цифровой тест
- •2.6.4. Удаленный цифровой тест
- •2.6.5. Удаленный цифровой тест с самодиагностикой
- •2.7. Назначение и использование s-регистров модема
- •2.8. Режимы работы модема. Сообщения и ответы модема
- •2.9. Протоколы передачи файлов
- •2.10. XDsl – модемы
- •Клавиатура
- •3.1. Основные параметры, классификация, принципы работы
- •3.2. Скан-коды
- •3.3. Интерфейс клавиатуры
- •4. Видеосистема компьютера
- •4.1. Классификация и характеристики мониторов
- •4.2. Видеоадаптер
- •4.2.1. История видеоадаптеров
- •4.2.2. Компоненты видеоадаптера
- •Принтер
- •5.1. Классификация принтеров и технологий печати
- •5.1.1. Матричный принтер
- •5.1.2. Струйный принтер
- •5.1.3 Лазерный принтер
- •5.2.Описание lpt-порта
- •5.3. Язык описания страниц
- •5.4.1. Поддержка pcl
- •Лабораторная работа №1 «Изучение интерфейс rs-232»
- •Лабораторная работа № 2 «Определение и анализ качественных характеристик модема»
- •Лабораторная работа №3 «Изучение взаимодействия клавиатуры и компьютера»
- •Пример выполнения лабораторной работы
- •1. Включить сканирование клавиатуры.
- •2. Сбросить на начальные установки контроллер клавиатуры.
- •3. Установить:
- •5. Послать подтверждение контроллером клавиатуры.
- •6. Послать Эхо-запрос компьютером.
- •7. Ответить на Эхо-запрос контроллером.
- •8. Подготовить строку в скан-кодах для ввода в компьютер фразы «There Can Be».
- •9. Запретить сканирование клавиатуры.
- •Варианты заданий Вариант 1
- •Вариант 2
- •Вариант 3
- •Вариант 4
- •Вариант 5
- •Лабораторная работа №4 «Изучение режимов работы видеокарты»
- •Выполнение
- •Варианты заданий Вариант 1
- •Вариант 2
- •Вариант 3
- •Вариант 4
- •Лабораторная работа № 5 «Управление печатью с помощью языка описания страниц»
- •Описание работы с программой
- •Варианты заданий Вариант 1
- •Вариант 2
- •Вариант 3
- •Вариант 4
- •Вариант 5
- •Библиографический список
- •Оглавление
- •Периферийные устройства эвм
- •170026, Г. Тверь, наб. Афанасия Никитина, 22
1.4.9. Использование функций Windows api
Работа с портами в API Windows строится так же, как работа с файлами. Порт открывается как файл с помощью функции CreateFile. Эта функция объявлена в файле winbase.h следующим образом:
HANDLE CreateFile(
LPCTSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDestribution,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
).
Параметр lpFileName содержит имя открываемого порта. Для последовательных портов используются имена COM1, COM2 и т.д. Однако невозможно открыть порт, к которому подключены мышь, принтер или другие устройства. Впрочем, порт, используемый модемом, можно открыть, если он в данный момент неактивен.
Параметр dwDesiredAccess определяет флаги доступа к порту. Он может содержать комбинацию следующих флагов:
0 – разрешает опрашивать атрибуты порта;
GENERIC_READ – разрешает чтение;
GENERIC_WRITE – разрешает запись.
Комбинация флагов с помощью операции ИЛИ позволяет открыть порт одновременно и для записи, и для чтения.
Параметр dwShareMode определяет режим совместного доступа. К порту совместный доступ невозможен, так что этот параметр всегда должен быть равен 0. Точно также при работе с портами должны быть равны NULL параметры lpSecurityAttributes (определяет наследование порождаемыми процессами) и hTemplateFile (шаблон и атрибуты создаваемого файла). Параметр dwCreationDistribution, определяющий действия с создаваемым файлом, должен для портов всегда иметь значение OPEN_EXISTING – открытие существующего порта.
Параметр dwFlagsAndAttributes в случае портов определяет режим работы: 0 – синхронный, FILE_FLAG_OVERLAPPED – асинхронный, то есть фоновая обработка ввода и вывода.
В случае успешного выполнения функция CreateFile возвращает дескриптор порта. Успешность выполнения можно проверить с помощью функции GetLastError. Перед запуском функции CreateFile имеет смысл применить функцию SetLastError(0) для того, чтобы исключить возможность чтения ложных (предыдущих) ошибок.
После завершения работы с портом он должен быть закрыт функцией CloseHandle: BOOL CloseHandle(IN OUT HANDLE hObject);
Таким образом, работа с портом организуется по следующей схеме:
HANDLE port;
. . . .
port = CreateFile(“COM1”,GENERIC_READ|GENERIC_WRITE,
0,0,OPEN_EXISTING,0,0);
< настройка порта >
< чтение/запись >
. . . .
CloseHandle(port).
Первый из приведенных выполняемых операторов открывает порт COM1 для чтения и записи в синхронном режиме. Последний оператор закрывает порт.
Если вы работаете с последовательным портом, то, после того как он открыт, можно получить информацию о его параметрах с помощью функции GetCommState, объявленной в файле Winbase.h следующим образом:
BOOL GetCommState (IN HANDLE hFile, OUT LPDCB lpDCB).
Параметр hFile – дескриптор порта, а параметр lpDCB определяет структуру типа TDCB, в которую функция GetCommState заносит информацию. Такой же тип структуры используется и при настройке порта. Ограничимся знаниями о тех полях, которые являются ключевыми для работы.
Поле BaudRate определяет скорость передачи данных в битах в секунду. Это целое число, которое можно указывать или непосредственно, или с помощью констант CBR_110, CBR_300, CBR_600, CBR_1200, . . ., CBR_256 000. Смысл констант ясен из наименований. Так что, если требуется установить значение BaudRate, его можно задать, например, равным 14 400 или равным CBR_14 400. Результат будет одинаковым.
Поле ByteSize определяет число битов данных в передаваемых и принимаемых байтах. Это поле может иметь значения 4, 5, 6, 7, 8. Впрочем, не всегда все перечисленные значения допустимы.
Поле Parity задает схему контроля четности. Оно может принимать следующие значения (константы и их значения описаны в файле Windows.h):
NOPARITY 0 Отсутствие бита четности
ODDPARITY 1 Дополнение до нечетности
EVENPARITY 2 Дополнение до четности
MARKPARITY 3 Бит четности всегда равен 1
SPACEPARITY 4 Бит четности всегда равен 0.
Поле StopBits задает число стоповых бит. Оно может принимать следующие значения (константы и их значения описаны в файле Windows.h):
ONESTOPBIT 0 Один бит
ONE5STOPBITS 1 Полтора бита
TWOSTOPBITS 2 Два бита.
Поле EvtChar задает символ, приход которого генерирует некоторое событие. Этот символ может использоваться в асинхронном режиме работы.
При ошибке выполнения функция GetCommState возвращает false. А если ошибки не произошло, функция заполняет структуру lpDCB типа TDCB текущими параметрами настройки порта. Далее можно изменить значения элементов этой структуры и передать новые значения параметров в порт с помощью функции SetCommState:
BOOL SetCommState (IN HANDLE hFile, IN LPDCB lpDCB).
Параметры этой функции тождественны параметрам функции GetCommState. В случае неудачи функция возвращает false. Неудача может быть связана с заданием недопустимых значений для данного порта.
Помимо основных параметров порта, существует еще ряд, не менее важных, определяющих максимальное время, отводимое на операции чтения и записи. Эти параметры определяют тайм-аут (timeout) – интервал времени, в течение которого функции записи и чтения ожидают появления новой информации. Если это время истекает, чтение или запись прерываются.
Получить информацию о временных параметрах порта можно функцией GetCommTimeouts:
BOOL GetCommTimeouts (IN HANDLE hFile,
OUT LPCOMMTIMEOUTS lpCommTimeouts).
Параметр hFile является дескриптором порта, а lpCommTimeouts – структура типа TCommTimeouts, содержащая следующие поля:
DWORD ReadIntervalTimeout – максимальное время, допустимое между двумя последовательными символами, считываемыми с коммуника-ционной линии.
DWORD ReadTotalTimeoutMultiplier – множитель, используемый для вычисления общего тайм-аута операции чтения.
DWORD ReadTotalTimeoutConstant – константа, используемая для вычисления общего тайм-аута операции чтения.
DWORD WriteTotalTimeoutMultiplier – множитель, используемый для вычисления общего тайм-аута операции записи.
DWORD WriteTotalTimeoutConstant – константа, используемая для вычисления общего тайм-аута операции записи.
Значения всех полей указывается в миллисекундах. Поле ReadIntervalTimeout определяет максимальный интервал между двумя последовательными символами, точнее, между началами передачи двух символов, включая время передачи самого символа. Если интервал между символами превысит заданное значение, операция чтения завершится и все данные, накопленные в буфере, передадутся в программу. Нулевое значение данного поля означает, что данный тайм-аут не используется. Если же в поле подать значение, соответствующее MAXDWORD (4294967295), и одновременно задать нулевые значения полей ReadTotalTimeoutConstant и ReadTotalTimeoutMultiplier, то операция чтения немедленно завершится и вернет уже принятый символ, даже если ни одного символа не было получено из линии.
Во время операции чтения временной период начинает отсчитываться с момента приема первого символа. Общий интервал времени на операцию чтения рассчитывается как произведение значения ReadTotalTimeoutMultiplier на количество запрошенных символов N, и к этому произведению добавляется значение ReadTotalTimeoutConstant.
Пусть, например, требуется прочитать 100 символов при скорости порта 1200. И пусть на каждый символ используется 8 бит данных, бит дополнения четности, стоповый бит и стартовый бит – итого 11 бит на символ. Значит, на всю операцию чтения требуется 100*11/12 000 с или 93 мс. К этому времени надо прибавить 99 интервалов между импульсами. Например, если средний ожидаемый интервал между окончанием одного и началом следующего символа равен 1 мс, то на всю операцию чтения потребуется 93 + 99 = 192 мс. Для решения подобной задачи можно задать ReadIntervalTimeout = 4 мс (в 2 раза больше среднего значения, складывающегося из времени передачи символа и промежутка между ними). Значение ReadTotalTimeoutMultiplier можно установить равным 2 мс и задать некоторое значение ReadTotalTimeoutConstant в качестве страховки от возможных колебаний скорости чтения. В результате в нашем примере общее время может составить 300 мс. Если операция чтения выполняется дольше, разумно предположить, что это вызвано какими-то ошибками внешнего устройства. В этом и заключается смысл задания тайм-аута: через заданный интервал времени считывание прекратится, и тем самым можно будет избежать возможного «зависания» программы. При этом будут возвращены символы, прием которых завершился до истечения тайм-аута. Остальные символы можно получить следующей операцией чтения. Если между началами двух последовательных символов пройдет более 4 мс, то операция чтения также будет завершена.
Параметры WriteTotalTimeoutMultiplier и WriteTotalTimeoutConstant аналогичны параметрам ReadTotalTimeoutMultiplier и ReadTotal- TimeoutConstant, но относятся к операции записи.
Рассмотренная функция GetCommTimeouts позволяет определить текущие временные параметры порта, а функция SetCommTimeouts устанавливает эти параметры:
BOOL SetCommTimeouts (IN HANDLE hFile,
IN LPCOMMTIMEOUTS lpCommTimeouts).
Синхронный режим работы
Рассмотрим операции чтения и записи. Обычно перед началом этих операций необходимо очистить буфер порта от мусора, а иногда и отменить выполняющуюся в данный момент предыдущую операцию записи или чтения. Это можно сделать при помощи функции PurgeComm:
BOOL PurgeComm (IN HANDLE hFile, IN DWORD dwFlags).
Параметр hFile является дескриптором порта, а параметр dwFlags указывает выполняемые операции. Он может комбинироваться операцией ИЛИ из следующих флагов:
PURGE_TXABORT – немедленно завершить все операции записи;
PURGE_RXABORT – немедленно завершить все операции чтения;
PURGE_TXCLEAR – очистить в драйвере очередь передачи;
PURGE_RXCLEAR – очистить в драйвере очередь приема.
Функция PurgeComm позволяет очистить буфер от мусора, который может быть следствием работы какой-то предыдущей программы, и позволяет прервать операции чтения и записи в случае ошибки. Полезно также вызвать эту функцию перед завершением работы вашего приложения, чтобы не оставлять мусор другим программам. Но надо учитывать, что очистка буфера не означает передачу находящихся в нем данных. Эти данные просто стираются. Если же надо завершить передачу данных, содержащихся в буфере, то вместо PurgeComm надо вызвать функцию FlushFileBuffers:
BOOL FlushFileBuffers (IN HANDLE hFile).
Эта функция обеспечивает передачу данных из выходного буфера и только после этого очищает его.
Синхронный прием и передача осуществляется функциями:
BOOL ReadFile (IN HANDLE hFile, OUT LPVOID lpBuffer,
IN DWORD nNumberOfBytesToRead,
OUT LPDWORD lpNumberofBytesRead,
IN LPOVERLAPPED lpOverlapped);
BOOL WriteFile (IN HANDLE hFile, IN LPCVOID lpBuffer,
IN DWORD nNumberOfBytesToWrite,
OUT LPDWORD lpNumberOfBytesWritten,
IN LPOVERLAPPED lpOverlapped).
Параметр hFile – дескриптор порта, параметр Buffer – буфер, данные которого передаются или в который заносятся принимаемые данные. Параметры nNumberOfBytesToRead и nNumberOfBytesToWrite – число байт, которые должны быть переданы или приняты. Параметры lpNumberOfBytesRead и lpNumberOfBytes-Written – число реально переданных или принятых байт. Это число может быть меньше ожидаемого из-за ошибок или прерываний по тайм-ауту. Параметр lpOverlapped используется для асинхронного чтения и записи. Для синхронных операций этот параметр должен быть равен NULL.
Пример передачи данных:
FlushFileBuffers (port);
WriteFile (port, buf.c_str(), buf.Lenght(), &DWORD(n), NULL);
ShowMessage (“Передано ”+IntToStr(n)+” байт”);
Пример чтения данных:
AnsiString buf; int n;
. . . .
buf = ””;
FlushFileBuffers (port);
ReadFile (port, buf.c_str(), 128, &DWORD(n), NULL);
ShowMessage (“Принято ”+IntToStr(n)+” байт: ”+buf).
Надо учитывать, что если для операций чтения не заданы временные параметры, то операция ReadFile может бесконечно ожидать прихода входных сигналов. В этом заключается один из недостатков синхронного чтения.
Порт можно перевести в состояние разрыва связи с помощью функции
BOOL SetCommBreak (IN HANDLE hFile).
При вызове этой функции передача данных прекращается, выходная линия переводится в состояние «0», после чего и приемник фиксирует состояние разрыва. Возобновить прерванную передачу данных можно функцией
BOOL ClearCommBreak (IN HANDLE hFile).
Асинхронный режим работы
В большинстве случаев синхронный режим работы с последовательным портом – не лучшее решение, так как приложение останавливается, ожидая завершения команды ввода или вывода. Более разумным является асинхронный режим работы с портами. В этом режиме вы можете указать системе, какие события порта ей надо отслеживать. Это делается с помощью функции
BOOL SetCommMask (IN HANDLE hFile, IN DWORD dwEvtMask).
Параметр hFile является дескриптором порта, а параметр dwEvtMask – маской, в которой можно указывать комбинацию следующих событий:
EV_BREAK – разрыв приемной линии;
EV_CTS – изменение состояния линии CTS;
EV_DSR – изменение состояния линии DSR;
EV_ERR – ошибка;
EV_RING – входящий звонок на модем;
EV_RLSD – изменение состояния линии RLSD;
EV_RXCHAR – принят символ и помещен в приемный буфер;
EV_RXFLAG – принят символ, заданный полем EvtChar структуры типа TDCB, использованной при настройке порта;
EV_TXEMPTY – передан последний символ буфера передачи.
Если параметр dwEvtMask в функции SetCommMask равен нулю, никакие события не отслеживаются.
Имеется функция GetCommMask, позволяющая получить текущую маску событий:
BOOL GetCommMask (IN HANDLE hFile, OUT LPDWORD lpEvtMask).
Она заносит маску в переменную, заданную параметром lpEvtMask.
Если вы задали маску событий, то можете приостановить выполнение приложения до наступления события. Это делает функция
BOOL WaitCommEvent (IN HANDLE hFile, OUT LPDWORD lpEvtMask,
IN LPOVERLAPPED lpOverlapped).
В параметр lpEvtMask будут заноситься флаги, соответствующие произошедшим событиям. Параметр lpOverlapped является указателем на структуру типа TOverlapped. Если вы просто хотите приостановить выполнение до появления соответствующего события, параметр lpOverlapped можно задать равным NULL.
Например, чтение можно организовать следующим образом:
AnsiString buf; int n; DWORD lpEvtMask;
. . . .
SetCommMask (port, EV_RXCHAR);
WaitCommEvent (port, &lpEvtMask, NULL);
ReadFile (port, buf.c_str(), 128, &DWORD(n), NULL);
ShowMessage (“Принято ”+IntToStr(n)+” байт: ”+buf).
В этом примере вызов функции ReadFile произойдет только после того, как на входную линию придет первый символ. До этого момента не будет возврата из функции WaitCommEvent.
Подобная организация чтения не очень улучшает ваше приложение. Правда, на время ожидания ресурсы компьютера освобождаются, но приложение все равно «зависает», пока не придет входной символ. Полноценный асинхронный режим, позволяющий вашему приложению работать, пока осуществляются чтение и запись, организуется следующим образом.
В вызове функции CreateFile задается dwFlagsAndAttributes = = FILE_FLAG_O-VERLAPPED. Вводится глобальная переменная типа TOverlapped. Это тип структуры, содержащей поля hEvent, Internal, InternalHigh, Offset, OffsetHigh. Для организации простой работы достаточно указать все эти поля равными 0.
В вызовах функций ReadFile и WriteFile параметр lpOverlapped должен быть указателем на введенную нами структуру типа TOverlapped. В этом случае функции немедленно возвращают управление, приложение может продолжать выполняться. Успешность запуска асинхронного чтения или записи можно проверить функцией GetLastError. Если эта функция вернет значение ERROR_IO_PENDING, значит, асинхронная операция стартовала успешно. Любое другое значение, возвращаемое функцией GetLastError, свидетельствует об ошибке. Также следует учесть, что, хотя параметры lpNumberOfBytesRead и nNumberOfBytesToWrite функций ReadFile и WriteFile по-прежнему надо задавать, они не будут содержать никакой полезной информации. Поскольку функции возвращаются сразу, соответствующие числа всегда окажутся равными нулю и не будут отражать число переданных или полученных байтов.
В процессе выполнения программы следует периодически опрашивать систему, чтобы получить информацию о завершении записи или чтения. Опрос производится функцией
BOOL GetOverlappedResult (IN HANDLE hFile,
IN LPOVERLAPPED lpOverlapped,
OUT LPDWORD lpNumberOfBytesTransferred,
IN BOOL bWait).
Параметр hFile является дескриптором порта, параметр lpOverlapped – адресом структуры типа TOverlapped. Параметр lpNumberOfBytesTransferred указывает переменную, в которой отображается число записанных или прочитанных байтов. Параметр bWait указывает, должна ли функция ждать окончания операции записи или чтения. Если задать значение этого параметра равным true, то функция будет ждать окончания соответствующей операции и, следовательно, будет реализован практически синхронный режим. Если задать bWait = false, функция немедленно вернет управление. Если возвращенное функцией значение равно true, значит соответствующая операция записи или чтения завершилась. В этом случае lpNumberOfBytesTransferred укажет число переданных байтов. Если возвращенное значение равно false, значит, операция не завершена или получилась ошибка в вызове функции GetOverlappedResult. Различить эти два варианта можно функцией GetLastError. Если она вернет ERROR_IO_INCOMPLETE, значит, операция не завершилась. В противном случае – ошибка в вызове функции GetOverlappedResult.
Рассмотренная выше организация асинхронной записи и чтения работает в Windows NT/2000/XP. Если требуется создать приложение, которое работает также в Windows 95/98, то организовать запись и чтение надо несколько иначе. В поле hEvent структуры TOverlapped надо заносить результат, возвращаемый функцией:
HANDLE CreateEvent (IN LPSECURITY_ATTRIBUTES pEventAttributes, IN BOOL bManualReset, IN BOOL InitialState,
IN LPCSTR lpName).
Эта функция создает объект события и возвращает его дескриптор. В простом случае параметры lpEventAttributes и lpName надо задать равными NULL, параметры bManualReset и bInitialState – равными false. Так что в приведенных примерах в процедурах записи и чтения необходимо добавить перед вызовами функций WriteFile и ReadFile операторы
Overlapp.hEvent = CreateEvent (NULL, false, false, NULL).
Опрос производится при помощи функции
DWORD WaitForSingleObject (IN HANDLE hHandle, IN DWORD dwMilliseconds).
Параметр hHandle является дескриптором ожидаемого события, а параметр dwMilliseconds указывает в миллисекундах максимальное время ожидания события. Если задать dwMilliseconds = 0, функция вернется немедленно. Если задать dwMilliseconds = INFINITE, ожидание будет бесконечным (аналог синхронной операции). Функция возвращает значение WAIT_OBJECT_0, если событие произошло, WAIT_TIMEOUT – если истекло заданное время ожидания, WAIT_FAILED – в случае ошибки.
Настоящая асинхронность опять же достигается при dwMilliseconds = 0. Пример функции обработчика по наступлению события от таймера будет следующий:
Void __fastcall TForm1::Timer1Timer (TObject *Sender)
{ int n;
if(WaitForSingleObject(Overlapp.hEvent,0)== WAIT_OBJECT_0)
{
if(GetOverlappedResult(port,&Overlapp,&DWORD(n), false))
{
Label1->Caption = “Получены/переданы новые данные = “
+IntToStr(n)+” байт”;
Timer1->Enabled = false;
CloseHandle(Overlapp.hEvent);
}
}
else Label1->Caption = “Новых данных нет”.
}
Следует обратить внимание на необходимость закрыть дескриптор объекта события функцией CloseHandle после того, как событие произошло. Приведенный пример годится для использования со всеми версиями Windows.
Модем