第四章:IEC61850数据读、写、遥控功能
最终开发成果展示:最终成果
上一章内容回顾:IEC61850数据模型加载
软件及完整源代码获取:欢迎咨询
一、IEC61850读写功能介绍
1.数据模型与分层结构
IEC61850采用面向对象的数据建模方法,将设备功能抽象为逻辑设备(LD)、逻辑节点(LN)、数据对象(DO)和数据属性(DA)的层次结构。例如,一个断路器的状态可能表示为LD1/XCBR1.Pos.stVal,其中Pos.stVal是开关位置的数据属性值。这种分层模型支持灵活的数据访问,用户可通过标准化路径精准读写目标数据。
2.数据读写服务类型
- 读数据值(GetDataValues):获取指定逻辑节点中数据对象的当前值(如遥测值、遥信状态)。
- 设置数据值(SetDataValues):修改数据属性值(如定值区切换、保护参数配置)。
- 批量读取(GetAllDataValues):一次性获取逻辑节点下的全部数据属性,常用于初始化或全数据同步。
- 模型发现服务(GetLogicalDeviceDirectory等):动态获取设备的数据模型结构,实现即插即用。
3.实现机制
- 基于MMS协议:数据读写通过制造报文规范(MMS)实现,映射到ISO/OSI应用层,支持客户端-服务器模式的请求与响应。
- 功能约束(FC):通过功能约束(如CO控制、CF配置)限定数据访问权限,确保操作的安全性。例如,仅允许通过Select Before Operate(SBO)机制执行遥控操作,防止误操作。
4.应用场景
- 遥测遥信:实时采集电流、电压、开关状态等数据。
- 定值管理:读写保护装置的定值参数(如过流保护阈值)。
- 动态配置:通过在线修改数据集(DataSet)或控制块(Report Control Block)调整数据上报规则。
二、IEC61850读数据实现
1.读单个值
- 选择需要读取的数据Item,点击读单个值按钮
展示
核心代码:
IedClientError error;
//获取DA属性
LinkedList dataAttributes = IedConnection_getDataDirectoryFC(m_iedConnectHandle,&error,Node->Ref.toUtf8().constData());
if(error!=IED_ERROR_OK)
return;
if (dataAttributes != nullptr) {
LinkedList dataAttribute = LinkedList_getNext(dataAttributes);
while (dataAttribute != nullptr) {
QString df = (char*) dataAttribute->data;//获取DA引用名
int start =df.indexOf("[");
int end = df.indexOf("]");
QString daName = df.mid(0,start);
QString fcstr=df.mid(start+1,end-1-daName.length());
QString dref = QString("%1.%2").arg(Node->Ref,daName);
QString reffc = QString("%1[%2]").arg(dref,fcstr);
m_mutex.lock();
Node_Data *nodeD = m_dataHash.value(reffc);
m_mutex.unlock();
if(nodeD==nullptr){
dataAttribute = LinkedList_getNext(dataAttribute);
continue;
}
//根据DA应用名称和功能约束读取DA值
MmsValue* tmms_das = IedConnection_readObject(m_iedConnectHandle,&error, dref.toUtf8().constData(),FunctionalConstraint_fromString(fcstr.toUtf8().constData()));
if(tmms_das!=nullptr){
//获取所读取数据的类型
MmsType type = MmsValue_getType(tmms_das);
nodeD->type = type;
if(type == MMS_STRUCTURE){//如果是结构体类型则递归读取
readSingalData(nodeD,citem);
}
else{
nodeD->Data = getValue(tmms_das);
}
MmsValue_delete(tmms_das);
}
dataAttribute = LinkedList_getNext(dataAttribute);
}
LinkedList_destroy(dataAttributes);
//以下需实现所读数据与界面UI结合进行数据展示
//TODO....
核心接口:IedConnection_readObject
2.读所有值
- 选择对应逻辑节点,点击读所有值按钮读所有值
展示:
- 说明:读所有值是可以一次读取整个模型数据,当模型数据量较大时,读取速度会变慢(5秒以上)。这里读所有值实现的功能是只读当前选择的逻辑节点下所有值,且通过多线程并发读取,提高读取效率。
核心代码:
void MainWindow::click_readAllData()
{
//判断连接是否在线
if(m_online!=IED_ERROR_ALREADY_CONNECTED)
return;
//将需要读取的DO、DA全部放入队列中
for(QString reffc:m_datasetRefList)
m_readQueue.enqueue(reffc);
if(m_threadDoDaPool==nullptr)
m_threadDoDaPool = new QThreadPool;
m_threadDoDaPool->setMaxThreadCount(4);
//启动4个子线程同时读取
for (int i = 0; i < 4; ++i) {
QRunnable* task = QRunnable::create([&](){
showMessage("正在读取所有数据...");
while(true){
m_mutex.lock();
if(m_readQueue.isEmpty()){
m_mutex.unlock();
break;
}
Node_Data *node = m_dataHash.value(m_readQueue.dequeue());
m_mutex.unlock();
if(node)
readAllData(node);
}
});
m_threadDoDaPool->start(task);
}
m_threadPool->start(QRunnable::QRunnable::create([&](){
m_threadDoDaPool->waitForDone();
emit ui->treeWidget->itemPressed(ui->treeWidget->currentItem(),0);
showMessage("读取所有数据完成");
}));
}
void MainWindow::readAllData(Node_Data *NodeFD)
{
FunctionalConstraint fc = FunctionalConstraint_fromString(NodeFD->FC.toUtf8().constData());
IedClientError error;
QString ref = NodeFD->Ref;
LinkedList daAtts = IedConnection_getDataDirectoryByFC(m_iedConnectHandle, &error, ref.toUtf8().constData(), fc);
if(daAtts==nullptr)
return;
LinkedList dataObject = LinkedList_getNext(daAtts);
if(dataObject==nullptr){
MmsValue *val = IedConnection_readObject(m_iedConnectHandle, &error,ref.toUtf8().constData(), fc);
if(val){
NodeFD->Data = getValue(val);
MmsValue_delete(val);
}
return;
}
QString name;
QString strFC = FunctionalConstraint_toString(fc);
while(dataObject) {
name = (char*) dataObject->data;
QString dref = QString("%1.%2").arg(ref,name);
m_mutex.lock();
Node_Data *Node_Child = m_dataHash.value(QString("%1[%2]").arg(dref,strFC));
m_mutex.unlock();
if(Node_Child==nullptr){
dataObject = LinkedList_getNext(dataObject);
continue;
}
MmsValue *val = IedConnection_readObject(m_iedConnectHandle, &error,dref.toUtf8().constData(), fc);
if(val!=nullptr){
MmsType type = MmsValue_getType(val);
if(type==MMS_STRUCTURE)
readAllData(Node_Child);
else
Node_Child->Data = getValue(val);
MmsValue_delete(val);
}
dataObject = LinkedList_getNext(dataObject);
}
LinkedList_destroy(daAtts);
}
三、IEC61850写数据实现
写数据时,只有一些特殊数据才可以进行写,如遥调数据、配置数据、描述类数据,即功能约束为CF、SP、DC等数类型数据。
展示:
核心代码:
connect(&writeBtn,&QPushButton::clicked,[&](){
IedClientError error;
//获取功能约束
FunctionalConstraint fc = FunctionalConstraint_fromString(Node->FC.toUtf8().constData());
QHashIterator<QString,Node_Data*> it(wHashData);
while (it.hasNext()) {
it.next();
Node_Data* node = it.value();
MmsValue *value=nullptr;
//创建不同类型的数据
if(MMS_FLOAT==node->type)
value = MmsValue_newFloat(node->Data.toFloat());
else if(MMS_BOOLEAN==node->type)
value = MmsValue_newBoolean(node->Data.toUInt());
else if(MMS_INTEGER==node->type)
value = MmsValue_newIntegerFromInt32(node->Data.toInt());
else if(MMS_UNSIGNED==node->type)
value = MmsValue_newUnsignedFromUint32(node->Data.toUInt());
else if(MMS_STRING==node->type)
value = MmsValue_newMmsString(node->Data.toUtf8().constData());
else if(MMS_UTC_TIME==node->type)
value = MmsValue_newUtcTimeByMsTime(QDateTime::fromString(node->Data,"yyyy-MM-dd hh:mm:ss.zzz").toMSecsSinceEpoch());
else{
if(error!=IED_ERROR_OK){
MessageReminder(QString("写数据失败,未找到对应的数据类型(%1)").arg(node->type).toUtf8(),"确定","取消");
return;
}
}
//写数据
IedConnection_writeObject(m_iedConnectHandle, &error,node->Ref.toUtf8().constData(),fc,value);
if(error!=IED_ERROR_OK){
MessageReminder(QString("写数据失败,error:%1").arg(node->type).toUtf8(),"确定","取消");
return;
}
}
showMessage("写数据成功");
核心接口:IedConnection_writeObject
四、IEC61850遥控功能介绍
1.遥控服务类型
- 直接控制(Direct Control):客户端直接发送控制命令,无需预选操作,适用于低风险场景。
- 预选确认控制(SBO Control):采用“选择-执行”两步操作,先验证设备可操作性(Select),再执行命令(Operate),确保安全性。
- 增强型控制:支持检同期(Synchrocheck)、检无压等条件判断,仅当电网状态满足条件时执行操作。
2. 实现机制
- MMS控制模型:通过Control类数据对象传递控制命令,例如LD1/CSWI1.Pos表示开关控制位置。
- GOOSE快速控制:对于需要毫秒级响应的操作(如保护跳闸),通过GOOSE报文实现无连接、实时广播控制指令。
- 安全机制:结合身份认证、操作权限分级和操作日志记录,防止未授权访问
3. 应用场景
- 断路器分合闸:远程控制开关状态,支持单命令或序列操作。
- 保护压板投退:通过软压板远程切换保护功能。
- 紧急联动:如火灾报警触发通风系统启动,通过GOOSE实现跨设备快速响应
五、IEC61850遥控功能实现
- 点击控制按钮,进行遥控命令下发,遥控功能只有遥控类数据才可以控制,即功能约束为CO的数据。
展示:
核心代码:
connect(&operBtn,&QPushButton::clicked,[&](){
//创建控制命令类型
if(cltYype==MMS_BOOLEAN)
ctlVal = MmsValue_newBoolean(valComBox.currentIndex()?true:false);
else if(cltYype==MMS_INTEGER)
ctlVal = MmsValue_newInteger(valComBox.currentText().toInt());
else if(cltYype==MMS_UNSIGNED)
ctlVal = MmsValue_newUnsigned(valComBox.currentText().toInt());
else if(cltYype==MMS_BIT_STRING)
ctlVal = MmsValue_newBitString(valComBox.currentText().toInt());
bool test = false;
for(Node_Data *node:cNode->ListNodeData){
if(node->DA=="Test"){
test = node->Data.toUInt()?true:false;
ControlObjectClient_setTestMode(ctlClient,test);
}
else if(node->DA=="origin"){
QString orIdent;
int orCat=0;
for (Node_Data *nodeOri:node->ListNodeData) {
if(nodeOri->DA=="orCat")
orCat = nodeOri->Data.toInt();
else if(nodeOri->DA=="orIdent")
orIdent = nodeOri->Data;
}
ControlObjectClient_setOrigin(ctlClient,orIdent.toUtf8().constData(),orCat);
}
}
if(!ctlVal){
MessageReminder("控制指令执行失败,数据类型错误","确定","取消");
return;
}
ControlObjectClient_setInterlockCheck(ctlClient,true);
ControlObjectClient_setSynchroCheck(ctlClient,true);
if(select){
if(!ControlObjectClient_selectWithValue(ctlClient,ctlVal)){
IedClientError error = ControlObjectClient_getLastError(ctlClient);
MessageReminder(QString("选择执行失败,错误码:%1").arg(error).toUtf8(),"确定","取消");
return;
}
showMessage("选择执行成功");
if(MessageReminder("选择执行成功,是否立即执行","是","否")){
//下发控制命令
bool operate = ControlObjectClient_operate(ctlClient, ctlVal, 0);
if(!operate){
IedClientError error = ControlObjectClient_getLastError(ctlClient);
MessageReminder(QString("控制指令执行失败,错误码:%1").arg(error).toUtf8(),"确定","取消");
return;
}
readSingalData(Node,parentitem);
showMessage("控制执行成功");
}
else{
operBtn.setText("立即执行");
select= false;
}
}
核心接口:ControlObjectClient_operate
六、总结
本章节讲解IEC61850标准中数据读取、写入和遥控功能的实现方法。在数据读取方面,详细展示了单个值和所有值的读取流程:通过IedConnection_readObject接口读取指定数据项,利用多线程并发提高批量读取效率;在数据写入部分,演示了如何修改设备参数并写入;遥控功能则实现了对设备的远程控制操作。且提供了核心代码示例,包括数据目录获取、递归读取结构体数据、多线程任务分配等关键技术实现,并配有操作界面截图说明。这些功能为智能变电站自动化系统提供了标准化的通信基础。
下期分享IEC61850规约报告功能。