Программирование arduino для OPC сервера.
- Войдите на сайт для отправки комментариев
Пнд, 26/05/2014 - 16:52
Добрый день.
Помогите пожалуйста с программированием ардуино (а конкретно mega 2560).
На opc сервер необходимо получить/передать данные с ардуино, который в свою очередь получает данные с датчика DS18B20 (датчик температуры). На данном этапе имеется реализация с помощью библиотек OPC, MODBUS, OneWire, DallasTemperature.
#include <OneWire.h> #include <modbus.h> #include <modbusDevice.h> #include <modbusRegBank.h> #include <modbusSlave.h> #include <DallasTemperature.h> // OneWire DS18S20, DS18B20, DS1822 Temperature Example // // http://www.pjrc.com/teensy/td_libs_OneWire.html // // The DallasTemperature library can do all this work for you! // http://milesburton.com/Dallas_Temperature_Control_Library OneWire ds(10); // on pin 10 (a 4.7K resistor is necessary) modbusDevice regBank; //All of the data accumulated will be stored here modbusSlave slave; //Create the modbus slave protocol handler DallasTemperature sensors(&ds); struct Sensor { float MV; // measured value - измереное значение датчика int HH_SP; // high high set point - уставка аварийно высокого уровня датчика int H_SP; // high set point - уставка высокого уровня датчика int L_SP; // low set point - уставка низкого уровня датчика int LL_SP; // low low set point - уставка аварийно низкого уровня датчика boolean HH_Detect; // high high detect - сработка уставки аварийно высокого уровня датчика boolean H_Detect; // high detect - сработка уставки высокого уровня датчика boolean L_Detect; // low detect - сработка уставки низкого уровня датчика boolean LL_Detect; // low low detect - сработка уставки аварийно низкого уровня датчика }; Sensor TMP01; //Датчик температуры TMP01 DeviceAddress TMP01_Address = { 0x28, 0x6B, 0xBC, 0x47, 0x05, 0x00, 0x00, 0x18 }; //Адрес предварительно считывается другой программой и вписывается сюда // if (OneWire::crc8(addr, 7) != addr[7]) { // Serial.println("CRC is not valid!"); // return; void setup(void) { Serial.begin(9600); sensors.begin(); regBank.setId(1); regBank.add(300001); regBank.add(300002); slave._device = ®Bank; slave.setBaud(9600); slave.run(); } void loop(void) { sensors.requestTemperatures(); TMP01.MV = sensors.getTempC(TMP01_Address); regBank.set(300001,TMP01.MV*100); byte i; byte present = 0; byte type_s; byte data[12]; byte addr[8]; float celsius, fahrenheit; if ( !ds.search(addr)) { Serial.println("No more addresses."); Serial.println(); ds.reset_search(); delay(2000); return; } Serial.print("ROM ="); for( i = 0; i < 8; i++) { Serial.write(' '); Serial.print(addr[i], HEX); } Serial.println(); // the first ROM byte indicates which chip switch (addr[0]) { case 0x10: Serial.println(" Chip = DS18S20"); // or old DS1820 type_s = 1; break; case 0x28: Serial.println(" Chip = DS18B20"); type_s = 0; break; case 0x22: Serial.println(" Chip = DS1822"); type_s = 0; break; default: Serial.println("Device is not a DS18x20 family device."); return; } ds.reset(); ds.select(addr); ds.write(0x44, 1); // start conversion, with parasite power on at the end delay(2000); // maybe 750ms is enough, maybe not // we might do a ds.depower() here, but the reset will take care of it. present = ds.reset(); ds.select(addr); ds.write(0xBE); // Read Scratchpad Serial.print(" Data = "); Serial.print(present, HEX); Serial.print(" "); for ( i = 0; i < 9; i++) { // we need 9 bytes data[i] = ds.read(); Serial.print(data[i], HEX); Serial.print(" "); } Serial.print(" CRC="); Serial.print(OneWire::crc8(data, 8), HEX); Serial.println(); // Convert the data to actual temperature // because the result is a 16 bit signed integer, it should // be stored to an "int16_t" type, which is always 16 bits // even when compiled on a 32 bit processor. int16_t raw = (data[1] << 8) | data[0]; if (type_s) { raw = raw << 3; // 9 bit resolution default if (data[7] == 0x10) { // "count remain" gives full 12 bit resolution raw = (raw & 0xFFF0) + 12 - data[6]; } } else { byte cfg = (data[4] & 0x60); // at lower res, the low bits are undefined, so let's zero them if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms //// default is 12 bit resolution, 750 ms conversion time } celsius = (float)raw / 16.0; fahrenheit = celsius * 1.8 + 32.0; Serial.print(" Temperature = "); Serial.print(celsius); Serial.print(" Celsius, "); Serial.print(fahrenheit); Serial.println(" Fahrenheit"); slave.run(); }
Я просмотрел библиотеку MODBUS в которой был описан пример, который использовал в программе. Во время запуска OPC сервера состояние тега показывает BAD. Помогите разобраться, что не так в коде или есть какие-то нюансы. Передача идет по COM порту. OPC сервер версии KepWare v4.
Орс — река в России, протекает в Орловской области. Левый приток реки Нугрь.
Никто не знает как помочь человеку???
У меня аналогичная проблема. К кому можно обратиться, если не писать на форум.
Нужно взять монитор COM порта и посмотреть что происходит на линии. Сервер должен передавать запрос, а slave на ардуине отвечать. Если ответа нет, то проблема в коде. Монитор: Eltima Software Serial Port Monitor.
Лично я бы использовал исходники Free Modbus или написал клиент самостоятельно.
Речь, скорее всего, идет о понимании того что должно происходить. Если не затруднит, сообщите какие используете библиотеки и откуда их можно загрузить. Возможно проблема в этом. Второй вопрос: что надо спросить у клиента и как это должно быть в стандартном ком-терминале?
Нужно правильно настроить master и slave: адрес прибора, параметры последовательного соединения, адрес регистра и его тип. Если эти параметры с обоих сторон настроены, то смотрим какие данные есть на линии. Что конкретно спрашивает мастер и то ли это что ожидает slave. FreeModbus можно найти в сети на одноимённом сайте, его можно использовать в c++ проекте.
Если не понятно, то нужно поискать стандарт Modbus RTU, там всё написано, дока есть на modbus.org.
Спасибо за ответ! Сейчас как раз разбираюсь с этим вопросом. Возможно есть четкие рекомендации где и что искать. Очень хотелось бы понять, для начала, как это работает на самом простом уровне (Arduino). Возможно есть готовые решения. Было бы интересно узнать, кто и как использует данные решения и какие OPC сервера.
Введение в протокол Modbus. Часть 1
Введение в протокол Modbus. Часть 2
Я готовых не видел, но собирал примеры на C++ для AVR на основе Free Modbus. Только ссылки там битые, т.к. я изменил адреса репозиториев.
Вот исходники примера на AVR: freemobdus
MasterOPC Universal Modbus Server я пользовался им. контроллер просто опрашивает? управлением он не занимается? смысл тогда его грузить, если это можно делать на стороне компа?просто опрашивайте порт и пишите в регистр.
Вот бесплатная программа, которая может опрашивать и управлять устройствами ModBus RTU 9600 по алгоритму, который сами напишите. К ней нужен любой преобразователь USB-RS485 (сам использую OWEN AC4).
http://alpha-se.ru/alpha.php?page1=406&page2=42&razdel=3&info=114
Если программу запустить с параметром /echo, то на экран будут выводиться все исходящие и входящие команды ModBus. Из неё же можно управлять регистрами ModBus устройств.
Обучающее видео по работе есть здесь: http://alpha-se.ru/alpha.php?page1=403&page2=124#ModBus
Спасибо за ответы! Проблема в том что клиент не желает общаться с сервером по "протоколу". Очень хотел бы увидеть живой пример передачи аналогового измерения ОРС серверу (можно одного). В сети нашел всего два примера, но оба заточены подо что-то свое и не желают работать. Механизм в общем понятен, но в одном случее все пережевано и не понятно что делать, а в другом автор просто запускает и все работает, но скейтч не желает передавть данные, а внимание настройкам ОРС - 0 (непонятно еще, зачем задействовать 4 канала если 3 значения).
Спасибо за рекомендацию ModBus RTU интересная штука;) Хорошо работает и на больших скоростях. Проблема уже решена. Всем Спасибо!
К сожалению, пока не получается передать данные Ардуино. Упорно не желает воспринимать внешние данные. Если кто знает, прошу подсказать.
В rs485 одна нога используется для переключения межу приемом и передачей. Подали в rs485 на контрольную ногу высокий уровень и передаем. Передали, установили низкий уровень и принимаем. В примерах, которые приводятся, об этом не говорится. Видимо, они приведены для rs232, где переключаться между приемом и передачей не нужно.
Ищу хорошую библиотеку Modbus
Актуальная ссылка на ОРС http://st4makers.com/old/phocadownload/arduinoopcserver_2_0.zip ибо старые не работают.
Здесь бесплатная программа-контроллер ModBus с if-then-else логикой и обучающими видео:
https://smart-elec.ru/show_mobile.php?page1=46&page2=42&razdel=1&info=121