ООО ЭФО
Поиск по складу
Программа поставок 2016
Сегодня
www.powel.ru
источники питания
www.korpusa.ru
конструктивы и корпуса РЭА
www.wless.ru
беспроводные технологии
www.mymcu.ru
микроконтроллеры
altera-plis.ru
микросхемы Altera
www.infiber.ru
волоконно-оптические
компоненты в
промышленности
www.efo-power.ru
силовая электроника
www.efo-electro.ru
электротехническая
продукция
www.efometry.ru
контрольно-измерительные приборы
www.golledge.ru
кварцевые резонаторы и генераторы Golledge
www.sound-power.ru
профессиональные усилители класса D
Поиск по сайту
Подписка на новости

Система менеджмента
качества сертифицирована на соответствие требованиям:
ISO 9001, ГОСТ Р ИСО 9001 и СРПП ВТ - подтверждено сертификатами соответствия в системах сертификации Русского Регистра, ГОСТ Р, международной сети IQNet, "Оборонсертифика" и "Военный Регистр".

ООО "ЭФО" в 2011г. получило Лицензию Федеральной службы по экологическому, технологическому и атомному надзору на изготовление оборудования для ядерных установок.


Rambler s Top100



ChipFind - поисковая система по электронным компонентам
EEN
webmaster
Санкт-Петербург: (812) 327-86-54  zav@efo.ru Москва: (495) 933-07-43  moscow@efo.ru Екатеринбург: (343) 278-71-36  ural@efo.ru Пермь: (342) 220-19-44  perm@efo.ru
Казань: (843) 518-79-20  kazan@efo.ru Ростов-на-Дону: (863) 220-36-79  rostov@efo.ru Н. Новгород: (831) 434-17-84  nnov@efo.ru Новосибирск: (383) 286-84-96  nsib@efo.ru
о нас склад библиотека статьи
 
Использование VCP-драйвера

Преимущество VCP-драйвера заключается в том, что для обмена данными по USB можно использовать ранее созданные программы ввода, предназначенные для работы с COM-портом, при условии, что эти программы осуществляли корректный доступ к последовательному порту через стандартные WIN32 API-функции. В этом случае модификация программы будет заключаться лишь в замене номера последовательного порта.

Следует отметить, что VCP-драйвер поддерживает работу со всеми микросхемами FTDI независимо от того, какой способ связи с микроконтроллером они используют: последовательный (как у FT232BM) или параллельный (как у FT245BM). Конечно, в последнем случае теряют смысл настройки коммуникационного порта, задающие режимы функционирования линий квитирования интерфейса RS232.

USB-интерфейс предусматривает возможность одновременной работы с несколькими устройствами. Последние идентифицируют себя, посылая хосту при подключении к шине свои дескрипторы, которые содержат идентификаторы устройства и информацию о режимах использования шины. Если микросхемы FTDI используются без внешней EEPROM, то при формировании дескрипторов подставляются стандартные идентификаторы FTDI (VID=0x0304, PID=0x6001). При этом сохраняется возможность использовать на шине несколько устройств, которые в этом случае различаются по номеру используемого USB-разъема. Вместе с тем пользователь может задать свои настройки путем подключения внешней микросхемы EEPROM типа 93С46 (64 x 16 бит), 93С56 (128 х 16 бит) или 93С66(256 х 16 бит). При этом для идентификации удобно использовать стандартные VID и PID - идентификаторы FTDI, но задавать свои собственные строковые идентификаторы для описания производителя и устройства.

Следует отметить, что запись и считывание EEPROM через USB становятся возможными только при использовании D2xx-драйвера.

Установка VCP-драйвера состоит из следующих шагов:

  1. Необходимо удостовериться, что на компьютере нет установленных ранее драйверов FTDI. Если это не так, то необходимо предварительно их удалить, используя в панели управления раздел "установка и удаление программ".
  2. Подключить к компьютеру микропроцессорное устройство, осуществляющее вывод данных на USB при помощи микросхем FTDI.
  3. Операционная система обнаружит новое устройство и попытается установить драйвер для него. Пользователь должен указать директорию, в которой расположен VCP-драйвер.Установка осуществляется за два этапа. Сначала устанавливается VCP-драйвер, а затем драйвер COM-порта.
  4. По завершении установки операционная система сообщит, что устройство успешно установлено и готово к работе. В окне менеджера устройств появится дополнительный последовательный Com-порт. Теперь можно обращаться к нему из рабочего приложения при помощи стандартных WIN32 API-функций.
  5. При необходимости можно поменять номер виртуального последовательного порта. Для этого в менеджере устройств нужно выбрать пункт Порты (COM и LPT) > USB последовательный порт > Свойства Параметры порта > Дополнительно и задать требуемый номер порта.

Организация обмена данными с последовательными портами при помощи Win32API функций

Для организации доступа к последовательному порту из Windows-приложения используют механизм доступа к файлу при помощи стандартных WIN32 API-функций, перечисленных в таблице 1.

Сначала необходимо открыть порт (файл), после этого следует настроить все его параметры. Затем можно выполнять операции ввода/вывода и по их завершении необходимо закрыть порт (файл).

Таблица 1
Название функции Назначение функции
HANDLE CreateFile(...) Открытие последовательного порта
BOOL CloseHandle(...) Закрытие последовательного порта
BOOL SetCommState(...) Установка параметров порта
BOOL SetCommTimeouts(...) Настройка таймаутов порта
BOOL ReadFile(...) Чтение из порта
BOOL WriteFile(...) Запись в порт

Рассмотрим более подробно эти шаги.

Прототип функции, открывающей порт, выглядит следующим образом:

HANDLE CreateFile(
  LPCTSTR
  DWORD
  DWORD
  LPSECURITY_ATTRIBUTES   
  DWORD
  DWORD
  HANDLE
);

При успешном открытии порта (файла), функция возвращает описатель (HANDLE) файла. При ошибке возвращается значение INVALID_HANDLE_VALUE.

Открытый порт должен быть закрыт перед завершением работы программы. В Win32 закрытие объекта по его описателю выполняет функция CloseHandle:

BOOL CloseHandle{
  HANDLE    hObject
};

Функция имеет единственный параметр - описатель закрываемого объекта. При успешном завершении функция возвращает ненулевое значение, при ошибке - нуль.

Открыв порт, программа получает его в своё распоряжение, и работать с ним сейчас может ТОЛЬКО эта программа. Для остальных программ порт занят.

Теперь необходимо настроить параметры порта. Основные параметры описываются структурой DCB. Временные параметры - структурой COMMTIMEOUTS. Настройка порта заключается в заполнении вышеуказанных структур с последующим вызовом функций настройки.

Рассмотрим структуру DCB:

typedef struct _DCB {
  DWORD   //sizeof(DCB)
  DWORD //current baud rate
  DWORD //binary mode, no EOF check
  DWORD //enable parity checking
  DWORD //CTS output flow control
  DWORD //DSR output flow control
  DWORD //DTR flow control type
  DWORD //DSR sensitivity
  DWORD //XOFF continues Tx
  DWORD //XON/XOFF out flow control
  DWORD //XON/XOFF in flow control
  DWORD //enable error replacement
  DWORD //enable null stripping
  DWORD //RTS flow control
  DWORD //abort reads/writes on error
  DWORD //reserved
  WORD //not currently used
  WORD //transmit XON threshold
  WORD //transmit XOFF threshold
  BYTE //number of bits/byte, 4-8
  BYTE //0-4=no,odd,even,mark,space
  BYTE //0,1,2 = 1, 1.5, 2
  char //Tx and Rx XON character
  char //Tx and Rx XOFF character
  char //error replacement character
  char //end of input character
  char //received event character
  WORD //reserved; do not use
} DCB;

Так как поля структуры DCB традиционно использовались для конфигурирования микросхем портов, на них накладываются некоторые ограничения. Так, параметр ByteSize может принимать только значения 5, 6, 7 или 8 бит. Не допускается одновременно задавать значения ByteSize=5 и StopBits=2, а также ByteSize=6/7/8 и одновременно StopBits=1,5.

Новую (пустую) DCB структуру можно заполнить при помощи функции GetCommState. Эта функция заполняет DCB информацией о текущем состоянии устройства, точнее о его настройках. Вот как она выглядит:

BOOL GetCommState(
  HANDLE   hFile,
  LPDCB lpDCB
);

У неё всего два параметра: указатель на открытый последовательный порт и указатель на DCB структуру (под неё должен быть выделен блок памяти)

После заполнения DCB структуры, необходимо сконфигурировать порт (установить параметры). Это делается при помощи функции SetCommState:

BOOL SetCommState(
  HANDLE   hFile,
  LPDCB lpDCB
);

Эта функция имеет точно такие же параметры, как GetCommState. Различается только направление передачи информации. GetCommState считывает информацию из внутренних управляющих структур и регистров порта, а SetCommState наоборот заносит ее. Следует быть осторожным при вызове функции SetCommState, поскольку она изменит параметры даже в том случае, если очереди приема/передачи не пусты, что может вызвать искажение потока передаваемых или принимаемых данных.

Следующей важной управляющей структурой является COMMTIMEOUTS. Она определяет параметры временных задержек при приеме и передаче.

typedef struct _COMMTIMEOUTS {
  DWORD  
  DWORD
  DWORD
  DWORD
  DWORD
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;

Как и для заполнения структуры DCB, для COMMTIMEOUTS существует функция считывания установленных в системе значений. Это функция GetCommTimeouts:

BOOL GetCommTimeouts(
  HANDLE hFile,
  LPCOMMTIMEOUTS   lpCommTimeouts
);

Заполнив структуру COMMTIMEOUTS можно вызывать функцию установки таймаутов порта. Это функция называется SetCommTimeouts:

BOOL SetCommTimeouts(
  HANDLE hFile,
  LPCOMMTIMEOUTS   lpCommTimeouts
);

Теперь перейдём непосредственно к приёму и передаче данных через порт. Так как мы работаем с портом, как с файлом, то и чтение/запись производятся так же, как и при работе с файлом, то есть с помощью функций ReadFile и WriteFile.

BOOL ReadFile(
  HANDLE
  LPVOID
  DWORD
  LPDWORD
  LPOVERLAPPED  
);

BOOL WriteFile(
  HANDLE
  LPVOID
  DWORD
  LPDWORD
  LPOVERLAPPED  
);

Рассмотрим пример организации структуры рабочей программы.

#include

. . .

DCB *dcb;
COMMTIMEOUTS   ct;
HANDLE hPort;
char *buf_out;
DWORD bc;


. . .

         // задание параметров порта
dcb=(DCB*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DCB));
dcb->DCBlength=sizeof(DCB);
dcb->BaudRate=CBR_9600;
dcb->ByteSize=8;
dcb->StopBits=1;
dcb->fParity=FALSE;
dcb->fNull=TRUE;

         // задание таймаутов порта
ct.ReadIntervalTimeout=10;
ct.ReadTotalTimeoutMultiplier=ct.ReadTotalTimeoutConstant=0;
ct.WriteTotalTimeoutMultiplier=ct.WriteTotalTimeoutConstant=0;


