共享内存 - C#与CoDeSys通讯

测试环境:

1、CODESYS 3.5.13.0(新建Codesys_ShareMemory项目)

2、SharedMemoryCommunication.package(Codesysy共享内存库)

链接:https://pan.baidu.com/s/1X2mSGRFnspZ_GRSGO53cug 
提取码:v499 

3、Visual Studio2015(新建C#_ShareMemory项目)

一、共享内存概念
1、顾名思义,共享内存就是建立一块供协作进程共享的内存区域,多个进程可以透过此共享区域读取或者写入数据来交换信息;

2、通信示意图:

二、CoDeSys程序
1、添加库文件

· SysShm,3.5.8.0 (System)

· SysTypes2 Interfaces,3.5.4.0 (System)

1)打开库管理器(Library Manager),选择“添加库(Add Library)”,点“高级(Advanced...)”;

2)在搜索框(String for a fulltext search...)中分别输入SysShm和SysTypes搜索添加SysShm,3.5.8.0 SysTypes2 Interfaces,3.5.4.0 ,

选中搜索到的库,点“OK”确认添加,

添加完成即可在库管理器(Library Manager)中查看到。

库文件介绍:


2、创建数据结构

共享内存进行数据共享交互需要通过数据结构来进行。

选中应用(Application)右键添加对象(Add Object),选择“DUT”,

创建数据结构,输入数据结构名称,选择类型(Type),点“Add”

本例分别创建两个数据结构,Str_ParaFromHMIStr_ParaToHMI

3、创建ShareMemory

新建ST(结构文本)程序,创建共享内存。

程序页面概览:

1)声明变量、共享内存名和功能函数等

PROGRAM ShareMemory
VAR
	
	bStart: BOOL:= FALSE;
	ReadHandle: RTS_IEC_HANDLE:= RTS_INVALID_HANDLE;
	WriteHandle: RTS_IEC_HANDLE:= RTS_INVALID_HANDLE;
	szNameRead: STRING:= 'CODESYS_MEMORY_READ';		//声明共享内存的读取内存名称
	szNameWrite: STRING:= 'CODESYS_MEMORY_WRITE';	//声明共享内存的写入内存名称
	ulPhysicalAddressRead: __UXINT:= 0;
	ulPhysicalAddressWrite: __UXINT:= 0;
	ulSizeRead: __UXINT:= 1024;
	ulSizeWrite: __UXINT:= 1024;
	ResultRead: ARRAY[0..2] OF RTS_IEC_RESULT;		//返回运行错误码
	ResultWrite: ARRAY[0..2] OF RTS_IEC_RESULT;
	
	SMRead: __UXINT;
	SMWrite: __UXINT;
	ulOffsetRead: __UXINT:= 0;
	ulOffsetWrite: __UXINT:= 0;
	
END_VAR

2)程序具体实现

//Init Memory
IF NOT bStart THEN
	ReadHandle:= SysSharedMemoryCreate(pszName:= szNameRead, ulPhysicalAddress:= ulPhysicalAddressRead, pulSize:= ADR(ulSizeRead), pResult:= ADR(ResultRead[0]));
	WriteHandle:= SysSharedMemoryCreate(pszName:= szNameWrite, ulPhysicalAddress:= ulPhysicalAddressWrite, pulSize:= ADR(ulSizeWrite), pResult:= ADR(ResultWrite[0]));
	IF RTS_INVALID_HANDLE <> ReadHandle AND RTS_INVALID_HANDLE <> WriteHandle THEN
		bStart:= TRUE;
	END_IF
END_IF

//读取数据
IF RTS_INVALID_HANDLE <> ReadHandle THEN
	SMRead:= SysSharedMemoryRead(
	hShm:= ReadHandle, 					//读取内存的设备句柄
	ulOffset:= ulOffsetRead,			//读取数据的偏移地址 
	pbyData:= ADR(GVL.GetPara), 		//指向读取数据的缓冲区
	ulSize:= SIZEOF(Str_ParaFromHMI), 	//读取数据的字节大小	
	pResult:= ADR(ResultRead[1]));		//返回执行的错误码
END_IF

//写入数据
IF RTS_INVALID_HANDLE <> WriteHandle THEN
	SMWrite:= SysSharedMemoryWrite(
	hShm:= WriteHandle, 				//写入内存的设备句柄
	ulOffset:= ulOffsetWrite, 			//写入数据的偏移地址
	pbyData:= ADR(GVL.SetPara), 		//指向写入数据的缓冲区
	ulSize:= SIZEOF(Str_ParaToHMI), 	//写入数据的字节大小
	pResult:= ADR(ResultWrite[2]));		//返回执行的错误码
END_IF

三、C#程序
1、引用命名空间

using System.IO.MemoryMappedFiles;      //引用共享内存命名空间
using System.Threading;                 
using System.Runtime.InteropServices;


2、定义数据结构

数据结构中的变量名不一定非要与Codesys的数据结构变量名保持相同(建议定义一致,便于查看和管理),但数据结构内的数据类型和数据总数必须保持一致。

    struct StrFromCodesys
    {
        internal bool bOut;
        internal int iOut;
        internal double fOut;
    }
    struct StrToCodesys
    {
        internal bool bIn;
        internal int iIn;
        internal double fIn;
    }


3、创建ShareMemory

1)声明定义共享内存使用的API

2)共享内存初始化,注意检查MappedFile的内存名与Codesys内存名一致,这样才能确保访问同一块内存地址

原代码:

 private void InitMemory()
        {
            try
            {
                MMF_Write = MemoryMappedFile.CreateOrOpen("CODESYS_MEMORY_READ", 1024);        //打开Codesys_Read内存区域,意思就是说Codesys的读取区域是C#的写入区域
                AccessorWrite = MMF_Write.CreateViewAccessor(0, Marshal.SizeOf(typeof(StrToCodesys)), MemoryMappedFileAccess.Write);

                MMF_Read = MemoryMappedFile.CreateOrOpen("CODESYS_MEMORY_WRITE", 1024);        //打开Codesys_Write内存区域,意思就是说Codesys的写入区域是C#的读取区域
                AccessorRead = MMF_Read.CreateViewAccessor(0, Marshal.SizeOf(typeof(StrFromCodesys)), MemoryMappedFileAccess.Read);

            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

该部分于2021年4月1日修改更新为以下代码

修改更新原因:因为原代码与CODESYS通讯时,C#会出现找不到路径无法通讯的问题。详细情况是:如果C#程序先运行,那么怎样都可以,但如果CODESYS程序先运行,C#程序就需要去找内存路径,找不到就连不上,所以在C#程序的路径中加上“Global\\”);

注意:使用环境上有所区别,当共享内存用在于仿真虚拟环境使用时,共享内存名不要加“Global\\”,而当共享内存用于实体控制器时,须加“Global\\”。(于2021年5月31日纠正)

private void InitMemory()
        {
            try
            {
                MMF_Write = MemoryMappedFile.OpenExisting("Global\\" + "CODESYS_MEMORY_READ", MemoryMappedFileRights.ReadWrite);
                AccessorWrite = MMF_Write.CreateViewAccessor(0, Marshal.SizeOf(typeof(StrToCodesys)), MemoryMappedFileAccess.ReadWrite);

                MMF_Read = MemoryMappedFile.OpenExisting("Global\\" + "CODESYS_MEMORY_WRITE", MemoryMappedFileRights.ReadWrite);
                AccessorRead = MMF_Read.CreateViewAccessor(0, Marshal.SizeOf(typeof(StrFromCodesys)), MemoryMappedFileAccess.ReadWrite);
            }
            catch(Exception ex)
            {
                if (MMF_Write == null)
                {
                    MMF_Write = MemoryMappedFile.CreateOrOpen("Global\\CODESYS_MEMORY_READ", 1024);
                    if (MMF_Write != null)
                    {
                        AccessorWrite = MMF_Write.CreateViewAccessor(0, Marshal.SizeOf(typeof(StrToCodesys)), MemoryMappedFileAccess.Write);
                    }
                }
                if (MMF_Read == null)
                {
                    MMF_Read = MemoryMappedFile.CreateOrOpen("Global\\CODESYS_MEMORY_WRITE", 1024);
                    if (MMF_Read != null)
                    {
                        AccessorRead = MMF_Read.CreateViewAccessor(0, Marshal.SizeOf(typeof(StrFromCodesys)), MemoryMappedFileAccess.Read);
                    }
                }
                MessageBox.Show(ex.Message);
            }
        }

3)读取数据

        private void ReadData()
        {
            while(true)
            {
                try
                {
                    Thread.Sleep(5);
                    AccessorRead.Read(0, out ParaFromCodesys);      //读取Codesys的数据
                    Thread.Sleep(5);
                    if(ParaFromCodesys.bOut == true)
                        picbox_bRead.BackColor = Color.Red;
                    else
                        picbox_bRead.BackColor = Color.Gray;

                    textbox_iRead.Text = ParaFromCodesys.iOut.ToString("0");
                    textbox_fRead.Text = ParaFromCodesys.fOut.ToString("0.000");

                }
                catch(Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

4)写入数据

        private void btnWriteB(object sender, EventArgs e)
        {
            ParaToCodesys.bIn = !ParaToCodesys.bIn;
            AccessorWrite.Write(0, ref ParaToCodesys);
            if(ParaToCodesys.bIn == true)
            {
                picbox_bWrite.BackColor = Color.Red;
            }
            else
            {
                picbox_bWrite.BackColor = Color.Gray;
            }
        }

四、通信测试
运行CoDeSys和C#程序,通过读取和写入数据测试通信结果

1)通信测试图片

2)通信测试动图

源码地址: C#与CoDeSys共享内存例程_上位机与codesys通讯-制造文档类资源-CSDN下载

  • 25
    点赞
  • 113
    收藏
    觉得还不错? 一键收藏
  • 57
    评论
CODESYS是一种用于编程控制系统的综合开发环境,而C是一种通用的高级编程语言。 CODESYS是一款广泛应用于工业自动化领域的开发工具,它提供了一个集成的开发环境,可以用来编写、调试和测试PLC控制器程序。CODESYS具有丰富的功能,包括图形化编程界面,强大的调试工具,灵活的网络通讯功能等。同时,CODESYS还支持多种编程语言,如结构化文本语言(ST)、功能块图(FBD)等。通过CODESYS,开发人员可以轻松地创建具有高度可靠性和灵活性的控制系统。 而C语言是一种通用的高级编程语言,广泛应用于嵌入式系统开发、操作系统内核等领域。C语言以其简洁而强大的语法,成为了编程界的事实标准。C语言提供了丰富的语法和库函数,方便开发人员进行底层编程,通过C语言可以直接访问硬件资源,进行底层控制和优化。C语言还具有较高的可移植性,可以在不同的平台上进行开发和调试。 CODESYS与C语言在某些方面有相似之处,如都可以用于嵌入式系统开发,可以编写控制算法、数据处理等。但CODESYS在工业自动化领域中更为广泛应用,提供了更加丰富的编程语言和工具,而C语言则具有更高的灵活性和可移植性。 总的来说,CODESYS和C语言都是非常有用的工具,在不同的领域中有不同的应用。CODESYS适用于工业自动化领域的控制系统开发,而C语言则适用于各种嵌入式系统和底层编程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 57
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值