感受面向?qū)ο缶幊痰镊攘?uCosII C++類封裝篇)
C++之父Bjarne Stroustrup也曾說過:“你使用一個語言特征是因?yàn)槟阈枰皇且驗(yàn)樗嬖凇?。設(shè)計(jì)ucClass(uCosII封裝類)的初衷是由于過去很多的實(shí)現(xiàn)都是在C++中完成,深切感受到面向?qū)ο蠓治?、設(shè)計(jì)乃至編程的獨(dú)特魅力。回想微軟的MFC1為win32程序設(shè)計(jì)所帶來的便利、DriverWork2在PC硬件的驅(qū)動開發(fā)的高效,促使完成ucClass的設(shè)計(jì)(這里頭沒有什么高深的學(xué)問),其實(shí)更重要的一點(diǎn)是它能改進(jìn)現(xiàn)有的設(shè)計(jì)模式,能讓今后的uCosII相關(guān)開發(fā)及維護(hù)變得更加輕松和高效!
對于OO我也就幾年的開發(fā)經(jīng)驗(yàn),沒有做過什么“巨項(xiàng)”,對于ARM也是接觸時間不長,不過有一個概念一直影響著我,“ARM不就是復(fù)雜一點(diǎn)的單片機(jī)嗎”,我想也不應(yīng)該難到那里去。于是有空就玩玩,對于很多做這行做開發(fā)的對C++這樣的面向?qū)ο缶幊陶Z言大多不甚了解,要想用OO思想來武裝自己又談何容易啊,這就是一種挑戰(zhàn)習(xí)慣、挑戰(zhàn)思維方式的行為,等于放棄過去曾經(jīng)為你有效解決難題完成工作的開發(fā)模式。在此我也沒有什么靈丹妙藥可改變這些處境,唯一的建議就是堅(jiān)持及不斷實(shí)踐、只有這樣的思想基礎(chǔ)才能提高成功的機(jī)會。
下面簡單設(shè)計(jì)一個ucClass的demo程序(當(dāng)然會可能隱藏了一些bug or error),目標(biāo)板使用的是菲利普LPC2100芯片(周立功的EasyARM 2100開發(fā)板),有些頭文件這里就不貼了,旨在看看主程序的結(jié)構(gòu)及設(shè)計(jì)過程,就讓一些軟件的大蝦們見笑了。
若有機(jī)會的我還準(zhǔn)備寫幾個基于OO之上的在嵌入式開發(fā)的應(yīng)用demo……
設(shè)計(jì)需求:
使用ucClass設(shè)計(jì)一個demo程序完成下列任務(wù):
任務(wù)編號 任務(wù)指責(zé)和功能描述 物理資源占用
1 每間隔1秒蜂鳴器短促發(fā)聲兩次,每10秒間隔使用信號量通知任務(wù)2,隨后自身進(jìn)入掛起等待狀態(tài)。 蜂鳴器及IO端口
2 無限等待由任務(wù)1觸發(fā)的信號量,當(dāng)有信號時引發(fā)1秒蜂鳴器長鳴,其后恢復(fù)任務(wù)1,自身再次進(jìn)入信號量的無限等待狀態(tài)中。 蜂鳴器及IO端口
3 孤立任務(wù),簡單的一秒間隔led1閃爍。 Led1及IO端口
4 孤立任務(wù),通過檢查key1按鍵狀態(tài)控制led4的二值狀態(tài)(亮/滅)。 key1,led4及IO端口
// main.cpp文件,ucClass測試主程序
// exdata 2004-8-18
#include "config.h" // 一些硬件相關(guān)的聲明
#include "GPIO.H" // GPIO類頭文件
#include "ucClass.H" // uCosII的收集類庫頭文件
/*
// 在瀏覽demo程序時要注意以下幾點(diǎn):
// 1,帶參數(shù)的對象構(gòu)造
// 2,靜態(tài)函數(shù)調(diào)用
// 3,帶參數(shù)的派生類構(gòu)造
// 4,虛擬函數(shù)重載
// 5,特別注意一些頭文件(不在此文檔中)包含寫法及原有C函數(shù)聲明方法,關(guān)注extern "C"
// 6,不拘泥于傳統(tǒng)的設(shè)計(jì)思想(模式)
// 7,比較不使用class時候又是如何處理的?分析每個對象背后隱藏了什么?
*/
/************************** 全局變量 *****************************/
// 定義幾個task對象,這是實(shí)例化對象,隱藏并實(shí)現(xiàn)了任務(wù)棧的構(gòu)造
CTask t1(128); // 參數(shù)是任務(wù)堆棧分配大小(在ARM中以32bit為單位)
CTask t2(64);
CTask t3(64);
CSem t2WaitEvent; // 定義一個信號量對象用于任務(wù)t1、t2通信
CGPIO buzz("P0.7",1); // 定義一個GPIO對象,輸出模式,用于控制蜂鳴器
/*
// 前置聲明幾個任務(wù)運(yùn)行函數(shù),這個與C模式下沒有什么區(qū)別。
// 還保留這種處理方法僅僅為求兼顧一些使用uCosII習(xí)慣,建議參考CMyTask的
// 設(shè)計(jì)及t4的定義,使用子類設(shè)計(jì)實(shí)現(xiàn)具體任務(wù)的處理方法要比C模式的的全局
// 孤立啟動函數(shù)更具有設(shè)計(jì)上及維護(hù)上的優(yōu)點(diǎn),當(dāng)做一個中大型項(xiàng)目時候效果尤
// 為明顯。
*/
void t1Run(void *p);
void t2Run(void *p);
void t3Run(void *p);
/*******************************************************************/
/*
// t1任務(wù)運(yùn)行函數(shù)。
// 功能:每間隔1秒蜂鳴器短促發(fā)聲兩次,每10秒間隔使用信號量t2WaitEvent通
// 知任務(wù)t2,隨后自身進(jìn)入掛起等待狀態(tài)。
*/
void t1Run(void *p)
{
TargetInit(); // 初始化硬件目標(biāo)板
INT32U i = 0;
while(1)
{
CuCos::TimeDlyHMSM(0,0,1,0);
if(++i == 10)
{
i = 0;
t2WaitEvent.Post();
t1.Suspend();
}
// 蜂鳴器短促發(fā)聲兩次
buzz.Clear();
CuCos::TimeDlyHMSM(0,0,0,50);
buzz.Set();
CuCos::TimeDlyHMSM(0,0,0,50);
buzz.Clear();
CuCos::TimeDlyHMSM(0,0,0,50);
buzz.Set();
}
p = p;
}
/*
// t2任務(wù)運(yùn)行函數(shù)。
// 功能:無限等待信號量t2WaitEvent,當(dāng)有信號時引發(fā)1秒蜂鳴器長鳴,其后恢
// 復(fù)t1任務(wù),任務(wù)t2再次自身進(jìn)入信號量t2WaitEvent的無限等待狀態(tài)。
*/
void t2Run(void *p)
{
INT8U err = 0;
while(1)
{
t2WaitEvent.Pend(0,&err);
buzz.Clear();
CuCos::TimeDlyHMSM(0,0,1,0);
buzz.Set();
CuCos::TimeDlyHMSM(0,0,0,50);
t1.Resume();
}
p = p;
}
/*
// t3任務(wù)運(yùn)行函數(shù)。
// 功能:簡單的一秒間隔led1閃爍。
*/
void t3Run(void *p)
{
static CGPIO led1("P0.22",1);
while(1)
{
led1.Set();
CuCos::TimeDlyHMSM(0,0,1,0);
led1.Clear();
CuCos::TimeDlyHMSM(0,0,1,0);
}
p = p;
}
/*
// 為求原汁原味體現(xiàn)一個task對象的封裝,下面設(shè)計(jì)一個子類實(shí)現(xiàn)一個特定任務(wù)
// 的處理,在此我們可以認(rèn)為一個任務(wù)就是一個子系統(tǒng),通過一個子類表現(xiàn)一個
// 特有任務(wù)的具體屬性和行為,注意這種設(shè)計(jì)方法與傳統(tǒng)的面向?qū)ο缶幊?/strong>模式是
// 有區(qū)別的。子系統(tǒng)是一個有自主能力主體,例如在MyTask子系統(tǒng)中我們有兩
// 個IO資源m_key1和m_led4分別對應(yīng)著電路板上的按鍵Key1和發(fā)光二極管Led4,
// 通過檢查key1按鍵狀態(tài)控制led4的二值狀態(tài)(亮/滅)。重載基類了Run函數(shù)為
// 求體現(xiàn)類的封裝特性及表現(xiàn)一個任務(wù)的內(nèi)聚能力,它是一個強(qiáng)制的運(yùn)行接口,
// 當(dāng)任務(wù)啟動時便能自動地從重載的Run函數(shù)開始運(yùn)行(具體調(diào)用的中轉(zhuǎn)過程在
// 基類中已經(jīng)實(shí)現(xiàn))。
*/
class CMyTask : public CTask // 注意這里的派生關(guān)系?。。?BR>{
public:
CMyTask(INT32U StkSize) : CTask(StkSize),m_key1("P0.16",0),m_led4("P0.25",1,0)
{
// 注意帶參數(shù)的構(gòu)造處理方法?。?!
}
protected:
virtual void Run(void *p); // 需要重載Run()函數(shù)實(shí)現(xiàn)任務(wù)執(zhí)行
private:
// 這是任務(wù)用到的一些資源定義,當(dāng)然添加子系統(tǒng)的其他的屬性和方法也是允許的
CGPIO m_key1;
CGPIO m_led4;
};
/*
// t4任務(wù)運(yùn)行函數(shù)。
// 通過函數(shù)重載實(shí)現(xiàn)重寫Run函數(shù),該函數(shù)也就是任務(wù)運(yùn)行函數(shù)。
// 功能:通過檢查key1按鍵狀態(tài)控制led4的二值狀態(tài)(亮/滅)。
*/
void CMyTask::Run(void *p) // Run函數(shù)將會被uCosII系統(tǒng)自動運(yùn)行!
{
while(1)
{
if(m_key1.GetStatus() == 0) // 判斷按鍵是否按下
{
if(m_led4.GetStatus() == 0)
{
m_led4.Set();
}
else
{
m_led4.Clear();
}
while(m_key1.GetStatus() == 0)
{
CuCos::TimeDly(20); // 等待按鍵釋放
}
}
else
{
CuCos::TimeDly(10);
}
}
p = p;
}
/*
// 注意一般應(yīng)該把上面的CMyTask定義及實(shí)現(xiàn)另行寫在其他的文件中!把它寫在
// 這里僅僅為求說明方便。
*/
/*-------------------------------------------------------------------------------------------------*/
CMyTask t4(128); //注意任務(wù)對象t4是由CMyTask實(shí)例化的對象
// 看看這個簡潔的main函數(shù),這時候您想到了什么?
int main()
{
CuCos::Init(); // uCosII的系統(tǒng)函數(shù),用于初始化uCosII,等效于OSInit()
t2WaitEvent.Create(); // 創(chuàng)建t2WaitEvent的信號量
// 創(chuàng)建任務(wù)(參數(shù)指定任務(wù)函數(shù)啟動地址、任務(wù)函數(shù)參數(shù)和優(yōu)先級)
t1.Create(t1Run,NULL,1);
t2.Create(t2Run,NULL,2);
t3.Create(t3Run,NULL,3);
t4.Create(NULL,4); // 創(chuàng)建任務(wù),注意Create函數(shù)的重載
CuCos::Start(); // 等效于OSStart()
return 0;
}
關(guān)于我……:
我是一個不折不扣硬件的狂熱者、焊機(jī)派,自會使用圓珠筆的年齡開始就愛上了烙鐵,開始玩弄萬用表,在高考后足足整理了兩箱電路板運(yùn)回老家,因?yàn)橐酵獾厣蠈W(xué)我這些家當(dāng)父母都幫我好好的“封存”。我可以自信及自豪地對那些比我大10歲的硬件工程師說:我焊板子的時候你還不知道什么是電阻電容呢!雖然對硬件有豐富感性認(rèn)識及解不開的情結(jié),但我現(xiàn)在清楚的明白到一點(diǎn),就算是天天在長江黃河里泡大的孩子也不是個個都能登上奧運(yùn)游泳項(xiàng)目的領(lǐng)獎臺,近些年硬件的發(fā)展也很快,現(xiàn)在自己在硬件上的工作也相對較少,沒有什么鍛煉的機(jī)會,三人行,必有我?guī)?,現(xiàn)在身邊牛人不少,也是一個學(xué)習(xí)的機(jī)會。對于軟件開發(fā)我也不是行家(更談不上什么程序員),比起有十幾年開發(fā)經(jīng)驗(yàn)的老前輩還是太嫩!用老江的話說就是too simple、sometimes naive!不過有愛好就可以發(fā)燒(在低于0度的室溫下對著黑底白字的debug窗口熬上幾個夜晚通宵不是一件容易的事情……這樣一不小心就回發(fā)燒~~~)。以前做51也是從ASM開始,馬老和Franklin帶給我第一次[硬件+C]的喜悅。在大二的時候就和畢業(yè)生混在一起搞畢業(yè)設(shè)計(jì),現(xiàn)在想起來這分明就是害了人家,不分明是一個搶手么?雖然不是求什么利益,只在乎有發(fā)揮和動手的機(jī)會,對這些鍛煉我樂此不疲,接下來的大學(xué)生活都是在項(xiàng)目中度過(錯失了很多陪mm花前月下的機(jī)會~~~),那時候軟硬件都做(專門有中間人聯(lián)系或者朋友介紹),就大三一年下來的開發(fā)報酬剩下來的就大于10K(對于很多工作后的人來說這也算不了什么,明顯我也不是一個揮霍的人)。那時候在學(xué)校帶領(lǐng)著一個學(xué)生的科技團(tuán)體,為學(xué)校、組織爭得不少得榮譽(yù),這當(dāng)然也包括為自己。回想過去,更值得懷念得是那些志同道合的朋友們,有師兄、有同學(xué)還有師弟和體諒我的學(xué)院和老師……,無論是技術(shù)還是生活上都不能缺少,有著開心快樂的日子……!現(xiàn)在在一家公司做開發(fā),軟件硬件也不怎么分了,自從做了一個硬件項(xiàng)目后就好像轉(zhuǎn)向了軟件開發(fā)(懷疑在掉價,他們都說做硬件的吃香、干得久),反正現(xiàn)開的工作性質(zhì)還算開心愉快、又不怎么需要養(yǎng)家糊口的,所以生活還算輕松(就是回家后要自己做飯,嗚嗚~~~)。
說了這么多,我只想說明的一點(diǎn)是我并不是寫了幾個hello world就用C++在這里大呼小叫,一些經(jīng)驗(yàn)一些想法都是實(shí)踐的體會,拿上來獻(xiàn)丑不要介意p,很多時候只想分享一下開發(fā)中的愉悅,為求拋磚引玉。
技術(shù)從來都只是一種手段,一個好的方法可讓您少掉好幾根頭發(fā),養(yǎng)妻活兒我可不敢包,但是做一個sohu的開發(fā)人員總是可以的吧,若是自娛自樂的則有更高的境界和追求。
多掌握一門技能就就多一條出路,生活多了一把小刀,工作也就少一點(diǎn)磨難。知識和學(xué)問最終以經(jīng)驗(yàn)的形式沉淀在你的大腦中,是你終生受用!
說多了,就此罷了。注意:如有雷同,實(shí)屬巧合,切勿對號入座。
愿大家工作愉快!
BTW,今天開學(xué)了,非常懷念我遠(yuǎn)方的同學(xué)和朋友,愿他們身體健康,在生活及技術(shù)道路上一馬平川!
exdata 2004-9-1