C++ MFC在子对话框中操作三菱PLC

前面有一篇文章讲过C++和三菱plc的通讯:https://blog.csdn.net/V_Gogol/article/details/103389983,本文是其拓展。

背景

前面讲过在工程中添加Activex控件,并使用控件创建变量,此对象包含了PLC的多个操作函数。但是在实际项目中遇到了一个问题,就是只能在主对话框放入activex控件,相当于这个对象的作用域仅限于主对话框对应的头文件和源文件,如果要在其他类中对PLC进行操作(例如设置或读取指定端口的值)就会显得比较麻烦(在其他类中创建主对话框类的对象并调用plc操作函数,执行时程序会报错)。本文讲的是编写一个专门的PLC操作类包含回调函数来实现其他类里也可以方便的对plc进行操作。

思路

想要将plc操作做成其他类可用,我的做法是采用回调函数。

为了代码的可重用性,我专门封装了一个关于plc操作的类,后续跟plc操作相关的直接调用里面的函数即可。

为什么用回调呢?

因为activex控件放在了主对话框中,导致plc操作相关的函数只能在主对话框对应的源文件可用(注意:不只是在主对话框类中,在主对话框对应整个源文件都可用,笔者亲测),用回调的优点在于,我可以把plc的操作函数放到一个全局可用的类中,任何其他类包含这个头文件创建对象后都可以使用,而把plc操作的具体实现代码放到主对话框类的源文件中。任何其他类调用plc的操作时,都会自动调用主对话框类中相应的操作代码,这样就避免前面说的那种问题了。

实现

前面说了,我专门封装了一个plc操作的类,下面代码是这个类的头文件中的内容

#pragma once


const	int		PLC_NO_ERROR = 0;
const	int		PLC_ERROR = 1;


class CFXPlc
{
protected:
	//回调函数指针类型及实例创建
	//轴数据传递给PLC回调--参数只含一个整型
	typedef	BOOL(CALLBACK*IADTPLC)(int);
	//设置端口值回调
	typedef	BOOL(CALLBACK*SPLCV)(CString, long );
	//读取端口值回调
	typedef	BOOL(CALLBACK*RPLCV)(CString,long*);
	///轴动作时将标志或数据发送到plc
	IADTPLC	m_pADaToPlc;				//数据传入plc 
	//设置plc指定端口值
	SPLCV		m_pSPlcV;
	//读取plc指定端口值
	RPLCV		m_pRPlcV;
	//回调中间函数
	//回调中间函数--轴相关数据传到PLC
	BOOL	Mid_DataToPlc(int axisno);
	//回调中间函数--设置指定端口值
	BOOL	Mid_SetPortValue(CString PortName, long PortValue);
	//回调中间函数--读取指定端口值
	BOOL	Mid_ReadPortValue(CString PortName, long* PortValue);

public:	///回调函数
	//回调--设置指定端口值
	BOOL	C_SetPortValue(BOOL(CALLBACK*lpSetPortValue)(CString PortName, long PortValue));
	//回调--读取指定端口值
	BOOL	C_ReadPortValue(BOOL(CALLBACK*lpReadPortValue)(CString PortName, long* PortValue));
	//回调--轴动作时将标志或数据发送到plc
	BOOL	C_AxisMovDataToPlc(BOOL(CALLBACK*lpAxsDataToPlc)(int));

public:
	//设置指定端口值
	int	SetPortValue(CString PortName, long PortValue);
	//读取指定端口值
	int	ReadPortValue(CString PortName, long* PortValue);

public:
	CFXPlc();
	~CFXPlc();
	
};

下面是plc操作类源文件中的函数实现:

#include "stdafx.h"
#include "FXPlc.h"
回调--设置指定端口值
BOOL	CFXPlc::C_SetPortValue(BOOL(CALLBACK*lpSetPortValue)(CString PortName, long PortValue))
{
	m_pSPlcV = lpSetPortValue;
	return	PLC_NO_ERROR;
}

//回调中间函数--设置指定端口值
BOOL	CFXPlc::Mid_SetPortValue(CString PortName, long PortValue)
{
	if (NULL == m_pSPlcV)
	{
		AfxMessageBox(L"fx-setportvalue未编写回调函数!");
		return	PLC_ERROR;
	}
	else
		return(*m_pSPlcV)(PortName, PortValue);
}

//设置指定端口值
int	CFXPlc::SetPortValue(CString PortName, long PortValue)
{
	if (PLC_ERROR == Mid_SetPortValue(PortName, PortValue))
	{
		AfxMessageBox(PortName + L"值设置失败!");
		return	PLC_ERROR;
	}
	else
		return	PLC_NO_ERROR;
}

//回调--读取指定端口值
BOOL	CFXPlc::C_ReadPortValue(BOOL(CALLBACK*lpReadPortValue)(CString PortName, long* PortValue))
{
	m_pRPlcV = lpReadPortValue;
	return	PLC_NO_ERROR;
}

//回调中间函数--读取指定端口值
BOOL	CFXPlc::Mid_ReadPortValue(CString PortName, long* PortValue)
{
	if (NULL == m_pRPlcV)
	{
		AfxMessageBox(L"fx-readportvalue未编写回调!");
		return	PLC_ERROR;
	}
	else
		return(*m_pRPlcV)(PortName, PortValue);	
}

//读取指定端口值
int	CFXPlc::ReadPortValue(CString PortName, long* PortValue)
{
	if (PLC_ERROR == Mid_ReadPortValue(PortName, PortValue))
	{
		AfxMessageBox(PortName + L"值读取失败!");
		return	PLC_ERROR;
	}
	else
		return	PLC_NO_ERROR;
}

上面是plc操作类中读取和设置plc指定端口值得函数实现,下面还有最后一步,就是在主对话框的源文件中进行回调注册和回调函数的代码实现。

注意,下面的代码是在主对话框的源文件中,而不是在plc操作类

首先,在主对话框类的初始化函数(OnInitDialog函数)中进行回调函数的注册

	///注册PLC轴动作时数据传送回调函数
	G::fxplc.C_SetPortValue(CB_SetPortValue);
	G::fxplc.C_ReadPortValue(CB_ReadPortValue);

 

前面的G::fxplc是我在主对话框类中创建的plc操作类的对象,下面再是括号内两个回调函数的代码实现:

//回调函数--设置指定端口值
BOOL	CALLBACK	CB_SetPortValue(CString PortName, long Value)
{
	try
	{
		if (PLC_NO_ERROR != SetPlcPortValue(0, PortName, Value))
			return	PLC_ERROR;
		else
			return	PLC_NO_ERROR;
	}
	catch (...)
	{
		AfxMessageBox(L"设置"+PortName+L"出错!");
		return PLC_ERROR;
	}
}

//回调函数--读取指定端口值
BOOL	CALLBACK	CB_ReadPortValue(CString PortName, long* Value)
{
	try
	{
		if (PLC_NO_ERROR != GetPlcPortValue(0, PortName, Value))
			return	PLC_ERROR;
		else
			return	PLC_NO_ERROR;
	}
	catch (...)
	{
		AfxMessageBox(L"读取" + PortName + L"出错!");
		return PLC_ERROR;
	}
}

里面的SetPlcPortValue函数和GetPlcPortValue函数是具体的plc实现函数,详细可见我的另一篇博文:https://blog.csdn.net/V_Gogol/article/details/103389983

本文中我的操作函数没有定义在主对话框内部,我的回调函数也是对源文件全局的,如果你的操作函数是定义在类中的话,把上面两个回调也作出相应的更改就可以了。

  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值