Ввод Modbus через MSComm в Visual C++

Я совершенно новичок в протоколе Modbus. Моя установка состоит из трех устройств с разными адресами. Все они подключены к COM1 через RS232. Я использовал Modbus Poll для проверки входных данных, который работает правильно. Что я хочу сделать сейчас, так это прочитать регистры хранения в приложении vc++ (MFC). Для последовательной связи я использую класс MSComm. Я написал небольшой код, но я вообще не получаю ввода.

Мой код на данный момент:

BOOL Crs232test4Dlg::OpenConnection ()
{
    char error [513];

    try
    {
        if (! m_MSComm.GetPortOpen ())
        {
            m_MSComm.SetCommPort (1);
            m_MSComm.SetSettings ("9600,N,8,1");
            m_MSComm.SetInputLen (4);
            // Receive Data as Text
            m_MSComm.SetInputMode (0);
            m_MSComm.SetPortOpen (true);
            m_MSComm.SetCommID (1);
           return m_MSComm.GetPortOpen ();
        }
        AfxMessageBox ("Success!!!!", MB_OK);
        return TRUE;
    }

    catch (CException *e)
    {
        e->GetErrorMessage (error, 512);
        AfxMessageBox (error, MB_OK);
        return FALSE;
    }
}


void Crs232test4Dlg::OnVaisalaComm ()
{
    if (m_MSComm.GetCommEvent () == 2)
    {
        COleVariant in_dat;
        in_dat = m_MSComm.GetInput ();
        Sleep (100);
        CString strInput (in_dat.bstrVal);
        m_Input = m_Input + strInput;
        UpdateData (FALSE);
    }
}

Я хочу выложить m_Input сейчас, но он ничуть не изменился. Я также получаю предупреждение (свойство доступно только для чтения) при установке SetCommID, что я не думаю, что это важно.

Может кто-нибудь, пожалуйста, направьте меня, так как я действительно невежественен в данный момент.

С уважением

РЕДАКТИРОВАТЬ: Согласно примеру связи, я пытался обращаться с устройством как с файлом.

m_hCom = CreateFile(m_sComPort, 
        GENERIC_READ | GENERIC_WRITE,
        0, // exclusive access
        NULL, // no security
        OPEN_EXISTING,
        0, // no overlapped I/O
        NULL); // null template
// :(colon) Address=1 Function=3 Starting register= 40001 (To write 400001 or 0?)
Registers to read=4 checksum CR LF
char    strASCII[] = "3A 30 31 30 33 30 30 30 30 30 30 30 34 46 38 0D 0A";

bWriteRC = WriteFile (m_hCom, strASCII, strlen(strASCII), &iBytesWritten, NULL);

memset(sBuffer,0,sizeof(sBuffer));
// Reading output of the M3
bReadRC = ReadFile (m_hCom, &sBuffer, 1, &iBytesRead, NULL);

if (bReadRC && iBytesRead > 0)
    {
        sResult = sBuffer;
    }
    else
    {
        sResult = "Read Failed";
        dwError = GetLastError();

        sprintf(sMsg, "Read length failed: RC=%d Bytes read=%d, "
                "Error=%d ",
                bReadRC, iBytesRead, dwError);
        AfxMessageBox(sMsg);
    } 

Я получаю ошибку длины чтения. strASCII обычно не разделяется, только для лучшего обзора. Я проверил связь в Modbus Poll. Мой вывод правильный, но, похоже, он не получает данные.

РЕДАКТИРОВАТЬ: я понял. Большое спасибо за Вашу помощь. Я ввел неправильную контрольную сумму.


person Andreas D.    schedule 04.02.2013    source источник
comment
Вы уверены, что целевое устройство работает в режиме ASCII? Если это так, ваша строка должна начинаться с : и заканчиваться на \r\n.   -  person Alexandre Vinçon    schedule 07.02.2013
comment
Кроме того, 400001 — это псевдоним для регистра хранения 1. Таким образом, начальный адрес в вашем запросе MODBUS должен быть 0 из-за смещения в схеме адресации.   -  person Alexandre Vinçon    schedule 07.02.2013
comment
Я преобразовал код в шестнадцатеричный, как того требует Modbus. У меня есть начальное двоеточие (3A) и \r\n (0D 0A). Адрес также преобразуется в 0. Согласно simplemodbus.ca/ASCII.htm   -  person Andreas D.    schedule 08.02.2013
comment
начальное двоеточие и конечный \r\n не должны преобразовываться в шестнадцатеричное представление. Ваш запрос должен иметь следующий формат: strASCII[] = :3031303330303030303030344638\r\n;   -  person Alexandre Vinçon    schedule 08.02.2013


Ответы (3)


не ответ, а руководство по устранению неполадок.

  • твои лучшие друзья должны быть:

    1) кабель нуль-модема 232female‹->232female со вторым компьютером, имеющим com-порт (или ноутбук с USB->последовательным преобразователем) ... пайка кабеля самостоятельно провод к проводу, возможно, лучшее решение.

    2) Windows Hyper-Terminal, простое, но надежное приложение, предустановленное на большинстве окон... запущенное в режиме comPort, с теми же параметрами битрейта/четности/стоп-бита, которые вы ожидаете от модулей.


  • сначала проверьте, в порядке ли соединение и кабель, запустив hterm на обоих компьютерах и в чате несколько предложений
  • во-вторых, проверьте, в порядке ли ваша программа, запустив ее на первом компе и hterm на другом
  • Модули Modbus иногда ничего не отправляют до того, как Master отправит какой-либо запрос по адресу модуля, поэтому, возможно, вашей программе нужно сначала что-то отправить (для этого вы можете зарегистрировать свой modbusPool с другим подключенным компом вместо MBUS-модулей)

... со всем уважением к очередям сигнализации Windows и классу MSCOmm, что, вероятно, нормально, но для устранения всех возможных причин сбоя связи при запуске проекта, возможно, вам следует предпочесть простую угрозу COM-порта как файла и чтение из него внутри некоторого цикла while ... некоторая короткая версия этого примера... Установка последовательных параметров при запуске и чтение файла с именем comX.

ссылка выше имеет хорошую реализацию cSerialClass при загрузке, но простой пример без проверки ошибок находится здесь, в pastebin .

person Asain Kujovic    schedule 04.02.2013
comment
Спасибо за ваш ответ. Я изучу ваш источник и расскажу, как все прошло. - person Andreas D.; 07.02.2013
comment
ссылка - не тестировалось с реальными данными, но выглядит нормально @AndreasD. - person Asain Kujovic; 07.02.2013
comment
Я все еще не получаю ответа. Какого черта? Настройки CommPort правильные. Может быть, символ WriteFile не должен быть записан в шестнадцатеричном формате? - person Andreas D.; 08.02.2013
comment
symplymodbas.ca -> sBuff[] =:1103006B00037E\r\n; ...sLen==17 @AndreasD. - person Asain Kujovic; 08.02.2013
comment
я преобразовал его для своих нужд (адрес 1, функция 3, начинается с 0, чтение 4 регистров, контрольная сумма). char sBuff[] =:01030000000448\r\n; Это все еще не работает - person Andreas D.; 08.02.2013
comment
возможно, lrc равен 256-(1+3+4)=248=0xF8 ... ':010300000004F8\r\n', но, возможно, вам следует попробовать RTU \x01\x03\x00\x00\x00\x04\xF8\xF8' с crc16 вместо f8f8, или зарегистрируйте успешное приложение ModbusPool @AndreasD. - person Asain Kujovic; 08.02.2013
comment
Я понял, ребята: поставил неправильную контрольную сумму. Я поставил строку в Hex и по своей глупости оставил контрольную сумму преобразованной в ASCII. char sBuff[] = :010300000004F8\r\n; @Александр Винсон - person Andreas D.; 08.02.2013

MODBUS намного сложнее, чем просто чтение простых данных через последовательный порт. Это сложный протокол, ориентированный на пакеты данных, со сложными функциями синхронизации. Он определяет ведущую и ведомую операции. Вы ничего не получите от устройства MODBUS, используя MSComm или Hyperterminal. Протокол MODBUS уже довольно хорошо задокументирован, но его не так просто внедрить. Также существует множество вариаций. Вероятно, потребуется несколько тысяч строк кода, чтобы понять основы. Известная и зрелая коммерческая библиотека, возможно, является лучшим подходом, и она также включает техническую поддержку, которая необходима для такого рода продуктов. Например, SuperCom, коммерческая программная библиотека, предлагающая MODBUS для последовательной передачи данных и передачи данных TCP, а также поддерживающая MFC. . Также включены клиентские (ведущие) и ведомые функции. И он предлагает множество примеров для известных компиляторов. Там наверняка есть больше коммерческих решений.

person lindev123    schedule 12.11.2015

Здесь две проблемы:

1/ Вы не можете подключить три устройства вместе через RS232. RS232 является двухточечным, что означает, что только два устройства могут быть соединены вместе.

2/ Ведомый отправляет данные только по запросу ведущего. Если ведущий не отправит запрос MODBUS первым, вы никогда не получите ответ от подчиненных.

PS: у меня такое ощущение, что m_MSComm.SetCommID() нужно вызывать до открытия порта, а не после.

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

В первом документе рассказывается, как создать запрос (PDU), а во втором подробно описано, как запрос должен быть инкапсулирован в «транспортный» кадр (ADU), подходящий для последовательной связи.

Самый распространенный запрос — «Чтение регистров временного хранения» (функция №3). Если ваше ведомое устройство имеет адрес 5, и вы хотите прочитать два регистра, начиная с адреса 10, то ваш запрос будет выглядеть примерно так: 0x05 0x03 0x000A 0x0002 0x???? (где '????' - значение CRC16, которое мне лень вычислять).

person Alexandre Vinçon    schedule 05.02.2013
comment
Спасибо за ваш ответ. У меня кстати одно устройство с тремя разными адресами. Моя формулировка была неточной. Вы случайно не знаете, как создать такой запрос? - person Andreas D.; 07.02.2013
comment
Я пытался обрабатывать устройство как файл. Пожалуйста, просмотрите мое редактирование. @Омер Мердан - person Andreas D.; 07.02.2013