Как стать автором
Обновить

Arduino для опроса счетчиков «Меркурий-230»

Время на прочтение16 мин
Количество просмотров21K
При обслуживании приборов учета Меркурий-230 ART, установленных на удаленных
трансформаторных подстанциях, часто возникает необходимость оперативной проверки работоспособности счетчиков.

Как правило, в местах, где счетчики работают в составе АСКУЭ и соединены в группы по витой
паре RS 485 и подключены к шлюзу Меркурий 228, происходит пропадание связи в момент
установления связи со стороны сервера.

Чтобы выяснить, по какой причине данные со счетчика не поступают на сервер, необходимо с
собой постоянно носить ноутбук и преобразователь Меркурий 221, а в случае проверки
правильности подключения счетчика в ячейке еще необходимо использовать прибор ВАФ.
Учитывая, что на подстанциях в ОРУ или ЗРУ не всегда имеется возможность обеспечения места для работы с компьютерным оборудованием, мною был разработан небольшой прибор на базе модулей Arduino от amperka.ru.

Опрос счетчиков производится из приложения установленного на смартфоне, при этом связь осуществляется через Bluetooth.

Плата преобразователя.


Плата преобразователя представляет собой набор модулей:

Iskra Mini — полноценная Arduino-платформа с установленным микроконтроллером ATmega328.
Плата расширения — Bluetooth-модуль HC-05.
Плата расширения — Приёмопередатчик RS-485.
— Аккумуляторный элемент питания 9В типа «Крона» (сразу оговорюсь неудачный вариант, лучше использовать аккумулятор для подзарядки телефонов)
— Кнопка включения.
— USB разъем для подачи питания 5В.
— Разъем RJ11 для подключения линии RS485.

Все элементы располагаются на отдельной материнской плате, помещенной в пластмассовом корпусе. При включении преобразователя Bluetooth-модуль HC-05 переходит в режим работы
«прозрачного UART» и ожидает подключения со стороны смартфона.

image

Схема соединений.


При включении переключателя SW1 напряжение питания 9-12 Вольт подается на электронный
регулятор LM7805 (желательно заменить на иную модель).

С выхода регулятора пониженное напряжение 5 Вольт подается на pin «+5V» Iskra Mini, pin «V» Bluetooth модуля и pin «V» модуля RS485. Отрицательный провод аккумулятора подключается к выводам GND всех модулей. При подаче напряжения питания 5 Вольт через разъем microUSB, все модули запитываются аналогично, минуя регулятор LM7805.

J1 и J2 являются перемычками и должны быть замкнуты в рабочем режиме.
J3 – шести контактный разъем, предназначенный для «прошивки» модуля Iskra Mini с помощью
USB-Serial адаптера.

При загрузке ПО в модуль Iskra Mini, перемычки J1 и J2 должны быть разомкнуты. Конденсатор С1 предназначен для осуществления сброса микроконтроллера в момент выполнения загрузки ПО.

Вывод «RX» Iskra Mini соединяется с выводом «TX» Bluetooth модуля, таким образом
микроконтроллер осуществляет прием данных из Bluetooth.
Вывод «ТX» Iskra Mini соединяется с выводом «RX» Bluetooth модуля, таким образом
микроконтроллер производит передачу команд в Bluetooth.
Вывод «8» Iskra Mini соединяется с выводом «DI» модуля RS485, микроконтроллер производит
передачу команд в линию.
Вывод «11» Iskra Mini соединяется с выводом «RO» модуля RS485, микроконтроллер производит
чтение ответов из линии.
Вывод «5» Iskra Mini соединяется с выводом «In/Out» модуля RS485, микроконтроллер
осуществляет переключение режимов работы приемо-передатчика RS485.
RJ11 – разъем для подключения линии RS485.

image

Программное обеспечение преобразователя.


После подачи питания на устройство микроконтроллер переходит в режим циклического
ожидания получения команды.

Перечень команд:

ping_ -- после получения этой команды МК в ответ отсылает «ping_».
Используется для тестирования канала связи между смартфоном и преобразователем.

scan_ -- команда сканирования сети на наличие приборов учета от адреса 0 до адреса 254

init_XXX – где ХХХ это сетевой адрес опрашиваемого прибора учета. Надо учитывать, что к сетевым адресам меньше 10 должны добавляться два нуля, 
а адресам меньше 100 – один ноль. 
После получения этой команды МК в ответ отсылает «init_XXX». 
Используется для однократного опроса прибора учета.
 Пример.
 Прибор учета № 13 02 97 02
 Команда: init_002
 Ответ: init_002
 Прибор учета № 16 24 07 32
 Команда: init_032
 Ответ: init_032
 Прибор учета № 17 14 51 52
 Команда: init_152
 Ответ: init_152

loop_XXX – После получения этой команды МК в ответ отсылает «loop_XXX». 
Используется для непрерывного опроса прибора учета.

stop_ – После получения этой команды МК в ответ отсылает «stop_000». Используется для
остановки режима непрерывного опроса прибора учета.

Варианты ответов микроконтроллера после выполнения команд:

Connect_OK – устройство с указанным сетевым адресом обнаружено в сети.
Connect_FAIL – устройства с этим сетевым адресом не отвечает.
Access_OK – пароль доступа передан, ответ получен.
Access_FAIL – доступ закрыт, пароль не принят.

Алгоритм работы ПО микроконтроллера.


После получения команды init или loop отправляется байтовая последовательность
Net Address, 0x00, 0x00, CRC 1, CRC 2.

В случае нахождения устройства в сети будет аналогичный ответ, после чего сравниваются сетевые адреса — отправленный и полученный.

Проверки CRC в ответном массиве на настоящий момент не производится.
При положительном сравнении в модуль Bluetooth отправляется строка Connect_OK, в противном случае Connect_FAIL.

Далее отправляется запрос доступа с передачей пароля Net Address, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, CRC 1, CRC.

При получении ответа, аналогичного в запросе на обнаружение устройства, в модуль Bluetooth отправляется строка Access_OK, в противном случае Access_FAIL.

После установления связи начинается передача запросов для получения данных согласно
протоколу.

Net Address, 0x00, 0x08, 0x00, CRC 1, CRC -- серийный номер
Net Address, 0x00, 0x08, 0x16, 0x40, CRC 1, CRC -- частота
Net Address, 0x00, 0x08, 0x16, 0x21, CRC 1, CRC -- ток
Net Address, 0x00, 0x08, 0x16, 0x11, CRC 1, CRC -- напряжение
Net Address, 0x00, 0x08, 0x16, 0x00, CRC 1, CRC-- мощность
Net Address, 0x00, 0x08, 0x16, 0x51, CRC 1, CRC -- углы
Net Address, 0x00, 0x05, 0x00, 0x00, CRC 1, CRC -- суммарная энергия прямая + обратная + активная + реактивная.

Ссылаясь на рекомендации производителя, особое внимание следует уделять величине timeout между запросом и ответом, поскольку преобразователь всегда является устройством Master, а опрашиваемые устройства -Slave.

Опыт показывает, что величина timeout и количество корректных ответов зависит от качества и длины линии RS485, поэтому возможно придется вносить корректировки в эти параметры.

m230.ino
#include <SoftwareSerial.h>
//-------- порты для rs 485
#define SSerialRx        11  // Serial Receive pin RO
#define SSerialTx        8   // Serial Transmit pin DI
//-------- инициализация 
SoftwareSerial RS485Serial(SSerialRx, SSerialTx); // Rx, Tx

