倍福PLC——ADS上位机通讯

倍福PLC——ADS上位机通讯

  • 前言
  • 一、ADS服务
  • 二、使用ads函数进行数据通讯
    • 1.通过句柄读写
      • c#读取写入代码


前言

工程中涉及与倍福plc的交互用到ads通讯,在此稍作研究总结。


一、ADS服务

本机没有安装倍福全家桶的需要安装一下这个TwinCAT System。
安装完成后需要配置一下服务中的端口。(具体操作等下次有机会再记录把)

二、使用ads函数进行数据通讯

1.通过句柄读写

先看一下两端的数据配置如下:
PLC端:
在这里插入图片描述
结构体定义:
在这里插入图片描述

此处顶部的{attribute ‘pack_mode’:= ‘1’}指示了内存排列的方式,与下文c#端设置结构体排列时有着对应的关系,请着重关注一下
上位机C#端:
看一下两边类型对照表:
在这里插入图片描述
重点是结构体定义:

很多人在这个地方喜欢把Struct用Class定义,在单独传输结构体数据时是没有问题的,但是当要传输一个结构体数组,用Class定义则会引起代码报错,此处注意!

        [StructLayout(LayoutKind.Sequential, Pack = 1)]public struct myStruct{public void StructIni() {b = false;bt = 0;word = 0;dword = 0;sint = 0;m_int = 0;dint = 0;lint = 0;real = 0;lreal = 0;string_en = "";intArr = new int[10];intArr2 = new int[9];}[MarshalAs(UnmanagedType.I1)]public bool b ;[MarshalAs(UnmanagedType.U1)]public byte bt ;[MarshalAs(UnmanagedType.U2)]public ushort word ;[MarshalAs(UnmanagedType.U4)]public uint dword ;[MarshalAs(UnmanagedType.I1)]public sbyte sint ;[MarshalAs(UnmanagedType.I2)]public short m_int;[MarshalAs(UnmanagedType.I4)]public int dint ;[MarshalAs(UnmanagedType.I8)]public long lint ;[MarshalAs(UnmanagedType.R4)]public float real;[MarshalAs(UnmanagedType.R8)]public double lreal ;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]public string string_en;		//plc端string长10[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]public int[] intArr ;[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]public int[] intArr2 ;     		//对应plc端是个二维数组}

结构体数组:

        [StructLayout(LayoutKind.Sequential, Pack = 1)]public struct myStructArr{[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]public myStruct[] arr ;}

c#读取写入代码

