0 / 0 / 0
Регистрация: 19.11.2012
Сообщений: 9
1

Обмен данными через СОМ-порт

02.12.2012, 18:13. Показов 59148. Ответов 36
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Помогите новичку, пожалуйста)
Нужно написать программу, которая ловит нажатия клавиш(стрелок) и соответственно отправляет это все через СОМ-порт на микроконтроллер. Но если с МК я более-менее разобрался, то вот с ПК-частью все очень-очень печально
Я тут на форуме покопался, но ничего не понимаю
Как вообще использовать этот СОМ в программе?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
02.12.2012, 18:13
Ответы с готовыми решениями:

Обмен данными по СОМ-порту
Доброго времени суток. Пишу 2 программы, обменивающиеся данными по COM-порту. Одна посылает...

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

Обмен данными через COM порт
Доброго времени суток. Требуется производить обмен данными с неким устройством через СОМ порт....

Обмен данными через ком порт в потоке
Программа выполняется в потоке идёт обмен данными через ком порт с мк! При выполнении программа...

36
836 / 343 / 67
Регистрация: 20.11.2012
Сообщений: 795
02.12.2012, 18:42 2
Примеры на Delphi, но все функции - из WinAPI. Если для windows нужно, конечно.
Кликните здесь для просмотра всего текста
Обмен данными через COM-порт в Windows
Разработчики высокоуровневых языков программирования, очевидно, считают прием/передачу данных по протоколу rs232 через коммуникационный порт экзотической процедурой: мол, рядовому пользователю как бы и без надобности, а нерядовой - разберется самостоятельно. Потому ни в turbo pascal, ни в delphi нет штатных средств обмена данными таким способом. Однако в последнее время, особенно в связи с распространением микропроцессорных устройств, такая задача встает в любительских программах все чаще - в силу простоты и дешевизны реализации последовательным портом оборудованы многие научные и инженерные приборы, разнообразные датчики и измерители.

Простота аппаратного исполнения (для обычной двусторонней связи требуется всего три провода) асинхронного коммуникационного порта ведет, однако, к некоторому усложнению необходимого программного обеспечения. Можно, конечно, попробовать послать байт на устройство com1 средствами dos, подобно тому, как это делается для lpt1 (оно же prn), но успех вряд будет достигнут - как минимум, надо сначала настроить скорость обмена. Потому для dos-программ это делается средствами bios или прямым программированием порта "по железу". А в windows, к счастью, есть соответствующие функции api.

Для организации обмена нужно проделать следующие шаги:

получить дескриптор порта (handle - указатель, куда посылать все относящееся к порту);
получить адрес dcb - data control block;
установить новые параметры dcb;
послать установленные параметры в порт;
приступить к чтению принимаемых данных или к передаче.
Рассмотрим все по порядку. Получить дескриптор можно с помощью универсальной функции createfile. Так как СОМ - устройство последовательное, то его можно рассматривать как файл, что и делается (и в dos, между прочим, тоже). У этой функции множество применений (описание в help, если распечатать, занимает страниц семь). Для нее требуется масса входных параметров, но большинство из них нам не нужны и приравниваются, в зависимости от типа, либо к 0, либо к величине nil (указатели, которые никуда не указывают). В нашем случае получается следующий синтаксис функции:

createfile (stcom, generic_read+generic_write, 0, nil, open_existing, 0, 0);

Здесь stcom - строка типа pchar, в которой записано имя файла, в данном случае - просто 'com1' или 'com2', смотря какой порт нужен. Параметр generic_read+generic_write означает, что порт открывается как для вывода, так и для ввода. open_existing означает проверку существования, и если объявленного порта нет, после вызова функции возникнет ошибка, которую можно проанализировать обычным методом delphi: try ... except.

