当前位置:文档之家› 运动控制卡C程序示例

运动控制卡C程序示例

运动控制卡C程序示例
运动控制卡C程序示例

2. VC 编程示例

2.1 准备工作

(1) 新建一个项目,保存为“ VCExample.dsw ”;

(2) 根据前面讲述的方法,将静态库“ 8840.lib ”加载到项目中;

2.2 运动控制模块

(1) 在项目中添加一个新类,头文件保存为“ CtrlCard.h ”,源文件保存为“ CtrlCard.cpp ”;

(2) 在运动控制模块中首先自定义运动控制卡初始化函数,对需要封装到初始化函数中的库函数进行初始化;

(3) 继续自定义相关的运动控制函数, 如:速度设定函数,单轴运动函数,差补运动函数等;

(4) 头文件“ CtrlCard.h ”代码如下:

# ifndef __ADT8840__CARD__

# define __ADT8840__CARD__

运动控制模块

为了简单、方便、快捷地开发出通用性好、可扩展性强、维护方便的应用系统,我们在控制卡函数库的

基础上将所有库函数进行了分类封装。下面的示例使用一块运动控制卡

******************************************************

#define MAXAXIS 4 //最大轴数

class CCtrlCard

{

public:

int Setup_HardStop(int value, int logic);

int Setup_Stop1Mode(int axis, int value, int logic); (设置stop1 信号方式)

int Setup_Stop0Mode(int axis, int value, int logic); (设置stop0 信号方式)

int Setup_LimitMode(int axis, int value1, int value2, int logic); (设置限位信号方式)

int Setup_PulseMode(int axis, int value); (设置脉冲输出方式)

int Setup_Pos(int axis, long pos, int mode); (设置位置计数器)

int Write_Output(int number, int value); (输出单点函数)

int Read_Input(int number, int &value); (读入点)

int Get_CurrentInf(int axis, long &LogPos, long &ActPos, long &Speed); (获取运动信息)

int Get_Status(int axis, int &value, int mode); (获取轴的驱动状态)

int StopRun(int axis, int mode); (停止轴驱动)

int Interp_Move4(long value1, long value2, long value3, long value4); (四轴差补函数)

int Interp_Move3(int axis1, int axis2, int axis3, long value1, long value2, long value3); (三轴差补函数)

int Interp_Move2(int axis1, int axis2, long value1, long value2); (双轴差补函数)

int Axis_Pmove(int axis ,long value); (单轴驱动函数)

int Axis_Cmove(int axis ,long value); (单轴连续驱动函数)

int Setup_Speed(int axis ,long startv ,long speed ,long add ); (设置速度模块)

int Init_Board(int dec_num); (函数初始化) (设置速度模块)

CCtrlCard(); (定义了一个同名的无参数的构造函数)

int Result; // 返回值

};

#endif

(5) 源文件 “ CtrlCard.cpp ”代码如下: #include "stdafx.h" #include "DEMO.h" #include "CtrlCard.h" #include

"adt8840.h" int devnum=-1;

CCtrlCard::CCtrlCard() (构造函数,为什么是空的?) {

初始化函数

该函数中包含了控制卡初始化常用的库函数 ,这是调用

其他函数的基础 ,所以必须在示例程序中最先调用 返回值 <=0 表示初始化失败 ,返回值 >0 表示初始化成功

int CCtrlCard::Init_Board(int devnum) {

int mode =0;// 应答模式为 1 时 ,响应串口接收有效 ,0 时无效 if(devnum==0) ( devnum :设备号)

{

for (int i = 1; i<=MAXAXIS (最大轴数) ; i++)

{

Result=adt8840a_set_command_pos(devnum, mode,i,0);(设定逻辑计数器)

adt8840a_set_actual_pos(devnum, mode,i,0);(设定实位计数器)

adt8840a_set_startv(devnum, mode,i,0);(设定初始速度)

adt8840a_set_speed(devnum, mode,i,0);(设定驱动速度) adt8840a_set_acc(devnum,

mode,i,0);(设定加速度)

} if(Result==0 )

return 1;

else

return Result;

}

else

return -1;

设置速度模块

依据参数的值 ,判断是匀速还是加减速

设置轴的初始速度、驱动速度和加速度 参数: axis - 轴号 startv - 初始速度 speed -驱动速度 add

-加速度

返回值 =0 正确 ,返回值 =1 错误

int CCtrlCard::Setup_Speed(int axis (轴号) , long startv (初始速度) , long speed (驱动速度) , long add {

if (startv - speed >= 0) // 匀速运动

加速度) )

}

}