//// линия управления передачи приема
#define SerialControl 5   // RS485 Direction control
/////// флаг приема передачи
#define RS485Transmit    HIGH
#define RS485Receive     LOW
/////// команды
byte testConnect[] = { 0x00, 0x00 };
byte Access[]      = { 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
byte Sn[]          = { 0x00, 0x08, 0x00 }; // серийный номер
byte Freq[]        = { 0x00, 0x08, 0x16, 0x40 }; // частота
byte Current[]     = { 0x00, 0x08, 0x16, 0x21 };//  ток
byte Suply[]       = { 0x00, 0x08, 0x16, 0x11 }; // напряжение
byte Power[]       = { 0x00, 0x08, 0x16, 0x00 };// мощность p
byte PowerQ[]       = { 0x00, 0x08, 0x16, 0x08 };// мощность Q
byte PowerS[]       = { 0x00, 0x08, 0x16, 0x04 };// мощность S

byte CosF[]       = { 0x00, 0x08, 0x16, 0x30 };// cosf


byte Angle[]       = { 0x00, 0x08, 0x16, 0x51 }; // углы
byte energyT0[]  =   { 0x00, 0x05, 0x00, 0x00 };///  суммарная энергия прямая + обратная + активная + реактивная
byte energyT1[]  =   { 0x00, 0x05, 0x00, 0x01 };///  суммарная энергия прямая + обратная + активная + реактивная
byte energyT2[]  =   { 0x00, 0x05, 0x00, 0x02 };///  суммарная энергия прямая + обратная + активная + реактивная
byte energyT3[]  =   { 0x00, 0x05, 0x00, 0x03 };///  суммарная энергия прямая + обратная + активная + реактивная
byte energyT4[]  =   { 0x00, 0x05, 0x00, 0x04 };///  суммарная энергия прямая + обратная + активная + реактивная


byte response[19];
int byteReceived;
int byteSend;
int netAdr;
int SCAN_YES_NO=0;
int TST_YES_NO=0;  
int ACCESS_YES_NO=0;
int ALLOW=0; 

void setup() {
RS485Serial.begin(9600);
Serial.begin(9600);
// 5 пин в режим выхода
pinMode(SerialControl, OUTPUT);
// ставим на прием
digitalWrite(SerialControl, RS485Receive);
delay(300);
Serial.println("Start_v2.3\r\n");
}

void loop() {

TST_YES_NO=0;  
ACCESS_YES_NO=0;
ALLOW=0;  
                      
               while (Serial.available()) 
              {    char incomingBytes[15]; 
              
                   if(Serial.available()>0)       
                    {      
                        Serial.readBytes(incomingBytes,10);
                     
                    }                   
                           String getS = String(incomingBytes);
                               if(getS.substring(0,5) == "init_") 
                            { ALLOW=1;  
                                   Serial.print(getS.substring(0,5)+getS.substring(5,8)+"\r\n");
                              netAdr=getS.substring(5,8).toInt();
                            }


                               if(getS.substring(0,5) == "loop_") 
                            { ALLOW=1;
                              SCAN_YES_NO=1;  
                              Serial.print(getS.substring(0,5)+getS.substring(5,8)+"\r\n");
                              netAdr=getS.substring(5,8).toInt();
                            }


                              if(getS.substring(0,5) == "scan_") 
                            { ALLOW=0;
                              SCAN_YES_NO=0;  
                              Serial.print(getS.substring(0,5)+"\r\n");

                                     netAdr=1;
                                     while(netAdr < 256)
                                     {
                                        testConnect[0] = netAdr;
                                        response[0] = 0;
                                        send(testConnect, sizeof(testConnect), response);
                                               if(response[0] == netAdr)
                                             { 
                                                   Serial.print("scan;ok;"+String(netAdr)+";0\r\n");   
                          
                                             }
                                                   else
                                             {     
                                                   Serial.print("scan;no;"+String(netAdr)+";0\r\n");   


                                             }
                                     netAdr++;
                                     delay(5);
                                     }
                                     netAdr=0;
                             
                            }


                                  if(getS.substring(0,5) == "stop_") 
                            { ALLOW=0;
                              SCAN_YES_NO=0;  
                              Serial.print(getS.substring(0,5)+"000\r\n");
                              //netAdr=getS.substring(5,8).toInt();
                            }

                                  if(getS.substring(0,5) == "ping_") 
                            {   
                              Serial.print(getS.substring(0,5)+"\r\n");
                              
                            }
                      
            
                }
 



 if(ALLOW==1 or SCAN_YES_NO==1)
{
 //========================================================================
  testConnect[0] = netAdr;
  response[0] = 0;
  send(testConnect, sizeof(testConnect), response);
       if(response[0] == netAdr)
      {      TST_YES_NO=1;
             Serial.print("Connect_OK\r\n");   
              
             
      }
       else
      {      TST_YES_NO=0;
             Serial.print("Connect_FAIL\r\n");   
      }


  //========================================================================

     if(TST_YES_NO==1)
     {
          
          delay(100);
          Access[0] = netAdr;
          response[0] = 0;
          send(Access, sizeof(Access), response);
              if(response[0] == netAdr)
             {      ACCESS_YES_NO=1;
                    Serial.print("Access_OK\r\n");   
             }
              else
             {      ACCESS_YES_NO=0;
                    Serial.print("Access_FAIL\r\n");   
             }

     }

        if(ACCESS_YES_NO==1)
     {

         String serNum = getSerialNumber(netAdr);
         Serial.print("s:"+ serNum +"\r\n");   
         String ARPower = getEnergyT0(netAdr);
         Serial.print("p:"+ ARPower+"\r\n");   
         String valFreq = getFreq(netAdr);
         Serial.print("f:"+ valFreq+"\r\n");   
         String U = getSuply(netAdr);
         Serial.print("u:"+ U+"\r\n");   
         String A = getCurrent(netAdr);
         Serial.print("a:"+ A+"\r\n");   
         String Angle = getAngle(netAdr);
         Serial.print("g:"+ Angle+"\r\n");   
         String PowerNow = getPowerNow(netAdr);
         Serial.print("e:"+ PowerNow+"\r\n");  
         String Tarif1 = getEnergyT1(netAdr);
         Serial.print("t1:"+ Tarif1+"\r\n");  
         String Tarif2 = getEnergyT2(netAdr);
         Serial.print("t2:"+ Tarif2+"\r\n");  
         String Tarif3 = getEnergyT3(netAdr);
         Serial.print("t3:"+ Tarif3+"\r\n");  
         String Tarif4 = getEnergyT4(netAdr);
         Serial.print("t4:"+ Tarif4+"\r\n");  
         String PQ = getPowerQ(netAdr);
         Serial.print("q:"+ PQ+"\r\n");  
         String PS = getPowerS(netAdr);
         Serial.print("c:"+ PS+"\r\n");  
         String CSF = getCosF(netAdr);
         Serial.print("k:"+ CSF+"\r\n");  
       
      
     }
   

  delay(1000);
}

}


String getSerialNumber(int netAdr)
{
  String s1,s2,s3,s4;
  response[0]=0;
  Sn[0] = netAdr;
  send(Sn, sizeof(Sn),response);
  if((int)response[1] < 10) { s1="0" + String((int)response[1]); } else {s1=String((int)response[1]);}
  if((int)response[2] < 10) { s2="0" + String((int)response[2]); } else {s2=String((int)response[2]);}
  if((int)response[3] < 10) { s3="0" + String((int)response[3]); } else {s3=String((int)response[3]);}
  if((int)response[4] < 10) { s4="0" + String((int)response[4]); } else {s4=String((int)response[4]);}
  String n = s1+s2+s3+s4;
  
  return String(response[0])+";"+n;
}


String getPowerNow(int netAdr)
{
 
  response[0]=0;
  Power[0] = netAdr;
  send(Power, sizeof(Power),response);
  long r = 0;
  int dir_U0=0;
  int dir_U1=0;
  int dir_U2=0;
  int dir_U3=0;

  if((long)response[1]<<16 == 0x40) dir_U0=1;
  if((long)response[1]<<16 == 0x80) dir_U0=-1;
  r |= (long)response[3]<<8;
  r |= (long)response[2];
  String U0= String(r * dir_U0);
  r = 0;

  if((long)response[4]<<16 == 0x40) dir_U1=1;
  if((long)response[4]<<16 == 0x80) dir_U1=-1;
  r |= (long)response[6]<<8;
  r |= (long)response[5];
  String U1= String(r * dir_U1);
  r=0;

  if((long)response[7]<<16 == 0x40) dir_U2=1;
  if((long)response[7]<<16 == 0x80) dir_U2=-1;
  r |= (long)response[9]<<8;
  r |= (long)response[8];
  String U2= String(r * dir_U2);
  r = 0;

  if((long)response[10]<<16 == 0x40) dir_U3=1;
  if((long)response[10]<<16 == 0x80) dir_U3=-1;
  r |= (long)response[12]<<8;
  r |= (long)response[11];
  String U3= String(r * dir_U3);
  if(response[0] == netAdr)   return String(String(response[0])+";"+U0+";"+U1+";"+U2+";"+U3);
  else   return String("Error");
 
 
}

String getPowerQ(int netAdr)
{
 
  response[0]=0;
  PowerQ[0] = netAdr;
  send(PowerQ, sizeof(PowerQ),response);
  long r = 0;
  int dir_U0=0;
  int dir_U1=0;
  int dir_U2=0;
  int dir_U3=0;

  if((long)response[1]<<16 == 0x40) dir_U0=1;
  if((long)response[1]<<16 == 0x80) dir_U0=-1;
  r |= (long)response[3]<<8;
  r |= (long)response[2];
  String U0= String(r * dir_U0);
  r = 0;

  if((long)response[4]<<16 == 0x40) dir_U1=1;
  if((long)response[4]<<16 == 0x80) dir_U1=-1;
  r |= (long)response[6]<<8;
  r |= (long)response[5];
  String U1= String(r * dir_U1);
  r=0;

  if((long)response[7]<<16 == 0x40) dir_U2=1;
  if((long)response[7]<<16 == 0x80) dir_U2=-1;
  r |= (long)response[9]<<8;
  r |= (long)response[8];
  String U2= String(r * dir_U2);
  r = 0;

  if((long)response[10]<<16 == 0x40) dir_U3=1;
  if((long)response[10]<<16 == 0x80) dir_U3=-1;
  r |= (long)response[12]<<8;
  r |= (long)response[11];
  String U3= String(r * dir_U3);
  if(response[0] == netAdr)   return String(String(response[0])+";"+U0+";"+U1+";"+U2+";"+U3);
  else   return String("Error");
 

}

String getPowerS(int netAdr)
{
 
  response[0]=0;
  PowerS[0] = netAdr;
  send(PowerS, sizeof(PowerS),response);
  long r = 0;
  int dir_U0=0;
  int dir_U1=0;
  int dir_U2=0;
  int dir_U3=0;

  if((long)response[1]<<16 == 0x40) dir_U0=1;
  if((long)response[1]<<16 == 0x80) dir_U0=-1;
  r |= (long)response[3]<<8;
  r |= (long)response[2];
  String U0= String(r * dir_U0);
  r = 0;

  if((long)response[4]<<16 == 0x40) dir_U1=1;
  if((long)response[4]<<16 == 0x80) dir_U1=-1;
  r |= (long)response[6]<<8;
  r |= (long)response[5];
  String U1= String(r * dir_U1);
  r=0;

  if((long)response[7]<<16 == 0x40) dir_U2=1;
  if((long)response[7]<<16 == 0x80) dir_U2=-1;
  r |= (long)response[9]<<8;
  r |= (long)response[8];
  String U2= String(r * dir_U2);
  r = 0;

  if((long)response[10]<<16 == 0x40) dir_U3=1;
  if((long)response[10]<<16 == 0x80) dir_U3=-1;
  r |= (long)response[12]<<8;
  r |= (long)response[11];
  String U3= String(r * dir_U3);
  if(response[0] == netAdr)   return String(String(response[0])+";"+U0+";"+U1+";"+U2+";"+U3);
  else   return String("Error");
 
 
}

String getCosF(int netAdr)
{
  response[0]=0;
  CosF[0] = netAdr;
  send(CosF, sizeof(CosF),response);
  long r = 0;

  int dir_U0=0;
  int dir_U1=0;
  int dir_U2=0;
  int dir_U3=0;

  if((long)response[1]<<16 == 0x40) dir_U0=1;
  if((long)response[1]<<16 == 0x80) dir_U0=-1;
  r |= (long)response[3]<<8;
  r |= (long)response[2];
  String U0= String(r * dir_U0);
  r = 0;

  if((long)response[4]<<16 == 0x40) dir_U1=1;
  if((long)response[4]<<16 == 0x80) dir_U1=-1;
  r |= (long)response[6]<<8;
  r |= (long)response[5];
  String U1= String(r * dir_U1);
  r=0;

  if((long)response[7]<<16 == 0x40) dir_U2=1;
  if((long)response[7]<<16 == 0x80) dir_U2=-1;
  r |= (long)response[9]<<8;
  r |= (long)response[8];
  String U2= String(r * dir_U2);
  r = 0;

  if((long)response[10]<<16 == 0x40) dir_U3=1;
  if((long)response[10]<<16 == 0x80) dir_U3=-1;
  r |= (long)response[12]<<8;
  r |= (long)response[11];
  String U3= String(r * dir_U3);
  if(response[0] == netAdr)   return String(String(response[0])+";"+U0+";"+U1+";"+U2+";"+U3);
  else   return String("Error");
 
}



String getAngle(int netAdr)
{
 
  response[0]=0;
  Angle[0] = netAdr;
  send(Angle, sizeof(Angle),response);
  long r = 0;
  r |= (long)response[1]<<16;
  r |= (long)response[3]<<8;
  r |= (long)response[2];
  String U1= String(r);
  r = 0;
  r |= (long)response[4]<<16;
  r |= (long)response[6]<<8;
  r |= (long)response[5];
  String U2= String(r);
  r=0;
  r |= (long)response[7]<<16;
  r |= (long)response[9]<<8;
  r |= (long)response[8];
  String U3= String(r);
  if(response[0] == netAdr)   return String(String(response[0])+";"+U1+";"+U2+";"+U3);
  else   return String("Error");

}


String getCurrent(int netAdr)
{
  response[0]=0;
  Current[0] = netAdr;
  send(Current, sizeof(Current),response);
  long r = 0;
  r |= (long)response[1]<<16;
  r |= (long)response[3]<<8;
  r |= (long)response[2];
  String U1= String(r);
  r = 0;
  r |= (long)response[4]<<16;
  r |= (long)response[6]<<8;
  r |= (long)response[5];
  String U2= String(r);
  r=0;
  r |= (long)response[7]<<16;
  r |= (long)response[9]<<8;
  r |= (long)response[8];
  String U3= String(r);
  if(response[0] == netAdr)   return String(String(response[0])+";"+U1+";"+U2+";"+U3);
  else   return String("Error");

}

String getSuply(int netAdr)
{
 
  response[0]=0;
  Suply[0] = netAdr;
  send(Suply, sizeof(Suply),response);
  long r = 0;
  r |= (long)response[1]<<16;
  r |= (long)response[3]<<8;
  r |= (long)response[2];
  String U1= String(r);
  r = 0;
  r |= (long)response[4]<<16;
  r |= (long)response[6]<<8;
  r |= (long)response[5];
  String U2= String(r);
  r=0;
  r |= (long)response[7]<<16;
  r |= (long)response[9]<<8;
  r |= (long)response[8];
  String U3= String(r);
  if(response[0] == netAdr)   return String(String(response[0])+";"+U1+";"+U2+";"+U3);
  else   return String("Error");

}


String getFreq(int netAdr)
{
 
  response[0]=0;
  Freq[0] = netAdr;
  send(Freq, sizeof(Freq),response);
 
  long r = 0;
  r |= (long)response[1]<<16;
  r |= (long)response[3]<<8;
  r |= (long)response[2];
  String fr= String(r);
  //return fr;
  if(response[0] == netAdr)   return String(response[0])+";"+fr;
  else   return String("Error");

}

String getEnergyT0(int netAdr)
{
  response[0]=0;
  energyT0[0] = netAdr;
  send(energyT0, sizeof(energyT0),response);
  if(response[0] == netAdr) 
  {
  long r = 0;
  r |= (long)response[2]<<24;
  r |= (long)response[1]<<16;
  r |= (long)response[4]<<8;
  r |= (long)response[3];
  String A_plus= String(r);
  r=0;
  r |= (long)response[6]<<24;
  r |= (long)response[5]<<16;
  r |= (long)response[8]<<8;
  r |= (long)response[7];
  String A_minus= String(r);
  r = 0;
  r |= (long)response[10]<<24;
  r |= (long)response[9]<<16;
  r |= (long)response[12]<<8;
  r |= (long)response[11];
  String R_plus= String(r);
  r = 0;
  r |= (long)response[14]<<24;
  r |= (long)response[13]<<16;
  r |= (long)response[16]<<8;
  r |= (long)response[15];
  String R_minus= String(r);
  return String(String(response[0])+";"+A_plus+";"+A_minus+";"+R_plus+";"+R_minus);
  }

  else   return String("Error");

  
}



String getEnergyT1(int netAdr)
{
 
  response[0]=0;
  energyT1[0] = netAdr;
  send(energyT1, sizeof(energyT1),response);
  if(response[0] == netAdr) 
  {
  long r = 0;
  r |= (long)response[2]<<24;
  r |= (long)response[1]<<16;
  r |= (long)response[4]<<8;
  r |= (long)response[3];
  String A_plus= String(r);
  r=0;
  r |= (long)response[6]<<24;
  r |= (long)response[5]<<16;
  r |= (long)response[8]<<8;
  r |= (long)response[7];
  String A_minus= String(r);
  r = 0;
  r |= (long)response[10]<<24;
  r |= (long)response[9]<<16;
  r |= (long)response[12]<<8;
  r |= (long)response[11];
  String R_plus= String(r);
  r = 0;
  r |= (long)response[14]<<24;
  r |= (long)response[13]<<16;
  r |= (long)response[16]<<8;
  r |= (long)response[15];
  String R_minus= String(r);
  return String(String(response[0])+";"+A_plus+";"+A_minus+";"+R_plus+";"+R_minus);
  }

  else   return String("Error");
 
}



String getEnergyT2(int netAdr)
{
 
  response[0]=0;
  energyT2[0] = netAdr;
  send(energyT2, sizeof(energyT2),response);
  if(response[0] == netAdr) 
  {
  long r = 0;
  r |= (long)response[2]<<24;
  r |= (long)response[1]<<16;
  r |= (long)response[4]<<8;
  r |= (long)response[3];
  String A_plus= String(r);
  r=0;
  r |= (long)response[6]<<24;
  r |= (long)response[5]<<16;
  r |= (long)response[8]<<8;
  r |= (long)response[7];
  String A_minus= String(r);
  r = 0;
  r |= (long)response[10]<<24;
  r |= (long)response[9]<<16;
  r |= (long)response[12]<<8;
  r |= (long)response[11];
  String R_plus= String(r);
  r = 0;
  r |= (long)response[14]<<24;
  r |= (long)response[13]<<16;
  r |= (long)response[16]<<8;
  r |= (long)response[15];
  String R_minus= String(r);
  return String(String(response[0])+";"+A_plus+";"+A_minus+";"+R_plus+";"+R_minus);
  }

  else   return String("Error");
 
}

String getEnergyT3(int netAdr)
{
 
  response[0]=0;
  energyT3[0] = netAdr;
  send(energyT3, sizeof(energyT3),response);
  if(response[0] == netAdr) 
  {
  long r = 0;
  r |= (long)response[2]<<24;
  r |= (long)response[1]<<16;
  r |= (long)response[4]<<8;
  r |= (long)response[3];
  String A_plus= String(r);
  r=0;
  r |= (long)response[6]<<24;
  r |= (long)response[5]<<16;
  r |= (long)response[8]<<8;
  r |= (long)response[7];
  String A_minus= String(r);
  r = 0;
  r |= (long)response[10]<<24;
  r |= (long)response[9]<<16;
  r |= (long)response[12]<<8;
  r |= (long)response[11];
  String R_plus= String(r);
  r = 0;
  r |= (long)response[14]<<24;
  r |= (long)response[13]<<16;
  r |= (long)response[16]<<8;
  r |= (long)response[15];
  String R_minus= String(r);
  return String(String(response[0])+";"+A_plus+";"+A_minus+";"+R_plus+";"+R_minus);
  }

  else   return String("Error");
 
}


String getEnergyT4(int netAdr)
{
 
  response[0]=0;
  energyT4[0] = netAdr;
  send(energyT4, sizeof(energyT4),response);
  if(response[0] == netAdr) 
  {
  long r = 0;
  r |= (long)response[2]<<24;
  r |= (long)response[1]<<16;
  r |= (long)response[4]<<8;
  r |= (long)response[3];
  String A_plus= String(r);
  r=0;
  r |= (long)response[6]<<24;
  r |= (long)response[5]<<16;
  r |= (long)response[8]<<8;
  r |= (long)response[7];
  String A_minus= String(r);
  r = 0;
  r |= (long)response[10]<<24;
  r |= (long)response[9]<<16;
  r |= (long)response[12]<<8;
  r |= (long)response[11];
  String R_plus= String(r);
  r = 0;
  r |= (long)response[14]<<24;
  r |= (long)response[13]<<16;
  r |= (long)response[16]<<8;
  r |= (long)response[15];
  String R_minus= String(r);
  return String(String(response[0])+";"+A_plus+";"+A_minus+";"+R_plus+";"+R_minus);
  }

  else   return String("Error");
 
}




//////////////////////////////////////////////////////////////////////////////////
void send(byte *cmd, int s, byte *response) {
 // Serial.print("sending...");

  unsigned int crc = crc16MODBUS(cmd, s);

  unsigned int crc1 = crc & 0xFF;
  unsigned int crc2 = (crc>>8) & 0xFF;
  delay(10);
  digitalWrite(SerialControl, RS485Transmit);  // Init Transceiver   
       for(int i=0; i<s; i++) 
       {
              RS485Serial.write(cmd[i]);
       }
  RS485Serial.write(crc1);
  RS485Serial.write(crc2);
  byte i = 0;
  digitalWrite(SerialControl, RS485Receive);  // Init Transceiver   
  delay(200);
         if (RS485Serial.available()) 
           {
             while (RS485Serial.available()) 
               {
                byteReceived= RS485Serial.read();    // Read received byte             
                delay(10);  
                response[i++] = byteReceived;
                }
           }

  
  delay(20);
}




unsigned int crc16MODBUS(byte *s, int count) {
  unsigned int crcTable[] = {
        0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
        0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
        0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
        0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
        0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
        0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
        0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
        0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
        0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
        0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
        0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
        0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
        0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
        0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
        0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
        0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
        0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
        0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
        0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
        0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
        0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
        0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
        0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
        0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
        0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
        0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
        0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
        0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
        0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
        0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
        0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
        0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
    };

    unsigned int crc = 0xFFFF;

    for(int i = 0; i < count; i++) {
        crc = ((crc >> 8) ^ crcTable[(crc ^ s[i]) & 0xFF]);
    }

    return crc;
}



Программное обеспечение смартфона.


После установки Android приложения, в смартфоне в меню приложений необходимо найти
ярлык с названием «М-230» и запустить программу.

В открывшемся приложении нажать на выпадающее меню рядом с надписью «Команды»
после чего появится список команд.

image
Поиск устройств – будет произведен поиск доступных Bluetooth устройств и предложено
подключиться.

Проверить связь – команда проверки связи с преобразователем.

Опросить – однократный опрос счетчика по указанному сетевому адресу.

Монитор – постоянный циклический опрос одного устройства по указанному сетевому адресу (online режим).

Остановить – остановка циклического опроса.

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

image

Здесь файл проекта для Android Studio
Теги:
Хабы:
Всего голосов 17: ↑16 и ↓1+15
Комментарии15

Публикации

Истории

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань