概要
由於目前在做一個比較複雜的嵌入式專案,想要藉此提升一下程式碼的結構設計能力,所以想要以物件導向
的思想來完成這個專案,即把每個板載外設資源視為一個物件,採用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);
}
總結
基於物件導向的思想對於程式碼的結構和可讀性上都有一定的利處,特別在裸機編寫過程中,由於不受系統的干預,對於思路與框架的設計都清晰起來,目前還在不斷改善中,這種方式的缺陷也很明顯,只適用在靜態的情況,要想動態實現只有編譯器能操作了,但還是希望這種方式可以很好的在專案中使用。