Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник |
Коллекция курьезных вопросов из форумов
KOL и MCK |
KOL и MCK - Компактные программы на Delphi
 
Стс прямой эфир интервью на стс.

Последовательный порт RS-232.

Введение.

Автоматизация различных систем с помощью компьютера меня интересовала всегда. Но когда я начал заниматься этой задачей, то столкнулся с множеством проблем. Одна из главных проблем это литература, в которой в доступной для меня форме был бы освещен данный вопрос. Но литературы по данной теме очень мало, особенно в нашем небольшом городке. Взять, например книгу в магазине за 300 руб. в которой уделяется искомому вопросу 2-3 страницы неинтересно, а покупать 2-3 книги дорого. Вы скажете "Сходи в библиотеку и нет проблем", о библиотеке я тоже думал. Но и там проблема с книгами стоит остро. Денег на новые книги у них нет, так как книги по компьютерной тематике в основном печатаются в коммерческих типографиях и поэтому стоят дорого. А тот мизер который выделяет государство на покупку книг настолько мал что его хватает только на содержание старых наиболее читаемых произведений. И тогда я решил поискать в интернете. И он меня не разочаровал. В первый же час поиска я нашел много интересного. В основном это статьи людей занимающиеся аналогичным вопросом . Они делятся своим опытом с начинающими и в примерах показывают, как реализовать ту или иную задачу.

Данная статья была задумана для объединения в себя всю ту информацию, которую я почерпнул в ходе своего изыскания в интернете.

История стандарта RS-232.

В 1969 г. Группой ведущих промышленных корпораций США был введен стандарт на соединение оборудования. Ассоциация электронной промышленности США (EIA) опубликовала вариант С своего рекомендуемого стандарта (Recommended Standart - RS) номер 232. Этот стандарт был озаглавлен "Интерфейс между оконечным оборудованием обработки данных и оконечным оборудованием линии с использованием последовательного обмена данными в двоичной форме" и известен просто как стандарт RS-232C. МККТТ ввел свой собственный вариант этого стандарта в виде стандартов V.24 и V.28.

Министерство обороны США выпустило практически идентичный стандарт Mil-Std-188C.

Хотя стандарт RS-232C был весьма популярен, определяемый им физический интерфейс долек от совершенства. Система передачи данных (передатчик, приемник, соединительные кобеля), реализованная в соответствии с техническими условиями стандарта RS-232C, должна гарантированно обеспечивать передачу сигнала со скоростями, не превышающими всего лишь 20 Кбит/с . Ассоциация электронной промышленности США ввела рекомендуемые стандарты для систем, работающих при больших скоростях, но стандарт RS-232C продолжает оставаться основной реализации последовательного интерфейса для IBM-совместимых персональных компьютеров.

Модификация D этого стандарта была введена в 1987 г. В ней были определены некоторые дополнительные линии тестирования, а также закреплено то, что многие рассматривали как недостаток стандарта RS-232C.

Самой последней (июль 1991 г.) модификацией стандарта RS-232 является стандарт EIA/TIA-232E. В модификации Е нет никаких технических изменений, которые могли бы привести к проблемам совместимости с оборудованием, согласованным с предыдущими вариантами этого стандарта.

Проблема.

Под MS-DOS приложение управляет всем компьютером. Это развязывало программисту руки. Достижение максимальной скорости работы осуществлялось непосредственным доступом к аппаратным средствам.

Под Windows 3.x эта свобода отчасти была ограничена. К примеру вы уже не имели полный доступ к экрану. Проблема объясняется легко: с тех пор, как пользователь мог запускать любое количество приложений, не было никакой гарантии, что приложения не получали одновременно те же самые аппаратные средства.

Другая проблема - вы уже должны были считаться с параллельно запущенными задачами, а не требовать у компьютера в свое распоряжение все ресурсы. Win 3.x осуществляет кооперацию параллельных задач, означая, что каждое приложение должно исходить из концепции совместного существования и не монополизировать ресурсы, а пользоваться услугами специализированного диспетчера. Захват CPU на длительное время здесь не приветствуется.

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

Факт, но тенденция отбивания рук от прямого доступа к железу победила на платформе Win32 (Windows NT и Windows 95). Это операционные системы с истинной многозадачностью. Каждый поток (выполняемый модуль) получает определенный квант процессорного времени. Когда лимит процессорного времени исчерпан, или появляется поток с более высоким приоритетом, система прекращает обслуживать первый поток, даже в случае, если он не завершен. Это переключение между потоками может произойти между двумя ассемблерными инструкциями, нет никакой гарантии, что поток сможет завершить определенное количество инструкций, прежде чем у него отнимут процессорное время, к тому же неизвестно как долго ждать следующей порции процессорного времени. Это приводит к проблеме с прямым доступом к аппаратным средствам. Например, типичное чтение из порта формируется из нескольких ассемблерных инструкций:

 mov dx, AddressPort
 mov al, Address
 out dx, al
 jmp Wait
 Wait:
 mov dx, DataPort
 in al, dx

