歡迎您光臨本站 登入註冊首頁

uCos II C++類封裝篇

admin @ 2014-03-25 , reply:0

概述

   OO思想已經出現了20多年,各種成功的實踐告訴我們它是軟體開發的必然趨勢。面向對象編程(OOP)的一個關鍵原則之一就是封裝(encapsulation),把暴露的數……

    OO思想已經出現了20多年,各種成功的實踐告訴我們它是軟體開發的必然趨勢。面向對象編程(OOP)的一個關鍵原則之一就是封裝(encapsulation),把暴露的數據封裝起來,儘可能的讓對象管理它們自己的狀態,因為過多的依存性會造就緊耦合(highly coupled)系統,使得任何一點小小改動都可能造成許多無法預料的結果。而數據隱藏/封裝機制是一個控制對象數據和狀態強而有力的方法,它對外部世界隱藏其內部細節,這就意味著每一個對象都應該儘可能少的了解系統的其他部分或者被其他部分所了解,這樣一來一旦發生了變化,需要了解這一個變化的對象會比較少,因此變化也就相對容易地進行。

    C++之父Bjarne Stroustrup也曾說過:“你使用一個語言特徵是因為你需要它,而不是因為它存在”。設計ucClass(uCosII封裝類)的初衷是由於過去很多的實現都是在C++中完成,深切感受到面向對象分析、設計乃至編程的獨特魅力。回想微軟的MFC1為win32程序設計所帶來的便利、DriverWork2在PC硬體的驅動開發的高效,促使完成ucClass的設計(這裡頭沒有什麼高深的學問),其實更重要的一點是它能改進現有的設計模式,能讓今後的uCosII相關開發及維護變得更加輕鬆和高效!

    對於OO我也就幾年的開發經驗,沒有做過什麼“巨項”,對於ARM也是接觸時間不長,不過有一個概念一直影響著我,“ARM不就是複雜一點的單片機嗎”,我想也不應該難到那裡去。於是有空就玩玩,對於很多做這行做開發的對C++這樣的面向對象編程語言大多不甚了解,要想用OO思想來武裝自己又談何容易啊,這就是一種挑戰習慣、挑戰思維方式的行為,等於放棄過去曾經為你有效解決難題完成工作的開發模式。在此我也沒有什麼靈丹妙藥可改變這些處境,唯一的建議就是堅持及不斷實踐、只有這樣的思想基礎才能提高成功的機會。

    下面簡單設計一個ucClass的demo程序(當然會可能隱藏了一些bug or error),目標板使用的是菲利普LPC2100晶元(周立功的EasyARM 2100開發板),有些頭文件這裡就不貼了,旨在看看主程序的結構及設計過程,就讓一些軟體的大蝦們見笑了。

    若有機會的我還準備寫幾個基於OO之上的在嵌入式開發的應用demo……

設計需求:
使用ucClass設計一個demo程序完成下列任務:

任務編號    任務指責和功能描述    物理資源佔用
1    每間隔1秒蜂鳴器短促發聲兩次,每10秒間隔使用信號量通知任務2,隨後自身進入掛起等待狀態。    蜂鳴器及IO埠
2    無限等待由任務1觸發的信號量,當有信號時引發1秒蜂鳴器長鳴,其後恢復任務1,自身再次進入信號量的無限等待狀態中。    蜂鳴器及IO埠
3    孤立任務,簡單的一秒間隔led1閃爍。    Led1及IO埠
4    孤立任務,通過檢查key1按鍵狀態控制led4的二值狀態(亮/滅)。    key1,led4及IO埠

// main.cpp文件,ucClass測試主程序
// exdata 2004-8-18

#include "config.h"            // 一些硬體相關的聲明
#include "GPIO.H"            // GPIO類頭文件
#include "ucClass.H"        // uCosII的收集類庫頭文件
/*
// 在瀏覽demo程序時要注意以下幾點:
// 1,帶參數的對象構造
// 2,靜態函數調用
// 3,帶參數的派生類構造
// 4,虛擬函數重載
// 5,特別注意一些頭文件(不在此文檔中)包含寫法及原有C函數聲明方法,關注extern "C"
// 6,不拘泥於傳統的設計思想(模式)
// 7,比較不使用class時候又是如何處理的?分析每個對象背後隱藏了什麼?
*/

/************************** 全局變數 *****************************/

// 定義幾個task對象,這是實例化對象,隱藏並實現了任務棧的構造
CTask     t1(128);        // 參數是任務堆棧分配大小(在ARM中以32bit為單位)
CTask     t2(64);
CTask     t3(64);

CSem      t2WaitEvent;        // 定義一個信號量對象用於任務t1、t2通信
CGPIO     buzz("P0.7",1);    // 定義一個GPIO對象,輸出模式,用於控制蜂鳴器
/*
// 前置聲明幾個任務運行函數,這個與C模式下沒有什麼區別。
// 還保留這種處理方法僅僅為求兼顧一些使用uCosII習慣,建議參考CMyTask的
// 設計及t4的定義,使用子類設計實現具體任務的處理方法要比C模式的的全局
// 孤立啟動函數更具有設計上及維護上的優點,當做一個中大型項目時候效果尤
// 為明顯。
*/
void t1Run(void *p);
void t2Run(void *p);
void t3Run(void *p);

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

/*
// t1任務運行函數。
// 功能:每間隔1秒蜂鳴器短促發聲兩次,每10秒間隔使用信號量t2WaitEvent通
// 知任務t2,隨後自身進入掛起等待狀態。
*/
void t1Run(void *p)
{
    TargetInit();        // 初始化硬體目標板
   
    INT32U i = 0;
   
    while(1)
    {
        CuCos::TimeDlyHMSM(0,0,1,0);
       
        if(++i == 10)
        {
            i = 0;
            t2WaitEvent.Post();
            t1.Suspend();
        }
       
        // 蜂鳴器短促發聲兩次
        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任務運行函數。
// 功能:無限等待信號量t2WaitEvent,當有信號時引發1秒蜂鳴器長鳴,其後恢
// 復t1任務,任務t2再次自身進入信號量t2WaitEvent的無限等待狀態。
*/
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任務運行函數。
// 功能:簡單的一秒間隔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;
}

/*
// 為求原汁原味體現一個task對象的封裝,下面設計一個子類實現一個特定任務
// 的處理,在此我們可以認為一個任務就是一個子系統,通過一個子類表現一個
// 特有任務的具體屬性和行為,注意這種設計方法與傳統的面向對象編程模式是
// 有區別的。子系統是一個有自主能力主體,例如在MyTask子系統中我們有兩
// 個IO資源m_key1和m_led4分別對應著電路板上的按鍵Key1和發光二極體Led4,
// 通過檢查key1按鍵狀態控制led4的二值狀態(亮/滅)。重載基類了Run函數為
// 求體現類的封裝特性及表現一個任務的內聚能力,它是一個強制的運行介面,
// 當任務啟動時便能自動地從重載的Run函數開始運行(具體調用的中轉過程在
// 基類中已經實現)。
*/
class CMyTask : public CTask    // 注意這裡的派生關係!!!
{
public:
CMyTask(INT32U StkSize) : CTask(StkSize),m_key1("P0.16",0),m_led4("P0.25",1,0)
    {
        // 注意帶參數的構造處理方法!!!
    }
   
protected:
    virtual void Run(void *p);    // 需要重載Run()函數實現任務執行
   
private:
// 這是任務用到的一些資源定義,當然添加子系統的其他的屬性和方法也是允許的
    CGPIO m_key1;
    CGPIO m_led4;
};
/*
// t4任務運行函數。
// 通過函數重載實現重寫Run函數,該函數也就是任務運行函數。
// 功能:通過檢查key1按鍵狀態控制led4的二值狀態(亮/滅)。
*/
void CMyTask::Run(void *p)                    // Run函數將會被uCosII系統自動運行!
{
    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;
}
/*
// 注意一般應該把上面的CMyTask定義及實現另行寫在其他的文件中!把它寫在
// 這裡僅僅為求說明方便。
*/

/*-------------------------------------------------------------------------------------------------*/

CMyTask     t4(128);    //注意任務對象t4是由CMyTask實例化的對象

// 看看這個簡潔的main函數,這時候您想到了什麼?

int main()
{
    CuCos::Init();        // uCosII的系統函數,用於初始化uCosII,等效於OSInit()
   
    t2WaitEvent.Create();        // 創建t2WaitEvent的信號量
   
    // 創建任務(參數指定任務函數啟動地址、任務函數參數和優先順序)
    t1.Create(t1Run,NULL,1);   
    t2.Create(t2Run,NULL,2);
    t3.Create(t3Run,NULL,3);
   
    t4.Create(NULL,4);            // 創建任務,注意Create函數的重載
   
    CuCos::Start();            // 等效於OSStart()
   
    return 0;
   
}


[admin via 研發互助社區 ] uCos II C++類封裝篇已經有4793次圍觀

http://cocdig.com/docs/show-post-42870.html