Compare commits

...

4 Commits

Author SHA1 Message Date
Вячеслав Штейбезандт
fc01a6c06d Pre-release.
Added:
1) Added check for transition to new speed and parity.
2) Added the ability to stop scanning before polling all addresses.
3) A window has been added that allows you to set the value of multiple registers at once. Supports both simple saving on the device and the saved-sent mode.
4) Added check for parity and speed changes.
5) Added output of current voltage to the table.
6) Now, when you click on an indicator in the table, the corresponding element will be highlighted.

Minor updates:
1) Now the device settings take into account the number of boards found during scanning.
2) When you close the main window, the device turns off.
2024-12-18 14:58:33 +03:00
Вячеслав Штейбезандт
49083ca06d Hot Fix 2.
>Некорректная индикация напряжения ТЭ была устранена.
>Исправлена ошибка с некорректным определением модели регистров.
>Исправлено некорректное визуальное отображение статуса работы МЗКТЕ

Примечание:
Необходимо отвязать индикацию ТЭ от панели управления, передав уставки и коилы на внутренние таблицы
2024-12-11 16:55:48 +03:00
Вячеслав Штейбезандт
d7063703b6 Hot Fix 1.
>Отображение кнопок статуса МЗКТЭ было изменено.
>Операция записи раньше использовала ИД вместо адреса - исправлено.
>Стартовый адрес опроса плат смещён с нуля до первого.
>При поиске плат в сети использовался адрес по умолчанию вместо итератора - исправлено.
>При поиске плат в сети добавлена проверка на наличие ошибок при приёме.
>Проверка на поведение терминала при отсутствии плат в сети - пройдена.
>Изменено поведение progressbar при поиске плат и опросе их текущих настроек.
>Добавлено сообщение об ошибке во время опроса плат об их текущих настройках.
>Добавлено сообщение об ошибке при некорректном ответе во время опроса текущего напряжения.
2024-12-11 10:57:49 +03:00
Вячеслав Штейбезандт
5b2a64a39b Программа нуждается в тестировании.
Реализовано и проверено:
1) Подключение устройства
2) Запись и чтение Coil и Holding регистров
3) Индикация работы МЗКТЭ и напряжения на ТЭ

Реализовано и нуждается в проверке:
1) Поиск плат и установление их адресов в сети
2) Сканирование текущих настроек платы при подключении
3) Опрос текущих значений напряжений ТЭ по таймеру
4) Изменение скорости обмена, сетевого адреса плат и настройка контроля четности.

#3
2024-12-10 17:19:23 +03:00
22 changed files with 17956 additions and 61 deletions

View File

@@ -1,4 +1,10 @@
QT += core gui
QT += widgets serialport
QT += serialbus widgets
requires(qtConfig(combobox))
QT += serialport
qtConfig(modbus-serialport): QT += serialport
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
@@ -16,14 +22,25 @@ DEFINES += QT_DEPRECATED_WARNINGS
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
devicesettingsdialog.cpp \
main.cpp \
m3kte.cpp
m3kte.cpp \
multiplesettings.cpp \
settingsdialog.cpp \
writeregistermodel.cpp
HEADERS += \
m3kte.h
devicesettingsdialog.h \
m3kte.h \
multiplesettings.h \
settingsdialog.h \
writeregistermodel.h
FORMS += \
m3kte.ui
devicesettingsdialog.ui \
m3kte.ui \
multiplesettings.ui \
settingsdialog.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin

View File

@@ -0,0 +1,131 @@
#include "devicesettingsdialog.h"
#include "ui_devicesettingsdialog.h"
DeviceSettingsDialog::DeviceSettingsDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::DeviceSettingsDialog)
{
ui->setupUi(this);
_currentBoardTimers[0] = ui->spinTimerBoard_1->value();
_currentBoardTimers[1] = ui->spinTimerBoard_2->value();
_currentBoardTimers[2] = ui->spinTimerBoard_3->value();
_currentBoardTimers[3] = ui->spinTimerBoard_4->value();
_m_timer[0] = ui->spinTimerBoard_1;
_m_timer[1] = ui->spinTimerBoard_2;
_m_timer[2] = ui->spinTimerBoard_3;
_m_timer[3] = ui->spinTimerBoard_4;
_currentSpeed = ui->speedBox->currentText().toUInt();
_currentParity = ui->parityBox->currentIndex();
for(int i = 0; i < 4; i++)
{
_currentAdrs[i] = i+1;
}
}
DeviceSettingsDialog::~DeviceSettingsDialog()
{
delete ui;
}
void DeviceSettingsDialog::on_buttonApplyChangeTimer_clicked()
{
_currentBoardTimers[0] = ui->spinTimerBoard_1->value();
_currentBoardTimers[1] = ui->spinTimerBoard_2->value();
_currentBoardTimers[2] = ui->spinTimerBoard_3->value();
_currentBoardTimers[3] = ui->spinTimerBoard_4->value();
}
void DeviceSettingsDialog::on_buttonApplyChangeSpeed_clicked()
{
_currentSpeed = ui->speedBox->currentIndex();
emit speedChanged();
}
void DeviceSettingsDialog::on_buttonApplyChangeParity_clicked()
{
_currentParity = ui->parityBox->currentIndex();
emit parityChanged();
}
void DeviceSettingsDialog::on_buttonApplyChangeAdr_clicked()
{
BoardIdHasBeenChanged* _boardIdHasBeenChanged = new BoardIdHasBeenChanged(ui->idComboBox->currentIndex(), ui->adrSpinBox->value());
QCoreApplication::postEvent(parent(), _boardIdHasBeenChanged);
close();
}
unsigned DeviceSettingsDialog::currentBoardTimer(unsigned short _ID)
{
return _currentBoardTimers[_ID];
}
unsigned DeviceSettingsDialog::currentSpeed()
{
return _currentSpeed;
}
unsigned short DeviceSettingsDialog::currentParity()
{
return _currentParity;
}
void DeviceSettingsDialog::updateSettingsAfterConnection(unsigned tmp_speed, unsigned tmp_parity, unsigned *tmp_adr, int CurrentConnectedDevice)
{
ui->speedBox->setCurrentText(QString::number(_currentSpeed=tmp_speed, 10));
if(tmp_parity>0)
tmp_parity--;
ui->parityBox->setCurrentIndex(_currentParity = tmp_parity);
for(int i = 0; i < CurrentConnectedDevice; i++)
{
_m_timer[i]->setEnabled(true);
ui->idComboBox->addItem(QString::number(i));
_currentAdrs[i] = tmp_adr[i];
}
for(int i = CurrentConnectedDevice; i < 4; i++)
{
_m_timer[i]->setEnabled(false);
}
on_idComboBox_currentIndexChanged(ui->idComboBox->currentIndex());
}
void DeviceSettingsDialog::on_idComboBox_currentIndexChanged(int index)
{
ui->adrSpinBox->setValue(_currentAdrs[index]);
}
void DeviceSettingsDialog::on_buttonBox_clicked(QAbstractButton *button)
{
switch (ui->buttonBox->buttonRole(button)) {
case QDialogButtonBox::ResetRole:
ui->spinTimerBoard_1->setValue(1000);
ui->spinTimerBoard_2->setValue(1000);
ui->spinTimerBoard_3->setValue(1000);
ui->spinTimerBoard_4->setValue(1000);
_currentBoardTimers[0] = ui->spinTimerBoard_1->value();
_currentBoardTimers[1] = ui->spinTimerBoard_2->value();
_currentBoardTimers[2] = ui->spinTimerBoard_3->value();
_currentBoardTimers[3] = ui->spinTimerBoard_4->value();
ui->speedBox->setCurrentText("31250");
_currentSpeed = ui->speedBox->currentText().toUInt();
ui->parityBox->setCurrentIndex(0);
_currentParity = ui->parityBox->currentIndex();
for(int i = 0; i < 4; i++)
{
_currentAdrs[i] = i+1;
}
ui->adrSpinBox->setValue(_currentAdrs[ui->idComboBox->currentIndex()]);
break;
case QDialogButtonBox::AcceptRole:
close();
break;
}
}

View File

@@ -0,0 +1,72 @@
#ifndef DEVICESETTINGSDIALOG_H
#define DEVICESETTINGSDIALOG_H
#include <QDialog>
#include <QEvent>
#include <QAbstractButton>
#include <QDialogButtonBox>
#include <QSpinBox>
class BoardIdHasBeenChanged : public QEvent
{
public:
BoardIdHasBeenChanged(const short num, const short newId) : QEvent(QEvent::User) {_BoardNum = num; _BoardNewID = newId;}
~BoardIdHasBeenChanged() {}
short BoardNum() const {return _BoardNum;}
short BoardNewID() const {return _BoardNewID;}
private:
short _BoardNum;
short _BoardNewID;
};
namespace Ui {
class DeviceSettingsDialog;
}
class DeviceSettingsDialog : public QDialog
{
Q_OBJECT
public:
explicit DeviceSettingsDialog(QWidget *parent = nullptr);
~DeviceSettingsDialog();
unsigned currentBoardTimer(unsigned short _ID);
unsigned currentSpeed();
unsigned short currentParity();
void updateSettingsAfterConnection(unsigned tmp_speed, unsigned tmp_parity, unsigned *tmp_adr, int CurrentConnectedDevice);
signals:
void parityChanged();
void speedChanged();
void firstBoardAdrHasBeenChanged();
void secondBoardAdrHasBeenChanged();
void thirdBoardAdrHasBeenChanged();
void fourthBoardAdrHasBeenChanged();
private slots:
void on_buttonApplyChangeTimer_clicked();
void on_buttonApplyChangeSpeed_clicked();
void on_buttonApplyChangeParity_clicked();
void on_buttonApplyChangeAdr_clicked();
void on_idComboBox_currentIndexChanged(int index);
void on_buttonBox_clicked(QAbstractButton *button);
private:
QSpinBox *_m_timer[4];
unsigned _currentBoardTimers[4];
unsigned _currentSpeed;
unsigned short _currentParity;
unsigned _currentAdrs[4];
Ui::DeviceSettingsDialog *ui;
};
#endif // DEVICESETTINGSDIALOG_H

View File

@@ -0,0 +1,306 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DeviceSettingsDialog</class>
<widget class="QDialog" name="DeviceSettingsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>243</width>
<height>431</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Скорость обмена</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1">
<widget class="QPushButton" name="buttonApplyChangeSpeed">
<property name="text">
<string>Применить</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QComboBox" name="speedBox">
<property name="currentIndex">
<number>3</number>
</property>
<item>
<property name="text">
<string>9600</string>
</property>
</item>
<item>
<property name="text">
<string>14400</string>
</property>
</item>
<item>
<property name="text">
<string>19200</string>
</property>
</item>
<item>
<property name="text">
<string>31250</string>
</property>
</item>
<item>
<property name="text">
<string>38400</string>
</property>
</item>
<item>
<property name="text">
<string>56000</string>
</property>
</item>
<item>
<property name="text">
<string>57600</string>
</property>
</item>
<item>
<property name="text">
<string>115200</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Период опроса плат</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<widget class="QLabel" name="boardLabel_5">
<property name="text">
<string>Плата №3</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="spinTimerBoard_3">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> мс</string>
</property>
<property name="maximum">
<number>1999999999</number>
</property>
<property name="value">
<number>1000</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="boardLabel_1">
<property name="text">
<string>Плата №1</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QPushButton" name="buttonApplyChangeTimer">
<property name="text">
<string>Применить</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinTimerBoard_2">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> мс</string>
</property>
<property name="maximum">
<number>1999999999</number>
</property>
<property name="value">
<number>1000</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="boardLabel_2">
<property name="text">
<string>Плата №2</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinTimerBoard_1">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> мс</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1999999999</number>
</property>
<property name="value">
<number>1000</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="boardLabel_4">
<property name="text">
<string>Плата №4</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="spinTimerBoard_4">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> мс</string>
</property>
<property name="maximum">
<number>1999999999</number>
</property>
<property name="value">
<number>1000</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Сетевой адрес МЗКТЭ</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QComboBox" name="idComboBox">
<property name="whatsThis">
<string>Номер платы</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="adrSpinBox">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>247</number>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="buttonApplyChangeAdr">
<property name="text">
<string>Применить</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Контроль четности</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="1">
<widget class="QPushButton" name="buttonApplyChangeParity">
<property name="text">
<string>Применить</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QComboBox" name="parityBox">
<item>
<property name="text">
<string>No</string>
</property>
</item>
<item>
<property name="text">
<string>Even</string>
</property>
</item>
<item>
<property name="text">
<string>Odd</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DeviceSettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DeviceSettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

1538
M3KTE_TERM/m3kte.cpp Normal file

File diff suppressed because it is too large Load Diff

121
M3KTE_TERM/m3kte.h Normal file
View File

@@ -0,0 +1,121 @@
#ifndef M3KTE_H
#define M3KTE_H
#include <QMainWindow>
#include <QModbusDataUnit>
#include <qprogressbar.h>
#include <QtSerialBus/QModbusDataUnit>
#include "writeregistermodel.h"
#include "devicesettingsdialog.h"
#include "multiplesettings.h"
#include <QModbusTcpClient>
#include <QModbusRtuSerialMaster>
#include <QTimer>
#include <QMessageBox>
#include <QProgressDialog>
#include <QErrorMessage>
#include <QPushButton>
#include <QtSerialBus/qtserialbusglobal.h>
#if QT_CONFIG(modbus_serialport)
#include <QSerialPort>
#endif
QT_BEGIN_NAMESPACE
namespace Ui { class M3KTE; class SettingsDialog;}
QT_END_NAMESPACE
class SettingsDialog;
class WriteRegisterModel;
class M3KTE : public QMainWindow
{
Q_OBJECT
private:
void initActions();
QModbusDataUnit readRequest() const;
QModbusDataUnit writeRequest() const;
void changeTable(int board, int tabletype);
void debug();
void errorAdrChange();
bool event(QEvent* event);
bool pingNetworkDevices();
void beginScanBoards();
void displayResultOfScan(QModbusReply *reply, int boardID);
void stepForScanCurrentSettings(QModbusReply *reply);
void multipleRegWrite();
void multipleRegSend();
void selectPositionOnTree(unsigned index);
private slots:
void slotmultipleRegWrite();
void slotmultipleRegWriteAndSend();
void onConnectClicked();
void onReadButtonClicked();
void onReadReady();
void timeForPingIsGone();
void checkAdrChange();
void onWriteButtonClicked();
void onSelectedBoardChanged(int index);
void onWriteTableChanged(int index);
void onSpeedUpdate();
void onParityUpdate();
void firstBoardScan();
void secondBoardScan();
void thirdBoardScan();
void fourthBoardScan();
void firstBoardReady();
void secondBoardReady();
void thirdBoardReady();
void fourthBoardReady();
public:
M3KTE(QWidget *parent = nullptr);
~M3KTE();
private:
Ui::M3KTE *ui;
bool timerForPingSignal = false;
int CurrentConnectedDevice = 0;
//int DeviceOnNetwork[4];
QProgressBar *m_ProgressBar[320];
QPushButton *ThePhantomMenace[320];
QModbusReply *lastRequest = nullptr;
QModbusClient *modbusDevice = nullptr;
DeviceSettingsDialog *m_deviceSettingsDialog = nullptr;
SettingsDialog *m_settingsDialog = nullptr;
MultipleSettings *m_regMultipleSettings = nullptr;
//WriteRegisterModel *writeModel = nullptr;
struct StatusM3KTE{
bool Warnings[4];
bool Accidents[4];
}statusM3KTE;
struct BoardModbusRegisters
{
int adr;
int _tmp_adr;
bool coil[85];
unsigned HR[170];
WriteRegisterModel *ModbusModelCoil;
WriteRegisterModel *ModbusModelHoldingReg;
QTimer *boardScanners;
}Boards[4];
};
#endif // M3KTE_H

14447
M3KTE_TERM/m3kte.ui Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
#include "multiplesettings.h"
#include "ui_multiplesettings.h"
MultipleSettings::MultipleSettings(QWidget *parent) :
QDialog(parent),
ui(new Ui::MultipleSettings)
{
ui->setupUi(this);
ui->buttonBox->button(QDialogButtonBox::Ok)->setText("Записать");
ui->buttonBox->button(QDialogButtonBox::SaveAll)->setText("Записать и установить");
}
MultipleSettings::~MultipleSettings()
{
delete ui;
}
void MultipleSettings::on_buttonBox_clicked(QAbstractButton *button)
{
if(button == ui->buttonBox->button(QDialogButtonBox::Ok))
{
newValue = ui->regValueLine->text().toInt(nullptr, 16);
typeReg = ui->regTypeBox->currentIndex();
startAdr = ui->adrBox->value();
countReg = ui->countBox->value();
boardId = ui->boardBox->currentIndex();
emit write();
}
else if (button == ui->buttonBox->button(QDialogButtonBox::SaveAll))
{
newValue = ui->regValueLine->text().toInt(nullptr, 16);
typeReg = ui->regTypeBox->currentIndex();
startAdr = ui->adrBox->value();
countReg = ui->countBox->value();
boardId = ui->boardBox->currentIndex();
emit writeAndSend();
}
else
{
}
}
void MultipleSettings::on_regTypeBox_currentIndexChanged(int index)
{
switch (index) {
case 0:
case 1:
ui->adrBox->setRange(0, 84);
ui->adrBox->setValue(0);
break;
case 2:
ui->adrBox->setRange(85, 170);
ui->adrBox->setValue(85);
break;
}
}
void MultipleSettings::on_boardBox_currentIndexChanged(int index)
{
switch (index) {
case 3:
ui->countBox->setRange(1, 65-ui->adrBox->value()+85*ui->regTypeBox->currentIndex()/2);
break;
default:
ui->countBox->setRange(1, 85-ui->adrBox->value()+85*ui->regTypeBox->currentIndex()/2);
}
}
void MultipleSettings::on_adrBox_valueChanged(int arg1)
{
ui->countBox->setRange(1, ((85-(20*(ui->boardBox->currentIndex()/3)))*(1+(ui->regTypeBox->currentIndex()/2))-arg1));
}

View File

@@ -0,0 +1,45 @@
#ifndef MULTIPLESETTINGS_H
#define MULTIPLESETTINGS_H
#include <QDialog>
#include <QPushButton>
namespace Ui {
class MultipleSettings;
}
class MultipleSettings : public QDialog
{
Q_OBJECT
public:
explicit MultipleSettings(QWidget *parent = nullptr);
~MultipleSettings();
quint16 getNewValue() {return newValue;}
unsigned getStartAdr() {return startAdr;}
unsigned getCountReg() {return countReg;}
short getTypeReg() {return typeReg;}
short getBoardId() {return boardId;}
signals:
void write();
void writeAndSend();
private slots:
void on_buttonBox_clicked(QAbstractButton *button);
void on_regTypeBox_currentIndexChanged(int index);
void on_boardBox_currentIndexChanged(int index);
void on_adrBox_valueChanged(int arg1);
private:
Ui::MultipleSettings *ui;
quint16 newValue = 0;
unsigned startAdr;
unsigned countReg;
short typeReg;
short boardId;
};
#endif // MULTIPLESETTINGS_H

View File

@@ -0,0 +1,198 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MultipleSettings</class>
<widget class="QDialog" name="MultipleSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>381</width>
<height>128</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Уставка</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="4">
<widget class="QLabel" name="countLabel">
<property name="text">
<string>Кол-во</string>
</property>
</widget>
</item>
<item row="0" column="2" colspan="2">
<widget class="QLabel" name="adrLabel">
<property name="text">
<string>Стартовый</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="boardLabel">
<property name="text">
<string>Плата</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QSpinBox" name="adrBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>84</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="boardBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<item>
<property name="text">
<string>1</string>
</property>
</item>
<item>
<property name="text">
<string>2</string>
</property>
</item>
<item>
<property name="text">
<string>3</string>
</property>
</item>
<item>
<property name="text">
<string>4</string>
</property>
</item>
</widget>
</item>
<item row="1" column="4">
<widget class="QSpinBox" name="countBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>85</number>
</property>
</widget>
</item>
<item row="1" column="5">
<widget class="QLineEdit" name="regValueLine"/>
</item>
<item row="0" column="5">
<widget class="QLabel" name="regValueLabel">
<property name="text">
<string>Значение (HEX)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="regTypeBox">
<item>
<property name="text">
<string>Coil</string>
</property>
</item>
<item>
<property name="text">
<string>Warning</string>
</property>
</item>
<item>
<property name="text">
<string>Accident</string>
</property>
</item>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="regTypeLabel">
<property name="text">
<string>Тип Регистра</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::SaveAll</set>
</property>
<property name="centerButtons">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>MultipleSettings</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>MultipleSettings</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,72 @@
#include "settingsdialog.h"
#include "ui_settingsdialog.h"
SettingsDialog::SettingsDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::SettingsDialog)
{
ui->setupUi(this);
ui->parityCombo->setCurrentIndex(0);
#if QT_CONFIG(modbus_serialport)
ui->baudCombo->setCurrentText(QString::number(m_settings.baud));
ui->dataBitsCombo->setCurrentText(QString::number(m_settings.dataBits));
ui->stopBitsCombo->setCurrentText(QString::number(m_settings.stopBits));
#endif
ui->timeoutSpinner->setValue(m_settings.responseTime);
ui->retriesSpinner->setValue(m_settings.numberOfRetries);
connect(ui->AcceptOrRejectButtonBox, &QDialogButtonBox::accepted, [this]() {
#if QT_CONFIG(modbus_serialport)
m_settings.portName = ui->portEdit->text();
m_settings.parity = ui->parityCombo->currentIndex();
if (m_settings.parity > 0)
m_settings.parity++;
m_settings.baud = ui->baudCombo->currentText().toInt();
m_settings.dataBits = ui->dataBitsCombo->currentText().toInt();
m_settings.stopBits = ui->stopBitsCombo->currentText().toInt();
#endif
m_settings.responseTime = ui->timeoutSpinner->value();
m_settings.numberOfRetries = ui->retriesSpinner->value();
hide();
});
}
SettingsDialog::~SettingsDialog()
{
delete ui;
}
SettingsDialog::Settings SettingsDialog::settings() const
{
return m_settings;
}
int SettingsDialog::UpdateBaud(int baud)
{
ui->baudCombo->setCurrentIndex(baud);
return (m_settings.baud = ui->baudCombo->currentText().toInt());
}
int SettingsDialog::UpdateParity(int parity)
{
ui->parityCombo->setCurrentIndex(parity);
if(parity>0)
{
return (m_settings.parity = ++parity);
}
else {
return (m_settings.parity = parity);
}
}
int SettingsDialog::curBaud()
{
return ui->baudCombo->currentIndex();
}
int SettingsDialog::curParity()
{
return ui->parityCombo->currentIndex();
}

View File

@@ -0,0 +1,45 @@
#ifndef SETTINGSDIALOG_H
#define SETTINGSDIALOG_H
#include <QDialog>
#include <QtSerialBus/QModbusDataUnit>
#include <QtSerialBus/qtserialbusglobal.h>
#if QT_CONFIG(modbus_serialport)
#include <QSerialPort>
#endif
namespace Ui {
class SettingsDialog;
}
class SettingsDialog : public QDialog
{
Q_OBJECT
public:
struct Settings {
QString portName;
int parity = QSerialPort::NoParity;
int baud = 115200;
int dataBits = QSerialPort::Data8;
int stopBits = QSerialPort::OneStop;
int responseTime = 500;
int numberOfRetries = 0;
};
explicit SettingsDialog(QWidget *parent = nullptr);
~SettingsDialog();
Settings settings() const;
int UpdateBaud(int baud);
int UpdateParity(int parity);
int curBaud();
int curParity();
private:
Settings m_settings;
Ui::SettingsDialog *ui;
};
#endif // SETTINGSDIALOG_H

View File

