代碼獲取
本文代碼託管於github上,歡迎各位star,https://github.com/zrw269113179/drv_pin
分層模型
分層模型可以使代碼的應用層邏輯與硬件解耦合,可以使你的代碼高度複用,完全解耦合,並且可以使你快速上手任意一款mcu。說了這麼多好處,如何具體實現?簡單來說就是定義一套統一的入口函數,無論什麼mcu都可以通過這套函數訪問硬件。
具體實現
本文講述的爲GPIO模型的具體實現。首先需要對GPIO模型進行抽象,顯而易見,GPIO只有2個功能,輸入和輸出。因此我們只需要完成以下這些函數:
1、pin_mode_set:端口模式設置
2、pin_write:端口輸出
3、pin_read:讀取端口電平
4、pin_irq_set:外部中斷設置
編寫完成這些函數後,在應用層只需要調用pin_write、pin_read就可以完成對端口的操作。
確定了函數名後,我們要對函數參數進行確定,因爲不同芯片對於GPIO的命名是不同的,有些芯片命名爲GPIOA、GPIOB…而有些命名爲GPIO1、GPIO2等,這裏我們拋棄芯片原有的port+pin來表示一個端口的模式,而直接用1234端口號來表示一個端口。
這裏我們以stm8l052舉例。
這裏我們用1來表示PA0,64表示PE7。
首先我們建立一張索引圖,將引腳號和端口名稱建立聯繫。
static unsigned char pin_map[] ={
(1 << 4) + 0, (1 << 4) + 1, (1 << 4) + 2, (1 << 4) + 3, (1 << 4) + 4, (1 << 4) + 5, (1 << 4) + 6,
(1 << 4) + 7, (0 << 4) + 0, (0 << 4) + 0, (0 << 4) + 0, (0 << 4) + 0, (0 << 4) + 0, (7 << 4) + 0,
(7 << 4) + 1, (7 << 4) + 2, (7 << 4) + 3, (0 << 4) + 0, (5 << 4) + 0, (5 << 4) + 1, (5 << 4) + 2,
(5 << 4) + 3, (5 << 4) + 4, (5 << 4) + 5, (4 << 4) + 0, (4 << 4) + 1, (4 << 4) + 2, (4 << 4) + 3,
(0 << 4) + 0, (0 << 4) + 0, (2 << 4) + 0, (2 << 4) + 1, (2 << 4) + 2, (2 << 4) + 3, (2 << 4) + 4,
(2 << 4) + 5, (2 << 4) + 6, (2 << 4) + 7, (6 << 4) + 0, (6 << 4) + 1, (6 << 4) + 4, (6 << 4) + 5,
(6 << 4) + 6, (6 << 4) + 7, (4 << 4) + 4, (4 << 4) + 5, (4 << 4) + 6, (4 << 4) + 7, (7 << 4) + 4,
(7 << 4) + 5, (7 << 4) + 6, (7 << 4) + 7, (3 << 4) + 0, (3 << 4) + 1, (0 << 4) + 0, (0 << 4) + 0,
(3 << 4) + 2, (3 << 4) + 3, (3 << 4) + 4, (3 << 4) + 5, (3 << 4) + 6, (3 << 4) + 7, (5 << 4) + 6,
(5 << 4) + 7
};
用一個unsigned char 表示存儲port和pin,其中前4位爲port號,1:GPIOA,2:GPIOB以此類推,後4位爲pin號,0:GPIO_Pin_0,1:GPIO_Pin_1以此類推,當數爲0((0 << 4) + 0)時表示該引腳沒有gpio功能(芯片上的vss,vdd等腳)。具體如何定義可以根據芯片靈活更改。
然後就可以編寫具體函數了,以pin_write()爲例:
void pin_write(unsigned char id, unsigned char level)
{
GPIO_TypeDef *port;
uint8_t pin;
switch (pin_map[id - 1] >> 4)
{
case 1:
port = GPIOA;
break;
case 2:
port = GPIOB;
break;
case 3:
port = GPIOC;
break;
case 4:
port = GPIOD;
break;
case 5:
port = GPIOE;
break;
case 6:
port = GPIOF;
break;
case 7:
port = GPIOG;
break;
default:
port = GPIOA;
break;
}
pin = 1 << (pin_map[id - 1] & 0xf);
if (level == 0)
{
GPIO_ResetBits( port, pin );
}
else
{
GPIO_SetBits( port, pin );
}
}
代碼很簡單,只需要調用pin_write(1,1);就可以使PA0輸出高電平了(不要忘了初始化)。
更換芯片
完成上述工作後,我們的應用層所有關於GPIO的代碼將通過這個drv_pin.c\drv_pin.h接管,又由於該文僅控制輸入輸出,所以當芯片更換後,只需更換drv_pin.c\drv_pin.h文件即可,新芯片的drv_pin.c\drv_pin.h只需完成drv_pin.h中的功能即可。
優缺點
優點
1、drv_pin.c和drv_pin.h只需編寫1遍即可重複使用,將這兩個文件交給新手,新手完全不需要重新讀datasheet就可以馬上上手,極大的減少項目時間,並且提高穩定性。
2、應用層完全與硬件隔離,應用層不再出現硬件提供的庫的代碼,這樣我們寫的一些其他組件就無需更改,如模擬iic、spi,當更換項目後就需要更改這些函數內部的代碼,如果使用drv_pin就不需要更改,有利於模塊的封裝。
缺點
因爲操作需要多一層代理,因此會佔用一些程序空間,在進行gpio操作時會略微增加一些運行時間(忽略不計)。
總體來說還是優點大於缺點的。