当前位置:文档之家› 运动控制卡应用编程技巧

运动控制卡应用编程技巧

运动控制卡应用编程技巧内容来源网络,由“深圳机械展(11万㎡,1100多家展商,超10万观众)”收集整理!更多cnc加工中心、车铣磨钻床、线切割、数控刀具工具、工业机器人、非标自动化、数字化无人工厂、精密测量、3D打印、激光切割、钣金冲压折弯、精密零件加工等展示,就在深圳机械展.关于源代码的阅读,需要读者有一定的C++编程基础,至少对以下表示形式不会产生误解:const char *pString; //指定pString邦定的数据不能被修改char * const pString; //指定pString的地址不能被修改const char * const pString; //含上面两种指定功能当然,随便提醒一下,这些源代码若需要加入你的软件工程当中,还需要作一些调整和修改,因此,这些源代码实质上称为伪代码也可以,之所以展现它们,是让程序员们有个可视化的快感,特别是那些认为源代码就是一切的程序员。

同时,为了提高针对性,大部分控制卡调用的函数会明确指出是邦定哪些卡的,实际应用时,程序员可自行选择,以体现一下自己的智商是可以写写软件的。

一、控制卡类的单一实例实现把控制卡类作一个类来处理,几乎所有C++程序员都为举双手表示赞同,故第一个什么都没有的伪代码就此产生,如下表现:class CCtrlCard{public:…Functionpublic:…attrib}于是,用这个CctrlCard可以产生n多个控制卡实例,只要内存足够。

然而,针对现实世界,情况并不那么美好。

通常情况下,PC机内只插同种类型的控制卡1到2张,在通过调用d1000_board_init或d3000_board_init函数时,它们会负责返回有效卡数nCards,然后从0-nCards*4- 1自行按排好轴数。

初始化函数就是C++的new或malloc的操作,取得系统的资源,但是控制卡的资源与内存不一样,取得资源后必需要释放才可以再次获取,即控制卡资源是唯一的。

既然控制卡资源是唯一的,那么最好Cctrlcard产生的实例也是唯一的,这样,我们可以方便的需要定义一个全局变量即可:CctrlCard g_Dmcard;在其它需要调用的地方,进行外部呼叫:extern CctrlCard g_DmcCard;以上方法实在太简单了,很多人都会开心起来。

实质上,方法还有很多,即然可以产生n 多对实例,我们的核心是只要保证调用board_init函数一次即可,故也可以单独定义一个InitBoard函数:class CctrlCard{public:static int InitBoard(); //定义一个静态函数,以表警示}int CctrlCard::InitBoard(){return d1000_board_init();}还有一种方法,情况稍加复杂,但表达的功能也要强一些,以下展现可以稍微安慰一下代码狂。

Class CctrlCard{public:CctrlCard(); //请注意这个构造函数的定义}CctrlCard::CctrlCard(){//呵呵,也很明了static int n(0); //注意,是个静态变量n++; //每次调用CctrlCard生成实例时,都会计数一次assert( n == 1 ); //在DEBUG版本下,只有n==1的情况下可以通过//否则,会出现致命错误,还好,它会告诉你错在哪个文件,//哪一行,呵呵,是个好东东啊。

}通过强行报警处理,当你有g_DmcCard这个实例时,其它的所有控制卡的定义都只能是以引用或指针的方式进行了,不会再产生新有效的实例了,对于由小组编程的项目软件,而你又恰好负责编程控制卡这一块的话,以上的显性报警,会让其它人心领神会。

当然,你也可以将上面的方法加入到InitBoard当中去,可以避你的无意识的多次调用了。

附:无意识的多次调用经常发生,特别是那些对MFC机制不明确的程序员,在多文档框架下,不知道这个CctrlCard::InitBoard函数到底是应该放在CmainFrame的OnCreate里面,还是应该放在CchildFrame的OnCreate,或者是Cview的OnInitUpdate里面进行调用。

在一言难尽MFC的情况下,我建议两个小方法:No.1 将CctrlCard的函数置于Cmainframe的OnCreate或者Capp::Initstance内调用No.2 将InitBoard函数稍加改造成这样:Int CctrlCard::InitBoard(){static int n(-1000);//注意,-1000是控制卡函数不可能返回的值if( n == -1000 )n = d1000_board_init();return n;//这样,即使多次调用也不样怕了,呵呵,雕虫小技也可以除虫啊}必须额外声明一下,不是不重视资源的释放,而是作为一个C++程序员写下这些代码是基本的义务(这也是我为什么要交待读者必须要有一定的C++基础):class CctrlCard{public:~CctrlCard(){//定义析构函数,在此释放资源,对此,我不想再转到读者的眼球了d1000_board_close();}}二、数据结构及数据类型的定义,部分相关声明调用控制卡驱动函数时,经常会有如下形式:单轴相对运动d1000_start_t_move( axis, pulse, start, speed, accel );单轴绝对运动d1000_start_ta_move( axis, pulse, start, speed, accel );两轴相对插补d1000_start_t_line( axisArray, distArray, start, speed, accel );两轴绝对插补d1000_start_ta_line( axisArray, distArray, start, speed, accel );圆弧相对插补d3000_start_t_arc( axisArray, C1, C2, E1,E2, dir, start, speed, accel ); 圆弧绝对插补d3000_start_ta_arc( axisArray, C1, C2, E1,E2, dir, start, speed, accel );以上的调用,很多重复枯燥,又不直观,难于理解,并且在面向客户时,常常是指每分多少米,或者每秒多少毫米,很少有人问每秒多少脉冲,移动多少脉冲作距离,故需要单位之间的换算。

显然,对于这些问题,我想,C++程序员应该找到用武之地了,所以我们一步一步来,慢慢统一各个问题。

实质上,在以下的几个技巧,也需要在此澄清一些概念。

先来几个宏定义提高一下情绪:# define MAX_AXIS 4 //最多轴数# define XCH 0 //定义X轴的值# define YCH 1# define ZCH 2# define UCH 3…..(其它以次类推)# define M_ABS 0x01 //定义一个绝对标志位# define M_INP 0x02 //定义一个插补位接下来深入一点点,再来几个结构定义:typedef struct tag_ARC{tag_ARC( double ox=0.0, double oy=0.0, double ex=0.0, double ey=0.0, int dir=0 ):ox(ox), oy(oy),ex(ex), ey(ey),dir(dir)//定义这样一个构造函数需要勇气,看似不合理,但是好用麻{}double ox,oy;double ex,ey;int dir;}ARC;typedef struct tag_SPEED{tag_SPEED( double start=0.0, double speed=0.0, double accel=0.0, double decel=0.0,double scc=0.0 ) :start(start),speed(speed),accel(accel),decel(decel),scc(scc){}double start;double speed;double accel;double decel;double scc;}SPEED;以上两个ARC和SPEED的结构定义,把几个参数变成一个参数。

比如要实现的单轴驱动函数,就变得非常明了:void Move( int nAxis, double fMM, const SPEED &speed, int nFlag = M_ABS );//往后我们再具体完善其实现。

以上的结构具有类的特性,但是由于其每个成员都可以给外部直接使用,故就不需要什么类的public及其析构函数的定义了。

之所以全都采用double的数据类型,是面向客户习惯及单位计算方便的。

接下来是对控制卡常用的单位计算及部分常用变量的声明:class Cctrlcard{public:…(其它略去)public://属性mutable int ORGIN; //指定原点状态位mutable int LIMIT_A, LIMIT_B; //指定左右限位状态位private://以下的属性不给外部访问的struct tag_AXIS{//单轴属性double fUnitPM; //脉冲当量long nRP; //每转脉冲数double fJourey; //行程};tag_AXIS m_axis[MAX_AXIS];};定义ORGIN,LIMIT_A, LIMIT_B为变量,是有两个意义:No.1 当你访问它们的状态时,不需要每次调用d1000_get_axis_status函数,你可以这样:Int nStatus = d1000_get_axis( XCH );If( nStatus & g_IN == g_IN )If( nStatus & g_DmcCard.LIMIT_A == g_DmcCard.LIMIT_A )If( nStatus & g_DmcCard.LIMIT_B == g_DmcCard.LIMIT_B );No.2你可以扩展不同的卡,当外部调用的程序逻辑已被确定时,当你需要从DMC1000控制卡升级到DMC3000控制卡时,只需要给ORGIN等状态位指定不同的值即可。

指定状态位的值也有一个小小的技巧,以ORGIN为例,在DMC1000控制卡,其位值在2位,则可以这样:ORGIN = 1<<2;在DMC3000控制卡,其值在第9位,则这样:ORGIN = 1<<9;方法都很简单,关键是要想得到。

相关主题