{

Result = adt8840a_set_startv(devnum,axis, startv); (设定初始速度) adt8840a_set_speed

(devnum,axis, startv);(设定驱动速度)

}

else

//加减速运动

{ Result = adt8840a_set_startv(devnum,axis, startv); (设定初始速度) adt8840a_set_speed

(devnum,axis, speed); (设定驱动速度) adt8840a_set_acc (devnum,axis, add); (设定加速

度)

}

return Result;

单轴驱动函数

该函数用于驱动单个运动轴运动 参数: axis-轴号 ,value- 输出脉冲数 返回值 =0 正确 ,返回值 =1

错误

int CCtrlCard::Axis_Pmove(int axis, long value)

{

Result = adt8840a_pmove(devnum,axis, value (脉冲数) ); return Result;

任意两轴插补函数 ********************

该函数用于驱动任意两轴进行插补运动

参数: axis1,axis2- 轴号、 value1,value2-脉冲数 返回值 =0 正确 ,返回值 =1 错误

int CCtrlCard::Interp_Move2(int axis1, int axis2, long value1, long value2) {

Result = adt8840a_inp_move2(devnum,axis1, axis2, value1, value2); return Result;

}

任意三轴插补函数

该函数用于驱动任意三轴进行插补运动

参数: axis1,axis2,axis3-轴号、 value1,value2,value3- 脉冲数 返回值 =0 正确 ,返回

值 =1 错误

int CCtrlCard::Interp_Move3(int axis1, int axis2, int axis3, long value1, long value2, long value3)

{

Result = adt8840a_inp_move3(devnum,axis1, axis2, axis3, value1, value2, value3); return

Result;

四轴插补函数

该函数用于驱动 XYZW 四轴进行插补运动 参数: value1,value2,value3,value4- 输出

脉冲数 返回值 =0 正确 ,返回值 =1 错误

int CCtrlCard::Interp_Move4(long value1, long value2, long value3, long value4)

{

}

} }

Result = adt8840a_inp_move4(devnum,value1, value2, value3, value4); return Result;

停止轴驱动

该函数用于立即或减速停止轴的驱动

参数:axis-轴号、mode- 减速方式(0-立即停止, 1-减速停止)返回值=0 正确,返回值=1 错误

int CCtrlCard::StopRun(int axis, int mode)

{ if(mode == 0) // 立即停止

{

Result = adt8840a_sudden_stop(devnum, axis); } else // 减速停止

{

Result = adt8840a_dec_stop(devnum, axis); } return Result;

}

获取轴的驱动状态

该函数用于获取单轴的驱动状态或插补驱动状态

参数:axis-轴号,value-状态指针(0- 驱动结束,非0-正在驱动) mode

(0-获取单轴驱动状态,1-获取插补驱动状态)返回值=0 正确,返回值=1

错误

int CCtrlCard::Get_Status(int axis, int &value, int mode) {

if (mode==0) //获取单轴驱动状态

Result=adt8840a_get_status(devnum,axis,&value);

else //获取插补驱动状态

Result=adt8840a_get_inp_status(devnum,&value); return Result;

}

/***************** 获取运动信息******************************

该函数用于反馈轴当前的逻辑位置,实际位置和运行速度

参数:axis-轴号,LogPos- 逻辑位置,ActPos-实际位置,Speed-运行速度返回值=0 正确,返回值=1 错误

int CCtrlCard::Get_CurrentInf(int axis, long &LogPos, long &ActPos, long &Speed )

{

Result = adt8840a_get_command_pos(devnum,axis, &LogPos); (获取逻辑位置) adt8840a_get_actual_pos (devnum, axis, &ActPos); (获取实际位置)

adt8840a_get_speed (devnum, axis, &Speed);(获取驱动速度)

return Result;

}

读取输入点

该函数用于读取单个输入点

参数:number-输入点(0 ~ 39)

}

返回值:0 -低电平,1 -高电平,-1 -错误

int CCtrlCard::Read_Input(int number,int &value)

{

Result = adt8840a_read_bit(devnum, number, &value); return Result;

}

输出单点函数

该函数用于输出单点信号

参数:number-输出点(0 ~ 15),value 0- 低电平、1-高电平返回值=0 正确,返回值=1 错误

int CCtrlCard::Write_Output(int number, int value)

{

Result = adt8840a_write_bit(devnum, number, value); return Result;

}

设置位置计数器

该函数用于设置逻辑位置和实际位置

参数:axis- 轴号,pos-设置的位置值

mode 0-设置逻辑位置,非0 -设置实际位置

返回值=0 正确,返回值=1 错误

int CCtrlCard::Setup_Pos(int axis, long pos, int mode)

{

if(mode==0)

{

Result = adt8840a_set_command_pos(devnum,axis, pos);(设置逻辑计数器) }

else

{

Result = adt8840a_set_actual_pos(devnum, axis, pos);(设置实位计数器) } return Result;

}

设置脉冲输出方式

该函数用于设置脉冲的工作方式

参数:axis-轴号, value- 脉冲方式0-脉冲+脉冲方式1-脉冲+方向方式返回值=0 正确,返回值=1 错误默认脉冲方式为脉冲+方向方式本程序采用默认的正逻辑脉冲和方向输出信号正逻辑

int CCtrlCard::Setup_PulseMode(int axis, int value)

{

Result = adt8840a_set_pulse_mode(devnum,axis, value, 0, 0);(设置脉冲模式)

return Result;

}

设置限位信号方式

该函数用于设定正/负方向限位输入nLMT 信号的模式

数:

axis

-轴号

value1 0 -正限位有效1-正限位无效

value2 0 -负限位有效1-负限位无效

logic 0-低电平有效1-高电平有效

默认模式为:正限位有效、负限位有效、低电平有效

返回值=0正确,返回值=1错误

int CCtrlCard::Setup_LimitMode(int axis, int value1, int value2, int logic)

{

Result = adt8840a_set_limit_mode(devnum,axis, value1, value2, logic);

return Result;

stop0 信号方式**********************

该函数用于设定stop0 信号的模式

参数:axis-轴号

value 0-无效 1 -有效

logic 0-低电平有效1-高电平有效默认模式为:无效

返回值=0正确,返回值=1错误

int CCtrlCard::Setup_Stop0Mode(int axis, int value, int logic)

{

Result = adt8840a_set_stop0_mode(devnum,axis, value ,logic); return Result;

}

设置stop1 信号方式

该函数用于设定stop1 信号的模式

参axis-轴号

value 0-无效 1 -有效

logic 0-低电平有效1-高电平有效

默认模式为:无效

返回值=0正确,返回值=1错误

int CCtrlCard::Setup_Stop1Mode(int axis, int value, int logic)

{

Result = adt8840a_set_stop1_mode(devnum,axis, value, logic); return Result;

}

单轴连续驱动函数

该函数用于驱动单个运动轴运动

参数:axis-轴号,value- 脉冲方向

返回值=0 正确,返回值=1 错误

int CCtrlCard::Axis_Cmove(int axis, long value)

Result = adt8840a_continue_move(devnum,axis, value); return Result; }

}

2.3 功能实现模块

2.3.1 界面设计

说明:

(1)速度设定部分—用于设定各轴的起始速度、驱动速度和加速度;位置设定—设定各轴的驱动脉冲;驱动信息—实时显

示各轴的逻辑位置、实际位置和运行速度。

(2) 驱动对象—通过选择驱动对象,确定参与联动或插补的轴;

(3) 联动—用于向所选驱动对象的所有轴发出单轴驱动指令;插补—用于向所选驱动对象的所有轴发出插补指令;停止

—停止所有轴的脉冲输出;

以上所有数据均以脉冲为单位。

2.3.2 运动控制卡初始化代码位于窗体初始化中,用户新增代码如下:

SetDlgItemText(IDC_EDIT_OPPIP,"192.168.0.123");// 指定控制卡IP 地址SetDlgItemText(IDC_EDIT_MAC,"00-AB-CD-00-01-23");// 指定网卡地址SetDlgItemText(IDC_EDIT_INFO," 请先执行初始化"); DeviceAddr_init();// 设备接口地址初始化

//******* 设置默认初始速度为100 *********

m_nStartvX = 100;

m_nStartvY = 100;

m_nStartvZ = 100;

m_nStartvA = 100;

//********* 设置默认驱动速度为2000********

m_nSpeedX = 2000;

m_nSpeedY = 2000;

m_nSpeedZ = 2000;

m_nSpeedA = 2000;

//********* 设置默认加速度为2500**********

m_nAddX = 2500;

m_nAddY = 2500;

m_nAddZ = 2500;

m_nAddA = 2500;

设置默认目标位置为1000000******

m_nPulseX = 1000000; m_nPulseY

= 1000000; m_nPulseZ = 1000000;

m_nPulseA = 1000000;

UpdateData(FALSE);

SetTimer(MAINTIMER,100,NULL);

//启动计时器

,其中依据选择对象的不同发出对应的驱动指令,代码如下:

2.3.3 联动代码位于联动按钮点击消息

*******************************

联动按钮动作

void CVCExampleDlg::OnButtonPmove()

{

UpdateData(TRUE);

long Startv[]={m_nStartvX,m_nStartvY ,m_nStartvZ,m_nStartvA}; // 初始速度

long Speed[]={m_nSpeedX,m_nSpeedY ,m_nSpeedZ,m_nSpeedA}; // 驱动速度

long Add[] ={m_nAddX,m_nAddY ,m_nAddZ,m_nAddA}; // 加速度if(m_bX)

//* *X 速度设定*//

g_CtrlCard.Setup_Speed(1, m_nStartvX, m_nSpeedX,

m_nAddX); }

if(m_bY )

//* *Y 速度设定*//

g_CtrlCard.Setup_Speed(2, m_nStartvY, m_nSpeedY, m_nAddY);

} if(m_bZ )

{

速度设定*//

g_CtrlCard.Setup_Speed(3, m_nStartvZ, m_nSpeedZ, m_nAddZ);

}

if(m_bA )

//* *A 速度设定*//

g_CtrlCard.Setup_Speed(4, m_nStartvA, m_nSpeedA, m_nAddA);

//驱动指令

//*************X 轴驱动***************//

if(m_bX)

g_CtrlCard.Axis_Pmove(1, m_nPulseX);

//*************Y 轴驱动***************//

if(m_bY)

g_CtrlCard.Axis_Pmove(2, m_nPulseY);

//*************Z 轴驱动***************//

if(m_bZ)

g_CtrlCard.Axis_Pmove(3, m_nPulseZ);

//*************A 轴驱动***************//

if(m_bA)

g_CtrlCard.Axis_Pmove(4, m_nPulseA);

if((!m_bX) && (!m_bY) && (!m_bZ) && (!m_bA))

MessageBox("请选择联动轴 !"," 提示 ");

}

2.3.4 插补代码位于插补按钮点击消息中 , 其中依据选择对象的不同发出对应的驱动指令 ,代码如下:

/*********************************

插补按钮动作

void CVCExampleDlg::OnButtonInpmove()

{

UpdateData();

long Startv[]={m_nStartvX,m_nStartvY ,m_nStartvZ,m_nStartvA}; // 初始速度

long Speed[]={m_nSpeedX,m_nSpeedY ,m_nSpeedZ,m_nSpeedA}; //驱动速度 long Add[]={m_nAddX,m_nAddY ,m_nAddZ,m_nAddA}; //加速度

long Pulse[]={m_nPulseX,m_nPulseY ,m_nPulseZ,m_nPulseA};

// 轴的驱动脉冲数 if(m_bX && m_bY && !m_bZ && !m_bA)

//XY 两轴插补

{ g_CtrlCard.Setup_Speed(1, Startv[0], Speed[0], Add[0]); g_CtrlCard.Interp_Move2(1, 2, Pulse[0], Pulse[1]);

}

else if(m_bX && !m_bY && m_bZ && !m_bA)

//XZ 两轴插补

{ g_CtrlCard.Setup_Speed(1, Startv[0], Speed[0], Add[0]); g_CtrlCard.Interp_Move2(1, 3, Pulse[0], Pulse[2]);

}

else if(m_bX && !m_bY && !m_bZ && m_bA)

//XW 两轴插补

{ g_CtrlCard.Setup_Speed(1, Startv[0], Speed[0], Add[0]); g_CtrlCard.Interp_Move2(1, 4, Pulse[0], Pulse[3]);

}

else if(!m_bX && m_bY && m_bZ && !m_bA)

{ g_CtrlCard.Setup_Speed(2, Startv[1], Speed[1], Add[1]); g_CtrlCard.Interp_Move2(2, 3, Pulse[1], Pulse[2]);

}

else if(!m_bX && m_bY && !m_bZ && m_bA)

//YW 两轴插补

{ g_CtrlCard.Setup_Speed(2, Startv[1], Speed[1], Add[1]); g_CtrlCard.Interp_Move2(2, 4, Pulse[1], Pulse[3]);

}

else if(!m_bX && !m_bY && m_bZ && m_bA)

//ZW 两轴插补

{ g_CtrlCard.Setup_Speed(3, Startv[2], Speed[2], Add[2]); g_CtrlCard.Interp_Move2(3, 4, Pulse[2], Pulse[3]);

}

else if(m_bX && m_bY && m_bZ && !m_bA) //XYZ 三轴插补

//*

两轴插补 ***********// //YZ 两轴插补

