今天,正运动小助手为大家分享一下应用C++开发一个硬件比较输出例程。
我们主要从新建MFC项目,添加函数库讲起,再了解PC函数用,最后通过项目实战——硬件比较输出例程讲解,来让大家熟悉运动控制卡的PC开发。
单点触发
多点触发
在正式学习之前,我们先了解一下正运动技术的运动控制卡ECI2828。这款产品是8轴运动控制卡。
正运动技术ECI2828 EtherCAT总线型运动控制卡,相对之前发布的ECI2618,新增了EtherCAT总线接口,电机轴数增加到8个,板载24+16点输入,16+16点输出(每个轴接口含2路通用输入和2路通用输出,可以做伺服使能、报警清除、到位信号、报警信号等控制);每轴输出脉冲频率可达10MHz;通过 CAN 总线,可扩展到512 个隔离输入或输出口。ECI2828支持硬件比较输出、精准输出、飞拍等功能。
运动控制卡ECI2828,支持C++、C#、LabVIEW、VB、Delphi、Linux、.Net平台、iMac、Python、Matlab等,统一的上位机API函数接口,具有开放、兼容、简单、易用等功能特性。
一
新建MFC项目 添加函数库
1.在VS2015菜单“文件”→“新建”→ “项目”,启动创建项目向导。
2.选择开发语言为“Visual C++”和程序类型“MFC应用程序”。
3.下一步即可。
4.选择类型为“基于对话框”,下一步或者完成。下一步则往后继续配置,完成就直接完成即可。这里就不需要再配置了,无关紧要的,只要这个类型选好就行,其他的可以在项目中编辑。
5.找到正运动技术厂家提供的光盘资料,路径如下(64位库为例):
(1)进入光盘资料找到PC函数文件夹。
(2)选择函数库2.1。
(3)Windows平台。
(4)根据需要选择对应的函数库这里选择64位库。
(5)解压C++的压缩包,里面有C++对应的函数库。
(6)函数库具体路径如下。
6.将厂商提供的C++的库文件和相关头文件复制到新建的项目里面。
7.在项目中添加静态库和相关头文件。
静态库:zauxdll.lib, zmotion.lib
相关头文件:zauxdll2.h, zmotion.h
(1)先右击头文件,接着依次选择:“添加”→“现有项”。
(2)在弹出的窗口中依次添加静态库和相关头文件。
8.声明用到的头文件和定义控制器连接句柄。
至此项目新建完成。
二
查看PC函数手册 了解PC函数用法
1.PC函数手册也在光盘资料里面,具体路径如下:
2.PC编程,一般先根据控制器连接方式选择对应的连接函数连接控制器,返回控制器句柄。接着用返回的控制器句柄,实现对控制器的控制。
3.比如通过网口连接控制器,先使用ZAux_OpenEth()链接控制器,获取控制器句柄handle。
指令7
|
ZAux_OpenEth
|
指令原型
|
int32 __stdcall ZAux_OpenEth(char *ipaddr, ZMC_HANDLE * phandle)
|
指令说明
|
以太网链接控制器。
|
指令类型
|
|
输入参数
|
输入参数1个,详细见下面说明。
|
ipaddr
|
链接的IP地址。
|
输出参数
|
输出参数1个,详细见下面说明。
|
Phandle
|
返回的链接句柄。
|
返回值
|
详细见错误码说明。
|
相关指令
|
|
指令示例
|
网口链接控制器
| 4.通过获取到的控制器句柄,使用ZAux_Direct_SetTable,来设置控制器的TABLE寄存器的数值。
指令162
|
ZAux_Direct_SetTable
|
指令原型
|
int32 __stdcall ZAux_Direct_SetTable(ZMC_HANDLE handle,int tabstart, int numes, float *pfValue)
|
指令说明
|
把数据写入到TABLE中。
|
指令类型
|
|
输入参数
|
共有3个输入参数,见下方说明。
|
handle
|
链接句柄。
|
tablestart
|
操作 TABLE 开始的起始编号
|
numes
|
写的个数
|
pfValue
|
数据列表
|
输出参数
|
无
|
返回值
|
详见错误码说明。
|
相关指令
|
|
指令示例
|
寄存器的读写测试
| 5.通过获取到的控制器句柄,使用ZAux_Direct_HwPswitch2,来启动并设置控制器的硬件比较输出的模式。
指令4
|
ZAux_Direct_HwPswitch2
|
指令原型
|
int32 __stdcall ZAux_Direct_HwPswitch2(ZMC_HANDLE handle,int Axisnum,int Mode, int Opnum, int Opstate, float ModeParal, float ModePara2, float Mode Para3 , float ModePara4)
|
指令说明
|
硬件位置比较输出2,4系列产品 20170513以上版本支持。 ZMC306E/306N支持。
|
指令类型
|
|
输入参数
|
共有9个输入参数,见下方说明。
|
handle
|
链接标识。
|
Axisnum
|
比较输出的轴号。
|
Mode
|
模式1-启动比较器
ModePara1 = 第一个比较点坐标所在TABLE编号
ModePara2 = 最后一个比较点坐标所在TABLE编号
ModePara3= 第一个点判断方向 0-坐标负向 1- 坐标正向 -1- 不使用方向
ModePara4 = 预留
模式2-停止并删除没完成的比较点
ModePara1 = 预留
ModePara2 = 预留
ModePara3 = 预留
ModePara4 = 预留
模式3-矢量比较方式
ModePara1 = 第一个比较点坐标所在TABLE编号
ModePara2 = 最后一个比较点坐标所在TABLE编号
ModePara3 = 预留
ModePara4 = 预留
模式4-矢量比较方式 单个比较点
ModePara1 = 比较点坐标
ModePara2 = 预留
ModePara3 = 预留
ModePara4 = 预留
模式5-矢量比较方式 周期脉冲模式
ModePara1 = 比较点坐标
ModePara2 = 重复周期,一个周期内比较两次,先输出有效状态,在输出无效状态
ModePara3= 周期巨鹿,每个这个距离输出Opstate,输出有效状态的距离(ModePara4)后还原为无效状态
ModePara4 = 输出有效状态的距离,(ModePara1-ModePara4)位无效状态距离
模式6-矢量比较方式 周期模式,这种模式一把与HW_TIMER一起使用
ModePara1 = 比较点坐标
ModePara2 = 重复周期,一个坐标只比较一次
ModePara3 = 周期距离,每隔这个距离输出一次
ModePara4 = 预留
|
Opnum
|
输出口编号。 4系列 out 0-为硬件位置比较输出。
|
Opstate
|
第一个比较点的输出状态。 0-关闭 1-打开
|
ModeParal
|
多功能参数
|
ModePara2
|
多功能参数。
|
ModePara3
|
多功能参数
|
ModePara4
|
多功能参数
|
输出参数
|
无。
|
返回值
|
见错误码详细说明。
|
相关指令
|
|
指令示例
|
|
6.通过获取到的控制器句柄,使用ZAux_Direct_Regist()来启动并设置控制器的锁存方式。
指令1
|
ZAux_Direct_Regist
|
指令原型
|
int32 __stdcall ZAux_Direct_Regist(ZMC_HANDLE handle,int iaxis, int imode)
|
指令说明
|
位置锁存指令。
|
指令类型
|
|
输入参数
|
共有1个输入参数,见下方说明。
|
handle
|
链接标识。
|
iaxis
|
轴号。
|
imode
|
锁存方式
1 当Z脉冲上升沿时的绝对位置送到REG_POS
2 当Z脉冲下降沿时的绝对位置送到REG_POS
3 当输入信号R0上升沿的绝对位置送到REG_POS
4当输入信号R0下降沿的绝对位置送到REG_POS
6输入信号R0上升沿时的绝对位置送到REG_POS,Z信号上升沿时的绝对位置送到REG_POSB
7输入信号R0上升沿时的绝对位置送到REG_POS,Z信号下降沿时的绝对位置送到REG_POSB
8输入信号R0下降沿时的绝对位置送到REG_POS,Z信号上升沿时的绝对位置送到REG_POSB
9输入信号R0下降沿时的绝对位置送到REG_POS,Z信号下降沿时的绝对位置送到REG_POSB
10输入信号R0上升沿时的绝对位置送到REG_POS,输入信号R1上升沿时的绝对位置送到REG_POSB
11输入信号R0上升沿时的绝对位置送到REG_POS,输入信号R1下降沿时的绝对位置送到REG_POSB
12输入信号R0下降沿时的绝对位置送到REG_POS,输入信号R1上升沿时的绝对位置送到REG_POSB
13输入信号R0下降沿时的绝对位置送到REG_POS,输入信号R1下降沿时的绝对位置送到REG_POSB
|
输出参数
|
无。
|
|
|
返回值
|
见错误码详细说明。
|
相关指令
|
|
指令示例
|
位置锁存
|
三
项目实战之硬件比较输出例程讲解
1.硬件比较输出
运动控制器内有位置比较单元,硬件比较输出是通过比较轴是否到达设定位置,来操作输出口动作,一般使用时将编码器位置与设定位置比较,当编码器的位置到达一个设定比较位置时,触发相应输出口电平翻转一次。
如下图所示,到达设置的位置1,电平翻转,到达位置2电平再次翻转,到达位置3电平再翻转,直达比较完所有的点后,电平维持最后一次翻转后的状态。
2.例程以建立板卡的连接,然后设置并开启硬件比较输出,将硬件比较输出的输出口和锁存的输入口进行连接,从而通过锁存记录硬件比较输出的位置。
(1)为了实验室测试方便,采用自发脉冲,同一轴编码器接收脉冲模式测试。同一个DB26轴接口的脉冲轴和编码器轴的连接方式(用于锁存硬件比较输出的位置),PUL+接EA+、PUL-接EA-、DIR+接EB+、DIR-接EB-。(或者直接通过脉冲型伺服电机进行位置反馈。)
(2)例程界面。
3.例程简易流程图。
4.通过网口连接控制器,获取控制器连接句柄。
//连接控制器void Ctest_PswitchDlg::OnBnClickedOpen(){char buffer[256]; int32 iresult;//从下拉框中获取IP地址 GetDlgItemText(IDC_IPLIST,buffer,255); buffer[255] = '\0';//通过网口连接控制器 iresult = ZAux_OpenEth(buffer, &g_handle);if(ERR_SUCCESS != iresult) { g_handle = NULL; MessageBox(_T("链接失败")); SetWindowText("未链接");return; } SetWindowText("已链接"); SetTimer(0,100,NULL);}5.通过运动按钮的事件处理函数去设置硬件比较输出的模式,并开始轴运动。
(1)通过对UI界面的控件添加对应的变量,实现硬件比较输出的模式的参数输入。
(2)运动按钮事件处理函数。//运动void Ctest_PswitchDlg::OnBnClickedStartmove() { m_RegistCount = 0; ShowRegistList(); UpdateData(TRUE);//设置轴参数 ZAux_Direct_SetAtype(g_handle, m_AxisNum, 1); ZAux_Direct_SetUnits(g_handle, m_AxisNum, 1000); ZAux_Direct_SetSpeed(g_handle, m_AxisNum, 200); ZAux_Direct_SetAccel(g_handle, m_AxisNum, 2000); ZAux_Direct_SetDecel(g_handle, m_AxisNum, 2000);//关闭硬件比较输出(停止并删除没有完成的比较点) ZAux_Direct_HwPswitch2(g_handle, m_AxisNum, 2, 0, 0, 0, 0, 0, 0);//开启硬件比较输出 MODE:1if (m_POS_IfOpen == false) //比较完成一次后需要重新调用HwPswitch {//将比较点填入TABLE ZAux_Direct_SetTable(g_handle, m_POS_StartTable, m_POS_EndTable- m_POS_StartTable+1, fPointPos);//开启硬件比较输出 ZAux_Direct_HwPswitch2(g_handle, m_AxisNum, 1, m_POS_out, m_POS_OutStatus, m_POS_StartTable, m_POS_EndTable, m_POS_dir, 0); }else {//关闭硬件比较输出 ZAux_Direct_HwPswitch2(g_handle, m_AxisNum, 2, 0, 0, 0, 0, 0, 0); }//打开示波器 ZAux_Trigger(g_handle); ZAux_Direct_SetDpos(g_handle, m_AxisNum, 0);//开始轴运动(绝对位置) ZAux_Direct_Single_MoveAbs(g_handle, m_AxisNum, m_Start_Pos); ZAux_Direct_Single_MoveAbs(g_handle, m_AxisNum, m_End_Pos); }6.根据设置情况判断是否开启锁存,并设置锁存模式。//启动或停止锁存void Ctest_PswitchDlg::OnBnClickedRegistStart() { int iret = 0; UpdateData(TRUE);if(m_Regist_IfOpen == FALSE) { m_RegistCount = 0;//必须是编码器轴才可以锁存 iret = ZAux_Direct_SetAtype(g_handle,m_RegistAxis,6); //设置锁存模式 int ReglistListSel = ((CComboBox *) GetDlgItem(IDC_REGIST_MODE))->GetCurSel() ;if(ReglistListSel >= 0 && ReglistListSel <=3) { RegistMode = ReglistListSel +1; }elseif(ReglistListSel == 4 || ReglistListSel ==5) { RegistMode = 10 + ReglistListSel; }elseif(ReglistListSel > 5 || ReglistListSel < 9) { RegistMode = 12 + ReglistListSel; }//开启锁存 iret = ZAux_Direct_Regist(g_handle,m_RegistAxis,RegistMode); SetTimer(1,5,NULL);
m_Regist_IfOpen = TRUE; SetDlgItemTextA(IDC_REGIST_START,_T("停止锁存")); ((CComboBox *)GetDlgItem(IDC_REGIST_MODE))->EnableWindow(FALSE); ShowRegistList(); }else { KillTimer(1); m_Regist_IfOpen = FALSE; SetDlgItemTextA(IDC_REGIST_START,_T("启动锁存")); ((CComboBox *)GetDlgItem(IDC_REGIST_MODE))->EnableWindow(TRUE); }}7.通过定时器1,更新锁存信息。void Ctest_PswitchDlg::OnTimer(UINT_PTR nIDEvent) //定时器刷新{if(NULL != g_handle) { CString str;if(nIDEvent == 1) {int iret = 0;int MarkStatus = 0;float RegistPos;//判断锁存是否触发if(RegistMode >= 0 && RegistMode < 4) { iret = ZAux_Direct_GetMark(g_handle,m_RegistAxis,&MarkStatus); }elseif(RegistMode >= 14 || RegistMode < 16) { iret = ZAux_Direct_GetMarkB(g_handle,m_RegistAxis,&MarkStatus); }elseif(RegistMode >= 18 || RegistMode < 20) { float tempc; iret = ZAux_Direct_GetParam(g_handle,"MARKC",m_RegistAxis,&tempc); MarkStatus = (int)tempc; }elseif(RegistMode >= 20 || RegistMode < 22) {float tempd; iret = ZAux_Direct_GetParam(g_handle,"MARKD",m_RegistAxis,&tempd); MarkStatus = (int)tempd; }//读取锁存的位置if(MarkStatus == -1) {if(RegistMode >= 0 && RegistMode < =4) { iret = ZAux_Direct_GetRegPos(g_handle,m_RegistAxis,&RegistPos); }elseif(RegistMode >= 14 || RegistMode < 16) { iret = ZAux_Direct_GetRegPosB(g_handle,m_RegistAxis,&RegistPos); }elseif(RegistMode >= 18 || RegistMode < 20) { iret = ZAux_Direct_GetParam(g_handle,"REG_POSC",m_RegistAxis,&RegistPos); }elseif(RegistMode >= 20 || RegistMode < 22) { iret = ZAux_Direct_GetParam(g_handle,"REG_POSD",m_RegistAxis,&RegistPos); } m_RegistList.InsertItem(m_RegistCount,""); str.Format(_T("%d"), m_RegistCount); m_RegistList.SetItemText(m_RegistCount,0,str); str.Format(_T("%.3f"), RegistPos); m_RegistList.SetItemText(m_RegistCount,1,str); m_RegistCount++;//重新触发锁存 iret = ZAux_Direct_Regist(g_handle,m_RegistAxis,RegistMode); } str.Format(_T("锁存触发状态:%d 次数:%d"), MarkStatus,m_RegistCount); SetDlgItemTextA(IDC_STATUS_REGIST,str); } } CDialogEx::OnTimer(nIDEvent);}
8.通过停止按钮的事件处理函数来停止运动。
//停止void Ctest_PswitchDlg::OnBnClickedStopmove() {int iret = ZAux_Direct_Single_Cancel(g_handle, m_AxisNum, 2); }
9.编译运行演示。
(1)将硬件比较输出的输出口(out0)和锁存的输入口(in0)用导线进行连接,将轴0的DB26接口上的脉冲轴和编码器轴进行连接。
(2)编译并运行例程。
(3)同时通过ZDevelop软件连接同一个控制器,通过示波器对运动过程进行监控。
|