轴配置及电子凸轮 添加的 EtherCAT 从站模块轴界面如下所示: 5、编码器轴配置 在上述界面选中“编码器轴”,右键可选择添加新的编码器轴。在“编码器来源”选项下为该轴选择对 应编码器,可选择输入相应映射地址(默认 V 区)确定编码器。 190
CTH300 系列 H5X-10 运动控制器用户手册 15.1.2 轴组配置 轴组配置即将配置好的轴两个或三个一组以轴组的形式自由组合,在“轴组配置”界面,右键点击“添 加轴组”进行轴组添加,如下图所示: 添加成功的轴组界面如下所示: “轴组基本配置”:“轴组号”不可更改,“轴组类型”下拉选项可选择“2-轴正交”或“3-轴正交”,分别对应可 选两组或三组“构成轴”;“运算周期”可选“脉冲”或“EtherCAT”;“加速模式”可选“梯形”,“sin*2”和“二次”。 “逻辑轴”:默认六组,不可更改。 “构成轴”:“2-轴正交”对应两个构成轴,“3-轴正交”对应三个构成轴,下拉选项可选择“脉冲轴”或“虚拟 轴”。 15.2 电子凸轮向导 在电子凸轮编辑器中可以通过图形或列表的方式实现电子凸轮盘(或者凸轮开关功能)。当根据相关的应用 程序产生代码时,将创建各种全局数据结构(CAM 数据),这些数据结构能够被 IEC 程序访问。 在硬件组态界面选择“工具”->“电子凸轮向导”即可进行电子凸轮配置。 191
轴配置及电子凸轮 电子凸轮向导配置界面如下,选中“CAM”右键可插入新的 CAM: 成功插入 CAM 后,在项目管理器界面选择“符号表”,可看到新增的 CAM。 点击“CAM0_SYM”出现以下界面,可查看对应 CAM 的符号地址。 插入 CAM 后,配置界面如下所示。 192
CTH300 系列 H5X-10 运动控制器用户手册 【基本配置】 “基本配置”:用户可手动更改“Cam 名称”以及主从站的起始和结束位置(主站位置对应 CAM 曲 线图中的横坐标,从站位置对应 CAM 曲线图中的纵坐标),勾选“周期变化”,CAM 中曲线图将 呈周期变化,主站结束位置即为周期。 “编译类型”:勾选“多项式(XYVA)”,CAM 在状态表中将以 x,y,a,v 的符号显示横纵坐标、速度与 加速度状态,目前暂不支持“一维数组”和“二维数组”的编译类型。 “生成选项”:勾选“自动映射”,将默认起始地址为 VB1000,取消勾选,可对起始地址进行修改, 起始地址对应符号表中的起始地址。 在基本配置中指定了凸轮数据的起始地址,配置之后将生成数据块(功能暂时未实现),或指定(V 内 存,符号表)起始地址。起始地址之后的一块内存存放 CAM 表数据。当凸轮表选择多项式方式时,数据 记录如下: 序号 名称 类型 注释 1 STRUCT X 轴坐标起点 2 xStart REAL X 轴坐标终点 3 xEnd REAL Y 轴坐标起点 4 yStart REAL Y 轴坐标终点 5 yEnd REAL 6 nElements WORD 元素个数 7 dX0 REAL 第0个 X 坐标 8 dY0 REAL 第0个点 Y 坐标 9 dV0 REAL 第0个点速度 10 dA0 REAL 第0个点加速度 11 dX1 REAL 第0个 X 坐标 12 dY1 REAL 第0个点 Y 坐标 13 dV1 REAL 第0个点速度 14 dA1 REAL 15 dX2 REAL ... END_STRUCT 用户可以通过修改此内存里数据,从而改变凸轮表数据,修改数据后,调用 MC_CamTableSelect,通知 PLC 凸轮表数据改变,如果此时系统处于循环凸轮表运行之中,改变后的数据将在下一个凸轮周期生效, 需要立即生效则在调用 MC_CamTableSelect 后,立即调用 MC_CamIn 指令。 193
轴配置及电子凸轮 凸轮偏移 Offset 和缩放比例 Scaling: 主轴输入转换的位置是根据以下公式进行的,并且使用转化后的 X 作为作为凸轮的输出: 计算公式:X=MasterScaling*MasterPosition+MasterOffset 因此,如果主轴的比例大于 1,所述凸轮将会运行在一个更高的速率,如果比例值小于 1, 速率将会随之降低。 从轴 SlaveOffset,SlaveScaling: 计算公式:Y=SlaveScaling*CAM(X)+SlaveOffset 如果 SlaveScaling>1 导致凸轮效果的拉伸,从轴的范围将会增加;如果 SlaveScaling<1 将会导致一个收 缩。 【CAM】 此页面以曲线图的形式分别显示“主站位置”与“从站位置”、“从站速率”以及“从站加速度”的关 系。横坐标“主站位置”最大值对应“基本配置”界面的“主站结束位置”设置值,纵坐标“从站位置” 最大值对应“基本配置”界面“从站结束位置”的设置值。点击红色节点,可将其拖动。 【CAM 表】 此页面对应显示 CAM 页面曲线图中红色节点的信息,一个红色节点对应一组数据,点击“ ”可添加新 节点,点击“ ”可删除已添加的节点。双击“X、Y、V、A”对应的数值,可进行手动修改。 194
CTH300 系列 H5X-10 运动控制器用户手册 【挺杆表】 功能保留,PLC 暂不支持此功能。 195
16 C 语言编程应用举例 16 本节结合编程软件 MagicWorks PLC 介绍 H56/H52 的 C 语言编程的具体应用 16.1 在 Magicworks PLC 中的 C 语言编程步骤 16.2 C 语言基础 16.3 运算符与表达式 16.4 for 循环语句 16.5 选择语句 16.6 libplc300.a 库介绍 196
CTH300 系列 H5X-10 运动控制器用户手册 C 函数编程语言是 MagicWorks PLC 软件功能的升级加强。在原有梯形图和 STL 两种编程语言基础上, 允许 C 函数编程与梯形图等编程语言一起工作。利用 C 语言编写功能块,增强程序的可读性和维护性, 同时,C 语言丰富的运算函数可实现各种调用功能,节省了内部空间,也提高了编程效率。目前有 H56-10/H52-10/H36-01/H32-01 支持 C 函数编程语言。 本章介绍 MagicWorks PLC 的 C 语言编程功能的使用,具体内容如下: 在 Magicworks PLC 中的 C 语言编程步骤 C 语言基础 运算符与表达式 for 循环语句 选择语句 libplc300.a 库的介绍 16.1 在 Magicworks PLC 中的 C 语言编程步骤 1、在 MagicWorks PLC 中新建项目,选择“程序块”后右键点击空白处,选择“插入新对象”“C 程 序块”。 2、编辑 C 程序属性,此处定义的符号名将自动作为 C 函数名,建议不要用中文定义,复制代码时 CF 块的符号名与 C 语言函数名一定要相同,否则将不执行。如果工程师希望进行代码保护,也可以参考以 下步骤增加密码保护。 197
C 语言编程应用举例 3、函数创建成功后,可在程序块中看到 CF0。 4、双击 CF0,进入 C 函数程序编程窗口。MagicWorks PLC 新建 CF0 后会默认加入以下三个头文件。 198
CTH300 系列 H5X-10 运动控制器用户手册 5、在局部变量窗口中定义需要外部输入或输出的参数值,全部定义完成后点击“ ”初始化 C 程序块, 重新生成函数模板。C 函数的名称和函数参数不要随便改动。 <备注> 局部变量窗口最多只能定义 16 个变量。 6、在生成的模板中,编写程序,编程完成后点击执行编绎操作,输出窗口中若无提示错误,即可被 OB1 或其他 FC 调用。从参数符号表定义的参数,输入参数会转变 C 语言相应类型的输入参数,参数可以直 接使用;而输入输出和输出参数,会变成相应类型的指针,通过指针在 C 函数里将结果写回 STL 系统, 即 C 函数无返回值,返回值只能通过指针传回。 199
C 语言编程应用举例 7、编写完成的 C 函数子程序,需在 OB1 主程序或者其它执行的 FC 中调用。当执行程序块下载时,C 子程序也将一同下载到 PLC 中。(注:C 函数内部不可在线监控,但是在梯形图调用处是可以监控输入 输出的)。以下程序执行的功能为:如果 M0.0=0,则 vw4=vw0-vw2;如果 M0.0=1,则 vw4=vw0+vw2。 200
CTH300 系列 H5X-10 运动控制器用户手册 16.2 C 语言基础 16.2.1 头文件 编译器提供了许多在头文件中声明的标准函数。头文件也称为包含文件,头文件作为一种包含功能函数、 数据接口声明的载体文件,主要用于保存程序的声明。 <stdio.h> 输入输出函数; <stdarg.h> 支持变元个数可变函数的宏; <math.h> 数学浮点函数; <stdlib.h> 内存分配函数; <string.h> 字符串处理函数; <stdbool.h> bool 类型和布尔值 true 和 false; <complex.h> 支持复数; <ctype.h> 字符分类函数; <wctype.h> 宽字符转换函数。 头文件包含了各种函数的声明以及各种变量的声明,MagicWorks PLC 新建 C 程序块后会默认加入以下 三个头文件。 #include \"math.h\" #include \"stdio.h\" #include \"plc300.h\" 其中,头文件<stdio.h>含有大量高级输入/输出(I/0)函数的声明,是 C 语言中的标准输入输出头文件,stdio 即 stand input output 的缩写,程序中含有输入输出操作,就必须使用该头文件。 头文件<math.h>中声明了常用的一些数学运算,比如乘方,开方运算、求三角函数、对数之类的函数, 可以直接调用。 plc300.h 是合信自己开发的库 libplc300.a 的头文件,库 libplc300.a 主要使用户能够调用底层函数和 STL PLC 系列进行交互,用户可以使用的函数可在头文件 plc300.h 中查看,头文件 plc300.h 在编程软件安装 目录\\ccompile\\include\\plc300.h 里。 16.2.2 变量 1、定义变量 变量定义的一般形式:数据类型 变量名 例如:FP32 real1; //定义 32 位浮点数 S16 int1; //定义 16 位有符号整型 const FP32 PI=3.1415926; //定义 32 位浮点数常量 PI 局部变量窗口定义的参数值,执行“初始化 C 程序块”,程序编程窗口会自动将参数定义到子程序中。 201
C 语言编程应用举例 注意: 变量名必须以字母或下划线开头,名字中间只能由字母、数字和下划线“_”组成;最后一个字符可以 是类型说明符。 变量必须先定义,后使用。 一个变量名只能定义一次,变量建议定义在程序头部,变量定义不允许使用中文变量,且严格区分大小 写。 一些较简单的字符变量名容易跟一些原有计数器混淆,例如 c 表示计数器,c1 就不允许使用。 2、static 局部变量与普通变量 局部变量与普通变量的区别 1) 内存分配和释放 普通局部变量只有执行到变量定义的语句时才分配空间。 static 局部变量在编译阶段(函数还没有执行),变量的空间已经分配。 普通局部变量离开作用域{},自动释放其空间,也就无法使用此变量。 static 局部变量只有在整个程序结束的时候才将其自动释放。 2) 初始化 普通局部变量不初始化,为随机值。 static 局部变量不初始化,为 0。 static 局部变量初始化语句只有第一次执行时有效,但是可以赋值多次。 static 局部变量只能用它常量初始化。 变量在全局数据区分配内存空间;编译器自动对其初始化其作用域为局部作用域,当定义它的函数结束 时,其作用域随之结束。 C 语言编程举例如下:只要 var1 不等于 0,则 var2 加一。 void CF_3( S16 var1, S16 *var2 ) { static S16 temp; if(var1!=0) { temp=temp+1; } setS16(var2,temp); } //temp 变量用 static 修饰符 202
CTH300 系列 H5X-10 运动控制器用户手册 16.2.3 注释的使用 编写 C 语言时使用注释有助于对代码的理解,注释不进行编绎,不会影响程序的执行。在 C 语言中有两 种注释方式: 以/*开始、以*/结束的块注释(block comment) 以//开始、以换行符结束的单行注释(line comment) Magicworks PLC 中既可手动注释,也可以采用注释键进行注释。点击菜单栏中的注释键 即可注释, 点击菜单栏中的取消注释键 即可取消注释。 16.2.4 各类数值型数据间的混合运算 在进行运算时,不同数据的类型需要转换成同一类型数据,然后进行运算。 运算过程:先自动转换成同类数据,再进行运算。 转换规则:低字节类型转换成高字节类型。 C 语言编程例程:c = S16 a + FP32 b,a 将自动转换为 FP32 的数据类型,再与 b 相加,结果得到一个 FP32 型的 c。 C 语言编程如下: #include \"math.h\" #include \"stdio.h\" #include \"plc300.h\" void CF_2( S16 data_a, FP32 data_b, FP32 *data_c ) { FP32 temp; temp=data_a+data_b; setFP32(data_c,temp); } 编译后得到的 CF 块,通过 OB1 或者其他 FC 调用: 203
C 语言编程应用举例 16.2.5 强制类型转换 将指定表达式的值转换为指定类型,需要编程者指定需要转换的类型。 形式:(类型名)(表达式) 例如:(S16)(a+b) 说明:1)类型名和表达式需加括号 2)在强制类型转换时,得到一个所需类型的中间变量,原来变量类型未发生变化。 C 语言编程例程:将一个 32 位浮点数四舍五入取整然后转换成 16 位整数。 void CF_2(FP32 data_b, S16 *data_c ) { S16 temp; If (data_b>0) { temp=(S16)(data_b+0.5); } else { temp=(S16)(data_b-0.5); } setS16(data_c,temp); } 编译后得到的 CF 块,通过 OB1 或者其他 FC 调用: 16.2.6 数组 数组是一组有序数据的集合,若将有限个类型相同的变量的集合命名,这个名称为数组名;数组中每个 元素的数据类型都相同,用户通过数组名和下标来确定数组中的元素。 一维数组的定义方式:类型说明符 数组名[整形常量表达式] 例如:FP32 real0[10]; 说明:定义了一个数组,数组名为 real0,有 10 个元素,每个元素的类型均为 FP32 型;这 10 个元素分 别是 real[0]、real[1]、real[2]、……real[8]、real[9]。 初始化数组:数组可在声明的初始化,初始化数组时,各个索引变量的值要封闭在{}内,并用逗号分隔, 例如:S16 aa[3]={2,6,1};等价于:S16 aa[3];aa[0]=2;aa[1]=6;aa[2]=1; 注意: 下标从 0 开始。如:数组第 1 个元素为 real1[0],第 8 个元素为 real1[7]。 C 语言一般是不允许对数组的大小做动态定义的,如 FP32 real1[n],这是不允许的。 语言不检查数组下标越界,因此使用时不要越界使用,本例中数组元素个数是 10 个,下标范围为:0-9, 不能超出 9。 数组中的各元素的存储是有先后顺序的,它们在内存中按照这个先后顺序连续存放在一起。 C 语言编程示例:将 VD100 开始连续 10 个值,复制到 VD200 后。 void CF_0( void* real1, void* real2 ) 204
CTH300 系列 H5X-10 运动控制器用户手册 { //定义数组 S16 i,j; //数组地址 FP32 temp[10] ={0,0,0,0,0,0,0,0,0,0}; for (i=0;i<10;i++) { temp[i]=getFP32(real1+4*i); } for (j=0;j<10;j++) { set FP32((real2+4*j),temp[j]); } } 调用生成的 CF0 状态表结果如下所示: 16.3 运算符与表达式 16.3.1 赋值运算符与赋值表达式 1、赋值运算符= 赋值表达式:将一个数值赋给一个变量或将一个变量的值赋给另一个变量。 赋值形式:变量名=常量或表达式; 205
C 语言编程应用举例 赋值作用:将右边常量或表达式的值赋给左边的变量。如: a=3、a=b*c 注意: 所有的语句,包括赋值语句,必须要以分号“;”结尾。 赋值后,原来左边的值被右边表达式的值替换 如果右边表达式的值类型与左边变量的类型不一致,以左边变量的类型为准,将右边表达式值的类型自 动转换为左边变量的类型。 2、多重赋值运算符:多重赋值是将表达式的值同时赋给几个变量,在这种情况下,要把被赋值的变量名 按次序写在赋值号的左边。 赋值形式:变量 1=变量 2=…=变量 n=表达式 等价于:变量 1=(变量 2=(…=(变量 n=表达式))) 例如:a=b=c=7; 3、复合赋值运算符:在赋值符“=”之前加上其它运算符。常见的有:+=、-=、*=、/=、%= 复合赋值运算的功能:与左边的变量进行复合运算后再赋给左边的变量。 例如: a+=3; 等价于 a=a+3 x*=y+8; 等价于 x=x*(y+8) x%=3; 等价于 x=x%3 int a=1,b=2,c=2; c*=a-b; 等价于 c=c*(a-b)=2*(-1)=-2 16.3.2 算术运算符 C 语言中的算术运算符有: +:加或取正值运算符 -:减或取负值运算符 *:乘运算符 /:除运算符 %:取余运算符 其中,加减乘除均为取余运算符,它们要求有两个运算对象。 16.3.3 自增自减运算符 运算符说明:++表示自增,变量值加 1, --表示自减,变量值减 1。 用法 1:单独作为一个表达式被使用。例如:i++或者++i 等价于 i=i+1 用法 2:出现在其他表达式中参与运算,++i/--i 表示 i 自增/自减 1 后再参与其它运算;而 i++/i-- 则是 i 参与运算后,i 的值再自增/自减 1。 例如:S16 j,i=3; j=++i; // i,j 的值为 4 j=i++; // j 的值为 4,然后 i 的值变为 5 j=-(i++); // j 的值为-5,然后 i 的值变为 6 16.3.4 关系运算符与表达式 关系运算:比较两个操作数是否满足给定的关系,用于简单的条件判断。在 C 语言中有以下关系运算符: (1) < 小于 206
CTH300 系列 H5X-10 运动控制器用户手册 (2) <= 小于或等于 (3) > 大于 (4) >= 大于或等于 (5) == 等于 (6) != 不等于 关系运算符的结果只能是 0 或者 1,值为真时结果为 1,值为假时结果为 0。 例如:3.24<=2.98; //值为假,运算结果为 0 0.5!=3+1; //值为真,运算结果为 1 关系表达式:用关系运算符将两个表达式(算术表达式、关系表达式、逻辑表达式、赋值表达式、字符 表达式)连接起来的式子,称为关系表达式 关系表达式的一般形式为:表达式 关系运算符 表达式 关系运算符的优先级低于算术运算符,高于赋值运算符。 例如:a=1+2>3-1; //等价于 a=((1+2)>(3-1)),结果为 a=1 16.3.5 逻辑运算符与表达式 逻辑运算也称布尔运算,用于复杂的条件判断。 运算符 含义 优先级 ST 描述 NOT ! 逻辑非 1 AND OR \&\& 逻辑与 2 A\&\&B ll 逻辑或 3 1 0 逻辑表达式的一般形式:表达式 逻辑运算符 表达式 0 0 逻辑运算真值表 A 取值 B 取值 !A AllB 1 非0 非0 0 1 1 非0 0 0 0 0 非0 1 000 C 语言编程例程:当(a>b)\&\&(b>c)结果为真时 d=1,当(a>b)\&\&(b>c)结果为假时 d=0。 void CF_1( BOOL *data_d ) { S16 data_a=3,data_b=2,data_c=1; if ((data_a>data_b)\&\&(data_b>data_c)) { *data_d=1; } else { *data_d=0; } } 207
C 语言编程应用举例 编译后得到的 CF 块,通过 OB1 或者其他 FC 调用: 16.3.6 条件运算符与条件表达式 条件运算符与条件表达式 有两个符号:问号和分号,它与三个操作数组成三元运算。 一般形式:<表达式 1>?<表达式 2>:<表达式 3> 优先级:逻辑>条件>赋值 例如:S16 max,a=5;b=3; max=a>b?a:b 结果:max=5 C 语言编程例程:比较 2 个值的大小,并将最大值输出。 void CF_0( FP32 real1, FP32 real2, FP32 *max ) { FP32 max_t; max_t=real1>real2?real1:real2; setFP32(max,max_t); } 编译后得到的 CF 块,通过 OB1 或者其他 FC 调用: 16.4 for 循环语句 在应用程序中,需要多次执行某些步骤,这个过程叫循环;for 循环是编程语言中一种循环语句,循环程 序的设计需要建立程序使它能够循环返回并循环执行自身程序。 for 循环语句的一般形式: for(单次表达式;条件表达式;末尾循环体) { 中间循环体; } 例如:for (i=1;i<=100;i++) { sum=i+sum; } for 循环中的语句反复被执行,每次循环后,变量 i 会自动加 1。i=1 和 i<=100 是循环控制变量的起始值 和终止值。当控制变量达到终止值时,程序就执行 for 语句后的下一条指令。 例如:求 1-20 的平方和! 208
CTH300 系列 H5X-10 运动控制器用户手册 void CF_1( S16 *int3 ) { S16 int3_t=0; S16 i; for (i=1;i<=20;i++) { int3_t=int3_t+i*i; } setS16(int3,int3_t); } 编译后得到的 CF 块,通过 OB1 或者其他 FC 调用: 16.5 选择语句 16.5.1 if 选择结构语句 if 选择结构:判断 if 条件,根据判断结果执行后续操作的选择结构。 1)单分支 if 选择结构的一般格式: if(表达式) //表达式:指判断条件,真为 1,假为 0 { 执行语句; //仅当表达式为真时,才执行此处执行语句 } 例如:输入一个数,判断能否被 4 或者 7 整除,满足条件输出为 1。 void CF_0( S16 int1, S16 *out1 ) { S16 out_t=0; if (int1%4==0||int1%7==0) { out_t=1; } setS16(out1,out_t); } 编译后得到的 CF 块,通过 OB1 或者其他 FC 调用: 2)双分支 if 选择结构的一般格式: if(表达式) //表达式:指判断条件,真为 1,假为 0 209
C 语言编程应用举例 { //仅当表达式为真时,才执行此处执行语句 执行语句; //条件为 0,执行 else 后的语句 } else { 执行语句; } 例如:输入一个数,偶数输出 a,奇数输出 b。 void CF_0(S16 int1, U8 *out1 ) { char out; if (int1%2==0) { out='a'; } else { out='b'; } setU8(out1,out); } 编译后得到的 CF 块,通过 OB1 或者其他 FC 调用: 3)多重 if 选择结构的一般格式: if(表达式) { 执行语句; } else if(表达式 1) { 执行语句; } else if(表达式 2) { 执行语句; } …… else { 执行语句; } //最后一个 else{}可以省略,有则必须放在 else if 后面 210
CTH300 系列 H5X-10 运动控制器用户手册 例如:输入成绩,大于等于 90 为 A,80-89 为 B,70-79 为 C,60 到 69 为 D,低于 60 为 E。 多重 if 执行的流程图如下: C 语言编程如下: void CF_1( S16 score, U8 *level ) { char level_t; if (score>=90) { level_t='A'; } else if (score>=80) { level_t='B'; } else if(score>=70) { level_t='C'; } else if(score>=60) { level_t='D'; } else { level_t='E'; } setU8(level,level_t); } 16.5.2 switch 多分支选择语句 switch 语句是多分支条件判断语句,它根据表达式的值使程序从多个分支中选择一个用于执行的分支。 switch 的一般格式: switch(表达式) { 211
C 语言编程应用举例 case 常量表达式 1 : 语句 1; break; case 常量表达式 2 : 语句 2; break; …… case 常量表达式 n : 语句 n; break; default : 语句 n+1; } 注意: case 条件执行语句后需加 break 跳出 switch 结构,否则无法分支; 常量表达式的值必须互不相等,否则有二异性; case 的顺序无关紧要, default 可有可无。 switch 语句不等同于 if 语句,switch 只能进行值的相等性检查,不是逻辑判断;if 语句不但可以进行值 的相等性判断,还可以计算关系表达式或逻辑表达式,进行逻辑判断的真假。 例如: void CF_0( S16 Level, BOOL *heat1, BOOL *heat2, BOOL *heat3, BOOL *fan ) { *heat1=*heat2=*heat3=*fan=0; switch (Level) { case 1:*fan=1; break; case 2:*fan=0; break; case 3:*heat1=1; break; case 4:*heat1=*heat2=1; break; case 5:*heat1=*heat2=*heat3=1; break; default:*heat1=*heat2=*heat3=1; } } 16.6 libplc300.a 库介绍 libplc300.a 库为 Magicworks PLC 自带的库,该库中含有从 STL 取值和将值写回 STL 的函数以及 STL 系统与 C 语言系统的数据转换操作函数,用户可直接调用这些函数。用户可以使用的函数可在头文件 plc300.h 里查看,头文件 plc300.h 在编程软件安装目录\\ccompile\\include\\plc300.h 里。 下面将对 C 程序块的数据类型以及各种操作函数进行介绍。 212
CTH300 系列 H5X-10 运动控制器用户手册 16.6.1 CF 块参数符号表中可选择的数据类型 关键字 数据类型 注释 unsigned char BOOL 位 unsigned char U8 S8 8 位无符号数 signed char U16 8 位有符号数 unsigned short S16 16 位无符号数 U32 16 位有符号数 signed short S32 32 位无符号数 unsigned int FP32 32 位有符号数 void* signed int 浮点数 float 指针:指向任何类型的数据 <备注> void*可以指向任何类型的数据,所有提供指针均使用 void* 型,让用户在 C 代码中进行强制转 换,返回值为空,返回结果,可通过指针传递。 16.6.2 大小端转换 由于 STL 系统的数据使用的是大端模式,而 C 语言使用的是小端模式,因此直接操作指针赋值会有字节 序混乱的问题,因此我们提供了一组通过指针从 STL 取值和将值写回 STL 的函数,函数的具体形式在 MagicWorks PLC 安装目录\\ccompile\\include\\plc300.h 里。 大端模式:数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中。 小端模式:是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。 参数通过指针在 C 语言系统和 STL 系统进行传递时,由于 C 语言系统使用的是小端模式,而 STL 系统 使用是的大端模式,所以需要调用大小端转换接口。 16.6.3 STL 系统与 C 语言系统的数据转换操作函数 1、通过指针将值写回 STL 环境:由于输入输出和输出参数会变成相应类型的指针类型,且大小端转换 的问题,所有的输入输出或输出参数都要通过以下指令将结果从 C 语言写回到 STL 环境。 void setU8(U8 *P, U8 d); //将一个 U8 数据,从 C 语言写回 STL 系统 void setS8(S8 *P, S8 d); //将一个 S8 数据,从 C 语言写回 STL 系统 void setU16(U16 *P, U16 d); //将一个 U16 数据,从 C 语言写回 STL 系统 void setS16(S16 *P, S16 d); //将一个 S16 数据,从 C 语言写回 STL 系统 void setU32(U32 *P, U32 d); //将一个 U32 数据,从 C 语言写回 STL 系统 void setS32(S32 *P, S32 d); //将一个 S32 数据,从 C 语言写回 STL 系统 213
C 语言编程应用举例 void setFP32(FP32 *P, FP32 d); //将一个 FP32 数据,从 C 语言写回 STL 系统 void setBOOL(BOOL *P, BOOL d); //将一个 BOOL 数据,从 C 语言写回 STL 系统 例子如下:输入 int1 与 int2 相加,输出 int4 进行了大小端转换,输出结果正确;输出 int3 没有进行大小 端转换,输出结果不正确。 2、通过指针从 STL 取值:如果在 C 函数输入参数中直接调用 PLC 的 V 区、M 区等寄存器,可以将 PLC 寄存器的指针输入给 C 函数,通过取指针值的方式获取 PLC 内存区的值到 C 语言,但必须通过以下函 数进行转换。 U8 getU8(U8 *p); //从 p 地址 取得一个 C 语言系统可用的 U8 数据 S8 getS8(S8 *p); //从 p 地址 取得一个 C 语言系统可用的 S8 数据 U16 getU16(U16 *p); //从 p 地址 取得一个 C 语言系统可用的 U16 数据 S16 getS16(S16 *p); //从 p 地址 取得一个 C 语言系统可用的 S16 数据 U32 getU32(U32* p); //从 p 地址 取得一个 C 语言系统可用的 U32 数据 S32 getS32(S32* p); //从 p 地址 取得一个 C 语言系统可用的 S32 数据 FP3 getFP32(FP32* p); //从 p 地址 取得一个 C 语言系统可用的 FP32 数据 FP3 getBOOL(BOOL* p); //从 p 地址 取得一个 C 语言系统可用的 BOOL 数据 <备注> 不通过指针从 STL 取值:输入变量不通过指针的方式,而是输入变量直接获取 PLC 寄存器的值, 就不需要使用 get 函数。 C 语言编程如下: 1、将 VW100 开始连续 20 个 VW 值赋给 VW200 地址段。 214
CTH300 系列 H5X-10 运动控制器用户手册 void CF_2( void* int1, void* int2 ) { S16 r,i; for(i=0;i<20;i++) { r=getS16(int1+2*i); setS16((int2+2*i),r); } } 调用生成的 CF 块 状态表结果如下所示: 2、将 V 区开始的 LEN 个 INT 值进行大小排序,显示到另一个 V 区。 void CF_0( void* varin, S16 len, void* varout ) { S16 i,j,n,k,l; S16 temp[len]; for (l=0;l<len;l++) //将 V 区的值存入 temp 数组 { temp[l]=getS16(varin+2*l); } for (i=len;i>1;i--) //冒泡法将大小值排序,每次最大就像气泡一样\"浮\"到数组的上面 { for(j=0;j<i-1;j++) //依次比较相邻的两个元素,使较大的元素向后移 if (temp[j]<temp[j+1]) { n=temp[j]; temp[j]=temp[j+1]; temp[j+1]=n; } } 215
C 语言编程应用举例 for(k=0;k<len;k++) //将 temp 数组值传出到 V 区 { setS16((varout+2*k),temp[k]); } } 编译后得到的 CF 块,通过 OB1 或者其他 FC 调用: 状态表结果如下所示: 16.6.4 获取内存基地址的操作函数 U8 *getLBase(void); //获取地址 LB0 的值 U8 *getIBase(void); //获取地址 IB0 的值 U8 *getQBase(void); //获取地址 QB0 的值 U16 *getAQBase(void); //获取地址 AQW0 的值 U16 *getAIBase(void); //获取地址 AIW0 的值 216
CTH300 系列 H5X-10 运动控制器用户手册 U8 *getSMBase(void); //获取地址 SMB0 的值 U8 *getVBase(void); //获取地址 VB0 的值 U8 *getTVBase(void); //获取地址 T0 的值(定时器值) U8 *getTBBase(void); //获取地址 T0 的值(定时器位) U8 *getSBase(void); //获取地址 SB0 的值 U8 *getCVBase(void); //获取地址 C0 的值(计数器值) U8 *getCBBase(void); //获取地址 C0 的值(计数器位) U8 *getACBase(void) //获取地址 AC0 的值 217
17 MQTT 协议及 OPC UA 配置 17 本节介绍 MQTT 协议及 OPC UA 服务器的配置 17.1 MQTT 协议 17.2 OPC UA 服务器配置 218
MQTT 协议及 OPC UA 配置 17.1 MQTT 协议 17.1.1 概述 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于客户端/服务器 的发布/订阅(publish/subscribe)模式的通讯协议,该协议构建于 TCP/IP 协议上。H56-10、H52-10 均 支持该协议,目前合信的 H56-10、H52-10 只能做客户端。 客户端与服务器可实现以下功能: 客户端:发布和订阅 ①发布其他客户端可能会订阅的信息; ②订阅其它客户端发布的消息; ③退订或删除应用程序的消息;-----使用指令失能 ④断开与服务器连接。-----使用指令失能 <备注> 合信 CPU 只做客户端。 服务器:消息代理(Broker),中转站,分发信息 ①接受来自客户的网络连接; ②接受客户发布的应用信息; ③处理来自客户端的订阅和退订请求; ④向订阅的客户转发应用程序消息。 17.1.2 指令详解 COMM_MQTT(V1.0).ctmwl 库实现的是 MQTT 的客户端功能,包括连接服务器,向主题发布消息,订阅 消息等功能。支持连接到一个消息代理,支持订阅 8 个主题。 包含的功能块有 MQTT_client-connect、MQTT-publish 以及 MQTT_subcrib,通过功能块可实现 PLC 的 MQTT 协议通信。 MQTT_client-connect(MQTT 客户端连接) 219
MQTT 协议及 OPC UA 配置 功能:此指令用于连接到 MQTT 服务器。 参数 参数名 输入输 参数描述 类型 备注 出属性 当执行条件由off变on时,执行连接服务器功能。 enable IN 指令执行条件 BOOL 当执行条件由on变off时,与服务器断开连接。 MQTT服务器的IP地址。 ipAddress IN 服务器的IP地址 DWORD MQTT服务器的端口号。 port IN 服务器的端口号 WORD 从站ID指针,指向从站ID字符串的变量。系统中 有多个从站,建议设成不同的ID。 clientid IN 从站ID的指针 指针 保活时间,单位:秒。 用户名指针,指向用户名字符串的变量。 keepAlive IN 保活时间 BYTE 密码指针,指向密码变量的指针。 username IN 用户名指针 指针 连接ID password IN 密码指针 指针 0:没有连接 connetid OUT 连接ID DINT 1:连接成功 当指令执行时,busy位被置位。 connsta OUT 连接状态 BYTE 当指令完成busy复位。 如果检测到有错误,error位被置位; busy OUT 指令执行位 BOOL 当指令的执行条件off时,error位被复位。 错误代码,详见错误码 err OUT 错误位 BOOL errid OUT 错误代码 WORD MQTT-publish(MQTT 消息发布) 功能:此指令用于向相应的主题发布消息,一个服务器可以发送的主题个数不受限制。触发指令后,服 务器会收到一条发布消息。 参数 参数名 输入输 参数描述 类型 备注 出属性 execute IN 指令执行条件 BOOL 当执行条件由off变on时,执行消息发布 connetid IN 连接ID DINT 连接服务器指令生成的id topic IN 主题指针 指针 指向主题字符串变量的指针。 0:“至多一次”(qoS=0),消息发布完全依赖底层 qos IN 消息等级 BYTE TCP/IP网络。会发生消息丢失或重复。这一级别可用 于如下情况,环境传感器数据,丢失一次读记录无所谓, 220
CTH300 系列 H5X-10 运动控制器用户手册 pmsg IN 消息指针 指针 因为不久后还会有第二次发送。 msglen IN 消息长度 WORD 1:“至少一次”(qoS=1),确保消息到达,但消息重 复可能会发生。 retain IN retain标记 BOOL 2:“只有一次”(qoS=2),确保消息到达一次。这一 级别可用于如下情况,在计费系统中,消息重复或丢失 done OUT 完成位 BOOL 会导致不正确的结果。 BOOL 消息指针,存放发布的消息 busy OUT 指令执行位 BOOL 消息长度 WORD retain标记为True,消息将在服务器端保存。MQTT服 err OUT 错误位 务器只会为每一个topic保存最近收到的一条retain消 errid OUT 错误代码 息,即客户端再次发布一条新的retain消息时,服务器 上原来的retain消息会被覆盖。每当MQTT客户端连接 到MQTT服务器并订阅了某个主题,如果该主题下有 retain消息,那么MQTT服务器会立即向客户端推送该 条retain消息。 当消息发布成功done位由off 变为on 当指令的执行条件off时,busy位被复位。 当指令执行时,busy位被置位。 当指令完成busy复位。 当指令的执行条件off 时,busy位被复位。 如果检测到有错误,error位被置位; 当指令的执行条件off 时,error位被复位。 错误代码,详见错误码 提示 如果客户端想让 MQTT 服务器删除某个 topic 下保存的 retained 消息,则需要给 MQTT 服务器发送一条 retain 标志位为 1 的空消息。删除了某个 topic 下保存的 retained 消息,若客户端没有再发布 retained 消 息,则 MQTT 服务器对该 topic 就没有 retained 消息。 举例说明: retain=1,发布消息 ab,长度为 2 字节,不管先触发订阅还是先触发发布,订阅客户端都收到消息 ab。 retain=0,发布消息 cd,长度为 2 字节,先触发订阅,再触发发布,则订阅客户端收到的消息为 cd。 先触发发布,再触发订阅,则订阅客户端收到的消息为 ab。 retain=1,发布消息 ef,长度为 0 字节,即可删除服务器中保存的 retain 消息。 retain=0,发布消息 gh,长度为 2 字节,先触发订阅,再触发发布,则订阅客户端收到的消息是 gh。 先触发发布,再触发订阅,则订阅客户端收不到消息。 221
MQTT 协议及 OPC UA 配置 MQTT_subcrib(MQTT 消息订阅) 功能:此指令用于订阅并接收相应主题的消息。 参数 参数名 输入输 参数描述 类型 备注 出属性 当执行条件由off变on时,执行订阅相应的消息, enable IN 指令执行条件 BOOL 订阅成功后一直等待并接收订阅的消息。 当执行条件由on变off时,取消订阅相应的消息。 connetid IN 连接ID DINT 连接服务器指令生成的id topic IN 主题 指针 指向主题字符串变量的指针。 0:“至多一次”(QoS=0),消息发布完全依赖 qos IN 消息等级 BYTE 底层TCP/IP网络。会发生消息丢失或重复。这 一级别可用于如下情况,环境传感器数据,丢失 pmsg IN 消息指针 指针 一次读记录无所谓,因为不久后还会有第二次发 done OUT 连接状态 BYTE 送。 1:“至少一次”(QoS=1),确保消息到达,但 busy OUT 指令执行位 BOOL 消息重复可能会发生。 2:“只有一次”(QoS=2),确保消息到达一次。 err OUT 错误位 BOOL 这一级别可用于如下情况,在计费系统中,消息 重复或丢失会导致不正确的结果。 errid OUT 错误代码 WORD 接收消息的指针。 recvLen OUT 接收到消息的长度 WORD on:订阅成功 当指令执行时。busy位被置位。 recvid OUT 接收的消息的id WORD 当指令完成busy复位。 当指令的执行条件off时,busy位被复位。 如果检测到有错误,error位被置位; 当指令的执行条件off 时,error位被复位。 错误代码,详见表17-1 错误码表 消息长度。 接收的消息的id,每接到一条消息,recvid自动 加一。 222
CTH300 系列 H5X-10 运动控制器用户手册 表 17-1 错误码表 错误详情 errid 无错 0 Port 变量错误 1 IP 地址变量错误 2 用户名变量错误 3 密码变量错误 4 从站 ID 变量错误 5 内存分配出错 6 连接忙 7 通讯失败 8 连接 ID 错误 9 主题变量错误 10 消息长度错误 11 消息变量错误 12 17.1.3 结合服务器对 MQTT 进行说明 步骤 1 安装服务器(第三方服务器,本例选用 Mosquitto 服务器) 直接双击安装文件 进行安装 注意:默认的安装目录有空格,需要修改安装目录,如下图所示,直接选择路径为 C:\\mosquitto。 步骤 2 启动服务器 打开运行对话框并输入 cmd,然后输入 cd(\\ 进入 C 盘)回车,输入 cd mosquitto(进入安装目录 mosquitto 文件夹)回车,输入 mosquitto.exe -c mosquitto.conf -v 回车,即可启动服务器,下图表示服务器已经启 动。 223
MQTT 协议及 OPC UA 配置 步骤 3 设置服务器 IP 及端口号 打开服务器安装目录下的 mosquitto.conf 文件,参考格式设置 IP 和端口号,例如任意加入一行 listener 1000 192.168.1.150,表示端口号设置为 1000,IP 地址设置为 192.168.1.150(IP 为本地 IP,也就是安 装服务器的电脑的 IP 地址,否则启动服务器会失败,提示请求的地址无效)。 步骤 4 设置服务器登录方式 登录服务器有两种方式,一种是匿名登录,另一种是用户名和密码登录。 匿名登录 打开 MQTT 的安装目录,打开 mosquitto.conf 文件,添加 allow_anonymous true,之后退出服务器(通 过按键“ctrl+c”退出),再登录服务器(mosquitto.exe -c mosquitto.conf -v)。 设置用户名和密码登录 打开 MQTT 的安装目录,打开 mosquitto.conf 文件并添加以下内容: allow_anonymous false password_file /mosquitto/pwfile.example 在命令提示符界面输入 mosquitto_passwd -c pwfile.example abc1 回车,之后输入密码 1234 回车,再 输入确认密码 1234 回车即设置成功,即用户名为 abc1,密码为 1234。 步骤 5 编辑程序 程序示例 网络 1:设置服务器 IP 地址,端口、客户端 ID、用户名以及密码。 224
CTH300 系列 H5X-10 运动控制器用户手册 网络 2:像主题发布信息,信息长度为 50 字节。 网络 3:订阅信息。 步骤 6 程序下载并读取数据 将程序下载至 PLC,通过初始化 V 数据块,可以直观看到参数值是如何设置的,初始化 V 数据块中设置 的值对应 MQTT 指令的输入参数值。 通过状态表监控,可看到发布指令发布的主题和信息,订阅指令收到发布指令发布的信息,即验证 MQTT 通信成功。 225
MQTT 协议及 OPC UA 配置 226
CTH300 系列 H5X-10 运动控制器用户手册 17.2 OPC UA 协议介绍及应用 OPC UA 概述 Magicworks PLC(V2.23)支持 OPC UA 服务器,OPC UA 服务器仅适用于 CTH300 系列 PLC。通过 网口与 OPC UA 客户端(如 UaExpert 客户端软件)进行数据交互,在 OPC UA 服务器配置中添加 OPC UA 元素,可实现对 PLC 变量和 DB 变量的读写权限、变量类型以及节点信息进行管理,从而实现组态 对 PLC 变量的访问。 合信 CTH300-H5X 系列 PLC 可直接通过网线与 OPC UA 客户端通信,下载组态有 OPC UA 变量工程后, PLC 只做 OPC UA 服务器。 使用 OPC UA Server 功能应用步骤: 1 启用 OPC UA 服务器功能 2 OPC UA 服务器登录权限的配置 3 添加 OPC UA 服务器接口 4 接口添加 OPC UA 服务器元素 5 修改元素信息 6 保存配置信息 7 使用客户端与服务器进行通信测试 本例使用 UaExpert 作为 OPC UA 客户端与作为 OPC UA 服务器的 CPU(H56-10)实现 OPC UA 通信 步骤 1 启用 OPC UA 服务器功能 新建工程,CPU 选择 H56-10,点击硬件组态,展开设备目录树,打开 CO-TRUST 300 下的 CPU 300 节点,选择其中一个节点拖拽进入机架模块列表的 1 号槽,然后双击打开其属性对话框,选择 OPC UA 标签,勾选“启动 OPC UA 服务器”“确定”,即可启动 OPC UA Server 功能。启动后可配置监控事 项最大数量以及 PLC 端口号。 227
MQTT 协议及 OPC UA 配置 步骤 2 OPC UA 服务器登录权限的配置 启用“匿名登录”,则在登录客户端时无需用户名以及密码。 启用“启动用户验证”,则在客户端进行认证时需输入配置的用户名和密码,双击表格名称和密码下的 输入栏进行编辑,即可配置登录服务器验证的用户名和密码。 步骤 3 添加 OPC UA 服务器接口 228
CTH300 系列 H5X-10 运动控制器用户手册 点击上方的“接口配置”,右键点击“服务器接口”弹出菜单,然后再点击“添加接口”,此时会弹出 服务器接口的对话框,输入显示名称后点击“确定”即可添加接口。 步骤 4 接口添加 OPC UA 服务器元素 在启用 OPC UA 服务器之前,需将变量添加至符号表中,再进行 OPC UA 配置,如此变量才会自动关联 到元素里。建立了 DB 块,DB 块中的变量就会出现在元素程序块里。 229
MQTT 协议及 OPC UA 配置 将变量里的地址变量、程序块或者程序块里面的变量拖入到已经添加后的接口或者拖入到显示位于右上 角的接口表格,即可添加 OPC UA 元素。 步骤 5 修改元素信息 右下角为选中的元素信息,可以对相应的访问等级、数据类型以及节点信息进行修改。 230
CTH300 系列 H5X-10 运动控制器用户手册 步骤 6 保存配置信息 设置完登录配置和接口配置后并且在 OPC UA 服务器功能是打开的情况下,点击“确定”,即可保存 OPC UA 服务器的配置信息。 步骤 7 使用客户端与服务器进行通信测试 开启 OPC UA 服务器功能后,将组态好的 PLC 工程下载到 PLC 上,运行工程;安装 OPC UA 客户端 UaExpert 软件。 1、打开 UaExpert 第一次打开 UaExpert 会弹出如下界面,主要填充 Subject 栏目下的信息即可,信息可以任意填写,然后 点击 OK。 231
MQTT 协议及 OPC UA 配置 2、添加 OPC UA 服务器 首先新增 server:点击工具栏的的“+”按钮,在“Custom Discovery”项目下的“<Double click to ADD Server>”,在弹出的界面里输入 server 所在的 IP 和监听的端口号,并点击 OK。其中,PLC 做 server 时,IP 即为 PLC 的 IP 地址值,监听的端口号为服务器中设置的端口号。 例如,下图显示 OPC UA 服务器端口号为 4840,做 server 的 CPU IP 地址为 192.168.1.201。 232
CTH300 系列 H5X-10 运动控制器用户手册 输入 192.168.1.201:4840。 233
MQTT 协议及 OPC UA 配置 等待 Server 出现,然后点击 Server 的下拉菜单“ ”,选择加密方式,其中“None-None”表示无加 密,选择无加密方式,点击 OK,即可在 ProjectServers 项目下看到新增的 Server。 201 根据 OPC UA 服务器设置的权限进行选择匿名或权限,设置有权限则根据在 OPC UA 服务器中设置的用 户名及密码进行填写。 234
CTH300 系列 H5X-10 运动控制器用户手册 3、连接 OPC UA 服务器 在 ProjectServers 下可看到未连接的 Server,选择该 Server,点击 (connect Server)进行连接。 当 Server 由未连接标识“ ”变为已连接标识“ ”,并且在 Address Space 这一栏出现了 server 信 息,即表示 UaExpert 和 Server 连接成功。 235
MQTT 协议及 OPC UA 配置 若未看到 Address Space,则点击“View”,选择 Address Space 即可。 4、监控变量 将 Address space 页面中将要监控的变量拖到中间 Data Address View 页中,就可以监控变量值,如下 图: 236
CTH300 系列 H5X-10 运动控制器用户手册 237
附录 附录主要介绍各种库指令、快速查询信息、订货信息等,具体如下: A 电源预算 B 编程卡(U 盘)使用说明 C CT_Modbus 库的使用介绍 D PID_T 库的使用介绍 E 以太网“ct_socket”通信库的使用介绍 F CT_tcp_server_lib 库的使用介绍 G 轴指令“ct_plcopen_lib(v2.4)”介绍 H ct_flash_access_lib(v1.0)库的使用介绍 I ETHERNET_SET(V1.2)指令库的介绍 J 特殊存储器说明 K Trace 追踪功能 L 指令速查 M 订货信息 N 指令速查 238
CTH300 系列 H5X-10 可编程控制器用户手册 A 电源预算 选择好各机架的 CPU、电源模块、中继模块和扩展模块后,还需要确认系统总线的电流消耗和功率消耗 是否满足以下条件: 条件 1:总线电流消耗确认 内部总线电压为 5VDC,电流由 CPU(无中继模块时)或中继模块提供。每个机架上扩展模块总线电流 消耗之和不能超过 CPU 或中继模块允许的最大总线电流。 条件 2:功率消耗确认 使用电源模块时,每个机架上其它模块的功率消耗之和不能超过电源模块允许的最大功耗。 使用外部电源时,根据所接的功率之和选择合适功率大小的型号。 表 A-1 5VDC 总线电流供给和消耗 产品型号 供给电流 消耗电流 -- H56-10 1600mA -- -- H52-10 1600mA -- ECT-00 1600mA 60mA 80mA INT-00 1600mA 130mA 70mA DIT-08 -- 120mA 210mA DIT-16 -- 45mA 60mA DIT-32 -- 50mA 30mA DQT-08 -- 30mA 40mA DQT-16 -- 40mA 50mA DQT-32 -- 50mA 50mA DQR-08 -- 50mA 50mA DQR-16 -- 100mA 100mA AIS-04 -- 100mA AIC-08 -- AIV-08 -- AQS-04 -- AQS-08 -- AMS-06 -- AIT-04 -- AIT-08 -- AIR-04 -- AIR-08 -- HSC-02 -- HSP-04 -- CAN-1M -- 239