//*

三轴插补 *//

{

}g_CtrlCard.Setup_Speed(1, Startv[0], Speed[0], Add[0]); g_CtrlCard.Interp_Move3(1, 2, 3, Pulse[0], Pulse[1], Pulse[2]);

}

else if(m_bX && m_bY && m_bZ && !m_bA) //XYZ 三轴插补

{

g_CtrlCard.Setup_Speed(1, Startv[0], Speed[0], Add[0]); g_CtrlCard.Interp_Move3(1, 2, 3, Pulse[0], Pulse[1], Pulse[2]);

}

else if(m_bX && m_bY && !m_bZ && m_bA) //XYW 三轴插补{

g_CtrlCard.Setup_Speed(1, Startv[0], Speed[0], Add[0]); g_CtrlCard.Interp_Move3(1, 2, 4, Pulse[0], Pulse[1], Pulse[3]);

}

else if(m_bX && !m_bY && m_bZ && m_bA) //XZW 三轴插补

{

g_CtrlCard.Setup_Speed(1, Startv[0], Speed[0], Add[0]); g_CtrlCard.Interp_Move3(1, 3, 4, Pulse[0], Pulse[2], Pulse[3]);

}

else if(!m_bX && m_bY && m_bZ && m_bA) //YZW 三轴插补

{

g_CtrlCard.Setup_Speed(2, Startv[1], Speed[1], Add[1]); g_CtrlCard.Interp_Move3(2, 3, 4, Pulse[1], Pulse[2], Pulse[3]);

}

else if(m_bX && m_bY && m_bZ && m_bA) //XYZW 四轴插补