Состояние всех регистров при переключении потоков сохраняется, состояние I/O портов (последовательные порты, порты ввода/вывода) - нет. Так, велика вероятность что другие приложения производят другие операции с I/O портом, в то время как вы "застряли" между инструкциями 'out' и 'in'.

Документированный путь.

Для решения этой проблемы мы должны как-то сообщить всем другим приложениям, что "К настоящему времени MyProg использует порт 546, и всем оставаться на своих местах до моего особого распоряжения." В этом случае подошел бы мьютекс. К сожалению, для использования созданного мьютекса все приложения должны знать его имя. Но даже если бы это было возможно, вы легко можете наткнуться на другие заковыристые проблемы. Рассмотрим два приложения - App1 и App2. Оба пытаются выполнить вышеприведенный код. К несчастью, они созданы разными программистами с разным взглядом на технологию доступа, поэтому App1 сначала требует AddressPortMutex, в то время как App2 требует DataPortMutex. И, по печальному совпадению, когда App1 получает AddressPortMutex, система переключается на App2, которое захватывает DataPortMutex и получается праздник смертельного объятия. App2 не может получить адрес порта, т.к. его захватило App1. App1 не может получить данные порта, т.к. это захватило App2. И все чего-то ждут...

Правильное решение - создание драйвера устройства, которой единолично владеет портами/памятью. Доступ к аппаратным средствам осуществляется посредством API. Вот типичный вызов:

 GetIOPortData(AddressPort, DataPort : word) : Byte; 

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

Создание драйвера устройства дело нелегкое. Он должен быть создать с помощью ассемблера или C и невероятно труден в отладке. Более того, из-за соображений безопасности драйверы устройств для Windows 95 (VxD) не совместимы с драйверами для Windows NT (VDD, virtual device driver - виртуальный драйвер устройства). Говорят, что в будущих версиях они будут совместимы, и Windows NT 6.0 и Windows 2000 будут использовать одни и те же драйвера, но пока разработчики вынуждены заниматься созданием двух различных версий.

Для получения более подробной информации рекомендую обратиться к следующим ресурсам:

Не документированный путь.

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

К счастью, в Windows 95 заложена совместимость с Windows 3.x. Это означает, что директивное использование I/O портов также возможно, поскольку до сих пор находятся в эксплуатации множество 16-битных программ, которые просто не могут работать по другому. Просто в этом случае при кодировании вам придется спуститься до уровня ассемблера. Автор следующего кода Arthur Hoornweg (hoornweg@hannover.sgh-net.de):

 //Базовые адреса двух COM портов, для справки: 
        
  COM1 - 3F8h 
  COM2 - 2F8h
  
  Function getport(p:word):byte; stdcall;
    begin 
	asm   
	   push edx    
	   push eax    
	   mov  dx,p    
	   in   al,dx    
	   mov  @result,al    
	   pop  eax    
	   pop  edx  
	 end;
    end;
	
 Procedure Setport(p:word;b:byte);stdcall;
  begin  
  asm    
   push edx    
   push eax   
   mov dx,p    
   mov al,b    
   out dx,al    
   pop  eax    
   pop  edx  
  end;
 end;

Francois Piette также предлагает свое решение прямого доступа к портам I/O на страничке http://rtfm.netline.be/fpiette/portiofr.htm.

Как насчет NT?

Но все вышесказанное под Windows NT работать не будет. NT более "прочная" операционная система, поэтому если она позволит в любое время кому попало обращаться к любым аппаратным средствам, она не была бы такой устойчивой. Кроме того, NT является кроссплатформенной системой, поэтому доступ к I/O портам может кардинально различаться при работе на различных процессорах.

Но тем не менее даже под NT можно добраться непосредственно до I/O портов, правда только на x86 процессорах. Это не является документированной особенностью, и, вероятно, исчезнет в будущих версиях этой операционной системы.

Я не обладаю достаточно полной информацией по этому вопросу, но интересующая нас статья D. Roberts в майском номере журнала Dr. Dobb's Journal за 1996 год так и называется "Direct Port I/O and Windows NT." К сожалению, я так и не нашел времени проверить приведенный там код. Статью и посвященный ей флейм вы можете почитать по адресу http://www.ddj.com.

Также рекомендую ознакомиться с опубликованной в Windows Developer Journal статьей "Port I/O under Windows." Опубликована Karen Hazzah в июне 1996 года. Статью и посвященный ей флейм вы можете найти по адресу http://www.wdj.com.

Визуальный компонент Comm32.