Получить адрес dcb можно, если применить функцию getcommstate (pcom, pdcb); здесь pcom - дескриптор порта, pdcb - возвращаемый адрес структуры dcb. Установить параметры порта в этой структуре можно непосредственно, но если вы обратитесь к ее описанию в help, то бессонная ночь вам обеспечена. Поэтому проще сделать это с помощью вызова функции buildcommdcb (stcom, pdcb), в которой stcom в данном случае содержит набор устанавливаемых параметров в виде строки (см. пример ниже). Установленные параметры посылаются в порт с помощью функции setcommstate (pcom, pdcb). Все эти функции возвращают значение типа boolean, которое равно true, если операция прошла успешно. Чтение из порта и запись в порт осуществляются с помощью симметричных функций readfile и writefile, также универсальных и потому содержащих ненужный нам параметр, который мы приравняем к nil:

boolean readfile (pcom, xb, 1, xn, nil);

Здесь xb - переменная любого целого типа, в которой возвращается прочитанное значение (для writefile в ней содержится, наоборот, записываемое), 1 - столько байт прочесть из xb (для СОМ-порта это, очевидно, всегда 1), xn - сколько байт действительно прочитано. Следующий программный фрагмент инициализирует порт СОМ1 и осуществляет прием данных до тех пор, пока не будет нажата любая клавиша на клавиатуре. Принимаемые данные преобразуются в строку и выводятся на экран через пробел в компоненте label1 (с переводом строки через каждые 32 значения; разумеется, можно выводить в любой компонент, имеющий свойство text или caption, или еще куда-нибудь):

stcom:='com1';
try
pcom:= createfile (stcom, generic_read+generic_write, 0, nil, open_existing, 0, 0);
except ;
if getcommstate(pcom,pdcb)
then stcom:='com1: baud=9600 parity=n data=8 stop=1'
else ;
if buildcommdcb(stcom,pdcb) then setcommstate(pcom,pdcb)
else ;
while (msg.message <> wm_keydown) do
begin
bb:=readfile(pcom,xb,1,xn,nil);
if not bb then break;
st:=st+' '+inttostr(xb);
if length(st) mod 32=0
then st:=st+chr(10)+chr(13);
label1.caption:=st;
peekmessage(msg,form1.handle,0, 0,pm_remove); {читаем сообщение из очереди, если есть - удаляем}
application.processmessages; {очищаем очередь сообщений - на всякий случай}
end;

Прежде чем подключать к компьютеру какие-либо устройства, следует сказать пару слов о технике безопасности. Если прибор беспаспортный или, тем более, самодельный, следует проверить следующее: а) напряжение на выходе порта прибора не должно превышать значений +/-15 В (минимум +/-3 В), и на экране осциллографа не должно наблюдаться заметных выбросов и "шпилек", превышающих эти значения, - в противном случае вы рискуете лишиться com-порта (это особенно неприятно, если порт расположен на материнской плате; в сомнительных случаях лучше экспериментировать с дополнительной isa-картой, оборудованной com-портами; б) нужно убедиться, что выход прибора электрически развязан с сетью.

Автор: Юрий Ревич
журнал "Компьютерра"
http://offline.computerra.ru/