{

g_CtrlCard.Setup_Speed(1, Startv[0], Speed[0], Add[0]); g_CtrlCard.Interp_Move4(Pulse[0], Pulse[1], Pulse[2], Pulse[3]); } else {

MessageBox("请选择插补轴!"," 提示");

//* 四轴插补*//

2.4 监控模块

监控模块用于实时获取所有轴的驱动信息,显示运动信息,同时控制在驱动进行过程中,不允许发出新的驱动指令。

定时器消息完成,代码如下:

// 获取逻辑位置、实际位置、运行速度和驱动状态//

// 读取正负限位、stop0 // //*********************************************************// void CVCExampleDlg::OnTimer(UINT nIDEvent) {

long log=0,act=0,spd=0;

UINT nID1[]={IDC_POS_LOGX,IDC_POS_LOGY ,IDC_POS_LOGZ,IDC_POS_LOGW};

UINT nID2[]={IDC_POS_ACTX,IDC_POS_ACTY ,IDC_POS_ACTZ,IDC_POS_ACTW};

UINT nID3[]={IDC_RUNSPEED_X,IDC_RUNSPEED_Y ,IDC_RUNSPEED_Z,IDC_RUNSPEED_W};

CStatic *lbl;

CString str; int status[4];

for (int i=1; i

lbl=(CStatic*)GetDlgItem(nID1[i-1]);

str.Format("%ld",log); lbl->SetWindowText(str);

lbl=(CStatic*)GetDlgItem(nID2[i-1]);

str.Format("%ld",act);

lbl->SetWindowText(str);

lbl=(CStatic*)GetDlgItem(nID3[i-1]); // 无倍率设定,实际速度=获取的值str.Format("%ld",spd);

lbl->SetWindowText(str);

//****** 获取驱动状态******// g_CtrlCard.Get_Status(i,status[i-1],0);

}

//****************** 信号检测

*****************

// X轴STOP0 0 Y 轴STOP0 1

// Z 轴STOP0 2 A轴STOP0 3

// x 轴正限位-4 x 轴负限位- 5

// Y 轴正限位-4 Y 轴负限位- 5

// Z 轴正限位-8 Z 轴负限位-9

// A 轴正限位-

10 A 轴负限位-11

/******************************************* UINT nIDIN1[]={

IDC_STOP0_X,IDC_STOP0_Y ,

IDC_STOP0_Z,IDC_STOP0_W,

IDC_LIMIT_X,IDC_LIMIT_X2,

IDC_LIMIT_Y ,IDC_LIMIT_Y2,

IDC_LIMIT_Z,IDC_LIMIT_Z2, 监控模块利用

//* 实时获取状态*//

g_CtrlCard.Get_CurrentInf(i,log,act,spd); //读取逻辑位置、实际位置和运行速度

//* 显示逻辑位置********//

//* 显示实际位置********//

//* 显示运行速度********//

//X,Y 原点

//Z,A 原点

//X 轴正负限位

//Y 轴正负限位

//Z 轴正负限位

btn=(CButton*)GetDlgItem(IDC_BUTTON_PMOVE); btn->EnableWindow(FALSE); btn=(CButton*)GetDlgItem(IDC_BUTTON_CMOVE); btn->EnableWindow(FALSE); btn=(CButton*)GetDlgItem(IDC_BUTTON_INPMOVE); btn->EnableWindow(FALSE); btn=(CButton*)GetDlgItem(IDC_BUTTON_CLEARPOS); btn->EnableWindow(FALSE);

IDC_LIMIT_W,IDC_LIMIT_W2 };

CButton *btn;

int value=0;

//A 轴正负限位 for (i=0; i<12; i++)

{ g_CtrlCard.Read_Input(i,value);// 读取信号 ,注意状态不是返回值

btn=(CButton*)GetDlgItem(nIDIN1[i]);

btn->SetCheck(value==0?1:0);

}

//* 信号检测

// 编码器 Z 相输入作 STOP1

//

X 轴 STOP1 38 Y 轴 STOP1 39 //

Z 轴 STOP1 40 A 轴 STOP1 41

//* UINT nIDIN2[]={

IDC_STOP1_X,IDC_STOP1_Y ,IDC_STOP1_Z,IDC_STOP1_W };

for (i=0; i<4; i++)

{ g_CtrlCard.Read_Input(38+i,value);// 读取 IN38 到 IN41 信号

btn=(CButton*)GetDlgItem(nIDIN2[i]);

btn->SetCheck(value==0?1:0);

}

//* 按钮控制

if(devnum==0&&status[0]==0 && status[1]==0 && status[2]==0 && status[3]==0) {

//* 驱动完成

btn=(CButton*)GetDlgItem(IDC_BUTTON_PMOVE);

btn->EnableWindow(TRUE);

btn=(CButton*)GetDlgItem(IDC_BUTTON_CMOVE);

btn->EnableWindow(TRUE);

btn=(CButton*)GetDlgItem(IDC_BUTTON_INPMOVE);

btn->EnableWindow(TRUE);

btn=(CButton*)GetDlgItem(IDC_BUTTON_CLEARPOS);

btn->EnableWindow(TRUE);

btn=(CButton*)GetDlgItem(IDC_BUTTON_BASEPARA);

btn->EnableWindow(TRUE);

}

else

{

//* 驱动进行中 **********

btn=(CButton*)GetDlgItem(IDC_BUTTON_BASEPARA);

btn->EnableWindow(FALSE);

}

CDialog::OnTimer(nIDEvent);

}

2.5 停止模块

,代码停止模块主要用于控制驱动过程中的突发事件,需要立即终止所有轴的驱动。停止模块的代码位于停止按钮的点击消

息中

如下:

void CVCExampleDlg::OnButtonStop()

{

for (int i = 1; i<=MAXAXIS; i++)

{

g_CtrlCard.StopRun(i,1);

}

相关主题
文本预览
相关文档 最新文档