一、代碼分析
本次分析的代碼非常簡(jiǎn)短
GPIO_QuickInit(HW_GPIOE, 6, kGPIO_Mode_OPP);
這句代碼的意思也和單一,就是將GPIOE模塊的第6引腳配置為推挽輸出方式。
但是內(nèi)部還是比較復(fù)雜的,其函數(shù)原型如下:
uint8_t GPIO_QuickInit(uint32_t instance, uint32_t pinx, GPIO_Mode_Type mode)
instance表示的是GPIO模塊號(hào);pinx表示引腳的標(biāo)號(hào),在0-31之間;mode表示引腳的使用模式。在gpio.h文件中有如下定義:
/* GPIO端口定義 */
#define HW_GPIOA (0x00U) /*GPIO模塊A,依次類推*/
#define HW_GPIOB (0x01U)
#define HW_GPIOC (0x02U)
#define HW_GPIOD (0x03U)
#define HW_GPIOE (0x04U)
#define HW_GPIOF (0x05U)//在數(shù)據(jù)手冊(cè)中是沒(méi)有GPIOF這個(gè)模塊的
/* GPIO 端口模式的定義*/
typedef enum
{
kGPIO_Mode_IFT = 0x00, /**< 浮空輸入 */
kGPIO_Mode_IPD = 0x01, /**< 下拉輸入 */
kGPIO_Mode_IPU = 0x02, /**< 上拉輸入 */
kGPIO_Mode_OOD = 0x03, /**< 開漏輸出 */
kGPIO_Mode_OPP = 0x04, /**< 推挽輸出 */
}GPIO_Mode_Type;
這個(gè)函數(shù)在gpio.c文件中的實(shí)現(xiàn)如下:
uint8_t GPIO_QuickInit(uint32_t instance, uint32_t pinx, GPIO_Mode_Type mode)
{
GPIO_InitTypeDef GPIO_InitStruct1;
GPIO_InitStruct1.instance = instance;
GPIO_InitStruct1.mode = mode;
GPIO_InitStruct1.pinx = pinx;
GPIO_Init(&GPIO_InitStruct1);
return instance;
}
在實(shí)現(xiàn)的過(guò)程中,在這里使用了一個(gè)結(jié)構(gòu)體變量GPIO_InitTypeDef,這個(gè)結(jié)構(gòu)體在gpio.h中定義如下:
typedef struct
{
uint8_t instance; ///<引腳端口HW_GPIOA~HW_GPIOF
GPIO_Mode_Type mode; ///<工作模式
uint32_t pinx; ///<引腳號(hào)0~31
}GPIO_InitTypeDef;
這樣,在GPIO初始化函數(shù)中的工作就和清楚了,就是將參數(shù)傳遞進(jìn)來(lái)完成結(jié)構(gòu)體的初始化。然后由GPIO_Init()函數(shù)完成初始化。到這里第一層的函數(shù)調(diào)用就結(jié)束了。
接下來(lái)是第二層的函數(shù)調(diào)用,也就是GPIO_Init()函數(shù).
由于這個(gè)函數(shù)過(guò)于復(fù)雜,這里只復(fù)制其中一部分代碼進(jìn)行分析,其他的大都是重復(fù)的結(jié)構(gòu)。這個(gè)函數(shù)內(nèi)部打功能大致是根據(jù)引腳的配置模式先進(jìn)行設(shè)置,然后再完成初始化,使用的代碼如下:
void GPIO_Init(GPIO_InitTypeDef * GPIO_InitStruct)
{
/* config state */
switch(GPIO_InitStruct->mode)
{
...
PORT_PinPullConfig(GPIO_InitStruct->instance, GPIO_InitStruct->pinx, kPullDisabled);
PORT_PinOpenDrainConfig(GPIO_InitStruct->instance, GPIO_InitStruct->pinx, DISABLE);
GPIO_PinConfig(GPIO_InitStruct->instance, GPIO_InitStruct->pinx, kOutput);
...
}
/* config pinMux */
PORT_PinMuxConfig(GPIO_InitStruct->instance, GPIO_InitStruct->pinx, kPinAlt1);
}
由此可見,第二層的函數(shù)調(diào)用內(nèi)部就是再次調(diào)用了四個(gè)函數(shù)。來(lái)進(jìn)行設(shè)置。依舊沒(méi)有涉及到真正的核心部分。
接下來(lái)我們進(jìn)入第三層的函數(shù)調(diào)用:
我現(xiàn)在逐個(gè)來(lái)進(jìn)行深入的分析,首先是第一個(gè)函數(shù):
PORT_PinPullConfig();
該函數(shù)的函數(shù)原型及實(shí)現(xiàn)如下:
void PORT_PinPullConfig(uint32_t instance, uint8_t pin, PORT_Pull_Type pull)
{
SIM->SCGC5 |= SIM_GPIOClockGateTable[instance];
switch(pull)
{
case kPullDisabled:
PORT_InstanceTable[instance]->PCR[pin] &= ~PORT_PCR_PE_MASK;
break;
case kPullUp:
PORT_InstanceTable[instance]->PCR[pin] |= PORT_PCR_PE_MASK;
PORT_InstanceTable[instance]->PCR[pin] |= PORT_PCR_PS_MASK;
break;
case kPullDown:
PORT_InstanceTable[instance]->PCR[pin] |= PORT_PCR_PE_MASK;
PORT_InstanceTable[instance]->PCR[pin] &= ~PORT_PCR_PS_MASK;
break;
default:
break;
}
}
該函數(shù)的功能就是通過(guò)編程人員選擇的引腳模式,對(duì)寄存器進(jìn)行配置,換句話說(shuō),到這里,就開始涉及到一些底層了。那么具體是如何做的呢?
首先,看第一句的代碼:
SIM->SCGC5 |= SIM_GPIOClockGateTable[instance];
對(duì)于這句代碼的分析如下:
在MK60D10.h文件中定義了如下語(yǔ)句:
#define SIM_BASE 0x40047000u
#define SIM (SIM_Type *)SIM_BASE
在這之中,SIM_Type 是一個(gè)結(jié)構(gòu)體,定義在MK60D10.h文件中。這兩句話表示:SIM是一個(gè)首地址為0x40047000的SIM_Type類型的結(jié)構(gòu)體。在這個(gè)結(jié)構(gòu)體中,定義了如下一句代碼:
__IO uint32_t SCGC5; /**< System Clock Gating Control Register 5, offset: 0x1038 */
其實(shí)到了這個(gè)地步,就是實(shí)實(shí)在在和底層硬件相關(guān)了。單單看注釋很簡(jiǎn)單,系統(tǒng)時(shí)鐘門控寄存器5,偏移0x1038.但是這幾句話什么意思呢?先放在這里!這幾天估計(jì)還不會(huì)有什么時(shí)間進(jìn)行系統(tǒng)的學(xué)習(xí),只是抽點(diǎn)時(shí)間零敲碎打。
今天的后面幾步是沒(méi)有什么時(shí)間做完了!明天繼續(xù),這兩天時(shí)間很緊,估計(jì)不會(huì)參閱什么文檔了!只是跟著代碼走,看到哪算哪!