概要 由於目前在做一個比較複雜的嵌入式項目,想要藉此提升一下代碼的結構設計能力,所以想要以面向對象的思想來完成這個項目,即把每個板載外設資源視為一個對象,採用msp+bsp的模式,對每個bsp外設實現對象化處理,現有方案需要手動傳入對象引用,調用方法時比較麻煩,所以考慮簡化調用方式。 面向對象實現思 ...
概要
由於目前在做一個比較複雜的嵌入式項目,想要藉此提升一下代碼的結構設計能力,所以想要以面向對象
的思想來完成這個項目,即把每個板載外設資源視為一個對象,採用msp+bsp
的模式,對每個bsp外設實現對象化處理,現有方案需要手動傳入對象引用,調用方法時比較麻煩,所以考慮簡化調用
方式。
面向對象實現思路
現有方案
對象就是具有屬性與方法的集合體,以LED
舉例,它的屬性就是埠
,引腳
,亮使能標誌
等,方法就是亮
,滅
。
瞭解到現有的c語言面向對象實現方法都需要手動傳入對象的引用,如下這種方式:
typedef struct _LED_TYPEDEF{
//屬性
struct _Privated_Attr{
GPIO_InitTypeDef GPIO_Body;
GPIO_TypeDef *GPIOx;
GPIO_PinState ENbit;
} Privated_Attr;
//方法
void (*LightUp)(struct _LED_TYPEDEF *);
void (*LightOff)(struct _LED_TYPEDEF *);
}LED_TypeDef;
上面的結構體中有一個嵌入的結構體變數,主要用途就是類似私有變數
,類外不可直接訪問的目的,也是出於屬性只由方法操作,這樣可以對屬性值的合理性做出一定限制與約束,然後方法的參數必須加入對象的引用
,也就是傳入對象地址。
此時調用方法為:
//實例化對象
LED_TypeDef BSP_LED1;
LED_TypeDef BSP_LED2;
//對象方法使用
BSP_LED1.LightUp(&BSP_LED1); //led1亮
BSP_LED2.LightOff(&BSP_LED2);//led2滅
這種方式比較麻煩,所以有必要引入c++
的this指針
方式。
this方案
目的:為了簡寫對象方法的調用模式。
所謂的this指針可以簡單理解為編譯器幫我們把對象引用傳遞到方法中了。
單一bsp方案
此單一bsp意為板子上只有這一個外設,所以這個bsp對象只需要一個this指針,以uart
舉例
typedef struct _UART_OBJ_TYPEDEF{
//屬性
struct _PrivateAttr{
uint16_t Buf_Cnt;
UART_HandleTypeDef UARTxHandler;
}PrivateAttr;
uint8_t Is_RX_OV;
uint8_t Is_RX_OK;
uint8_t RX_Buf[UART_RX_MAX_SIZE];
//方法
void (*SendChar)(struct _UART_OBJ_TYPEDEF *,uint8_t chr);
void (*SendStr)(struct _UART_OBJ_TYPEDEF *,uint8_t *str);
void (*ClearBuf)(void);
void (*ClearFlag)(void);
void (*BufAppend)(uint8_t byte);
uint16_t (*GetBufLength)(void);
}UART_Obj_TypeDef;
可以看到方法中不再需要手動傳入對象引用了。
UART_Obj_TypeDef UART_Debug_Obj; //實例化對象
static UART_Obj_TypeDef *mthis = &UART_Debug_Obj; //this指針實現對象引用
這樣就利用static
文件的作用域實現為每個bsp對象實現一個this
指針效果。
//將數據放入緩衝區
UART_Debug_Obj.BufAppend(res);
//清空緩衝區
UART_Debug_Obj.ClearBuf();
多個同類bsp方案
//bsp對象的this數組偏移量
#define BSP_LED1_OFFSET 0
#define BSP_LED2_OFFSET 1
//間接改變this的指向
#define BSP_LED1 (this_ledx = BSP_LED1_OFFSET);_BSP_LED1
#define BSP_LED2 (this_ledx = BSP_LED2_OFFSET);_BSP_LED2
struct _LED_TYPEDEF;
typedef struct _LED_TYPEDEF{
struct _Privated_Attr{
GPIO_InitTypeDef GPIO_Body;
GPIO_TypeDef *GPIOx;
GPIO_PinState ENbit;
} Privated_Attr;
void (*LightUp)(void);
void (*LightOff)(void);
}LED_TypeDef;
使用巨集定義的方式間接改變this
的指向
//實例化2個同類對象
LED_TypeDef _BSP_LED1;
LED_TypeDef _BSP_LED2;
//this指針與this數組
static LED_TypeDef* This_Arr[LED_NUM] = {&_BSP_LED1,&_BSP_LED2};
static LED_TypeDef* mthis;
//this指向偏移量(因為外面要用,所以名字不要衝突,最好和bsp對象相關)
uint8_t this_ledx = BSP_LED1_OFFSET;
//方法定義
void LightUp(){
mthis = This_Arr[this_ledx]; //通過this指針偏移來確定使用哪個對象
HAL_GPIO_WritePin(mthis->Privated_Attr.GPIOx,\
mthis->Privated_Attr.GPIO_Body.Pin,\
mthis->Privated_Attr.ENbit);
}
總結
基於面向對象的思想對於代碼的結構和可讀性上都有一定的利處,特別在裸機編寫過程中,由於不受系統的干預,對於思路與框架的設計都清晰起來,目前還在不斷改善中,這種方式的缺陷也很明顯,只適用在靜態的情況,要想動態實現只有編譯器能操作了,但還是希望這種方式可以很好的在項目中使用。
本文來自博客園,作者:pie_thn,轉載請註明原文鏈接:https://www.cnblogs.com/pie-o/p/17874200.html