@@ -0,0 +1,285 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsDialog</class>
<widget class="QDialog" name="SettingsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>311</width>
<height>288</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="1" colspan="2">
<widget class="QSpinBox" name="timeoutSpinner">
<property name="suffix">
<string> мс</string>
</property>
<property name="minimum">
<number>-1</number>
</property>
<property name="maximum">
<number>5000</number>
</property>
<property name="singleStep">
<number>20</number>
</property>
<property name="value">
<number>200</number>
</property>
</widget>
</item>
<item row="2" column="1" rowspan="2" colspan="2">
<widget class="QSpinBox" name="retriesSpinner">
<property name="enabled">
<bool>false</bool>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="timeoutLabel">
<property name="text">
<string>Тайм-аут ответа:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>127</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="3">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Serial Parameters</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="portLabel">
<property name="text">
<string>Порт</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="portEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="parityLabel">
<property name="text">
<string>Чётность</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="parityCombo">
<item>
<property name="text">
<string>No</string>
</property>
</item>
<item>
<property name="text">
<string>Even</string>
</property>
</item>
<item>
<property name="text">
<string>Odd</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="baudLabel">
<property name="text">
<string>Скорость</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="baudCombo">
<property name="currentIndex">
<number>7</number>
</property>
<item>
<property name="text">
<string>9600</string>
</property>
</item>
<item>
<property name="text">
<string>14400</string>
</property>
</item>
<item>
<property name="text">
<string>19200</string>
</property>
</item>
<item>
<property name="text">
<string>31250</string>
</property>
</item>
<item>
<property name="text">
<string>38400</string>
</property>
</item>
<item>
<property name="text">
<string>56000</string>
</property>
</item>
<item>
<property name="text">
<string>57600</string>
</property>
</item>
<item>
<property name="text">
<string>115200</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="dataBitsLabel">
<property name="text">
<string>Биты данных</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="dataBitsCombo">
<property name="currentIndex">
<number>3</number>
</property>
<item>
<property name="text">
<string>5</string>
</property>
</item>
<item>
<property name="text">
<string>6</string>
</property>
</item>
<item>
<property name="text">
<string>7</string>
</property>
</item>
<item>
<property name="text">
<string>8</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="stopBitsLabel">
<property name="text">
<string>Стоп-биты</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="stopBitsCombo">
<item>
<property name="text">
<string>1</string>
</property>
</item>
<item>
<property name="text">
<string>3</string>
</property>
</item>
<item>
<property name="text">
<string>2</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0" rowspan="2">
<widget class="QLabel" name="retriesLabel">
<property name="text">
<string>Количество повторов:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QDialogButtonBox" name="AcceptOrRejectButtonBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>AcceptOrRejectButtonBox</sender>
<signal>accepted()</signal>
<receiver>SettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>AcceptOrRejectButtonBox</sender>
<signal>rejected()</signal>
<receiver>SettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,148 @@
#include "writeregistermodel.h"
#include "writeregistermodel.h"
enum { NumColumn = 0, NameColumn = 1, CoilsColumn = 2, HoldingColumn = 3, ColumnCount = 5, CurrentUColumn = 4};
WriteRegisterModel::WriteRegisterModel(QObject *parent, int _tmpRC, bool _isHR)
: QAbstractTableModel(parent),
m_coils(RowCount=_tmpRC, false), m_holdingRegisters(RowCount=_tmpRC, 0u), m_currentU(RowCount=_tmpRC)
{
isHR=_isHR;
}
int WriteRegisterModel::rowCount(const QModelIndex &/*parent*/) const
{
return RowCount;
}
int WriteRegisterModel::columnCount(const QModelIndex &/*parent*/) const
{
return ColumnCount;
}
QVariant WriteRegisterModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= RowCount || index.column() >= ColumnCount)
return QVariant();
Q_ASSERT(m_coils.count() == RowCount);
Q_ASSERT(m_holdingRegisters.count() == RowCount);
if (index.column() == NumColumn && role == Qt::DisplayRole)
return QString::number(index.row());
if (index.column() == NameColumn && role == Qt::DisplayRole)
return QString("ТЭ%1").arg(index.row()%(RowCount/(1+isHR))+1);
if (index.column() == CoilsColumn && role == Qt::CheckStateRole) // coils
return m_coils.at(index.row()) ? Qt::Checked : Qt::Unchecked;
if (index.column() == HoldingColumn && role == Qt::DisplayRole) // holding registers
return QString("0x%1").arg(QString::number(m_holdingRegisters.at(index.row()), 16));
if(index.column() == CurrentUColumn && role == Qt::DisplayRole)
return QString("%1 В").arg(QString::number((double)((double)m_currentU.at(index.row())/(double)1000)));
return QVariant();
}
QVariant WriteRegisterModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Horizontal) {
switch (section) {
case NumColumn:
return QStringLiteral("#Reg");
case NameColumn:
return QStringLiteral("Fuel Cell");
case CoilsColumn:
return QStringLiteral("Coils");
case HoldingColumn:
return QStringLiteral("Holding Registers");
case CurrentUColumn:
return QStringLiteral("Current U");
default:
break;
}
}
return QVariant();
}
bool WriteRegisterModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || index.row() >= RowCount || index.column() >= ColumnCount)
return false;
Q_ASSERT(m_coils.count() == RowCount);
Q_ASSERT(m_holdingRegisters.count() == RowCount);
if (index.column() == CoilsColumn && role == Qt::CheckStateRole) { // coils
auto s = static_cast<Qt::CheckState>(value.toUInt());
s == Qt::Checked ? m_coils.setBit(index.row()) : m_coils.clearBit(index.row());
emit dataChanged(index, index);
return true;
}
if (index.column() == HoldingColumn && role == Qt::EditRole) { // holding registers
bool result = false;
quint16 newValue = value.toString().toUShort(&result, 16);
if (result)
m_holdingRegisters[index.row()] = newValue;
emit dataChanged(index, index);
return result;
}
return false;
}
Qt::ItemFlags WriteRegisterModel::flags(const QModelIndex &index) const
{
if (!index.isValid() || index.row() >= RowCount || index.column() >= ColumnCount)
return QAbstractTableModel::flags(index);
Qt::ItemFlags flags = QAbstractTableModel::flags(index);
if ((index.row() < m_address) || (index.row() >= (m_address + m_number)))
flags &= ~Qt::ItemIsEnabled;
if (index.column() == CoilsColumn) // coils
return flags | Qt::ItemIsUserCheckable;
if (index.column() == HoldingColumn) // holding registers
return flags | Qt::ItemIsEditable;
return flags;
}
void WriteRegisterModel::setStartAddress(int address)
{
m_address = address;
//emit updateViewport();
}
void WriteRegisterModel::setNumberOfValues(const QString &number)
{
m_number = number.toInt();
//emit updateViewport();
}
bool WriteRegisterModel::get_coil(const QModelIndex &index)
{
return m_coils.at(index.row());
}
uint WriteRegisterModel::get_holreg(const QModelIndex &index)
{
return m_holdingRegisters.at(index.row());
}
bool WriteRegisterModel::set_currentU(unsigned _tmpU, unsigned index)
{
m_currentU[index] = _tmpU;
if(isHR)
m_currentU[index + m_number] = _tmpU;
return true;
}

View File

@@ -0,0 +1,43 @@
#ifndef WRITEREGISTERMODEL_H
#define WRITEREGISTERMODEL_H
#include <QAbstractItemModel>
#include <QBitArray>
#include <QObject>
class WriteRegisterModel : public QAbstractTableModel
{
private:
bool isHR;
int RowCount;
public:
WriteRegisterModel(QObject *parent = nullptr, int _tmpRC = 85, bool _isHR = false);
bool get_coil(const QModelIndex &index);
uint get_holreg(const QModelIndex &index);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
bool set_currentU(unsigned _tmpU, unsigned index);
public slots:
void setStartAddress(int address);
void setNumberOfValues(const QString &number);
signals:
void updateViewport();
public:
int m_number = 0;
int m_address = 0;
QBitArray m_coils;
QVector<quint16> m_holdingRegisters;
QVector<quint16> m_currentU;
};
#endif // WRITEREGISTERMODEL_H

View File

@@ -1,15 +0,0 @@
#include "m3kte.h"
#include "ui_m3kte.h"
M3KTE::M3KTE(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::M3KTE)
{
ui->setupUi(this);
}
M3KTE::~M3KTE()
{
delete ui;
}

21
m3kte.h
View File

@@ -1,21 +0,0 @@
#ifndef M3KTE_H
#define M3KTE_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class M3KTE; }
QT_END_NAMESPACE
class M3KTE : public QMainWindow
{
Q_OBJECT
public:
M3KTE(QWidget *parent = nullptr);
~M3KTE();
private:
Ui::M3KTE *ui;
};
#endif // M3KTE_H

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>M3KTE</class>
<widget class="QMainWindow" name="M3KTE">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>M3KTE</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar"/>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

373
ТЗ/modbus_data.h Normal file
View File

@@ -0,0 +1,373 @@
/**
**************************************************************************
* @file modbus_data.h
* @brief Заголовочный файл с описанием даты MODBUS.
* @details Данный файл необходимо подключается в rs_message.h. После rs_message.h
* подключается к основному проекту.
*
* @defgroup MODBUS_DATA
* @ingroup MODBUS
* @brief Modbus data description
*
*************************************************************************/
#include "stdint.h"
//--------------DEFINES FOR REGISTERS---------------
// DEFINES FOR ARRAYS
/**
* @addtogroup MODBUS_DATA_RERISTERS_DEFINES
* @ingroup MODBUS_DATA
* @brief Defines for registers
Структура дефайна адресов
@verbatim
Для массивов регистров:
R_<NAME_ARRAY>_ADDR - модбас адресс первого регистра в массиве
R_<NAME_ARRAY>_QNT - количество регистров в массиве
@endverbatim
* @{
*/
/**
* @brief Скорость обмена
*/
typedef enum //MB_SpeedTypeDef
{
MB_9600bs = 0x0000, ///< Скорость 9600 б/с
MB_14400bs = 0x0001, ///< Скорость 14400 б/с
MB_19200bs = 0x0002, ///< Скорость 19200 б/с
MB_31250bs = 0x0003, ///< Скорость 31250 б/с
MB_38400bs = 0x0004, ///< Скорость 38400 б/с
MB_56000bs = 0x0005, ///< Скорость 56000 б/с
MB_57600bs = 0x0006, ///< Скорость 57600 б/с
MB_115200bs = 0x0007, ///< Скорость 115200 б/с
mb16bit = 0x1000, ///< костыль чтобы enum был 16-битный... или забить на enum, пока не определился
}MB_SpeedTypeDef;
/**
* @brief Контроль четности
*/
typedef enum //MB_ParityCtrlTypeDef
{
NoParityCtrl = 0x0000, ///< контроля нет
EvenParityCtrl = 0x0400, ///< четный контроль
OddParityCtrl = 0x0600, ///< нечетый контроль
}MB_ParityCtrlTypeDef;
/**
* @brief Регистры хранения для уставок параметров МКЗТЭ
*/
typedef struct //MB_DataHoldRegsTypeDef
{
uint16_t Warning_Setpoints[85]; /*!< @brief Адреса 0-84: Уставки «Предупреждение»
@details Задает пороговое напряжение, при достижении которого будет сформирован сигнал «Предупреждение».
Максимальное значение (записываемое в регистр) - 1100 (1,1 В *1000) */
uint16_t Errors_Setpoints[85]; /*!< @brief Адреса 85-169: Уставки «Авария»
@details Задает пороговое напряжение, при достижении которого будет сформирован сигнал «Авария».
Максимальное значение (записываемое в регистр) - 1100 (1,1 В *1000) */
uint16_t Commands_Mode; /*!< @brief Адрес 170: Уставка «Команды»
@details Принимаемые значения:
- 0x0000 стандартная работа
- 0x0001 запрет опроса ТЭ (активен только обмен с ЛСУ ЭС, ТЭ не контролируются) */
uint16_t reserved; ///< Адрес 171 зарезервирован
uint16_t MZKTE_Network_Adress; /*!< @brief Адрес 172: Уставка «Сетевой адрес МЗКТЭ»
@details При удачной записи этого регистра ответный фрейм не отправляется */
MB_SpeedTypeDef Modbus_Speed:16; /*!< @brief Адрес 173: Уставка «Скорость обмена»
@details Принимаемые значения описаны в @ref MB_SpeedTypeDef.
При удачной записи этого регистра ответный фрейм не отправляется */
MB_ParityCtrlTypeDef Parity_Control:16; /*!< @brief Адрес 174: Уставка «Команды»
@details Принимаемые значения описаны в @ref MB_ParityCtrlTypeDef.
При удачной записи этого регистра ответный фрейм не отправляется */
}MB_DataHoldRegsTypeDef;
/**
* @brief Номер неисправности МЗКТЭ
*/
typedef enum //MB_MZKTEErrorsTypeDef
{
No_Err = 0x00, ///< Неисправность отсутствует
Err_Digit_5V_Power = 0x01, ///< Неисправность цифрового источника питания +5 В
Err_Analog_15V_5V_3V_Power = 0x02, ///< Неисправность аналогового источника питания (±15 В/+5 В/+3,3 В)
Err_SCI_5V_Power = 0x03, ///< Неисправность источника питания последовательных интерфейсов микроконтроллера +5 В
Err_24V_Power = 0x04, ///< Неисправность источника питания +24 В
Program_Err_1 = 0x05, ///< Программная ошибка 1
Program_Err_2 = 0x06, ///< Программная ошибка 2
Program_Err_3 = 0x07, ///< Программная ошибка 3
Program_Err_4 = 0x08, ///< Программная ошибка 4
Program_Err_5 = 0x09, ///< Программная ошибка 5
Program_Err_6 = 0x0A, ///< Программная ошибка 6
Program_Err_7 = 0x0B, ///< Программная ошибка 7
Program_Err_8 = 0x0C, ///< Программная ошибка 8
}MB_MZKTEErrorsTypeDef;
/**
* @brief Сборный параметр
* @details Информация о состоянии МЗКТЭ
*/
typedef union //MB_MZKTEStatusTypeDef
{
uint16_t all; ///< Доступ к регистру целиком
struct
{
unsigned TE_ErrActive:1; /*!< @brief Бит [0]: Авария на ТЭ
@details Состояния:
- 0 - напряжения на всех ТЭ выше аварийных порогов, задаваемых уставками «Авария»
- 1 - напряжение на одном или нескольких ТЭ достигло или ниже аварийного порога, задаваемого уставкой «Авария» */
unsigned TE_WarnActive:1; /*!< @brief Бит [1]: Предупреждения на ТЭ
@details Состояния:
- 0 - напряжения на всех ТЭ выше предупредительных порогов, задаваемых уставкой «Предупреждение»
- 1 - напряжение на одном или нескольких ТЭ достигло или ниже предупредительного порога, задаваемого уставкой «Предупреждение» */
unsigned Opros_TE:1; /*!< @brief Бит [2]: Разрешение опроса ТЭ
@details Состояния:
- 0 опрос ТЭ разрешен
- 1 опрос ТЭ запрещен */
unsigned MZKTE_ErrStatus:2; /*!< @brief Биты [4:3]: Состояние МЗКТЭ
@details Состояния:
- 0 - МЗКТЭ функционирует нормально. Идет опрос ТЭ.
- 1 - неисправность МЗКТЭ, при которой МЗКТЭ может выполнять свои основные функции
(некоторые программные ошибки из @ref MB_MZKTEErrorsTypeDef)
- 2 - Неисправность МЗКТЭ, при которой выполнение основных функций не представляется возможным
(ошибки 1-3 и некоторые программные ошибки из @ref MB_MZKTEErrorsTypeDef) */
unsigned reserved:3; ///< Биты [7:5] зарезервированны
MB_MZKTEErrorsTypeDef MZKTE_Error:8; /*!< @brief Биты [15:8]: Номер неисправности МЗКТЭ
@details Номера неисправностей описаны в @ref MB_MZKTEErrorsTypeDef */
}param; ///< Доступ к регистру по параметрам
}MB_MZKTEStatusTypeDef;
/**
* @brief Входные регистры для контроля состояния МЗКТЭ
*/
typedef struct //MB_DataInRegsTypeDef
{
uint16_t U_TE[85]; /*!< @brief Адреса 0-84: Текущие значения напряжения ТЭ
@details Значения передаются умноженными на 1000 (т.е. если Uтэ = 0,625 В, то будет передано число 625) */
MB_MZKTEStatusTypeDef Status; /*!< @brief Адрес 85: Сборный параметр
@details Информация о состоянии МЗКТЭ @ref MB_MZKTEStatusTypeDef */
}MB_DataInRegsTypeDef;
// DEFINES FOR REGISTERS ARRAYS
#define R_INREG_ADDR 0
#define R_INREG_QNT 86
#define R_HOLDREG_ADDR 0
#define R_HOLDREG_QNT 175
// DEFINES FOR REGISTERS LOCAL ADDRESSES
//#define R_SET_ERROR(_te_num_) 0
/** MODBUS_DATA_RERISTERS_DEFINES
* @}
*/
//----------------DEFINES FOR COILS-----------------
/**
* @addtogroup MODBUS_DATA_COILS_DEFINES
* @ingroup MODBUS_DATA
* @brief Defines for coils
@verbatim
Структура дефайна
Для массивов коилов:
C_<NAME_ARRAY>_ADDR - модбас адресс первого коила в массиве
C_<NAME_ARRAY>_QNT - количество коилов в массиве (минимум 16)
@endverbatim
* @{
*/
/**
* @brief Флаги исключения ТЭ из алгоритма формирования сигналов «Предупреждение» и «Авария»
* @details В случае установки нулевого значения конкретной ячейки значение напряжения ТЭ,
* связанного с этой ячейкой, не будет учитываться при формировании сигналов «Предупреждение» и «Авария»
*/
typedef struct //MB_DataCoilsTypeDef
{
union
{
struct
{
uint64_t TE0_63; ///< Ячейки ТЭ №0-63
uint32_t TE64_84:21; ///< Ячейки ТЭ №64-84
}all;
struct
{
unsigned TE0_Exclude:1;
unsigned TE1_Exclude:1;
unsigned TE2_Exclude:1;
unsigned TE3_Exclude:1;
unsigned TE4_Exclude:1;
unsigned TE5_Exclude:1;
unsigned TE6_Exclude:1;
unsigned TE7_Exclude:1;
unsigned TE8_Exclude:1;
unsigned TE9_Exclude:1;
unsigned TE10_Exclude:1;
unsigned TE11_Exclude:1;
unsigned TE12_Exclude:1;
unsigned TE13_Exclude:1;
unsigned TE14_Exclude:1;
unsigned TE15_Exclude:1;
unsigned TE16_Exclude:1;
unsigned TE17_Exclude:1;
unsigned TE18_Exclude:1;
unsigned TE19_Exclude:1;
unsigned TE20_Exclude:1;
unsigned TE21_Exclude:1;
unsigned TE22_Exclude:1;
unsigned TE23_Exclude:1;
unsigned TE24_Exclude:1;
unsigned TE25_Exclude:1;
unsigned TE26_Exclude:1;
unsigned TE27_Exclude:1;
unsigned TE28_Exclude:1;
unsigned TE29_Exclude:1;
unsigned TE30_Exclude:1;
unsigned TE31_Exclude:1;
unsigned TE32_Exclude:1;
unsigned TE33_Exclude:1;
unsigned TE34_Exclude:1;
unsigned TE35_Exclude:1;
unsigned TE36_Exclude:1;
unsigned TE37_Exclude:1;
unsigned TE38_Exclude:1;
unsigned TE39_Exclude:1;
unsigned TE40_Exclude:1;
unsigned TE41_Exclude:1;
unsigned TE42_Exclude:1;
unsigned TE43_Exclude:1;
unsigned TE44_Exclude:1;
unsigned TE45_Exclude:1;
unsigned TE46_Exclude:1;
unsigned TE47_Exclude:1;
unsigned TE48_Exclude:1;
unsigned TE49_Exclude:1;
unsigned TE50_Exclude:1;
unsigned TE51_Exclude:1;
unsigned TE52_Exclude:1;
unsigned TE53_Exclude:1;
unsigned TE54_Exclude:1;
unsigned TE55_Exclude:1;
unsigned TE56_Exclude:1;
unsigned TE57_Exclude:1;
unsigned TE58_Exclude:1;
unsigned TE59_Exclude:1;
unsigned TE60_Exclude:1;
unsigned TE61_Exclude:1;
unsigned TE62_Exclude:1;
unsigned TE63_Exclude:1;
unsigned TE64_Exclude:1;
unsigned TE65_Exclude:1;
unsigned TE66_Exclude:1;
unsigned TE67_Exclude:1;
unsigned TE68_Exclude:1;
unsigned TE69_Exclude:1;
unsigned TE70_Exclude:1;
unsigned TE71_Exclude:1;
unsigned TE72_Exclude:1;
unsigned TE73_Exclude:1;
unsigned TE74_Exclude:1;
unsigned TE75_Exclude:1;
unsigned TE76_Exclude:1;
unsigned TE77_Exclude:1;
unsigned TE78_Exclude:1;
unsigned TE79_Exclude:1;
unsigned TE80_Exclude:1;
unsigned TE81_Exclude:1;
unsigned TE82_Exclude:1;
unsigned TE83_Exclude:1;
unsigned TE84_Exclude:1;
}bit; ///< Биты для доступа к каждой ячейке ТЭ
}Exclude; ///< Юнион для исключения ТЭ
}MB_DataCoilsTypeDef;
// DEFINES FOR COIL ARRAYS
#define C_TE_EXCLUDE_ADDR 0
#define C_TE_EXCLUDE_QNT 84
/** MODBUS_DATA_COILS_DEFINES
* @}
*/
//-----------MODBUS DEVICE DATA SETTING-------------
// MODBUS DATA STRUCTTURE
/**
* @brief Структура со всеми регистрами и коилами модбас
* @ingroup MODBUS_DATA
*/
typedef struct // mzkt modbus data
{
MB_DataInRegsTypeDef InRegs; ///< Modbus input registers @ref MB_DataInRegsTypeDef
MB_DataCoilsTypeDef Coils; ///< Modbus coils @ref MB_DataCoilsTypeDef
MB_DataHoldRegsTypeDef HoldRegs; ///< Modbus holding registers @ref MB_DataHoldRegsTypeDef
}MB_DataStructureTypeDef;
extern MB_DataStructureTypeDef MB_DATA;
/////////////////////////////////////////////////////////////
///////////////////////TEMP/OUTDATE/OTHER////////////////////
//typedef enum //MB_MZKTECommandsTypeDef
//{
// StandartMode = 0x00, ///< Стандартная работа
// Opros_TE_Disable = 0x01, ///< Запрет опроса ТЭ (активен только обмен с ЛСУ ЭС, ТЭ не контролируются)
//}MB_MZKTECommandsTypeDef;
///**
// * @brief Состояние МЗКТЭ
// */
//typedef enum //MB_MZKTEErrStatusTypeDef
//{
// MZKTE_OK = 0x0, ///< МЗКТЭ функционирует нормально. Идет опрос ТЭ.
// NonCritical_Err = 0x1, ///< Неисправность МЗКТЭ, при которой МЗКТЭ может выполнять свои основные функции (некоторые программные ошибки из @ref MB_MZKTEErrorsTypeDef).
// Critical_Err = 0x2, ///< Неисправность МЗКТЭ, при которой выполнение основных функций не представляется возможным (ошибки 1-3 и некоторые программные ошибки из @ref MB_MZKTEErrorsTypeDef)
//
//}MB_MZKTEErrStatusTypeDef;
//typedef enum
//{
// TE_No_Err = 0x0, ///< Напряжения на всех ТЭ выше аварийных порогов, задаваемых уставками «Авария»
// TE_Err = 0x1, ///< Напряжение на одном или нескольких ТЭ достигло или ниже аварийного порога, задаваемого уставкой «Авария»
//}MB_TEErrActiveTypeDef;
//typedef enum
//{
// TE_No_Warn = 0x0, ///< Напряжения на всех ТЭ выше предупредительных порогов, задаваемых уставкой «Предупреждение»
// TE_Warn = 0x1, ///< Напряжение на одном или нескольких ТЭ достигло или ниже предупредительного порога, задаваемого уставкой «Предупреждение»
//}MB_TEWarnActiveTypeDef;
//typedef enum
//{
// OprosTE_Enable = 0x0, ///< Опрос ТЭ разрешен
// OprosTE_Disable = 0x1, ///< Опрос ТЭ запрещен (см. регистр хранения 170)
//}MB_OprosTETypeDef;

37
ТЗ/неофтз.txt Normal file
View File

@@ -0,0 +1,37 @@
По модбасу: нужна терминалка для общения с МЗКТЭ. Вот краткое ТЗ
Команды:
0x01 Read Coils
0x03 Read Holding Registers
0x04 Read Input Registers
0x05 Write Single Coil
0x06 Write Single Register
0x0F Write Multiple Coils
0x10 Write Multiple Registers
Т.е. обращение будет к следующим типам данных:
- Входные регистры (MB_DataInRegsTypeDef),
- Регистры хранения (MB_DataHoldRegsTypeDef),
- Коилы (MB_DataCoilsTypeDef).
Там некоторые регистры еще парсяться, поэтому скидываю файл с структурой данных, который я сделал. В скобках указал имя typedef соответствующего типа данных в файле. Можешь его использовать, заодно мб придумаешь че можно улучшить.
По программе:
Там идет управление и контроль ТЭ (топливные элементы), которых всего 85 штук. С них снимается задаются две уставки: предупреждение и авария. Коилами можно исключать ТЭ из работы.
Также есть пару управляющих настроек и статус-регистр.
Соответственно можно сделать два окна:
- одно небольшое - для статуса МЗКТЭ
- второе большое - для ТЭ. Можно сделать 4 вкладки, в каждой 85 ячеек:
- Напряжение на ТЭ,
- Уставки "Предупреждение",
- Уставки "Авария",
- Исключения ТЭ
И можно сделать одно открываемое окно для настроек. Типа по кнопке "Настройки МЗКТЭ". Это для регистров хранения 170-174. И если что их запись должна быть только по команде 0x06 (сингл). Остальные уставки поддерживают запись 0x10 (мультипл).
Статус МКЗТЭ и Напряжения на ТЭ только считывается (команда 0x04)
Уставки "Предупреждение" и "Авария" можно считать и записать всеми способами (0x03, 0x06, 0x10)
Настройки МЗКТЭ можно считывать и записать только по одному регистру (0x03, 0x06)
Исключения ТЭ можно считывать и записывать всеми способами (0x01, 0x05, 0x0F)

BIN
ТЗ/прил.MODBUS.pdf Normal file

Binary file not shown.