定义类型与句柄结构方便操作:

        public struct PLCPointInfo{public PLCType plcType;public int Handel;public int byteCount;}public enum PLCType{BOOL,BYTE,WORD,DWORD,SINT,INT,DINT,LINT,USINT,UINT,UDINT,ULINT,REAL,LREAL,STRING,			//STRING_CH,  //本来是用网上转UTF8格式的来处理,但是我已发现的bug太多,在此不推荐WSTRING,	STRUCT}

首先需要获取对应数据的句柄:

TcAdsClient ads;private void Form1_Load(object sender, EventArgs e)  //连接{ads = new TcAdsClient();ads.Connect("169.254.109.125.1.1", 851);}//存储数据结构的字典Dictionary<string, PLCPointInfo> dic = new Dictionary<string, PLCPointInfo>();private void button1_Click(object sender, EventArgs e)  //获取数据句柄{dic.Clear();foreach (PLCType item in Enum.GetValues(typeof(PLCType))){dic.Add(item.ToString().ToLower(), new PLCPointInfo(){plcType = item,Handel = ads.CreateVariableHandle("MAIN." + item.ToString().ToLower() + "1")});}dic["string"] = new PLCPointInfo(){plcType = PLCType.STRING,Handel = ads.CreateVariableHandle("MAIN." + "string" + "1"),byteCount = 10};//dic["string_ch"] = new PLCPointInfo()//{//    plcType = PLCType.STRING_CH,//    Handel = ads.CreateVariableHandle("MAIN." + "string_ch" + "1"),//    byteCount = 10//};dic["wstring"] = new PLCPointInfo(){plcType = PLCType.WSTRING,Handel = ads.CreateVariableHandle("MAIN." + "wstring" + "1"),byteCount = 10};}

读取PLC中的数据:

        public object GetPLCValue(PLCPointInfo info, Type type = null){switch (info.plcType){case PLCType.BOOL:return (ads.ReadAny(info.Handel, typeof(bool)));case PLCType.BYTE:case PLCType.USINT:return (ads.ReadAny(info.Handel, typeof(byte)));case PLCType.WORD:case PLCType.UINT:return (ads.ReadAny(info.Handel, typeof(ushort)));case PLCType.DWORD:case PLCType.UDINT:return (ads.ReadAny(info.Handel, typeof(uint)));case PLCType.SINT:return (ads.ReadAny(info.Handel, typeof(sbyte)));case PLCType.INT:return (ads.ReadAny(info.Handel, typeof(short)));case PLCType.DINT:return (ads.ReadAny(info.Handel, typeof(int)));case PLCType.LINT:return (ads.ReadAny(info.Handel, typeof(long)));case PLCType.ULINT:return (ads.ReadAny(info.Handel, typeof(ulong)));case PLCType.REAL:return (ads.ReadAny(info.Handel, typeof(float)));case PLCType.LREAL:return (ads.ReadAny(info.Handel, typeof(double)));case PLCType.STRING:return (ads.ReadAny(info.Handel, typeof(string), new int[] { info.byteCount == 0 ? 255 : info.byteCount }));//case PLCType.STRING_CH:  //不建议使用UTF8编码传输//    object o = (ads.ReadAny(info.Handel, typeof(string), new int[] { info.byteCount == 0 ? 255 : info.byteCount+10 }));//    byte[] byteArr = Encoding.Default.GetBytes(o.ToString());//    return Encoding.UTF8.GetString(byteArr);case PLCType.WSTRING:			//wstring类型直接这样读取就行,plc端wstring编码是UTF16,所有直接转换成Unicode就行object o2 = (ads.ReadAny(info.Handel, typeof(string), new int[] { info.byteCount == 0 ? 255 : info.byteCount }));byte[] byteArr2 = Encoding.Default.GetBytes(o2.ToString());return Encoding.Unicode.GetString(byteArr2);case PLCType.STRUCT:if (type == null){throw new Exception("输入结构体C#端类型为null!");}return (ads.ReadAny(info.Handel, type));default:return null;break;}}//数据结果存放的字典Dictionary<string, object> value = new Dictionary<string, object>();private void button2_Click(object sender, EventArgs e){value.Clear();foreach (var item in dic){if (item.Value.plcType == PLCType.STRUCT){value.Add(item.Key, GetPLCValue(item.Value, typeof(myStructArr)));}else{value.Add(item.Key, GetPLCValue(item.Value));}}}

结果:
在这里插入图片描述

数据写入PLC:

        public void SetPLCValue(PLCPointInfo info,object value, Type type = null){object input;switch (info.plcType){case PLCType.BOOL:input = (bool)value;ads.WriteAny(info.Handel, input);break;case PLCType.BYTE:case PLCType.USINT:input = Convert.ToByte(value);ads.WriteAny(info.Handel, input);break;case PLCType.WORD:case PLCType.UINT:input = Convert.ToUInt16(value);ads.WriteAny(info.Handel, input);break;case PLCType.DWORD:case PLCType.UDINT:input = Convert.ToUInt32(value);ads.WriteAny(info.Handel, input);break;case PLCType.SINT:input = Convert.ToSByte(value);ads.WriteAny(info.Handel, input);break;case PLCType.INT:input = Convert.ToInt16(value);ads.WriteAny(info.Handel, input);break;case PLCType.DINT:input = Convert.ToInt32(value);ads.WriteAny(info.Handel, input);break;case PLCType.LINT:input = Convert.ToInt64(value);ads.WriteAny(info.Handel, input);break;case PLCType.ULINT:input = Convert.ToUInt64(value);ads.WriteAny(info.Handel, input);break;case PLCType.REAL:input = Convert.ToSingle(value);ads.WriteAny(info.Handel, input);break;case PLCType.LREAL:input = Convert.ToDouble(value);ads.WriteAny(info.Handel, input);break;case PLCType.STRING:ads.WriteAnyString(info.Handel, value.ToString(), info.byteCount == 0? value.ToString().Length : info.byteCount, Encoding.Default);break;//case PLCType.STRING_CH:       //用UTF8以WriteAny发送过去的数据会存在最后一个字符乱码的情况(最后一个编码被改成63空格结束符)用stream流发送,不会乱码,但是在此读取时又会出现奇怪的乱码问题,原因以后有时间再研究一下//更新一下,在通过这种往内存里写东西的时候,比如string(10)我写入(“嗡嗡嗡”)后再次写入(“哇哇”)则会呈现(“哇哇嗡”)的情况//也就是写入内存小的,没用到的内存不会被清除,读取的时候就会有问题//我在写入时新增结束符或把其他内存都付0也不行//在读取时最后一位莫名其妙变成了63导致最后一个字符乱码,由于找不到倍福数据传输的结构,实在找不到原因了。若以后有新发现,会继续更新//    byte[] byteArr = Encoding.UTF8.GetBytes(value.ToString());//    byte[] newbyteArr;//    newbyteArr = new byte[byteArr.Length+1];//    byteArr.CopyTo(newbyteArr, 0);//    for (int i = byteArr.Length; i < byteArr.Length + 1; i++)//    {//        newbyteArr[i] = Convert.ToByte('\0');//    }//    //if (byteArr.Length < info.byteCount)//    //{//    //    newbyteArr = new byte[info.byteCount];//    //    byteArr.CopyTo(newbyteArr, 0);//    //    for (int i = byteArr.Length; i < newbyteArr.Length; i++)//    //    {//    //        newbyteArr[i] = Convert.ToByte('\0');//    //    }//    //}//    //else if (byteArr.Length > info.byteCount)//    //{//    //    throw new Exception("输入数据长度超过设定长度!");//    //}//    //else//    //{//    //    newbyteArr = byteArr;//    //}//    //ads.WriteAnyString(info.Handel, Encoding.Default.GetString(newbyteArr), info.byteCount == 0 ? value.ToString().Length : info.byteCount, Encoding.Default);//    using (AdsStream rStream = new AdsStream(newbyteArr.Length))//    {//        rStream.Seek(0, System.IO.SeekOrigin.Begin);//        using (AdsBinaryWriter writer = new AdsBinaryWriter(rStream))//        {//            writer.Write(byteArr);//            ads.Write(info.Handel, rStream, 0, newbyteArr.Length);//        }//    }//    break;case PLCType.WSTRING:			//读取时选定Encoding.Unicode就行(不支持UTF8编码读取)ads.WriteAnyString(info.Handel, value.ToString(), info.byteCount == 0 ? value.ToString().Length : info.byteCount, Encoding.Unicode);break;case PLCType.STRUCT:if (type == null){throw new Exception("输入结构体C#端类型为null!");}ads.WriteAny(info.Handel, value);break;default:input = null;break;}}private void button3_Click(object sender, EventArgs e)   //写入数据{foreach (var item in dic){switch (item.Value.plcType){case PLCType.BOOL:SetPLCValue(item.Value, true);break;case PLCType.BYTE:SetPLCValue(item.Value, 100);break;case PLCType.WORD:SetPLCValue(item.Value, 300);break;case PLCType.DWORD:SetPLCValue(item.Value, 2000);break;case PLCType.SINT:SetPLCValue(item.Value, -100);break;case PLCType.INT:SetPLCValue(item.Value, -2000);break;case PLCType.DINT:SetPLCValue(item.Value, -20000);break;case PLCType.LINT:SetPLCValue(item.Value, -2000000);break;case PLCType.USINT:SetPLCValue(item.Value, 200);break;case PLCType.UINT:SetPLCValue(item.Value, 20000);break;case PLCType.UDINT:SetPLCValue(item.Value, 200000);break;case PLCType.ULINT:SetPLCValue(item.Value, 200000);break;case PLCType.REAL:SetPLCValue(item.Value, 2.23);break;case PLCType.LREAL:SetPLCValue(item.Value, -32.15);break;case PLCType.STRING:SetPLCValue(item.Value, "zxcvb");break;//case PLCType.STRING_CH://    SetPLCValue(item.Value, "我的天哪");//    break;case PLCType.WSTRING:SetPLCValue(item.Value, "哇撒");break;case PLCType.STRUCT:myStructArr mstruct = new myStructArr(){arr = new myStruct[9]};for (int i = 0; i < mstruct.arr.Length; i++){mstruct.arr[i].StructIni();mstruct.arr[i].dint = i+1;mstruct.arr[i].intArr[0] = i + 1;mstruct.arr[i].string_en = (i+1).ToString();}SetPLCValue(item.Value, mstruct,typeof(myStructArr));break;default:break;}}}

写入结果:
在这里插入图片描述
结构体数组:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/39424.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

股价大跌、现金流承压,工业富联风光不再?

‍ ‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 昔日的消费电子赛道独角兽工业富联正渐渐失去光环。8月&#xff0c;工业富联发布了2022年上半年财报&#xff0c;数据背后&#xff0c;工业富联处境如何&#xff1f; 净利润增幅放缓&#xff0c;现金流净额大幅下滑 2022…

工业富联灯塔工厂白皮书:智能制造里程碑.pdf(附下载链接)

大家好&#xff0c;我是文文&#xff08;微信&#xff1a;sscbg2020&#xff09;&#xff0c;今天给大家分享富士康工业互联网、亿欧和腾讯云于2020年6月联合发布的白皮书《工业富联灯塔工厂白皮书&#xff1a;智能制造里程碑.pdf》,本白皮书共59页&#xff0c;包含如下四大部分…

工业富联智能嬗变

配图来自Canva可画 提到代工厂&#xff0c;很多人很容易就想到富士康、比亚迪、立讯精密。而作为脱胎于富士康集团的工业富联&#xff0c;也很容易被外界贴上“代工厂”的标签。 事实上&#xff0c;自成立之初工业富联就将它的发展方向&#xff0c;放在了工业互联网和智能制造…

飞桨PaddleTS携手信润富联:共建工业异常检测精准智能化系统

在信润富联的一间实验室中&#xff0c;CTO冯建设正在与研发部的同事探讨“精密制造在线异常监测系统” MachineProphet的测试效果。结果让冯建设的技术团队兴奋不已&#xff1a; 这款最新研发的智能冲压检测系统上线测试各项指标表现优异&#xff0c;可实现最高1000SPM&#xf…

百度飞桨助力信润富联实现工业异常检测智能化

在信润富联的一间实验室中&#xff0c; CTO冯建设正在与研发部的同事探讨“精密制造在线异常监测系统” MachineProphet 的测试效果。结果让冯建设的技术团队兴奋不已&#xff1a; 这款最新研发的智能冲压检测系统上线测试各项指标表现优异&#xff0c;可实现最高1000SPM(Stro…

工业富联左赣鸿 | 解密全场景互联互通的灯塔工厂

前段时间&#xff0c;在【2021中国“智造”数字化转型峰会】上&#xff0c;工业富联数字化转型首席专家左赣鸿先生为大家带来了《解密全场景互联互通的灯塔工厂》的主题分享&#xff0c;阐述工业富联灯塔工厂整体解决方案&#xff0c;将这些最优实践背后的方法路径进行总结&…

干货分享:小红书商业化+微信社区运营,引流自动裂变拓客方案

干货分享&#xff1a;小红书商业化微信社区运营&#xff0c;引流自动裂变拓客方案 背景&#xff1a;2023为止小红书基本已是当代年轻人都会下载和使用的软件了&#xff0c;小红书是生活方式平台和消费决策入口&#xff0c;通过智能机器人学习和对用户的精准智能匹配走红&#x…

【读书笔记】《经验会计与财务研究方法-原理、应用及SAS实现》 鲁桂华

热泪盈眶&#xff0c;这么一本贴合我需求的书竟然现在才找到。唉&#xff0c;这么说不太合适&#xff0c;鲁老师牛逼&#xff01; 第一章 分析性研究与经验性研究&#xff08;Theoretical research or empirical research) 个人感觉&#xff1a;Top Down Method Vs. Bottom Up…

ChatGPT爆火,对制造业销售增长的AI建议

北京时间2023年2月8日&#xff0c;微软宣布推出由ChatGPT支持的最新版本人工智能搜索引擎Bing&#xff08;必应&#xff09;和Edge浏览器。 ChatGPT的问世再次掀起AI热潮。 接下来让我们一起试试与ChatGPT对话&#xff0c;看看传说中上知天文下知地理的他是如何回答工业制造业…

AI算力拉动,存储行业迎来新拐点?

提到固态硬盘&#xff0c;应该许多人都有着对它的第一印象&#xff0c;那就是“贵”。 确实&#xff0c;在过去的几年中&#xff0c;SSD固态硬盘的价格的确是高得离谱。这也让很多用户望而却步&#xff0c;很多想要更换1TB固态硬盘的消费者&#xff0c;最后都选择了存储量更小的…

马斯克指定接班人?传特斯拉大中华区CEO朱晓彤接任全球CEO,官方疑否认

视学算法报道 编辑&#xff1a;David 【导读】有消息称&#xff0c;马斯克打算把特斯拉全球CEO一职交给中国区一把手朱晓彤&#xff0c;不过特斯拉中国方面疑似否认了这个消息。 车坛大事件&#xff01;特斯拉全球CEO要换人了&#xff1f; 据品玩Pingwest独家报道&#xff0c…

Android 端直播源代码如何实现简单的帧动画

直播源代码在实现礼物特效时&#xff0c;为了保证动画的流畅程度&#xff0c;很少会使用动图&#xff0c;而是使用帧动画&#xff0c;这篇文就讲讲直播源代码如何实现简单的帧动画。 要求&#xff1a;多张图&#xff1a;两张或以上&#xff1b;第一步&#xff1a;新建一个动画…

解决安卓系统和app直播源代码的兼容问题

解决安卓Android7.0兼容问题(兼容Android6.0到Android9.0) 当你处于Android7.0环境下&#xff0c;开发的app直播源代码快收尾完了的时候&#xff0c;进入测试环境Android9.0发生错误 是不是特别郁闷怎么突然错误了&#xff0c;我们先来看看错误&#xff08;这里使用HUAWEI Mate…

如何实现app直播源代码,通过HLS进行直播观看

app直播源代码需要通过网页观看直播&#xff0c;无插件方案就是移动端使用HLS 方法为FFMPEG推流到带Nginx-RTMP-Module的Nginx上&#xff0c;转出RTMP流和HLS流 所用命令为&#xff1a; ffmpeg.exe -ss 0 -rtsp_transport tcp -i rtsp://192.168.1.1/stream/0 -vcodec copy …

期末作业成品代码——威海影视(1页) HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 计算机毕设网页设计源码

HTML5期末大作业&#xff1a;影视网站设计——威海影视(1页) HTMLCSSJavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 计算机毕设网页设计源码 常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动…

马斯克决定任命朱晓彤为特斯拉全球CEO

作者 | 品玩 编辑 | 智能汽车设计 点击下方卡片&#xff0c;关注“自动驾驶之心”公众号 ADAS巨卷干货&#xff0c;即可获取 点击进入→自动驾驶之心【全栈算法】技术交流群 第一手消息&#xff0c;马斯克决定任命朱晓彤为特斯拉全球CEO。 公开资料显示&#xff0c;朱晓彤于 2…

Node.js

开发环境搭配 数值类型 export default{} // 数值类型 let num:number; num100 // num"刘亦菲" num3.14 console.log(num); // 布尔类型 let flag:boolean; flagtrue flagfalse // 字符串类型 let string:string string"haha" // string17 let mag我的是${…

路晓彤的作业

<h1 style"text-align: center;">学生信息</h1><table align"center" border1;><tr><th>编号</th><th>学号</th><th>姓名</th><th>专业</th><th>班级</th><th>…

教你如何实现直播源代码的搜索功能

一、需求描述 直播源代码实现一个搜索框&#xff1a; 1、输入关键字&#xff0c;按键抬起后可以实现查询功能&#xff1b; 2、下拉列表展示搜索结果&#xff0c;搜索结果中关键字要用特殊颜色突出显示&#xff0c;默认选中搜索结果的第一项&#xff1b; 3、可以按上下键切换选中…

虚拟号码认证如何开通?

近年来&#xff0c;经常会接到外卖、房产中介、信用贷款等电话&#xff0c;让顾客不胜其扰。现在电话标记功能使用越来越普遍&#xff0c;可以大概了解电话“来意”&#xff0c;同时也会让误标记、恶意标记很方便。对于开展业务或办公司或企业的人&#xff0c;更加不能让自己的…