聲明一下,寫下這些編程技巧,即不是什么祖?zhèn)髅丶,也不是什么必殺招或絕招,在此只為方便同仁們在編程控制軟件時,對此可以進行適當(dāng)?shù)恼遄。以下展現(xiàn)的編程思想及奉上的源代碼都非常簡易,但并不是隨手寫寫,可都是經(jīng)過實踐的。若沒有成功經(jīng)驗作后盾,我也就沒有必要在此打字練五筆了。 事實上,正如一個編程大師所言( Michael Abrash ),當(dāng)你的軟件正常而且有效率的運行起來時,好像一切都是那么顯而易見。故,在此,我仍堅持那句編程口號,將事情變得越簡單越好,越簡單就越有效率,越穩(wěn)定。 在以下的介紹中,我將盡可能的展示本人的編程思想,最大可能的給出知其然也知其所然的解釋。若你有更好的見解,希望能得到你的指正。人長大了明顯標(biāo)志就是變得不太負(fù)責(zé),而且不敢承認(rèn)自己還需要努力,害怕面對自己的錯誤。若是這樣,放心,我還沒長大。因為我無法保證我能面面俱到。 關(guān)于源代碼的閱讀,需要讀者有一定的 C++ 編程基礎(chǔ),至少對以下表示形式不會產(chǎn)生誤解: const char *pString; // 指定 pString 邦定的數(shù)據(jù)不能被修改 char * const pString; // 指定 pString 的地址不能被修改 const char * const pString; // 含上面兩種指定功能 當(dāng)然,隨便提醒一下,這些源代碼若需要加入你的軟件工程當(dāng)中,還需要作一些調(diào)整和修改,因此,這些源代碼實質(zhì)上稱為偽代碼也可以,之所以展現(xiàn)它們,是讓程序員們有個可視化的快感,特別是那些認(rèn)為源代碼就是一切的程序員。 同時,為了提高針對性,大部分控制卡調(diào)用的函數(shù)會明確指出是邦定哪些卡的,實際應(yīng)用時,程序員可自行選擇,以體現(xiàn)一下自己的智商是可以寫寫軟件的。 留個電話: 0755-26434329 E_mail: support@leisai.com 有更濃興趣的上這個 QQ 號嗎也行: 372161225 一、 控制卡類的單一實例實現(xiàn) 把控制卡類作一個類來處理,幾乎所有 C++ 程序員都為舉雙手表示贊同,故第一個什么都沒有的偽代碼就此產(chǎn)生,如下表現(xiàn): class CCtrlCard { public: …Function public: …attrib } 于是,用這個 CctrlCard 可以產(chǎn)生 n 多個控制卡實例,只要內(nèi)存足夠。然而,針對現(xiàn)實世界,情況并不那么美好。通常情況下, PC 機內(nèi)只插同種類型的控制卡 1 到 2 張,在通過調(diào)用 d1000_board_init 或 d3000_board_init 函數(shù)時,它們會負(fù)責(zé)返回有效卡數(shù) nCards ,然后從 0-nCards*4 - 1 自行按排好軸數(shù)。初始化函數(shù)就是 C++ 的 new 或 malloc 的操作,取得系統(tǒng)的資源,但是控制卡的資源與內(nèi)存不一樣,取得資源后必需要釋放才可以再次獲取,即控制卡資源是唯一的。 既然控制卡資源是唯一的,那么最好 Cctrlcard 產(chǎn)生的實例也是唯一的,這樣,我們可以方便的需要定義一個全局變量即可 : CctrlCard g_Dmcard; 在其它需要調(diào)用的地方,進行外部呼叫: extern CctrlCard g_DmcCard; 以上方法實在太簡單了,很多人都會開心起來。實質(zhì)上,方法還有很多,即然可以產(chǎn)生 n 多對實例,我們的核心是只要保證調(diào)用 board_init 函數(shù)一次即可,故也可以單獨定義一個 InitBoard 函數(shù): class CctrlCard { public: static int InitBoard(); // 定義一個靜態(tài)函數(shù),以表警示 } int CctrlCard::InitBoard() { return d1000_board_init(); } 還有一種方法,情況稍加復(fù)雜,但表達(dá)的功能也要強一些,以下展現(xiàn)可以稍微安慰一下代碼狂。 Class CctrlCard { public: CctrlCard(); // 請注意這個構(gòu)造函數(shù)的定義 } CctrlCard::CctrlCard() {// 呵呵,也很明了 static int n(0); // 注意,是個靜態(tài)變量 n++; // 每次調(diào)用 CctrlCard 生成實例時,都會計數(shù)一次 assert( n == 1 ); // 在 DEBUG 版本下,只有 n==1 的情況下可以通過 // 否則,會出現(xiàn)致命錯誤,還好,它會告訴你錯在哪個文件, // 哪一行,呵呵,是個好東東啊。 } 通過強行報警處理,當(dāng)你有 g_DmcCard 這個實例時,其它的所有控制卡的定義都只能是以引用或指針的方式進行了,不會再產(chǎn)生新有效的實例了,對于由小組編程的項目軟件,而你又恰好負(fù)責(zé)編程控制卡這一塊的話,以上的顯性報警,會讓其它人心領(lǐng)神會。當(dāng)然,你也可以將上面的方法加入到 InitBoard 當(dāng)中去,可以避你的無意識的多次調(diào)用了。 附:無意識的多次調(diào)用經(jīng)常發(fā)生,特別是那些對 MFC 機制不明確的程序員,在多文檔框架下,不知道這個 CctrlCard::InitBoard 函數(shù)到底是應(yīng)該放在 CmainFrame 的 OnCreate 里面,還是應(yīng)該放在 CchildFrame 的 OnCreate ,或者是 Cview 的 OnInitUpdate 里面進行調(diào)用。 在一言難盡 MFC 的情況下,我建議兩個小方法: No.1 將 CctrlCard 的函數(shù)置于 Cmainframe 的 OnCreate 或者 Capp::Initstance 內(nèi)調(diào)用 No.2 將 InitBoard 函數(shù)稍加改造成這樣: Int CctrlCard::InitBoard() { static int n(-1000);// 注意, -1000 是控制卡函數(shù)不可能返回的值 if( n == -1000 ) n = d1000_board_init(); return n;// 這樣,即使多次調(diào)用也不樣怕了,呵呵,雕蟲小技也可以除蟲啊 } 必須額外聲明一下,我們不是不重視資源的釋放,而是作為一個 C++ 程序員寫下這些代碼是基本的義務(wù)(這也是我為什么要交待讀者必須要有一定的 C++ 基礎(chǔ)): class CctrlCard { public: ~CctrlCard() {// 定義析構(gòu)函數(shù),在此釋放資源,對此,我不想再轉(zhuǎn)到讀者的眼球了 d1000_board_close(); } } 二、 數(shù)據(jù)結(jié)構(gòu)及數(shù)據(jù)類型的定義,部分相關(guān)聲明 調(diào)用控制卡驅(qū)動函數(shù)時,經(jīng)常會有如下形式: 單軸相對運動 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 ); 以上的調(diào)用,很多重復(fù)枯燥,又不直觀,難于理解,并且在面向客戶時,常常是指每分多少米,或者每秒多少毫米,很少有人問每秒多少脈沖,移動多少脈沖作距離,故需要單位之間的換算。顯然,對于這些問題,我想,C++程序員應(yīng)該找到用武之地了,所以我們一步一步來,慢慢統(tǒng)一各個問題。實質(zhì)上,在以下的幾個技巧,也需要在此澄清一些概念。 我們先來幾個宏定義提高一下情緒: # define MAX_AXIS 4 // 最多軸數(shù) # define XCH 0 // 定義X軸的值 # define YCH 1 # define ZCH 2 # define UCH 3 …..( 其它以次類推 ) # define M_ABS 0x01 // 定義一個絕對標(biāo)志位 # define M_INP 0x02 // 定義一個插補位 接下來深入一點點,再來幾個結(jié)構(gòu)定義: 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)// 定義這樣一個構(gòu)造函數(shù)需要勇氣,看似不合理,但是好用麻 { } 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 的結(jié)構(gòu)定義,把幾個參數(shù)變成一個參數(shù)。比如要實現(xiàn)的單軸驅(qū)動函數(shù),就變得非常明了: void Move( int nAxis, double fMM, const SPEED &speed, int nFlag = M_ABS );// 往后我們再具體完善其實現(xiàn)。 以上的結(jié)構(gòu)具有類的特性,但是由于其每個成員都可以給外部直接使用,故就不需要什么類的 public 及其析構(gòu)函數(shù)的定義了。之所以全都采用 double 的數(shù)據(jù)類型,是面向客戶習(xí)慣及單位計算方便的。 接下來是對控制卡常用的單位計算及部分常用變量的聲明: class Cctrlcard { public: …( 其它略去 ) public: // 屬性 mutable int ORGIN; // 指定原點狀態(tài)位 mutable int LIMIT_A, LIMIT_B; // 指定左右限位狀態(tài)位 private: // 以下的屬性不給外部訪問的 struct tag_AXIS{// 單軸屬性 double fUnitPM; // 脈沖當(dāng)量 long nRP; // 每轉(zhuǎn)脈沖數(shù) double fJourey; // 行程 }; tag_AXIS m_axis[MAX_AXIS]; }; 定義 ORGIN , LIMIT_A, LIMIT_B 為變量,是有兩個意義: No.1 當(dāng)你訪問它們的狀態(tài)時,不需要每次調(diào)用 d1000_get_axis_status 函數(shù),你可以這樣: Int nStatus = d1000_get_axis( XCH ); If( nStatus & g_DmcCard.ORGIN == g_dmcCard.ORGIN ) If( nStatus & g_DmcCard.LIMIT_A == g_DmcCard.LIMIT_A ) If( nStatus & g_DmcCard.LIMIT_B == g_DmcCard.LIMIT_B ); No.2 你可以擴展不同的卡,當(dāng)外部調(diào)用的程序邏輯已被確定時,當(dāng)你需要從 DMC1000 控制卡升級到 DMC3000 控制卡時,只需要給 ORGIN 等狀態(tài)位指定不同的值即可。指定狀態(tài)位的值也有一個小小的技巧,以 ORGIN 為例,在 DMC1000 控制卡,其位值在 2 位,則可以這樣: ORGIN = 1<<2; 在 DMC3000 控制卡,其值在第 9 位,則這樣: ORGIN = 1<<9; 方法都很簡單,關(guān)鍵是要想得到。 對于 tag_AXIS 定義,引出幾個函數(shù)的聲明,專門為其服務(wù): void SetUP( nit nAxis, double fMM, double nPulse, double fMax );// 設(shè)定當(dāng)量 double P2M ( int nAxis, long nPulse ); // 脈沖轉(zhuǎn)成毫米 pulse to metric long M2P( int nAxis, double fMM ); // 毫米轉(zhuǎn)成脈沖 mitric to pulse 現(xiàn)在,我們再回過頭來完成 Move 函數(shù)的實現(xiàn),以便獲得一點點成就感,同時也展示一下以上的大堆表述是有其意義的。 void Move( int nAxis, double fMM, const SPEED &speed, int nFlag = M_ABS ) { ( nFlag & M_ABS == M_ABS ) ? d1000_start_ta_move( nAxis, // 絕對 M2P( nAxis, fMM), M2P( nAxis, speed.start ), M2P( nAxis, speed.speed), Speed.accel ): // 注意是冒號, ?: 是一個表達(dá)式 d1000_start_t_move( nAxis, // 相對 M2P( nAxis, fMM), M2P( nAxis, speed.start ), M2P( nAxis, speed.speed), Speed.accel ); } 是不是很簡單呢,當(dāng)外部調(diào)用時,客戶的觀念就直接面對 Metric 即可,如: Move( XCH, 10.0, SPEED(5,10,0.1), M_ABS );// 達(dá)到絕對位置 10.0 毫米處。 以上羅嗦了一大堆,對于剛開始 C++ 編程的程序員來說應(yīng)該是收益不小,對于高手,則希望能夠體會一下我的良苦用心。在以下的技巧介紹當(dāng)中,我將變得很簡易。一般來講,程序員的基礎(chǔ)不是太差的話,至少能夠在 1 分鐘內(nèi)明白是什么道理。
狀 態(tài):
離線
公司簡介
產(chǎn)品目錄
公司名稱:
深圳市雷賽智能控制股份有限公司
聯(lián) 系 人:
梁邦敏
電 話:
755-26401178
傳 真:
地 址:
深圳市南山區(qū)登良路天安南油工業(yè)區(qū)2棟3樓
郵 編:
518000
主 頁: