Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Чтение из COM порта


Автор: Nil 16.6.2007, 21:46
Здравствуйте.
Ответа именно на мои вопросы не нашел, поэтому все же решил создать новую тему.
Код

hPort=CreateFile(TEXT("\\\\.\\COM16"),GENERIC_WRITE|GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

Таким образом открываю порт для чтения/записи. 
Есть следующие проблемы:
1) Если сразу после записи в порт начаь читать из него, то получу только что записанную строку, что не очень удобно, как бороться ? Как правильно читать ?
2) Можете пояснить на счет структуры COMMTIMEOUTS - какое поле за что отвечает ?..
ReadTotalTimeoutMultiplier - сколько макс. ждем одного символа ?
ReadTotalTimeout               -  ? не совсем понял логику...
----------

Вообще требуется после того как записал в порт строку, ждать ответа в виде "ОК" максимально в течение 5 секунд, как это лучше реализовать ?..

Автор: Static 9.9.2009, 08:42
Это, конечно, староватый топик, но наиболее подходящий...
Есть у меня задача - подключить электронные весы к компу. Пока весы фиг знает где стоят, решил потренироваться на чем-нить еще - никогда с com не работал. Нашел модем. И... я, наверно, делаю что-то не так.
Если с модемом связаться через гипертерминал, например, - все ок: пишем AT - получаем OK. Ну и т.п.
А вот прога, которую я наваял, получает только эхо :( Перерыл дофига всего - везде все (на первый взгляд) идентично, даже в исходниках другого терминала, который тоже работает нормально.
Мой код:
Код

#include <iostream>
#include <cstdio>
#include <windows.h>

using namespace std;

bool OpenComPort(const char* port_name, HANDLE &com_handle, COMSTAT &ComState)
{
COMMTIMEOUTS CommTimeOuts;
DCB dcb;

com_handle = CreateFile(port_name, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, NULL, 0);
if (com_handle == INVALID_HANDLE_VALUE)
    {
    cout << "CreateFile failed" << endl;
    return false;
    }
GetCommState(&com_handle, &dcb);

dcb.BaudRate = 9600;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;

GetCommTimeouts(com_handle, &CommTimeOuts);
CommTimeOuts.ReadIntervalTimeout= 100;
CommTimeOuts.ReadTotalTimeoutMultiplier = 15;
CommTimeOuts.ReadTotalTimeoutConstant = 100;
CommTimeOuts.WriteTotalTimeoutMultiplier = 1;
CommTimeOuts.WriteTotalTimeoutConstant = 1000;
SetCommTimeouts(com_handle, &CommTimeOuts);
SetCommState(com_handle, &dcb);

DWORD temp = 0;
if (!ClearCommError(com_handle, &temp, &ComState))
    {
    cout << "ClearCommError failed" << endl;
    }
SetupComm(com_handle, 64, 64);
return true;
}

int main(int argc, char* argv[])
{
HANDLE com_handle;
COMSTAT ComState;

if (!OpenComPort("COM1", com_handle, ComState))
        {
        cout << "OpenComPort returned false :(" << endl;
        }
    else
        {
        cout << "Port was opened" << endl;
        }

DWORD numbytes_ok = 0;
unsigned char buf[62] = {0};
unsigned char outbuf[64] = {0};

while (true)
    {
    cin >> buf;
    if (!strcmp((char*)buf, "stop"))
        break;

    DWORD temp = 0;
    ClearCommError(com_handle, &temp, &ComState);
    if (!temp)
        {
        WriteFile(com_handle, buf, strlen((char*)buf), &numbytes_ok, NULL);
        }

    ClearCommError(com_handle, &temp, &ComState);
    if (!temp)
        {
        ReadFile(com_handle, outbuf, 64, &numbytes_ok, NULL);
        cout << "received " << numbytes_ok << " bytes: " << outbuf << endl;
        }

    memset(buf, 0, 64);
    memset(outbuf, 0, 64);
    }

CloseHandle(com_handle);

return 0;
}


Подозреваю, что-то элементарное забыл/не сделал/не знал. Подскажите, пожалуйста.

Автор: GremlinProg 9.9.2009, 09:53
некрофилия, конечно у нас не в почете, но поскольку вопрос привязан только к названию темы...

Цитата(Static @  9.9.2009,  10:42 Найти цитируемый пост)
Подозреваю, что-то элементарное забыл/не сделал

для AT-команд, думаю, это элементпрное - символ перевода строки в конце команды, т.е. "\r" или "\n" или "\r\n"

Автор: Static 9.9.2009, 10:05
да пробовал... было и вот так:
Код

WriteFile(com_handle, buf, strlen((char*)buf), &numbytes_ok, NULL);
WriteFile(com_handle, crlf, 2, &numbytes_ok, NULL); //crlf = "\r\n"


и вот так:
Код

buf[strlen((char*)buf)] = '\r';
buf[strlen((char*)buf)] = '\n';
WriteFile(com_handle, buf, strlen((char*)buf), &numbytes_ok, NULL);


никакой разницы. Может еще вариант подкинете?

Автор: GremlinProg 9.9.2009, 10:15
так будет логичнее:
Код

int len = strlen((char*)buf);
buf[len++] = '\r';
buf[len++] = '\n';
buf[len++] = '\0';
WriteFile(com_handle, buf, len, &numbytes_ok, NULL);


Добавлено через 55 секунд
это можно не добавлять:
Код

buf[len++] = '\0';

это просто для красоты )