Этот сайт содержит фишинговые ссылки, вырезано
1
0 / 0 / 0
Регистрация: 19.11.2012
Сообщений: 9
02.12.2012, 18:54  [ТС] 3
Нужно-то конечно для Windows, и желательно на C++)
Я Delphi ну совсем не знаю =(
0
4063 / 3317 / 924
Регистрация: 25.03.2012
Сообщений: 12,483
Записей в блоге: 1
02.12.2012, 19:54 4
всё просто. можно даже в консольном приложении принимать. Я сам недавно пробовал. Прекрасный приём.
открываешь порт. Можно создать отдельный поток для приёма данных. В этом потоке в цикле ставишь ReadFile(...)
а после него условие: если nBytesRead>0, то записать прочтённый байт в массив на очередное место. Когда массив заполнится, сделать SetEvent, событие которого будет ожидаться WaitForSingleObject в главной функции.

Добавлено через 35 минут
Программа на С++++. Ждёт данные из порта, принимает их, Выводит их на экран, пишет в файл на диске С и передаёт в COM порт на передачу.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <locale.h>
char buf[128];
char* pbuf=buf;
int counter=0;
 
HANDLE hCom, hEvent;
DWORD bytesRead, bWritten;
 
BOOL fSuccess;
HANDLE hThread;
DWORD dwParam, dwThreadId;
 
VOID WINAPI ThreadProc(PVOID* dummy){
    printf("Ждите данные из порта СОМ4...\n");
    while(true){
        ReadFile(hCom, pbuf, 1, &bytesRead, NULL);
        if (bytesRead>0)
        {
            WriteFile(hCom, pbuf++, 1, &bWritten, NULL);
            counter++;
            if(counter==10){
                SetEvent(hEvent);
                buf[counter]='\0';
                counter=0;
                pbuf=buf;
            }
        }
    }
}
 
int main(void){
    setlocale(LC_ALL, "Russian");
    char* pcComPort= "COM4";
    DCB dcb;
    FILE* fout;
    hCom=CreateFile(pcComPort, GENERIC_READ | GENERIC_WRITE, 
        0, NULL, OPEN_EXISTING, 0, NULL);
    if (hCom==INVALID_HANDLE_VALUE){
        printf("Ошибка открытия COM4!\n");
        while(!kbhit());
        return 1;
    }
    GetCommState(hCom, &dcb);
    dcb.BaudRate=CBR_9600;
    dcb.ByteSize=8;
    dcb.Parity=NOPARITY;
    dcb.StopBits=ONESTOPBIT;
    fSuccess=SetCommState(hCom, &dcb);
    if (!fSuccess){
        printf("Попытка вызвать SetCommState провалилась!\n");
        while(!kbhit());
        return 1;
    }
    printf("COM порт %s успешно сконфигурирован\n", pcComPort);
    GetCommState(hCom, &dcb);
    printf("Скорость порта %s равна %d\n", pcComPort, dcb.BaudRate);
 
    hEvent= CreateEvent(NULL, FALSE, FALSE, NULL);
    hThread=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc,
        &dwParam, 0, &dwThreadId);
    if ((fout=fopen("C:\\test", "a+"))==NULL){
        printf("Не могу создать файл C:\\test");
        while(!kbhit());
        return 1;
    }
    printf("Нажмите клавишу для выхода...\n");
    do{
        WaitForSingleObject(hEvent, INFINITE);
        printf("%s\n", buf);
        fwrite(buf, sizeof(char), 10, fout);
    }while(!kbhit());
    fclose(fout);
    CloseHandle(hCom);
    return 0;
}
Добавлено через 6 минут
Опрос порта происходит в отдельном потоке, что как бы хорошо, потому что в главном цикле окна, в одном потоке со всеми этими выводами на экран и записями в файл, ловить данные из порта не стоит.
Эй! разве эта тема не в ветке для начинающих была?

Добавлено через 15 минут
Vistaern, эй, ты куда вообще ушёл? Я ж тебе отвечал!
2
0 / 0 / 0
Регистрация: 19.11.2012
Сообщений: 9
03.12.2012, 16:11  [ТС] 5
Извиняюсь, что вчера так неожиданно свалил, внезапно у меня внезапно интернет отвалился=(
Буду очень благодарен, если бы кто-нибудь пояснил мне пример на С++ , потому что для меня это пока черная магия))
Все равно всем большое спасибо)
*пошел разбираться с WinAPI*
0
4063 / 3317 / 924
Регистрация: 25.03.2012
Сообщений: 12,483
Записей в блоге: 1
03.12.2012, 16:42 6
Что конкретно пояснить? До какого уровня? Ты winAPI не знаешь или вообще С++?

Добавлено через 10 минут
функции для работы с СОМ-портом:
CreateFile - открывает ком-порт
GetCommState - читает его текущие настройки
SetCommState - изменяет его настройки
ReadFile - читает из порта массив байтов (точнее 1 байт в этом случае)
WriteFile - пишет в порт массив байтов
CloseHandle - "закрывает" порт

функции для работы с событиями и потоками
CreateThread - создаёт поток
CreateEvent - создаёт событие, сохраняет дескриптор события
SetEvent - вызывает наступление события
WaitForSingleObject - ожидает наступление события

