Re[7]: чтение из FTDI-устройства
От: grom555 Беларусь  
Дата: 11.07.07 12:59
Оценка:
Здравствуйте, cr lf, Вы писали:

CL>Наверное я тупой, но я не вижу разницы в твоих словах и в моем коде ;(

CL>Я читаю данные из USB, которые и описывают состояние датчика.
CL>Датчик является тем самым устройством, которое замыкает/размыкает цепь, подающую сигнал на вход микросхемы FTDI, а она в свою очередь переправляет его в USB.
Тогда вопрос: в какой момент начинать считывать инфу? Сейчас? Через минуту? Через 10 минут? Ведь для функции чтения есть TimeOut.
Прочитав все, могу спросить: Что будет, если машины совсем не поедут?

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

CL>>>Мне надо
CL>>>1. записать в устройство 4 байта — 00000000,000000001,00000010,00000011,
CL>>>2. дождаться прихода от него других 3-х байт — 00010000b,00001000,00000100.
CL>>>3. засечь интервалы времени между этими сигналами.
G>>Я обычно пишу свой класс для работы с устройствами, в котором есть поток, отвечающий за прием/передачу данных. В классе есть методы для
G>> отправки команд и события по их приходу с устройства. Поток должен иметь синхронизацию! Я использую критические секции и TEvent.
G>>Больше сказать сложно, т.к. не понятно назначение этих байт... Как часто нужно их получать...
CL>Непонятно насчет синхронизации ... ;(
CL>Мне там синхронизировать особенно нечего.
Когда работаешь с потоками, то синхронизация обязательна почти всегда. Особенно в случае, когда твой поток работает постоянно, а ты только подсовываешь ему различные данные для обработки или в качестве параметров. Или в случае, если поток выводит что-нить на экран.

CL>Записываемые байты пишутся с интервалом в 1 сек.

CL>После чего следует ожидать 00010000b,00001000b,00000100b именно в этой последовательности.
CL>Хотя 00010000b может прийти и раньше, чем будут отправлены в устройство первые 4 байта.
CL>Короче суть задачи:
CL>стоит автомобиль на старте, перед ним светофор.
CL>Зажигается
CL>- красный сигнал (00000000b)
CL>- красный сигнал (00000001b)
CL>- красный сигнал (00000010b)
CL>- зеленый сигнал (00000011b)
CL>Старт — срабатывает фотоэлемент — получаем 00010000b, начинаем отсчет времени.
CL>Где-то посередине дистанции другой фотоэлемент, проехав через который, получаем 00001000b.
CL>И в конце дистанции третий фотоэлемент, который даст нам 00000100b
CL>Вот собственно и все.
CL>Разве что, если у водителя дрогнут нервы, он может стартовать раньше зеленого сигнала и тогда мы получим сигнал от первого фотоэлемента раньше, чем запишем 00000011b
Вот теперь стало гораздо понятней!
Можно уже придумать архитектуру софта.
Например реализовать так:
I) Создать класс для работы с USB устройством
Методы (необходимые): -подключить устройство
-отключить устройство
-послать байт
События: -сработал фотоэлемент номер N
В этом классе должен быть поток по приему/передаче данных. В теле потока пишешь процедуру:
while not Terminated do
begin
1) Если есть данные для отправки, то отправить
2) Читать из порта с таймаутом ~100ms (таймаут должен быть небольшой <1sec)
3) Если принято сообщение от датчика, то вызов обработчика события с номером датчика (обработчик не должен быть длительным, т.к. здесь происходит затык в ходе выполнения потока)
end;
При вызове метода "-подключить устройство" нужно законектиться с USB устройством и запустить поток.
При вызове метода "-отключить устройство" нужно вызвать у потока Terminate, подождать WaitFor и отконектить девайс.
При вызове метода "-послать байт" нужно вызвать у потока метод посылки байта в девайс. (вот тут и нужна синхронизация критическими секциями, т.к. два разных потока попытаются обратиться к одним данным). В методе потока по посылке просто устанавливаи переменную в нужное значение <>0, а в теле потока делай ее =0 после отправки;

Решение не самое красивое, но подойдет. Лучше конечно пользоваться WaitForSingleObject.

G>>>>Лучше конечно с устройствами работать в отдельных потоках, а при работе с портами использовать Overlap-структуры.

CL>>>Что такое Overlap-структуры ?
G>>Это просто другой способ общения через порты. Почитай... Есть доки. Даже в справке Delphi описано. Основной смысл в том, что ты НЕ
G>> ИСПОЛЬЗУЕШЬ просто ReadFile/WriteFile и не ждешь данных, а можешь повесить на прием евент и ждать его WaitForSingleObject (тогда будешь
G>> точно знать когда пришли данные и прога не останавливает работу).
CL>Вот я и говорю, что есть там какая-то FT_SetEventNotification

CL>
CL>FT_STATUS FT_SetEventNotification (FT_HANDLE ftHandle, DWORD dwEventMask, PVOID pvArg)
CL>Sets conditions for event notification.
Она и нужна для Overlap.

CL>Parameters
CL>ftHandle - Handle of the device.
CL>dwEventMask - Conditions that cause the event to be set.
CL>pvArg - Interpreted as the handle of an event.
CL>


CL>но воспользоваться ей у меня так и не получилось, хотя там и пример есть.

CL>Вот ты говоришь, что прога не останавливает работу...
CL>Как же не останавливает ?! — WaitForSingleObject в данном случае вешает программу навечно:
CL>
CL>hEvent := CreateEvent(0,false,false,'');
CL>FT_SetEventNotification(h,FT_EVENT_RXCHAR,@hEvent);
CL>WaitForSingleObject(hEvent,Infinite);
CL>FT_GetStatus(h,@RxBytes,@TxBytes,@EventDWord);
CL>if RxBytes > 0 then begin
CL>  FT_Read(h,@Buf,1,@Count);
CL>  WriteLn('buf = ',IntToBin(buf));
CL>end;
CL>

Навечно она останавливается из-за вызова WaitForSingleObject с параметром Infinite. Лучше всего вызывать WaitForSingleObject из какого-нить потока, ответственного за прием данных. (к моему примеру выше это не относится, хотя его можно переписать с использованием WaitForSingleObject)


G>>>> Хотя можно еще на таймер повесить проверку, но это не лучший стиль (лучше так не делать).

CL>>>Почему ?
G>>Потому, что это плохой стиль. Все равно что GOTO использовать.
CL>Остается TThread ?
Да. Таймером не привыкай пользоваться в таких задачах.

На будущее по поводу Overlap. Винда рекомендует пользоваться именно этим для работы с портами. Говорят, что стабильнее работает.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.