Автор: Static 9.9.2009, 10:44
ну, видать, не красота спасет мир... То же только в профиль.
Передается "AT\r\n" - это точно. А принимается только эхо. Т.е. точно то же, что и послали. Может я неправильно делаю ReadFile?

Автор: GremlinProg 9.9.2009, 11:01
для теста сойдет,
а в гипертерминале то же самое?
или ОК все же приходит?

если и там не приходит, смотри документацию к модему,
тут может потребоваться перевод модема в командный режим "+++", вобщем, это уже специфка конкретного модема

Автор: Static 9.9.2009, 11:20
Цитата(Static @  9.9.2009,  07:42 Найти цитируемый пост)
Если с модемом связаться через гипертерминал, например, - все ок: пишем AT - получаем OK. Ну и т.п.

Проблема где-то в моем коде...

Автор: xvr 9.9.2009, 11:33
'ОК' придет, но позже - модем довольно медленное устройство, а уж COM порт и подавно  smile 
Стоит разобраться как работает модем с COM портом -
Когда в модем передают символы (те самые AT), он их отправляет назад (так же посимвольно) - таким образом получается эхо (сам по себе COM порт эхо НЕ ОБЕСПЕЧИВАЕТ!)
Когда модеи получает символ CR ('\r'), он начинает выполнять команду, ПОСЛЕ чего посылает ответ.

Рекомендую перед ReadFile поставить Sleep(500) - должно хватить для приема ответа


Автор: Static 9.9.2009, 11:36
Спасибо за подсказку... Сейчас попробую.

Автор: GremlinProg 9.9.2009, 11:39
ну да, а может и Get/SetCommState возвращаются с ошибкой,
т.к. DCB инициирован неправильно, тут пропущена по крайнеймере установка длины структуры:
Код

dcb.DCBlength = sizeof(dcb);

Автор: Static 9.9.2009, 11:43
Нет... это не то. Да и в гипретерминале модем почти мгновенно отвечает.
Даже Sleep(5000) не решает.
Я правильно понимаю, что полученные данные никуда не деваются, а спокойно лежат в буфере? И ReadFile их просто оттуда достает?.. Может модем просто не понимает, что я ему команду отправил? Кодировка или еще что-нить может не совпадать?

Добавлено через 4 минуты и 40 секунд
Ошибок ни то, ни другое не возвращает. И, насколько я понимаю, получив структуру при помощи GetCommState, длину ей задавать уже не надо. В лбом случае - явное задание ничего не решает.

Автор: GremlinProg 9.9.2009, 11:52
Цитата(Static @  9.9.2009,  13:43 Найти цитируемый пост)
Может модем просто не понимает, что я ему команду отправил?

поставь  проверки на все вызовы, тогда возможно будет понятно где проблема

Автор: Static 9.9.2009, 12:44
ок. Только какие проверки? Единственный вызов write/read проверять?

Автор: smoke_man 9.9.2009, 13:32
Посмотри http://forum.vingrad.ru/index.php?showtopic=234366&view=findpost&p=1690295 может поможет.

Автор: Static 9.9.2009, 14:18
Пример не помог. Ибо если его скопипастить - получается то же самое. Но елки-ж-палки! Терминал-то работает!!!

