好久沒更帖子了,寫這篇帖子有點底氣不足,畢竟沒有太深厚的內力(功底),算是借鑒心法總綱出來拋磚引玉吧,希望給道友們打開一片新的世界。
第一個疑惑點:單片機大部分情況下都是使用C語言進行開發,雖然IDE也支持C++,但是真正要用到C++的幾乎微乎其微,提起面向對象,腦子里第一個詞可能就是:C++。其實告訴你一個小秘密,linux操作系統絕大部分都是用C語言開發的,同樣應用了大量的面向對象的設計,也就是說,C語言的威力可能超乎我們的想象。
本篇帖子是以RT-thread中設備IO驅動框架的實現為例子(心法總綱)來聊一聊單片機的中分層技術和面向對象:
上圖是設備管理層的構架圖(分層思想一目了然),面向對象的類與繼承應用最多,這里我們只關注設備驅動框架層以下的三層,因為用到的是pin設備,比較特殊,她并沒有應用I/O設備管理層。
其實設備驅動的核心就是抽象出了一個設備對象,一切都圍繞著設備驅動對象展開,pin設備抽象類(結構體實現)如下:
Pin設備對象的定義如下:static struct rt_device_pin _hw_pin;
這里定義了一個設備實例,但是沒有對實例對象初始化,還無法具體的操作,因為其內部結構體成員為空。
接下來需要進行關鍵的一步,就是設備實例的初始化。
以下函數中進行hw_pin設備實例的初始化:
int rt_hw_pin_init(void)
{
#if defined(__HAL_RCC_GPIOA_CLK_ENABLE)
__HAL_RCC_GPIOA_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOB_CLK_ENABLE)
__HAL_RCC_GPIOB_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOC_CLK_ENABLE)
__HAL_RCC_GPIOC_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOD_CLK_ENABLE)
__HAL_RCC_GPIOD_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOE_CLK_ENABLE)
__HAL_RCC_GPIOE_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOF_CLK_ENABLE)
__HAL_RCC_GPIOF_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOG_CLK_ENABLE)
#ifdef SOC_SERIES_STM32L4
HAL_PWREx_EnableVddIO2();
#endif
__HAL_RCC_GPIOG_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOH_CLK_ENABLE)
__HAL_RCC_GPIOH_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOI_CLK_ENABLE)
__HAL_RCC_GPIOI_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOJ_CLK_ENABLE)
__HAL_RCC_GPIOJ_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOK_CLK_ENABLE)
__HAL_RCC_GPIOK_CLK_ENABLE();
#endif
return rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
}
關鍵的在于調用rt_device_pin_register函數,這個函數來自于設備驅動框架層,其中hw_pin對象也來自于設備驅動框架層。
輸入參數有注冊設備名稱”pin”,設備操作函數結構體指針_stm32_pin_ops,這兩個參數,通過上層注冊函數將hw_pin對象與底層的設備的操作函數建立聯系。
關于_stm32_pin_ops的結構體(其實C語言中的結構體,在面向對象中可以看作是類,結構體與實例,對應于類與對象的概念)原型如下:
接下來看一下rt_device_pin_register函數:
_hw_pin的parent成員是device類型對象,pin設備并沒有用到設備管理層API ,而是直接用的設備驅動框架層提供的API函數:
主要有以下幾個:
void rt_pin_mode(rt_base_t pin, rt_base_t mode); //設置引腳模式
void rt_pin_write(rt_base_t pin, rt_base_t value); //引腳電平輸出設置
int rt_pin_read(rt_base_t pin); //引腳電平輸入讀取
設備對象注冊函數rt_device_register(&_hw_pin.parent,name,RT_DEVICE_FLAG_RDWR);完成了對象管理器相關的注冊(實際是鏈表相關的操作):
執行之后,當系統運行起來以后,我們可以在shell命令窗口輸入list_device命令,查看系統當前所有的設備,會發現我們的設備成功注冊:
到這里,扔出來的磚就結束了,其實很想能夠將自己想表達的東西傳遞給大家,但是讀完寫的帖子又總覺得差強人意,如果筒子們對嵌入式軟件感興趣,一定要嘗試著去玩玩RTT,她會帶給你很多意想不到的收獲,底子扎實的又有機會的可以直接晉級嵌入式linux領域(其實多數RTOS都是linux的皮毛,學術角度,當然各有所長),她不止能帶給你高大上的趕腳: