Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Системное программирование и WinAPI > Программирование интерфейса RS232 |
Автор: Gremlin 28.8.2006, 11:03 |
Если ктото имеет информацию по данному вопросу или писал программы большая просьба выложить здесь листинги функций или ссылки на них где люди смогут найти ответы на свои вопросы! А меня собственно интересует список апи функций для работы с этим интерфейсом! Заранее благодарен! |
Автор: chozen 28.8.2006, 23:34 |
bugtraq.ru/library/programming/rs232.html www.opennet.ru/openforum/vsluhforumID9/5319.html - первые же строчки гугла ![]() ![]() |
Автор: bel_nikita 28.8.2006, 23:53 | ||
Собственно одним списком не отделаешься ![]() Тема не раз уже обсуждалась. http://www.codeproject.com/system/serial.asp, правда сделано через MFC, но можешь "заточить" под себя |
Автор: Gremlin 29.8.2006, 21:01 |
ой а нет ли случайно у кого Агуров П. - Последовательные интерфейсы ПК. в электронном варианте выложите сцылочку Добавлено @ 21:08 да и ешо вот посмотрел я все выложенные сцылки! у меня в ммануале на прибор сказано типа команда LVn - выбор канала (n=1..10) или экзамплы (Pc->Instrument) TS4.85E+0 типа выставить погрешность дак вот я не понял как мне послать данные команды ![]() |
Автор: GremlinProg 30.8.2006, 07:43 |
В этом мануале и поищи формат команд для твоего девайса, для RS232 нет специализированного языка, каждый может использовать свой интерфейс ввода-вывода |
Автор: Gremlin 30.8.2006, 11:27 |
а вот я столкнулся с двумя случаями какой выбрать есть класс CSerial и HANDLE ? оба открывают порты устанавливают скорость и тд и тп |
Автор: chozen 30.8.2006, 11:31 |
Что-то мне сомнительным кажется наличие класса HANDLE... Мож это не класс, а что-нибудь другое ![]() ![]() ![]() Если одинаковые, используй тот, название которого передает смысл области применения - CSerial. |
Автор: Gremlin 30.8.2006, 11:39 | ||||
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. Добавлено @ 11:49
Написано так The protocol structure is defined in the syntax below. Data transfer takes place as simple ASCII protocol with Command code - 2 characters Parameters: 1..8 characters Separator: ,;:/ Terminators: <cr><lf>, <cr> or <lf> Blanks are ignored Upper and lower case letters are allowed и пример дан Command(PC -> Instrument): TS<cr> Replay(Instrument -> PC): TS4.26E+0<cr> |
Автор: GremlinProg 30.8.2006, 14:11 | ||||
ну, эта команда, по крайней мере понятна:
вот, к примеру её инициализация и посылка
RS232Write - условная функция для посылки в RS232 с двумя параметрами: 1 - адрес данных, 2 - размер данных PS: структуру надо упаковыть прагмой. |
Автор: Fixin 30.8.2006, 14:12 |
Пример посылки командыа это ответ: |
Автор: Fixin 30.8.2006, 14:31 | ||||
GremlinProg, ты думаешь? Вообщето, послав такую структуру мы не получим команду видаа что-то вроде
|
Автор: GremlinProg 30.8.2006, 16:11 | ||
Fixin, может быть... наверное 4.26E+0 - это и есть параметр, тогда нужно сделать иначе:
а в общем случае, если параметров несколько, разделять их чем нибудь из ",;:/" |
Автор: Gremlin 31.8.2006, 17:53 |
В хидере класса объявил DCB DcbPort; В конструкторе класса пишу DcbPort.ByteSize = 8; Поставил точку остановки после этого и смотрю значение DcbPort.ByteSize = 8 +'пустой квадратик' т.е. эта переменная имеет тип unsigned char, но как такое может быть если оно должно быть типа BYTE _DcbPort.ByteSize! Подскажите пожалуйста как решить данный трабл! |
Автор: _hunter 31.8.2006, 18:17 |
а BYTE это и есть unsigned char (правой кнопкой по BYTE тыкни и там выбери Goto declaration) |
Автор: Fixin 2.9.2006, 21:51 |
ну это уже офтоповый трабл - это раз, и в чем проблема-то - это два. имхо, квадратик после циферки в дебаггере - это отображения символа из таблицы ASCII по номеру, в данном случае, 8 - неотображаемый символ, вот и видишь ты квадратик пустой. |
Автор: Gremlin 3.9.2006, 12:43 | ||
Как мне послать устройству команды описанные выше например TS
BYTE WriteBytes[2] = "TS"; --- вот здесь как записать команду |
Автор: GremlinProg 3.9.2006, 13:24 | ||||
показал ведь уже:
после выполнения sprintf, в массиве WriteBytes будет содержаться команда TS4.26E+0<CR> Здесь epsilon выставили в 4.26E+0, но если её поменяешь, соответственно поменяется и команда в массиве WriteBytes отправляешь WriteBytes так:
|
Автор: Gremlin 3.9.2006, 13:50 |
ок тока чото я не понимаю запись TS%.2e\n и разве не нужно <cr>? |
Автор: GremlinProg 3.9.2006, 14:21 |
\n - это и есть <cr>, в принципе, исходя из информации, которую ты тут выложил, можно использовать любой из четырех вариантов завершения команды: \n , \r, \r\n, \n\r, я выбрал первый. %.2e - строка, форматирующая вещественное число в такой вот, экспоненциальный вид: x.xxE+x |
Автор: Gremlin 3.9.2006, 14:59 |
Аааа понятно!! Вот ешо! Я открываю ком порт у него есть такие свойства как parity, bitssize, stopbits какие значения мне необходимо выставить ибо в мануале только сказано что baudrate = 9600, а остальное не сказано ![]() |
Автор: GremlinProg 3.9.2006, 16:34 | ||
обычно на железе сильно не заморачиваются, так что обычно програмят с параметрами Dcb, выставленными следующим образом
но для большей надежности, я заполняю Dcb исходя из текущего состояния порта, т.е. пееред тем как выставлять Parity, ByteSize..., вызови GetCommState(port,Dcb). Это установит флаги Dcb так, как они были установлены при последнем обращении к порту. |
Автор: Gremlin 4.9.2006, 12:40 | ||
Сделал так
На месте WaitForSingleObject(OverRead.hEvent, INFINITE); он уходит в раздумья типа ничего с прибора не получает ответа даже опшибки ![]() |
Автор: GremlinProg 4.9.2006, 17:42 | ||
перед тем, как отправлять в порт свои команды, пошли в него просто 1-2 байта для синхронизации, например таких: "\0\n". Это, скорее всего, решит проблему. |
Автор: Gremlin 5.9.2006, 07:17 |
ой а мне сказали нужно разделить потоки Thread для чтения тока не сказали как! И кстати у меня не получается послать команду т.е. прибор не реагирует на команду ![]() |
Автор: GremlinProg 5.9.2006, 10:10 |
всю прверку WaitCommEvent нужно положить в "бесконечный" цикл, а цикл - в отдельный поток. Любое чтение байт из порта нужно каждый раз сбрасывать в отдельный буфер (организовать очередь), а после добавления новых байт в эту очередь - выполнять, нужную тебе, процедуру обработки буфера. Перед работой потока желательно синхронизировать I/O порта с I/O машины (см. предыдущий пост), иначе будешь практически всегда терять, по крайней мере, первый байт как на прием, так и на передачу(возможно из за рассинхронизации команда и не принимается устройством). Все это нужно делать в идеальном случае. |
Автор: Gremlin 8.9.2006, 06:55 |
Ошибка первая была в том что нужно инициализировать OVERLAPPED OverRead ={0}; и теперь я нормально посылаю команды Read еще не пробовал но если можно то мне бы сэмпл по поводу создания отдельного потока |
Автор: GremlinProg 8.9.2006, 07:11 | ||
по идее, OverRead и OverWrite должны быть инициализированы в ноль перед использованием
Добавлено @ 07:14 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__beginthread.2c_._beginthreadex.asp |
Автор: Gremlin 13.9.2006, 07:09 | ||
Сходил по ссылке данной в начале топика http://www.izone.kiev.ua/articles/delphi/16/282.htm там пример но в делфи тама написано так: "Рассмотрение работы с потоками в Windows, в частности того, как это реализовано в Delphi, выходит за рамки данной статьи. Предполагаю, что читатель встречался или по крайней мере знаком с этим. Скажу лишь, что у любого потока есть главная функция, которая начинает выполняться после его создания. В Delphi для потоков существует класс TThread, а его главная процедура называется TThread.Execute(). Вот так выглядит главная процедура отдельного потока, которая ожидает появление одного или нескольких символов и считывает их:
В приведенном примере в потоке крутится цикл, тем самым инициируется ожидание события порта вызовом функции WaitCommEvent(), ожидание же самого этого события задается функцией WaitForSingleObject(). Для определения количества принятых символов используется функция ClearCommError(). Когда количество принятых символов (dwRead) известно, непосредственное чтение символов выполняется функцией ReadFile(). " Как это реализовать в Си? не могу найти какой функцией в Си пользоваться вместо TReadThread.Execute помогите плз! |
Автор: GremlinProg 13.9.2006, 09:00 |
Сходи по ссылкам предыдущего поста. 2 ссылки - 2 решения, выбирай любое, какое нравится. Примеры там же, но для первой ищи For an example, see... в конце страницы. |
Автор: Gremlin 15.9.2006, 13:40 | ||||
_beginthread( ReadBuff, 0, NULL ); где
|
Автор: dumb 15.9.2006, 13:50 | ||
дык
|
Автор: Gremlin 17.9.2006, 20:59 |
Не там просил void(cdecl *)(void *) я сделал так объявил в хидере void (__cdecl *ReadABuffer)(void *dummy); без описания _beginthread( ReadABuffer, 0, NULL ); компилит без проблем но кагда я её пытаюсь описать эту функцию void (__cdecl *ReadABuffer)(void *dummy) {} то на на скобке вылезает еггог d:\C++_Project\Visual C++.NET\Kistler Measuring Hardware\MultiAmp.cpp(833): error C2470: 'ReadABuffer' : looks like a function definition, but there is no formal parameter list; skipping apparent body тоесть функция выглядит как функция но не функция гыгы и не знаю что и сделать теперь ![]() |
Автор: Gremlin 18.9.2006, 14:01 |
Возможно в компиляторе нужно чтото включить? хотя там мультитридинг стоит |
Автор: GremlinProg 18.9.2006, 15:42 |
это называется "гадание на кофейной гуще" покажи код |
Автор: GremlinProg 18.9.2006, 17:54 | ||||
для _beginthread callback должен выглядеть так:
void(__cdecl*FType)(void *) - это описание ТИПА функции(здесь имя типа FType) void __cdecl func(void *) - это описание функции(здесь имя функции func) разницу видишь? |
Автор: Gremlin 19.9.2006, 05:31 |
Ааааааа два дня сижу думаю твою дивизию тоесть я сделал так в хидере void (__cdecl *ReadABuffer)(void *dummy); а в цпп описываю не указатель а саму функцию void __cdecl ReadABuffer(void *dummy); блин как сразу не допенькал![]() |
Автор: Gremlin 19.9.2006, 08:05 | ||||
Такс серавно чото не получается вопщем у меня есть класс его хидер:
СPP:
И блин если я так объявляю то члены класса не видны в функции ReadABuffer а мне нужно чтоб это все в классе делалось ![]() |
Автор: GremlinProg 19.9.2006, 10:09 | ||
|
Автор: Gremlin 19.9.2006, 17:29 |
ага сибо мудреное объявление но вроде робит![]() |
Автор: GremlinProg 19.9.2006, 18:36 |
у меня не ругается, компилер другой, вынеси реализацию этих методов в cpp или хотя бы StaticReadABuffer |
Автор: Gremlin 19.9.2006, 18:50 | ||
Но я думал что создав другой поток я смогу работать с остальным приложением нормально а оно виснет и ждет ответа с ком порта |
Автор: GremlinProg 19.9.2006, 19:01 | ||
Ну убери WaitForSingleObject вообще, либо поставь перед завершением программы. |
Автор: Gremlin 19.9.2006, 19:15 | ||
|
Автор: GremlinProg 19.9.2006, 20:28 | ||
Я говорю вот про вэйт после создания потока :
Убери его пока, чтобы ничего не висло. Правильнее будет поставить его перед завершением программы, например в WM_DESTROY (это только в случае, если нужно освободить какие-нибудь ресурсы, используемые в потоке, например буфер, в который ты складываешь инфу с кома или сбросить буфера в файл и т.п.) |
Автор: Gremlin 20.9.2006, 08:20 | ||||||
При выполнении
заметил что переводит в состояние Ожидание байтов, и даже после выполнения функции и завершения потока я не могу записать в порт. поэтому в конце я стал ставить
тогда все нормально! Но вот проблема начинается в другом! Задача у меня следующая: Есть кнопки Старт и Стоп. Нажимаю Старт и открывается поток с функией Write которая причом в цикле посылает команду опрашивать текущее значение! Нажимаю клавишу Стоп цыкл останавливается. Сразу после открытия потока Write открывается поток с Read
Но в buf ничего не приходит тк ком порт занят Write, подскажите как мне разрулить эти два потока! |
Автор: Gremlin 6.10.2006, 18:41 | ||
вот так реализован цикл
|
Автор: Gremlin 8.10.2006, 14:28 |
Это сообщение отредактировал Fixin - 7.10.2006, 09:03 ???????? |
Автор: Gremlin 8.10.2006, 14:48 |
и еше вопрос почему чтобы получить коректно данные мне приходится вводить Sleep и подбирать милисекунды хотя поидее назначая маску EV_RXCHAR (событие получение символа) а потом идет (!WaitCommEvent(hPort, &dwMask, &OverRead)) тоесть ждать до наступления события маски дак почему мне приходится искуственно вводить задержку? |
Автор: GremlinProg 8.10.2006, 22:02 |
писать то в цикле не надо, это читать может понадобится несколько раз. пишешь 1 раз, затем начинаешь читать и пока не прочитаешь верный отклик от железки, ни чего писать в порт не надо. Дождись ответа, затем можно снова писать команду и снова читать и т.д. Сделай эту операцию парной чтение-запись, тогда все будет ок. Добавлено @ 22:07 поток, по сути нужен только для того, чтобы винду не вешать во время чтения. |
Автор: Gremlin 9.10.2006, 05:28 |
дак мне тогда придется чтобы послать кнопочку старт жать ![]() Добавлено @ 05:30 я то делаю поток на Write именно для того чтоб из основного потока смог остановить цыкл и завершить поток |
Автор: GremlinProg 9.10.2006, 10:26 |
Это-то понятно, но в любом случае, на каждую команду записи нужно дождаться отклика. Это можно сделать 2-мя способами: 1. Использовать события. Создай 2 события с помощью функций CreateEvent, допустим hReadCommand и hAbort. В потоке чтения, после того как отклик получен, поднимаешь событие hReadCommand, на которое реагирует поток записи, он проверяет флаг fStopped и если флаг опущен, то посылает очередной запорс в железку. В конце программы поднимай событие hAbort, на которое реагируют оба потока, они по этому событию будут выходить из цикла, тем самым, савершая потоки. После того, как в основной программе поднимаешь событие hAbort, жди оба потока с помощью функции WaitForMultiplyObjects. Можно завести 3-тье событие hWriteCommand, вместо флага fStopped, которое поднимается при нажатии кнопки "Пролдолжить" и "Старт". На это событие будет реагировать поток записи, оно будет сигнализировать, чтобы начать цикл посылки команд в железо. 2. Использовать сообщения. То же самое, но только заводишь не события а дополнительные сообщения(либо с помощью RegisterWindowMessage, либо просто WM_USER + 500), которые обрабатываешь в основном окне, а вместо сигнализации посылаешь из потока чтения SendMessage самому себе, либо крутишь PostMessage. В этом случае достаточно и 1 потока. Выбирай любой способ, который по душе. Конечно, не просто, но раз уж взялся за такое дело... ЗЫ: мусор в буфере как раз и обуславливается бесконечной посылкой в железо команд: в то время, как первая команда начинает ложится в буфер, приходит вторая, в буфере собирается кусок первой и кусок второй и т.д., в конечном счете ни одну команду толком разобрать не можешь, поэтому и ставишь искусственно задержку слипом, не хорошо. |
Автор: Gremlin 19.10.2006, 07:08 |
"В конце программы поднимай событие hAbort, на которое реагируют оба потока, они по этому событию будут выходить из цикла, тем самым, савершая потоки. " Не понял как это реализовать тоесть потоки должны робить и одновременно ожидать этого события! Следовательно по аналогии с hReadCommand WaitForSingleObject(hAbort, 2000) использовать нельзя дак как мне в любом месте выполнения потока отловить это сообщение и закрыть потоки/циклы? |