Приветик всем! Помогите девушке написать программу на Паскале для работы с Com-портом! надо считать данные из одного приборчика 
Программирование Com-порта
Программирование Com-порта
|
28.01.2010 21:44:40
|
|
|
|
|
|
31.01.2010 23:31:17
С радостью, а чуть-чуть конкретнее можете описать проблему? Хоть что-нибудь в данном направлении сделано. Если ничего не сделано тоже не страшно. Будем решать проблему с нуля. Вы программу на чем пишите Delphi, TurdoPascal или еще в чем-то?
|
|
|
|
|
|
13.03.2010 21:22:10
Вот неплохая статья в интернет нашел, может поможет =) + исходник
Вступление Порядок запуска и работы "службы" (назовем все описываемое ниже так) Com-портов состоит из нескольких достаточно хорошо описанных шагов ( см. статьи по теме ): 1. Инициализация Com-порта посредством вызова функции CreateFile. 2. Установка параметров Com-порта посредством последовательного вызова функций GetCommState и SetCommState, а также SetupComm. 3. Установка параметров тайм-аутов для чтения и записи - GetCommTimeouts и SetCommTimeouts. 4. Собственно записи в Com-порт - WriteFile и чтения из него - ReadFile. 5. Закрытие порта по окончанию работ CloseHandle. Очень большой сложности описанные выше шаги не представляют, однако реализация чтения данных из порта в асинхронном (неблокирующем) режиме заставляет почесать затылок. Об этом и поговорим. Чтение из Com-порта. Судя по контексту справки, касающейся функции CreateFile, для "отлова" момента поступления данных в Com-порт следует использовать функцию WaitCommEvent. Предварительно установив маску SetCommMask на то событие, которое хотелось бы отследить. Нужное событие наступает - вызываем функцию ReadFile для чтения поступающих данных. Казалось бы все в порядке, но... Вызов функции WaitCommEvent насмерть тормозит приложение, пока какие-либо данные не поступят в Com-порт. Можно конечно, просто взять и запустить в непрерывном цикле ReadFile, однако приложение хотя и будет как-то шевелиться, но это шевеление скорее всего будет напоминать предсмертные судороги. Как выход из ситуации многие предлагают использовать потоки (thread), забывая при этом описать как это делать Итак потоки. В модуле Classes для потоков определен специальный класс TThread. Для создания потоков специалисты рекомендуют использовать именно его, а не создавать потоки используя BeginThread и EndThread, т.к. библиотека VCL не является защищенной для потоков в такой реализации. Следуя советам экспертов, для организации контроля поступающих данных в Com-порт и будем использовать готовый класс TThread. В раздел interface определим тип переменных этого класса, переопределив только один метод класса - Execute, ну и дополнительно объявим свой метод, который и займется опросом Com-порта. Далее в разделе глобальных переменных определим поток-переменную полученного выше типа CommThread:TCommThread; //наш поток, в котором будет работать процедура опроса порта Затем в разделе implementation начинаем ваять. ВНИМАНИЕ!!! К этому времени порт уже должен быть инициализирован функцией CreateFile. 1. 1. Инициализируем поток, используя метод Create. type //определим тип TComThread - наследника класса TThread TCommThread = class(TThread) private //процедура, занимающаяся опросом порта procedure QueryPort; protected //переопределим метод запуска потока procedure Execute; override; end; procedure StartComThread; //инициализация нашего потока begin {StartComThread} //пытаемся инициализировать поток CommThread := TCommThread.Create(False); //проверяем получилось или нет if CommThread = nil then begin {Nil} //ошибка, все выключаем и выходим SysErrorMessage(GetLastError); fmMain.btnStop.Click; Exit; end; {Nil} end; {StartComThread} Куски кода взяты из файла проекта, поэтому нажимание на кнопку btnStop главной формы fmMain - это "примочки" примера, не обращайте внимания. 2. Запускаем процедуру опроса порта в нашем потоке. procedure TCommThread.Execute; begin {Execute} repeat QueryPort; //процедура опроса порта будет производиться пока поток не будет прекращен until Terminated; end; {Execute} 3. Реализуем асинхронные опрос порта и чтение из него данных procedure TCommThread.QueryPort; var MyBuff: array[0..1023] of Char; //буфер для чтения данных ByteReaded: Integer; //количество считанных байт Str: string; //вспомогательная строка Status: DWord; //статус устройства (модема) begin {QueryPort} //получим статус COM-порта устройства (модема) if not GetCommModemStatus(hPort, Status) then begin {ошибка при получении статуса модема} //ошибка, все выключаем и выходим SysErrorMessage(GetLastError); fmMain.btnStop.Click; Exit; end; {ошибка при получении статуса модема} //Обработаем статус устройства (модема) и будем включать(выключать) лампочки //готовность устройства (модема) получать данные fmMain.imgCTSOn.Visible := ((Status and MS_CTS_ON) = MS_CTS_ON); //готовность устройства (модема) к сеансу связи fmMain.imgDSROn.Visible := ((Status and MS_DSR_ON) = MS_DSR_ON); //принимаются данные с линии сигнала fmMain.imgRLSDOn.Visible := ((Status and MS_RLSD_ON) = MS_RLSD_ON); //входящий звонок fmMain.imgRingOn.Visible := ((Status and MS_RING_ON) = MS_RING_ON); //читаем буфер из Com-порта FillChar(MyBuff, SizeOf(MyBuff), #0); if not ReadFile(hPort, MyBuff, SizeOf(MyBuff), ByteReaded, nil) then begin {ошибка при чтении данных} //ошибка, все закрываем и уходим SysErrorMessage(GetLastError); fmMain.btnStop.Click; Exit; end; {ошибка при чтении данных} //данные пришли if ByteReaded > 0 then begin {ByteReaded>0} //посчитаем общее количество прочитанных байтов ReciveBytes := ReciveBytes + ByteReaded; //преобразуем массив в строку Str := string(MyBuff); //отправим строку на просмотр fmMain.Memo1.Text := fmMain.Memo1.Text + Str; //покажем количество считанных байтов fmMain.lbRecv.Caption := 'recv: ' + IntToStr(ReciveBytes) + ' bytes...'; end; {ByteReaded>0} end; {QueryPort} На этом по поводу использования потоков для считывания данных из Com-порта, пожалуй, все. Прилагающийся пример Следуя правилам хорошего тона, прикладываю ко всему написанному работающий пример. В примере используется самое доступное устройство для пользователей интернет - модем (на Com-порту). В качестве "примочек" я использовал лампочки, которые включаются (или выключаются) при изменении статуса модема. Можно было прикрутить лампочки-детекторы входящих-выходящих сигналов, но вместо них используются счетчики байтов. Реализация кода включения-выключения не самая лучшая: можно было бы использовать TImageList для хранения изображений лампочек. Но почему-то ??? (кто знает почему - напишите) использование ImageList.GetBitmap при наличии запущенного потока "подвешивает" приложение насмерть. Причем это происходит под Windows'98, если тоже самое делать под Windows'95, то все в порядке. Для проверки работоспособности примера попробуйте понабирать AT-команды * ATZ - инициализировать модем * ATH - положить трубку * ATH1 - поднять трубку * ATS0=1 - включить автоподнятие трубки на первый сигнал * ATS0=0 - выключить автоподнятие трубки * ATDP_номер_телефона_интернет_провайдера - мне нравится больше всего * ATDP - набор в импульсном режиме, ATDT - набор в тоновом режиме Да, еще. Проект написан под Delphi3, при использовании Delphi более свежих версий возможны ошибки "несовпадения типов". В этом случае поменяйте типы "ошибочных" переменных с Integer на Cardinal.
Хочется сказать больше, та вот длины TMemo не хватает.
|
|
|
|
|
|
12.12.2010 19:09:34
Открытие порта:
HANDLE CreateFile( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDistribution, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile );
Cyber
|
|
|
|
|
|
12.12.2010 19:12:15
lpFileName — указатель на строку с нулевым завершающим символом. Обычно это имя открываемого файла, но в нашем случае это должно быть название порта (COM1, COM2, …).
dwDesiredAccess — тип доступа. В нашем случае должен быть равен GENERIC_READ|GENERIC_WRITE. dwShareMode — параметр совместного доступа. Для коммуникационных портов всегда равен 0. lpSecurityAttributes — атрибут защиты. Для коммуникационных портов всегда равен NULL. dwCreationDistribution — режим автосоздания. Для коммуникационных портов всегда равен OPEN_EXESTING. dwFlagsAndAttributes — атрибут режима обработки. Для коммуникационных портов должен быть равен 0 или FILE_FLAG_OVERLAPPED. hTemplateFile — описатель файла-шаблона. Для коммуникационных портов должен быть равен NULL. При успешном открытии порта функция возвращает его описатель, а в случае ошибки возвращает INVALID_HANDLE_VALUE.
Cyber
|
|
|
|
|
|
12.12.2010 19:12:38
Это на Delphy
Cyber
|
|
|
|
|
|
14.12.2010 10:58:50
На C минус минус
|
||||
|
|
|
|||
Читают тему (гостей: 1, пользователей: 0, из них скрытых: 0)