функции, которые ты и так должен знать
printf - вывод текста в консоль
fopen - открытие файла на диске для записи
fwrite - запись в файл массива данных
kbhit - проверяет, нажата ли клавиша.

все функции описаны в MSDN
http://msdn.microsoft.com/ru-RU/
2
0 / 0 / 0
Регистрация: 19.11.2012
Сообщений: 9
03.12.2012, 16:46  [ТС] 7
Вот теперь совсем спасибо, больше вопросов не имею)

Хор-роший вопрос) Про WinAPI узнал только позавчера, С++ более-менее, вот с Forms разбираюсь... Изучаю по мере надобности все) А это будет робот, который с компа управляется. Через Bluetooth serial module. Причем с AVR-кой у меня вообще проблем не возникает)
P.S. В школе информатики нет вообще, да здравствуют мануалы.
P.S.S. Учусь в 11 классе.

Ну, стандартные-то функции естественно знаю))
0
0 / 0 / 0
Регистрация: 31.10.2013
Сообщений: 8
31.10.2013, 16:36 8
Здравствуйте товарищи. Извиняюсь за вмешательство. Но хотелось бы узнать как можно регулировать время таймаута, между отправленными посылками. Необходимо для реализации протокола modbus . Посылаю запрос по определенному адресу и если ответ от ведомого не приходит, то по истечению тайм-аута , необходимо обратиться к ведомому со следующим адресом.
0
5 / 5 / 1
Регистрация: 25.10.2013
Сообщений: 230
19.03.2014, 17:24 9
Цитата Сообщение от Kuzia domovenok Посмотреть сообщение
C++
1
2
3
VOID WINAPI ThreadProc(PVOID* dummy){ printf("Ждите данные из порта СОМ4...\n");
 while(true){ 
ReadFile(hCom, pbuf, 1, &bytesRead, NULL);
Каким образом можно прервать попытку считать байт? Понадобилось, например, приостановить чтение/изменить логику/закрыть поток из самого потока, то как и образом это сделать, если поток по сути висит?
0
4063 / 3317 / 924
Регистрация: 25.03.2012
Сообщений: 12,483
Записей в блоге: 1
19.03.2014, 23:46 10
DarkMasterW, ну и пусть висит. А зачем в этом потоке что-то ещё делать кроме зависания в ожидании приёма байта? В конце концов, если поток больше не нужен, грохни его из основного потока.
0
5 / 5 / 1
Регистрация: 25.10.2013
Сообщений: 230
20.03.2014, 10:04 11
Код взят за основу, в текущем виде действительно смыла нет, но если копать дальше, то возникают неудобные вопросы. Приходящие данные будут построчно падать в вектор в виде буфера. Считали мы часть буфера, надо очистить. Очистить - надо притормозить поток, а при висящем чтении мы даже не сможем удостовериться, что он встал и ожидает. Ну по крайней мере я не вижу корректных способов. Завершение потока тоже естественным способом через return можно получить только после прихода данных. Казалось бы suspended и terminate, но из прочитанного мной это, мягко говоря, очень не правильно..
0
Эксперт С++
2924 / 1274 / 114
Регистрация: 27.05.2008
Сообщений: 3,465
20.03.2014, 13:22 12
Разумеется, неправильно. Правильнее просигнализировать потоку "завершись!" с помощью события:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
 
void WINAPI ThreadProc(PVOID* dummy)
{ 
    printf("Ждите данные из порта СОМ4...\n");
    while(WaitForSingleObject(hEvent, 0) != WAIT_OBJECT_0)
    { 
        ReadFile(hCom, pbuf, 1, &bytesRead, NULL);
    }
}
 
// где-то....
{
    // здесь создается поток чтения и читаются данные...
    
    // пришла пора остановить чтение:
    SetEvent(hEvent);
    
    // тут дальнейшие действия...
}
0
5 / 5 / 1
Регистрация: 25.10.2013
Сообщений: 230
20.03.2014, 15:57 13
Цитата Сообщение от CheshireCat Посмотреть сообщение
Правильнее просигнализировать потоку "завершись!" с помощью события:
это понятно, но как раз проблема прерывания чтения тут и встает. Как мы считаем евент, если у нас программа пытается бесконечно считать байт?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
VOID WINAPI ThreadProc(PVOID* dummy){
    printf("Ждите данные из порта СОМ4...\n");
    int counter = 0;
    while (true){
        ReadFile(hCom, pbuf, 1, &bytesRead, NULL);
        // Поток будет жить вечно, пока не прилетит байт данных.
        return;
        if (bytesRead > 0)
        {
 
            printf(buf);
        }
    }
}
И что с этим делать? Ну повис он читать, а дальше то что? А если устройство вообще больше данных пересылать не будет?
0
Эксперт С++
2924 / 1274 / 114
Регистрация: 27.05.2008
Сообщений: 3,465
20.03.2014, 16:01 14
Программа не должна пытаться бесконечно считать байт. Это регулируется таймаутами чтения (см. SetCommTimeouts: http://msdn.microsoft.com/en-u... 85%29.aspx).
2
5 / 5 / 1
Регистрация: 25.10.2013
Сообщений: 230
20.03.2014, 17:12 15
вооо. спасибо.
0
0 / 0 / 0
Регистрация: 01.11.2013
Сообщений: 12
22.05.2014, 10:59 16
Подскажите есть ли у COM порта системный контроль передачи данных? Если есть, то как он работает?
0
1 / 1 / 0
Регистрация: 11.03.2012
Сообщений: 70
11.03.2016, 11:15 17
Здравствуйте! Подскажите пожалуйста что за проблема, я скопировала код, и он не компилируется. Выдает такую ошибку : Ошибка 1 error C2664: CreateFileW: невозможно преобразовать параметр 1 из 'char *' в 'LPCWSTR'
Что это может значить?
и возвращает на строку hCom=CreateFile(pcComPort, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
5 Параметр ему не нравится что ли...

Добавлено через 14 минут
а это не 5 параметр. а не нравится походу char* pcComPort= "COM4";
но почему?
0
Практикантроп
4823 / 2717 / 524
Регистрация: 23.09.2011
Сообщений: 5,777
11.03.2016, 13:54 18
Ну, замените тип pcComPort, - не char*, а String
0
240 / 213 / 84
Регистрация: 18.03.2010
Сообщений: 750
11.03.2016, 14:16 19
Цитата Сообщение от jgotka Посмотреть сообщение
Подскажите пожалуйста что за проблема, я скопировала код, и он не компилируется. Выдает такую ошибку : Ошибка 1 error C2664: CreateFileW: невозможно преобразовать параметр 1 из 'char *' в 'LPCWSTR'
Проект настроен на использование UNICODE символов. И ваша CreateFile ждет строку WCHAR.
Вызовите явно ANSI версию CreateFileA, или измените тип строкового литерала на WCHAR.
0
1 / 1 / 0
Регистрация: 11.03.2012
Сообщений: 70
14.03.2016, 05:00 20
спасибо большое! завтра попробую!

Добавлено через 22 часа 38 минут
всяко пробовала. и вот этот вариант сработал спасибо большое!!

wchar_t *pcComPort = TEXT("COM4");
0
14.03.2016, 05:00
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
14.03.2016, 05:00
Помогаю со студенческими работами здесь

управление через СОМ порт
Как сдельть сигнал на RTS,DTR по нажатию BUTTON1и2 соответственно. Причём при их отпускании сигналы...

Передача пакета по протоколу ОВЕН через СОМ порт
задача такая. Я должна сделать скаду-систему контоля микроклимата. Т.е. я как пользователь, задаю...

Обмен через порт
нужно написать две программки под UNIX, которые общались бы между собой через последовательный порт...

Взаимодействие процессов, обмен сообщениями через порт
Народ, нужна помощь с лабораторной работой. Нужна вот такая программа на С++: &quot;Вычислить f (x) *...

Обмен данными через интернет
Доброго времени суток!!! При помощи чего реализовать обмен данными между компьютерами через...

Обмен данными через интернет
Искал ответ но так и не нашел... Прошу прощения если плохо искал Проблема такая... Хочу...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru