Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Чтение из COM-порта [D5, NT4, WinXP]


Sherev ©   (2002-09-18 17:31:00) 

Точно известно, что аппаратура посылает в порт 15 байт, а вот в программе принимаются только первые 8.
Подскажите, пожалуйста, в чем проблема.

Следующей процедурой осуществляется чтение из порта:

var Buf1: Array[1..20] of Byte;
read_bytes: DWORD;
j,i: Integer;
begin
repeat
FillChar(Buf1,SizeOf(Buf1),0);
ReadFile(hPort, Buf1, SizeOf(Buf1), read_bytes, nil);
if read_bytes>0 then begin
for i:=1 to SizeOf(Buf1) do
if Buf1[i]<>0 then
Form1.Memo2.Lines.Add(" Byte: "+IntToStr(Buf1[i])+
" Char: "+Chr(Buf1[i])+
" Bin: "+DecToBin(Buf1[i]));
end;
PurgeComm(hPort, PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR);


Sherev   (2002-09-19 13:43:00) [1]

Так оно и было: принималось 8 байт, затем очищались приемный и передающий буферы вместе с последними 7-ю байтами...

Все большое спасибо! ;-)


pasha676   (2002-09-19 12:11:00) [2]

Разберись с эвентами порта. Там есть всякие фенечки, типа читать порт только когда в нем набралось 15 символов или по приходу определенного символа. Ориентируйся на эти эвенты, а не на таймер.


Александр Спелицин   (2002-09-19 11:46:00) [3]

Все очень просто. Ваша программа / Железо / ОС / драйвер Com порта не знают (и не обязаны знать), сколько байт собирается послать некое устройство в порт.
ReadFile вернет управление, как только в буфере порта появятся какие-то данные. Если Вы говорите про 8 байт, значит так решила ОС. Это не означает, что про оставшиеся 7 она забыла, просто информация о том, что они помещены в буфер появится в следующий квант времени, отведенный системному потоку, который отвечает за работу с последовательными портами. 7 оставшихся байт Вы получите вызвав еще раз (или несколько раз) ReadFile.
А PurgeComm действительно очищает входящий буфер, вместе с 7-ю байт принятых следом. Используйте ее только при инициализации порта, а также перед отключением от него.


Sherev   (2002-09-19 11:43:00) [4]

Если убрать
PurgeComm(hPort, PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR);

то проблема исчезает.
Видимо чистить буферы нужно только при ошибках, а в остальных случаях буфер очищается сам после приема всего пакета.
Спасибо.


REA   (2002-09-19 10:43:00) [5]

> PurgeComm не шлет нули. Он очищает приемный (или передающий) буфер с полной потерей данных, так же как пурген очищает организм

Я тоже так думал, пока на осциллограф не посмотрел.
Он не во всех режимах шлет (PURGE_TXCLEAR только кажется).
Так что аналогия с пургеном очень к месту.

Sherev:
Может 10мс нехватает? Можно установить таймаут более чем на неск. байт, но не менее чем на 1 и читать пока читается в цикле, а буффер суммировать. Если некритично ко времени - просто увеличить таймаут. И еще: Checked может и не прокатить - события то не обрабатываются. И еще: раз данные в отдельном потоке используй синхронизацию при выводе в форму.


Sherev   (2002-09-19 09:53:00) [6]

Компоненты не желательны... хотелось бы на API.


Veey   (2002-09-19 09:38:00) [7]

Есть хороший компонентик Async32. Принимает все, что посылает аппаратура. Проверял


Sherev   (2002-09-19 08:59:00) [8]

Timeout устанавливаю следующим образом:
{ Set ComPort Time outs }
TimeOuts.ReadIntervalTimeout := MaxDWord;
TimeOuts.ReadTotalTimeoutMultiplier := MaxDWord;
TimeOuts.ReadTotalTimeoutConstant := 10;
SetCommTimeOuts(hPort, TimeOuts);

и полная функция чтения данных из порта (в отдельном потоке)

function MainReadDataOne(Data: Pointer): Integer; stdcall;
var Buf1: Array[1..20] of Byte;
read_bytes: DWORD;
j,i: Integer;
begin
repeat
FillChar(Buf1,SizeOf(Buf1),0);
ReadFile(hPort, Buf1, SizeOf(Buf1), read_bytes, nil);
if j>=10000 then begin Form1.Memo2.Clear; j:=0; end;
if read_bytes>0 then begin
for i:=1 to 20 do
if Buf1[i]<>0 then
Form1.Memo2.Lines.Add(" Byte: "+IntToStr(Buf1[i])+
" Char: "+Chr(Buf1[i])+
" Bin: "+DecToBin(Buf1[i]));
end;
PurgeComm(hPort, PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR);
until not Form1.CBox1.Checked;
Result:=0;
end;

а это не связано с аппаратным буфером?


Пурген   (2002-09-19 03:50:00) [9]

Ты пробовал применять пурген на себе?
PurgeComm не шлет нули. Он очищает приемный (или передающий) буфер с полной потерей данных, так же как пурген очищает организм. В остальном, как указал REA (18.09.02 18:02) - имеют значение таймауты порта.
Но главное. В общем случае прием данных из СОМ-порта не стоит выполнять одним вызовом ReadFile.


REA   (2002-09-18 18:02:00) [10]

А таймаут какой? Осторожнее с PurgeComm - он шлет нули


Наверх

Титульная страница Поиск, карта сайта Написать письмо