hPort=CreateFile("COM1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0, NULL);   // открытие порта

SetCommState(hPort,dcb);          // установка параметров порта
SetCommTimeouts(hPort,&ct);   // установка таймаутов порта

         // выполнение операций ввода/вывода
buf_out="Test";
WriteFile(hPort,buf_out,strlen(buf_out),&bc,NULL);

. . .

CloseHandle(hPort);         // закрытие порта

Как видно, инициализация порта состоит из нескольких шагов: заполнения структур DCB и COMMTIMEOUTS, открытия порта и назначения соответствия между портом и инициализирующими структурами DCB и COMMTIMEOUTS.

В приведенном примере общие таймауты операций чтения и записи не используются, конец сообщения определяется по таймауту между двумя последовательными символами, большему чем10 миллисекунд.

После инициализации в основном цикле программы происходит обмен данными с портом, перед завершением программы порт закрывается.

Недостатком рассмотренного выше синхронного режима работы с портом является то, что программа вынуждена ждать окончания операции ввода/вывода. Для того, чтобы иметь возможность выполнять в это время какую-либо полезную работу, необходимо использовать асинхронный режим работы. Чтобы открыть порт в асинхронном режиме, в качестве параметра dwFlagsAndAttributes функции CreateFile() вместо 0 следует указать FILE_FLAG_OVERLAPPED. Кроме того, для функций ReadFile и WriteFile необходимо в качестве параметра lpOverlapped указывать адрес правильно инициализированной структуры OVERLAPPED, которая выглядит следующим образом:

typedef struct _OVERLAPPED {
  DWORD Internal;
  DWORD InternalHigh;
  DWORD Offset;
  DWORD OffsetHigh;
  HANDLE   hEvent;
} OVERLAPPED, *LPOVERLAPPED;

В простейшем случае можно просто обнулить все поля этой структуры.

Функции записи/чтения для файла, открытого в асинхронном режиме, будут немедленно возвращать управление с кодом ошибки ERROR_IO_PENDING. Это означает, что асинхронная операция успешно стартовала. Если возвращается другой код ошибки, то операция не стартовала (например, из-за ошибки в параметрах). Теперь можно спокойно заниматься другой работой, периодически проверяя, завершилась ли операция ввода/вывода. Эта проверка выполняется функцией GetOverlappedResult, которая выглядит следующим образом:

BOOL GetOverlappedResult(
  HANDLE
  LPOVERLAPPED  
  LPDWORD
  BOOL
);

Рассмотрим пример организации программы для выполнения обмена данными с портом в асинхронном режиме:

HANDLEhPort;
Char*buf;
OVERLAPPED  ovr;
DWORDbc;
INTbuf_size;

// открытие порта
hPort=CreateFile("COM1",GENERIC_READ,0,NULL,OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); // заполнение нулями полей структуры ovr
memset(&ovr,0,sizeof(ovr));
ovr.hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);

    // чтение из порта
ReadFile(hPort,buf,buf_size,&bc,&ovr);        //Выполняем некую полезную работу
    // чтение полученных байт
GetOverlappedResult(hPort,&ovr,&bc,FALSE);
    // закрытие порта
CloseHandle(hPort);
CloseHandle(ovr.hEvent);

В этом примере переменная bc, предназначенная для получения количества считанных байт, после вызова ReadFile будет равна 0, так как никакой передачи информации еще не было. После вызова GetOverlappedResult в эту переменную будет помещено число реально считанных байт.

Еще одним способом организации работы с последовательным портом является использование многопотоковой обработки.

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

Потоки создаются функцией CreateThread и уничтожаются функцией ExitThread (или всё той же CloseHandle).

Прототип функции CreateThread выглядит следующим образом:

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES  
  SIZE_T
  LPTHREAD_START_ROUTINE   
  LPVOID
  DWORD
  LPDWORD
);

Мы привели здесь основные функции, необходимые для работы с последовательными портами. Существуют и другие функции WIN32 API, которые позволяют осуществлять более сложные манипуляции, связанные с коммуникационными портами. Их описание можно найти, например, в широко известной справочной системе MSDN.

Скорость обмена данными при использовании VCP-драйвера

Использование VCP-драйвера описанными выше способами позволило получить минимальную скорость передачи данных - 1200 бит/сек, максимальную - 256000 бит/сек. Ограничение скорости обусловлено использованием DCB структуры. Поле этой структуры, которое устанавливает скорость обмена, может принимать только дискретные значения. А так как DCB структура первоначально создавалась для низкоскоростного коммуникационного порта RS232, то максимально возможное значение скорости обмена данными тоже сильно ограничено.

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

Теперь Вы имеете все необходимое для того, чтобы приступить к написанию своей программы обмена данными через USB с использованием VCP-драйвера компании FTDI.

Но хочется подчеркнуть еще раз, что основное назначение VCP-драйвера состоит в том, чтобы использовать при обмене данными по USB ранее написанные программы для стандартного компьютерного порта RS232. VCP-драйвер не позволяет получить максимально возможные для кристаллов FTDI скорости передачи данных и не позволяет осуществлять чтение/запись внешней EEPROM через USB из Windows-приложения.

Использование D2XX-драйвера FTDI

© 1999-2016 All Right Reserved. EFO Ltd. При использовании материалов ссылка на источник обязательна.
Контактная информация