Работа с последовательными портами в Windows 95

Журнал "Радио", номер 1, 2000г.
Автор: Р. Кусяпкулов, г. Уфа

    В справочной литературе по IBM PC можно найти немало примеров программирования операций с последовательными портами компьютера, использующих функции его базовой системы ввода/вывода (BIOS) и операционной системы MS DOS. Предлагаемая статья посвящена особенностям работы с последовательными портами в приложениях операционной системы Windows 95, установленной сегодня на большинстве IBM-совместимых компьютеров.

    Операционная система Windows 95 в отличие от Windows NT не скрывает системные ресурсы компьютера, и прикладные программы имеют к ним непосредственный доступ. Благодаря этому под Windows 95 успешно работают старые программы для MS DOS. Разрабатывая новые приложения Windows 95, можно пользоваться последовательными портами, вставляя в программу фрагменты на языке ассемблера, содержащие команды обращения к портам ввода/вывода процессора и вызовы функций DOS и BIOS. Но в многозадачном режиме такие приложения часто работают некорректно, сбиваясь и теряя информацию.

    Правильнее обращаться с последовательными портами через встроенные в Windows 95 функции WinAPI (API Application Programming Interface, интерфейс программирования приложений). Их полное описание можно найти в справочной системе MS SDK Help files, поставляемой со многими системами разработки приложений. Функции для работы с коммуникационным оборудованием описаны в разделе Communications файла Win32 Programmer's Reference.

    Любые коммуникационные ресурсы, физические и логические устройства ввода/вывода с точки зрения Windows 95 - одиночные двунаправленные асинхронные потоки данных. Их открывают, инициализируют и конфигурируют функцией CreateFile, закрывают CloseHandle. Для хранения параметров коммуникационных ресурсов определен тип tDCB (Device Control Block блок управления устройством) - структура, в полях которой задают скорость обмена, число бит в посылке, число стоп-бит, режим проверки на четность. Предусмотрены функции GetCommState и SetCommState, которыми читают и устанавливают эти параметры. Размер буферов ввода и вывода задают функцией SetupComm. Для чтения и записи в порт вызывают функции ReadFile, ReadFileEx, WriteFile, WriteFileEx.

    Структура типа tCOMSTAT имеет поля cblnQueue и cbOutQueue, содержащие сведения о числе принятых байтов в буфере приема и числе еще не переданных в буфере передачи. Функция ClearCommError обновляет эту информацию и сообщает о возникших в процессе работы порта ошибках.

    Ядро Windows 95 самостоятельно обрабатывает все события, возникающие при работе последовательных портов, настраивает прерывания и программирует контроллеры портов ввода/вывода, принимает и передает байты данных. Прикладной программе остается читать принятые данные из буфера приемника, а предназначенные для передачи - записывать в буфер передатчика. Эти операции обычно выполняют блоками с периодичностью, зависящей от скорости приема/передачи и объема буферов.

    Рассмотрим пример разработки с помощью систем программирования Delphi 3 или Delphi 4 простого приложения, принимающего данные через последовательный порт и записывающего их в дисковый файл. Так как в примере используются в основном стандартные функции WinAPI, его без труда можно перевести на другой язык.

    Запустив систему программирования, прежде всего разместите на форме приложения компонент Timer (таймер) со страницы System и два компонента Label (метка) со страницы Standard. Таймер будет синхронизировать процесс обработки данных, метки послужат для вывода на экран сообщений о его ходе. С помощью инспектора объектов введите в поле значения свойства Label 1.Caption строку "Идет инициализация" (без кавычек), a Label2. Caption пустую строку. Период прерывания по таймеру выбирается исходя из размера буферов ввода/вывода и скорости обмена данными, в данном примере его изменять не нужно.

    В секцию переменных (var) программного модуля, кроме уже имеющейся там Formi, добавьте описания еще нескольких глобальных переменных, как показано в табл. 1.

    Опишите и константу BufSize - длину буфера временного (до записи в файл) хранения принятых данных. Задание этой константы показанным в табл.1 способом гарантирует ее равенство фактической длине буфера.

    Теперь можно приступать собственно к программированию. Потребуются процедуры обработки событий создания формы (Formi.OnCreate), ее закрытия (Form1.OnClose) и истечения заданного интервала времени (Timer1.OnTimer). Выберите объект Form1 и откройте страницу Events (события) инспектора объектов. После двойного щелчка в поле обработчика события OnCreate в тексте программного модуля появится шаблон, содержащий заголовок процедуры FormCreate с ограничивающими ее тело операторами begin и end. Таким же образом создайте шаблоны обработчиков двух других событий и заполните все три в соответствии табл.2.

    Процедура FormCreate, прежде всего, инициализирует порт COM2. С точки зрения программиста, эта операция ничем не отличается от создания обычного файла. WinAPI "понимает", что COM2 - последовательный порт, и действует соответствующим образом. Успешно инициализированный порт процедура настраивает, задавая длину его буферов, скорость приема/передачи и другие параметры. И наконец, она открывает дисковый файл OUT.BIN для записи принятых данных. В случае неудачи любой из операций на экран выводится сообщение об этом и приложение прекращает работу.

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

    Чтением принятых данных из буферов порта и записью их в файл занимается процедура Timer1 Timer. Ее Windows 95 вызывает автоматически с периодом, заданным в миллисекундах свойством Timer1.Interval. В рассматриваемом примере предполагается, что источник данных (внешнее устройство, подключенное к порту COM2) выдает их порциями по 45 байт. Поэтому чтение из буфера приема и запись в файл производятся блоками такой же длины. Если перед записью данные необходимо обработать, вызов соответствующей подпрограммы может быть помещен в указанном в процедуре Timer1 Timer месте.

    Логической переменной Lock на время выполнения операций чтения, обработки и записи данных присваивают значение true, а по их завершению false. При очередном вызове процедура Timer1 Timer прежде всего проверяет значение этой переменной и приступает к работе только в случае, если оно false, т.е. предыдущий вызов завершен. Такая ситуация возможна при неправильном выборе периода прерывания таймера.

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







Рекомендуемый контент




Copyright © 2010-2018 housea.ru. Контакты: info@housea.ru При использовании материалов веб-сайта Домашнее Радио, гиперссылка на источник обязательна.