Автор: smoke_man 9.9.2009, 15:41
Вот пример - проверил на своем модеме.
Код


#include <windows.h>
#include <iostream>
#include <cstdlib>


int main()
{
    //Это вместо DWORD
    unsigned long int portErr      = 0;
    int count = 0;
    //Посылаемые данные в порт
    const  char *buff = "at\r\n";
    //Буфер под данные из порта 
    char *Inbuff = new char[255];
    //Количесвто записанных байт в порт и прочитанных из порта
    DWORD WritingByte = 0, ReadByte = 0;
    //Таймаут на прием
    int notanswer = 10000;
    //Струкутра состояния порта
    _COMSTAT st;
    //Структура настройки порта
    DCB dcb;
    //Таймаут порта
    COMMTIMEOUTS timeouts = {MAXDWORD,MAXDWORD,600,0,0};
    //Открываем com-порт 1
    HANDLE ComHandle=CreateFileA("\\\\.\\COM20",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,0); 
    if (ComHandle == INVALID_HANDLE_VALUE)
    {

        MessageBoxA(NULL,"Порт не создан","!",MB_OK);
        delete Inbuff;

        return 0;
    }
    //После открытия настраиваем его
    SetupComm(ComHandle,1024,1024);
    SetCommTimeouts(ComHandle,&timeouts);
    GetCommState(ComHandle,&dcb);
    dcb.DCBlength = sizeof(dcb);
    dcb.BaudRate= 57600;
    dcb.fParity = FALSE;
    dcb.ByteSize = 8;
    dcb.Parity = NOPARITY;

    dcb.fBinary = TRUE;
    dcb.fOutxCtsFlow = FALSE;
    dcb.fOutxDsrFlow = FALSE;
    dcb.fDtrControl = DTR_CONTROL_ENABLE;
    dcb.fDsrSensitivity = FALSE;
    dcb.fOutX = FALSE;
    dcb.fInX = FALSE;
    dcb.fNull = FALSE;
    dcb.fRtsControl = RTS_CONTROL_DISABLE;
    dcb.fAbortOnError = TRUE;

    dcb.StopBits = ONESTOPBIT;
    //Устанавливаем настройки
    SetCommState(ComHandle,&dcb);

    EscapeCommFunction(ComHandle, SETRTS);
    EscapeCommFunction(ComHandle, SETDTR);
    //Сбрасываем ошибки
    ClearCommError(ComHandle,&portErr,NULL);
    PurgeComm(ComHandle, PURGE_TXCLEAR | PURGE_RXCLEAR);


    //ПИшем в порт 2  байта
    WriteFile(ComHandle,buff,4,&WritingByte,NULL);
    if(WritingByte == 0)
    {
        MessageBoxA(NULL,"Ошибка записи","!",MB_OK);
        delete Inbuff;

        return 0;
    }
    //Принимаем данные из порта
    Sleep(2000);
    while(count<=0)
    {
        ClearCommError(ComHandle,&portErr,&st);
        //Считываем количесво принятых байт
        count = st.cbInQue;
        //Проверяем наш таймаут
        if(notanswer == 0)
        {

            MessageBoxA(NULL,"Нет ответа","!",MB_OK);
            delete Inbuff;
            return 0;
        }
        if(count<=0)
        {
            notanswer--;
            continue;
        }
        //Если данные есть в порте читаем их и выходи из цикла приема
        ReadFile(ComHandle,Inbuff,count,&ReadByte,NULL);
        break;
    }
    for(int i = 0;i<count;i++)
    {
        std::cout<<Inbuff[i];
    }
    system("PAUSE");

    return EXIT_SUCCESS;
}

Успешно работает.
Картинка прилагается.

Автор: Static 9.9.2009, 15:56
Спасибо за пример. А теперь внимание (барабанная дробь). У меня с этим кодом НИ-ЧЕ-ГО не поменялось. Что может быть не так кроме кода? Настройки проекта, подключаемые либы, качество кожи на бубне?

Добавлено через 4 минуты и 34 секунды
так... я добился от модема ответа. Пока не понял, как именно smile Всем, кто участвовал - спасибо еще раз. Пошел мучать железяку

Автор: Static 9.9.2009, 16:15
Проблема все же была в недоинициализированной структуре dcb. Вот так... :(

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)