Программирование arduino для OPC сервера.

Po1SoN
Offline
Зарегистрирован: 25.05.2014

Добрый день.

Помогите пожалуйста с программированием ардуино (а конкретно 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 = &regBank;
    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.

toc
Offline
Зарегистрирован: 09.02.2013

Орс — река в России, протекает в Орловской области. Левый приток реки Нугрь.

ont_07
Offline
Зарегистрирован: 10.09.2016

Никто не знает как помочь человеку???

У меня аналогичная проблема. К кому можно обратиться, если не писать на форум.

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Нужно взять монитор COM порта и посмотреть что происходит на линии. Сервер должен передавать запрос, а slave на ардуине отвечать. Если ответа нет, то проблема в коде. Монитор: Eltima Software Serial Port Monitor.

Лично я бы использовал исходники Free Modbus или написал клиент самостоятельно.

ont_07
Offline
Зарегистрирован: 10.09.2016

Речь, скорее всего,  идет о понимании того что должно происходить. Если не затруднит, сообщите какие используете библиотеки и откуда их можно загрузить. Возможно проблема в этом. Второй вопрос: что надо спросить у клиента и как это должно быть в стандартном ком-терминале?

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Нужно правильно настроить master и slave: адрес прибора, параметры последовательного соединения, адрес регистра и его тип. Если эти параметры с обоих сторон настроены, то смотрим какие данные есть на линии. Что конкретно спрашивает мастер и то ли это что ожидает slave. FreeModbus можно найти в сети на одноимённом сайте, его можно использовать в c++ проекте.

Если не понятно, то нужно поискать стандарт Modbus RTU, там всё написано, дока есть на modbus.org.

ont_07
Offline
Зарегистрирован: 10.09.2016

Спасибо за ответ! Сейчас как раз разбираюсь с этим вопросом. Возможно есть четкие рекомендации где и что искать. Очень хотелось бы понять, для начала, как это работает на самом простом уровне (Arduino). Возможно есть готовые решения. Было бы интересно узнать, кто и как использует данные решения и какие OPC сервера.

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Введение в протокол Modbus. Часть 1

Введение в протокол Modbus. Часть 2

Я готовых не видел, но собирал примеры на C++ для AVR на основе Free Modbus. Только ссылки там битые, т.к. я изменил адреса репозиториев.

Вот исходники примера на AVR: freemobdus

James
Offline
Зарегистрирован: 26.02.2016

MasterOPC Universal Modbus Server я пользовался им. контроллер просто опрашивает? управлением он не занимается? смысл тогда его грузить, если это можно делать на стороне компа?просто опрашивайте порт и пишите в регистр.

SmartRnd
Offline
Зарегистрирован: 13.09.2016

Вот бесплатная программа, которая может опрашивать и управлять устройствами 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

ont_07
Offline
Зарегистрирован: 10.09.2016

Спасибо за ответы! Проблема в том что клиент не желает общаться с сервером по "протоколу". Очень хотел бы увидеть живой пример передачи аналогового измерения ОРС серверу (можно одного). В сети нашел всего два примера, но оба заточены подо что-то свое и не желают работать. Механизм в общем понятен, но в одном случее все пережевано и не понятно что делать, а в другом автор просто запускает и все работает, но скейтч не желает передавть данные, а внимание настройкам ОРС - 0 (непонятно еще, зачем задействовать 4 канала если 3 значения).

ont_07
Offline
Зарегистрирован: 10.09.2016

Спасибо за рекомендацию ModBus RTU интересная штука;)  Хорошо работает и на больших скоростях. Проблема уже решена. Всем Спасибо!

ont_07
Offline
Зарегистрирован: 10.09.2016

К сожалению, пока не получается передать данные Ардуино. Упорно не желает воспринимать внешние данные. Если кто знает, прошу подсказать.

SmartRnd
Offline
Зарегистрирован: 13.09.2016

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

Tarantino
Offline
Зарегистрирован: 04.06.2017

Po1SoN пишет:
Я просмотрел библиотеку MODBUS в которой был описан пример, который использовал в программе.

Ищу хорошую библиотеку Modbus

 

cuperxs
Offline
Зарегистрирован: 16.10.2018

Актуальная ссылка на ОРС http://st4makers.com/old/phocadownload/arduinoopcserver_2_0.zip ибо старые не работают.

SmartRnd
Offline
Зарегистрирован: 13.09.2016

Здесь бесплатная программа-контроллер ModBus с if-then-else логикой и обучающими видео:
https://smart-elec.ru/show_mobile.php?page1=46&page2=42&razdel=1&info=121