From 5d9deb8e95cd78a4f3beadfbc1bcc3a9160026ba Mon Sep 17 00:00:00 2001 From: Dmitry Borisenko <67171972+IoTManagerProject@users.noreply.github.com> Date: Sun, 25 Jun 2023 18:41:09 +0200 Subject: [PATCH] ... --- .../Smi2_m/Modbus_master_for_Smi2_m.cpp | 175 ++++++++++++++++++ .../display/Smi2_m/Modbus_master_for_Smi2_m.h | 81 ++++++++ src/modules/display/Smi2_m/Smi2_m.cpp | 75 ++++++++ src/modules/display/Smi2_m/modinfo.json | 57 ++++++ 4 files changed, 388 insertions(+) create mode 100644 src/modules/display/Smi2_m/Modbus_master_for_Smi2_m.cpp create mode 100644 src/modules/display/Smi2_m/Modbus_master_for_Smi2_m.h create mode 100644 src/modules/display/Smi2_m/Smi2_m.cpp create mode 100644 src/modules/display/Smi2_m/modinfo.json diff --git a/src/modules/display/Smi2_m/Modbus_master_for_Smi2_m.cpp b/src/modules/display/Smi2_m/Modbus_master_for_Smi2_m.cpp new file mode 100644 index 00000000..7840ac2d --- /dev/null +++ b/src/modules/display/Smi2_m/Modbus_master_for_Smi2_m.cpp @@ -0,0 +1,175 @@ +#include "Modbus_master_for_Smi2_m.h" +#include "HardwareSerial.h" +#include + +Smi_display::Smi_display() { + +} + + +// Modbus Master +void Smi_display:: modbus_update() +{ + idle(); +} + +void Smi_display:: idle() +{ + static unsigned int packet_index; + + unsigned int failed_connections = 0; + + unsigned char current_connection; + + do + { + if (packet_index == total_no_of_packets) // wrap around to the beginning + packet_index = 0; + + // proceed to the next packet + packet = &packetArray[packet_index]; + + // get the current connection status + current_connection = packet->connection; + + if (!current_connection) + { + // If all the connection attributes are false return + // immediately to the main sketch + if (++failed_connections == total_no_of_packets) + return; + } + packet_index++; + + // if a packet has no connection get the next one + }while (!current_connection); + + constructPacket(); +} + +void Smi_display:: constructPacket() +{ + packet->requests++; + frame[0] = packet->id; + frame[1] = packet->function; + frame[2] = packet->address >> 8; // address Hi + frame[3] = packet->address & 0xFF; // address Lo + frame[4] = packet->data >> 8; // MSB + frame[5] = packet->data & 0xFF; // LSB + + unsigned char frameSize; + + // construct the frame according to the modbus function + if (packet->function == PRESET_MULTIPLE_REGISTERS) + frameSize = construct_F16(); + else // else functions 1,2,3,4,5 & 6 is assumed. They all share the exact same request format. + frameSize = 8; // the request is always 8 bytes in size for the above mentioned functions. + + unsigned int crc16 = calculateCRC(frameSize - 2); + frame[frameSize - 2] = crc16 >> 8; // split crc into 2 bytes + frame[frameSize - 1] = crc16 & 0xFF; + sendPacket(frameSize); +} + + +unsigned char Smi_display::construct_F16() +{ + unsigned char no_of_bytes = packet->data * 2; + + // first 6 bytes of the array + no_of_bytes + 2 bytes CRC + frame[6] = no_of_bytes; // number of bytes + unsigned char index = 7; // user data starts at index 7 + unsigned char no_of_registers = packet->data; + /*unsigned*/ int temp; + + for (unsigned char i = 0; i < no_of_registers; i++) + { + temp = register_array[packet->local_start_address + i]; // get the data + frame[index] = temp >> 8; + index++; + frame[index] = temp & 0xFF; + index++; + } + unsigned char frameSize = (9 + no_of_bytes); // first 7 bytes of the array + 2 bytes CRC + noOfBytes + return frameSize; +} + +void Smi_display::modbus_configure(HardwareSerial* SerialPort, + long baud, + unsigned char byteFormat, + int rx, + int tx, + unsigned int _TxEnablePin, + Packet* _packets, + unsigned int _total_no_of_packets, + /*unsigned*/ int* _register_array) +{ + + + + TxEnablePin = _TxEnablePin; + total_no_of_packets = _total_no_of_packets; + packetArray = _packets; + register_array = _register_array; + + + + ModbusPort = SerialPort; + (*ModbusPort).begin(baud, byteFormat,rx,tx); + + pinMode(TxEnablePin, OUTPUT); + digitalWrite(TxEnablePin, LOW); + +} + +void Smi_display::modbus_construct (Packet *_packet, + unsigned char id, + unsigned char function, + unsigned int address, + unsigned int data, + unsigned int local_start_address) +{ + _packet->id = id; + _packet->function = function; + _packet->address = address; + _packet->data = data; + _packet->local_start_address = local_start_address; + _packet->connection = 1; +} + +unsigned int Smi_display::calculateCRC(unsigned char bufferSize) +{ + unsigned int temp, temp2, flag; + temp = 0xFFFF; + for (unsigned char i = 0; i < bufferSize; i++) + { + temp = temp ^ frame[i]; + for (unsigned char j = 1; j <= 8; j++) + { + flag = temp & 0x0001; + temp >>= 1; + if (flag) + temp ^= 0xA001; + } + } + // Reverse byte order. + temp2 = temp >> 8; + temp = (temp << 8) | temp2; + temp &= 0xFFFF; + // the returned value is already swapped + // crcLo byte is first & crcHi byte is last + return temp; +} + +void Smi_display::sendPacket(unsigned char bufferSize) +{ + digitalWrite(TxEnablePin, HIGH); + + for (unsigned char i = 0; i < bufferSize; i++) + (*ModbusPort).write(frame[i]); + + (*ModbusPort).flush(); + + + digitalWrite(TxEnablePin, LOW); +} \ No newline at end of file diff --git a/src/modules/display/Smi2_m/Modbus_master_for_Smi2_m.h b/src/modules/display/Smi2_m/Modbus_master_for_Smi2_m.h new file mode 100644 index 00000000..6b435399 --- /dev/null +++ b/src/modules/display/Smi2_m/Modbus_master_for_Smi2_m.h @@ -0,0 +1,81 @@ +#pragma once + +#include + + + +#define PRESET_MULTIPLE_REGISTERS 16 +#define BUFFER_SIZE 64 + +typedef struct +{ + // ���������� � ������ + unsigned char id; + unsigned char function; + unsigned int address; + + + unsigned int data; + unsigned int local_start_address; + + // modbus �������������� ��������. + unsigned int requests; + unsigned int successful_requests; + unsigned int failed_requests; + unsigned int exception_errors; + unsigned int retries; + + // ��������� ���������� ������ + unsigned char connection; + +}Packet; + +class Smi_display { + public: + Smi_display(); + + ~Smi_display(); + + +public: + void modbus_update(); + void modbus_construct(Packet *_packet, + unsigned char id, + unsigned char function, + unsigned int address, + unsigned int data, + unsigned _local_start_address); + + void modbus_configure(HardwareSerial* SerialPort, + long baud, + unsigned char byteFormat, + int rx, + int tx, + unsigned int _TxEnablePin, + Packet* _packets, + unsigned int _total_no_of_packets, + /*unsigned*/ int* _register_array); + + + private: + void idle(); + void constructPacket(); + unsigned char construct_F16(); + unsigned int calculateCRC(unsigned char bufferSize); + void sendPacket(unsigned char bufferSize); + + private: + unsigned char state; + unsigned char retry_count; + unsigned int TxEnablePin; + unsigned char frame[BUFFER_SIZE]; + unsigned char buffer; + unsigned int T1_5; // ��� ������� �������, ������� � ������������� + unsigned int frameDelay; // � ������������� ������� ������ + unsigned int total_no_of_packets; + Packet* packetArray; // ��������� ����� ������ + Packet* packet; // ������� ����� + /*unsigned*/ int* register_array; // ��������� �� ����� ��������� master ���������� + HardwareSerial* ModbusPort; + +}; diff --git a/src/modules/display/Smi2_m/Smi2_m.cpp b/src/modules/display/Smi2_m/Smi2_m.cpp new file mode 100644 index 00000000..38cfe32d --- /dev/null +++ b/src/modules/display/Smi2_m/Smi2_m.cpp @@ -0,0 +1,75 @@ + +#include "Global.h" +#include "classes/IoTItem.h" + +#include "Modbus_master_for_Smi2_m.h" +#include "modules/sensors/UART/Uart.h" + +#include +#include + +// Общая сумма доступной памяти на ведущем устройстве, чтобы хранить данные +#define TOTAL_NO_OF_REGISTERS 4 + +// This is the easiest way to create new packets +// Add as many as you want. TOTAL_NO_OF_PACKETS +// is automatically updated. +enum { + PACKET1, + TOTAL_NO_OF_PACKETS // leave this last entry +}; + +// Масив пакетов модбус +Packet packets[TOTAL_NO_OF_PACKETS]; + +// Массив хранения содержимого принятых и передающихся регистров +/*unsigned*/ int regs[TOTAL_NO_OF_REGISTERS]; + +class Smi2_m : public IoTItem { + private: + Smi_display* smi; + unsigned int _pin; // номер порта, управляющий передачей по RS-485 + long int _baud; // скорость обмена, бит/с + int _rx, _tx; // номера ножек мк, к которым подключен UART + String _show; + int i = 10; + + public: + public: + Smi2_m(String parameters) : IoTItem(parameters) { + smi = new Smi_display(); + + _pin = jsonReadInt(parameters, "pin"); + _baud = jsonReadLInt(parameters, "baud"); + _rx = jsonReadInt(parameters, "rx"); + _tx = jsonReadInt(parameters, "tx"); + // Настраиваем пакеты + // Шестой параметр - это индекс ячейки в массиве, размещенном в памяти ведущего устройства, в которую будет + // помещен результат или из которой будут браться данные для передачи в подчиненное устройство. В нашем коде - это массив reg + // Пакет,SLAVE адрес,функция модбус,адрес регистра,количесво запрашиваемых регистров,локальный адрес регистра. + // Пакет,SLAVE адрес,функция модбус,адрес регистра,данные,локальный адрес регистра. + smi->modbus_construct(&packets[PACKET1], 1, PRESET_MULTIPLE_REGISTERS, 4200, 1, 0); + smi->modbus_configure(&Serial, _baud, SERIAL_8N1, _rx, _tx, _pin, packets, TOTAL_NO_OF_PACKETS, regs); + + jsonRead(parameters, "id2show", _show); + } + + void doByInterval() { + if (smi) { + smi->modbus_update(); + + float tmpStr = getItemValue(_show).toFloat(); + regs[0] = tmpStr * 10; + } + } + + ~Smi2_m(){}; +}; + +void* getAPI_Smi2_m(String subtype, String param) { + if (subtype == F("Smi2_m")) { + return new Smi2_m(param); + } else { + return nullptr; + } +} diff --git a/src/modules/display/Smi2_m/modinfo.json b/src/modules/display/Smi2_m/modinfo.json new file mode 100644 index 00000000..7b31c361 --- /dev/null +++ b/src/modules/display/Smi2_m/modinfo.json @@ -0,0 +1,57 @@ +{ + "menuSection": "Экраны", + "configItem": [ + { + "global": 0, + "name": "Smi2_m", + "type": "Writing", + "subtype": "Smi2_m", + "id": "Smi", + "widget": "", + "page": "Дисплеи", + "descr": "", + "int": 2, + "pin": 4, + "id2show": "id датчика", + "baud": "9600", + "rx": "16", + "tx": "17" + } + ], + "about": { + "moduleName": "Smi2_m", + "moduleVersion": "1.0", + "usedRam": { + "esp32_4mb": 15, + "esp8266_4mb": 15 + }, + "moduleDesc": "Позволяет вывести индикацию на семисегментный индикатор по Modbus (Работает в Slave режиме, Read Holding Registers 0х03)", + "propInfo": { + "int": "Период времени в секундах обновления информации на экране по конкретному элементу.", + "pin": "номер порта, управляющий передачей по RS-485", + "id2show": "id элемента конфигурации.", + "baud": "скорость обмена, бит/с" + }, + "funcInfo": [ + { + "name": "descr", + "descr": "Задает приставку слева от значения", + "params": [ + "Строка" + ] + }, + { + "name": "id2show", + "descr": "Задает ИД элемента, значение которого хотим отображать на экране", + "params": [ + "Имя элемента конфигурации" + ] + } + ] + }, + "defActive": true, + "usedLibs": { + "esp32_4mb": [], + "esp8266_4mb": [] + } +} \ No newline at end of file