admin 发表于 2020-6-17 12:12:18

共享内存 - C#与CoDeSys通讯

测试环境:1、CODESYS 3.5.13.0(新建Codesys_ShareMemory项目)2、SharedMemoryCommunication.package(Codesysy共享内存库)链接:https://pan.baidu.com/s/1JM0RXUR8h1L5UE2pVhY4BQ
提取码:ql7w

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_ParaFromHMI和Str_ParaToHMI3、创建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 OF RTS_IEC_RESULT;                //返回运行错误码
      ResultWrite: ARRAY 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));
      WriteHandle:= SysSharedMemoryCreate(pszName:= szNameWrite, ulPhysicalAddress:= ulPhysicalAddressWrite, pulSize:= ADR(ulSizeWrite), pResult:= ADR(ResultWrite));
      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));                //返回执行的错误码
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));                //返回执行的错误码
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、创建ShareMemory1)声明定义共享内存使用的API2)共享内存初始化,注意检查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);
            }
      }


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)通信测试动图源码地址: https://download.csdn.net/download/m0_37846617/12440773

g2575 发表于 2021-6-24 13:37:49

请问网盘链接失效了,可以再分享一下吗

wx_9111375397 发表于 2022-4-7 23:52:46


请问网盘链接失效了,可以再分享一下吗

madlax2008 发表于 2022-11-10 01:21:46

我只想问,这个必须要求codesys运行在c#所在的主机上吗?如果是网线连接的plc可不可以
页: [1]
查看完整版本: 共享内存 - C#与CoDeSys通讯