Вы спросите "Все это хорошо. Но есть ли визуальный компонент сторонних фирм, работающих с Com портом?". Да есть. И он называется Comm32. На мой взгляд, он один из лучших на сегодняшний день. Чтобы вам было легче с ним разобраться я приведу пример, реализации данного компонента.

Программа называется Psion. Она задумывалась для тестирования теплосчетчиков Clorius.

В первый Edit мы вводим сетевой адрес теплосчетчика. По умолчанию он равен 0. С помощью второго мы посылаем команды теплосчетчику. Третий Edit служит для вывода информации, которую теплосчетчик посылает нам.

Вот исходный текст программы написанной на Delphi5:

type    TXXXX=array[1..255] of Char;  //Определяем символьный массив  PXXXX=^TXXXX;

//Функция отвечающая за подсчет контрольной суммы
function TForm1.CheckSum(AStr: String): Char;  
var crc,i: Integer;  //Вводим свои целочисленные переменные
begin  
crc:=0;  
for i := 1 to Length(AStr) do     
crc:=crc+Ord(AStr[i]);          
crc:=(crc and $3F) + $30;  
Result:=Chr(crc);
end;

//Функция сравнивания контрольной суммы с полученными данными
function TForm1.CompareCheckSum(AStr: String; CS: Char): boolean;
begin    
Result:=CheckSum(AStr)=CS;
end;

//Возвращает тело пакета без сетевого адреса и контрольной суммы
function TForm1.GetInput: String;
var l:integer;
begin  
Result:='';  
l:=Length(FInput);  
if InputState = 1 then 
begin
 if StartTime+3000 < GetTickCount then InputState := 2;     
 Exit;  
end;  
if l<3 then Exit;  
if CompareCheckSum(Copy(FInput,1,l-2),Copy(FInput,l-1,1)[1])=true  then  
begin     
InputState := 0;     
NetNumber:=FInput[1];     
AddrEdt.Text:=NetNumber;     
Result:=copy(FInput,2,l-3);  
end  
else     
InputState := 3;
end;

//Данная процедура возникает, когда мы пытаемся послать команду
//устройству
procedure TForm1.SetOutput(const Value: String);
var XXXX:TXXXX;
    S:String;    
    L,i:Integer;
begin  
S:=NetNumber+Value;  
S:=S+CheckSum(S)+#13;  
L:=Length(S);  
if L>255 then Exit;  
for i:=1 to L do XXXX[i] := S[i];  
InputState := 1;  
FInput:='';  
CommPortDriver1.SendData(@XXXX,L);  
StartTime:=GetTickCount;
end;

//Процедура возникает при запуске программы
procedure TForm1.FormCreate(Sender: TObject);
begin  
NetNumber:='0';  
CommPortDriver1.Connect;
end;

//Процедура возникает при выходе из программы
procedure TForm1.FormDestroy(Sender: TObject);
begin  
CommPortDriver1.Disconnect;
end;

//Процедура возникает при ответе устройства
procedure TForm1.CommPortDriver1ReceiveData(Sender: TObject;  DataPtr: Pointer; DataSize: Integer);
var PX:PXXXX;    
    i:integer;
begin 
InputState := 4; 
Application.ProcessMessages; FInput:=''; 
PX:=DataPtr; 
for i := 1 to DataSize do 
begin   
 FInput:=FInput+PX^[i]; 
end; 
InputState := 5; 
Application.ProcessMessages; 
Edit2.Text:=Input;
end;

//Процедура возникает при подборе визуального состояния программы 
procedure TForm1.SetInputState(const Value: integer);
begin  
FInputState := Value;  
case Value of
    0: Caption:='Данные успешно приняты';   
	1: Caption:='Ждем ответа';    
	2: Caption:='Таймаут';    
	3: Caption:='Пакет принят с ошибкой';    
	4: Caption:='Принимаем ответ';    
	5: Caption:='Ответ получен';  
end;
end;

//Процедура возникает при нажатии клавиши "Отправить"
procedure TForm1.SendBtnClick(Sender: TObject);
begin 
Output:=OutputEdt.Text; 
SendBtn.Enabled:=False; 
repeat  
 Edit2.Text:=Input; 
until InputState<>1; 
SendBtn.Enabled:=True;
end;

//Процедура возникает при изменении сетевого адреса устройства
procedure TForm1.AddrEdtChange(Sender: TObject);
begin 
NetNumber:=AddrEdt.Text[1];
end;         

Если возникнут, какие либо вопросы или вы встретите какие либо технические неувязки в данной статье, вы можете мне написать по e-mail.

   Внимание! Запрещается перепечатка данной статьи или ее части без согласования с автором. Если вы хотите разместить эту статью на своем сайте или издать в печатном виде, свяжитесь с автором.
Автор статьи:  Фофанов Дмитрий
  

Другие статьи Наверх


  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо