|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
Асинхронное чтение принятых байтов от COM-порта
Пишу программу на Delphi 7 для управления устройством на микроконтроллере. Устройство подключается к COM-порту. Устройство работает по следующему принципу: программа посылает один или несколько байт, которые устройство расценивает как команды. В зависимости от команды оно посылает соответствующий ответ в виде одного или нескольких байт.
В программе есть два потока. Один – для чтения, второй – для записи в порт. Поток чтения постоянно запущен. Как только приходят байты, происходит их считывание в буфер, представляющий собой TList. Поток записи запускается по необходимости. Мне нужно контролировать принятые байты, чтобы знать, как устройство отреагировало на команды. Так вот вопрос следующий: как мне заставить программу подождать, пока в списке TList появится первый элемент, т.е. придет хотя бы один байт? В микроконтроллере это реализуется просто. Запускается цикл while, в котором ожидается наступление какого-то события, например установки какого-либо флага. Если использовать такой метод в моей программе, то она будет зависать. Как организовать ожидание прихода байта (или нескольких байт), без зависания программы? |
#2
|
|||
|
|||
Чтение должно происходить в не в основном потоке программы, а в специально созданном для этого. Тогда зависания окна программы не будет. Что бы поток не грузил проц на 100% нужно его приостанавливать, а пробуждать по приходу байта в порт. делается примерно так:
Код:
procedure TRdThread.Execute; Var ComStat:TComStat; //состояние порта Errs:Cardinal; RdOvr:TOverlapped; //параметры асинхронной операции чтения begin FillChar(RdOvr,SizeOf(TOverlapped),0);// инициализируем структуру TOverlapped RdOvr.hEvent:=CreateEvent(nil, //параметры защиты, если nil, то беруться от родительского процесса true, //режим управления событием false,//начальное состояние false - несигнальное состояние (занят) nil //имя обекта nil - нет имени ); SetCommMask( //задаем события, которые будут отслеживаться портом Port, //дескриптор порта //EV_RXCHAR //маска событий EV_RXCHAR-принят байт EV_RXFLAG //маска событий EV_RXCHAR-принят байт ); while not Terminated do begin WaitCommEvent( // инициируем ожидание Port, //дескриптор порта mask, //маска событий @RdOvr //указатель на WrOvr ); WaitForSingleObject(RdOvr.hEvent,INFINITE); //ждем GetOverlappedResult(Port,RdOvr,nRead,false); //после этого в переменной mask будет маска того события которое произошло ClearCommError(Port,Errs,@ComStat); //считываем состояние порта nToRead:=ComStat.cbInQue; //считываем число байт для чтения из структуры GetMem(RcBuf,nToRead); if not ReadFile(Port,RcBuf^,nToRead,nRead,@RdOvr) //считываем данные then Synchronize(UpdateMainFormlabel5) //Если данные не считались выводим сообщение об ошибке else Synchronize(UpdateMainForm); //Если данные считались выводим их на форму FreeMem(RcBuf); //Освободим буфер end; end; С помощью CreateEvent сначала создаем объект "событие", потом настраиваем COM порт (функция SetCommMask) так что бы при определенных событиях (например прием байта) изменялось состояние объекта "событие", созданного функцией CreateEvent. Потом "связываем" нужный порт с нужным объектом "событием" с помощью функции WaitCommEvent, затем останавливаем поток(WaitForSingleObject), который проснется автоматически как только изменится сотояние "события", а оно меняется при появлении данных. Вот как то так. http://compconnect.ru/ - как подключить микроконтроллер к компьютеру |
#3
|
|||
|
|||
Спасибо, Grey_p9! Но это у меня уже так и было реализовано. Вопрос был в другом. Я решил эту проблему с помощью Application.ProcessMessages
Теперь вопрос в другом: WaitForSIngleObject ждет одного байта, и буффер заполняется только на один байт и потом снова на один, а как мне сделать, чтобы он заполнялся пачками байтов по 8 штук? |
#4
|
|||
|
|||
можно ждать не прихода первого байта, а прихода определенного символа, например символа конца строки и в конце каждой посылки из контроллера вставлять этот символ. Для этого в SetCommMask нужно использовать вместо EV_RXCHAR (событие возникает при приеме любого байта) EV_RXFLAG (событие возникает при приеме байта определенного в структуре DCB в поле EvtChar)
http://compconnect.ru/ - как подключить микроконтроллер к компьютеру Последний раз редактировалось Grey_p9, 18.06.2010 в 11:39. |