STM32F103VET6學習(3)

一.前言

這次的對象仍然是LED的點亮,不過由此開始就是自己寫庫函數實現。

也就是外設的最初定義與封裝是自己完成的。同樣也是結合數據手冊來寫。因爲我寫的是用C語言,對於編譯器來說它什麼都不知道,因此所有的定義都不能想當然。爲了使地址與寄存器一一對應,在定義地址時,就以寄存器的名字來對應相應的地址,這樣見名知意也方便。
有人可能不好找到數據手冊,附在下面,自提即可。

中文數據手冊:
鏈接:https://pan.baidu.com/s/12G6-A_V2b-v7itHy_oy3Vw
提取碼:df9b

英文數據手冊:
鏈接:https://pan.baidu.com/s/1uDyv1Yl7K-0tV3h6VY-p9g
提取碼:en4u

二.正文

正文有兩大部分內容,簡介如下:
(1)基址的宏定義以及寄存器的封裝,放在stm32f10x_gpio.h文件中
(2)端口操作與設置函數,放在stm32f10x_gpio.c文件中

1.基址宏定義與寄存器的封裝

基址部分要定義的就是總線的地址,通過數據手冊知道有APB1、AHB、APB2總線三條總線,每條總線上都掛有寄存器:
存儲器映像
因此基於此,便可以進行寄存器的定義。
在這裏的截圖我並沒有截全,只是表示在總線上掛有寄存器的意思。下來的基址宏定義就根據這個來寫,我會分別截圖來看的。
通過上圖可以看到,對於每一條總線,其上寄存器的地址都是自下而上的分佈,也就是下面的數值小,往上依次增加,注意是每條總線的地值範圍。下來就開始寫地址的定義。
1.總線基址的宏定義

首先,通過下圖截圖可以看到:
總線地址
總線的地址從APB1總線開始,最小的是0x4000 0000,而其他的總線基地址都是在0x4000 0000 基礎上的偏移,故將0x4000 0000作爲總線的基地址:

#define PERIPH_BASE 0x40000000

總線APB1搭載低速外設,APB2搭載高速外設,我使用高速外設,因此在此就不定義APB1總線的基地址。
APB2總線基地址
從數據手冊的截圖可以看到,APB2總線的基地址是在總線PERIPH_BASE的基礎上加了0x0001 0000,也就是加了0x1 0000,因此以此作爲APB2總線的基地址:

#define APB2PERIPH_BASE (PERIPH_BASE+0x10000)

AHB總線上掛載了外設時鐘,在第一次就說過外設時鐘必須要打開,因此AHB總線的基地址也要定義。
AHB總線基地址
與剛纔的思想相同,由於我要用的是RCC時鐘,因此定義AHB總線就仍從PERIPH_BASE總線的基礎上定義,之後在定義RCC時就在AHBPERIPH_BASE基礎上定義。因此定義AHB總線基地址爲

#define AHBPERIPH_BASE (PERIPH_BASE+0x20000)

2.寄存器的定義
爲了方便,對無符號整型和無符號短整型的變量類型定義別名:

typedef unsigned int uint32_t;
typedef unsigned short uint16_t;

下來是爲了防止編譯器優化變量,使用volatile關鍵字。有些變量在未用時,CPU會從緩存中隨機取值作爲變量的值,籍此提高執行速度。而我們爲了讓變量保持不變,就要防止自動優化。
同樣也給這個關鍵字用宏定義取個別名:

#define __IO volatile

下來就是封裝GPIO寄存器和RCC外設時鐘結構體,待用。

typedef struct
{
	__IO uint32_t CRL;    //端口配置低寄存器,地址偏移0x00
	__IO uint32_t CRH;    //端口配置高寄存器,地址偏移0x04
	__IO uint32_t IDR;    //端口數據輸入寄存器,地址偏移0x08
	__IO uint32_t ODR;    //端口數據輸出寄存器,地址偏移0x0C
	__IO uint32_t BSRR;   //端口位設置/清除寄存器,地址偏移0x10
	__IO uint32_t BRR;    //端口位清除寄存器,地址偏移0x14
	__IO uint32_t LCKR;   //端口配置鎖定寄存器,地址偏移0x18
}GPIO_TypeDef;

typedef struct
{
	__IO uint32_t APB2ENR;
}RCC_TypeDef;

下來就是各個GPIOx(x=A,B,…,G)和RCC的定義。看數據手冊:
APB2
可以看到這7個GPIO口(GPIOA - GPIOG)的地址有規律。自下而上,高四位都是4001,也就是剛纔定義的APB2PERIPH_BASE的地址的高四位,不同之處就在於低四位的三四位,GPIOA從0800開始,每次加4(十六進制加法),便得到了這七個口的基地址:

#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
#define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00)
#define GPIOG_BASE (APB2PERIPH_BASE + 0x2000)

爲了一致性,在這裏把RCC外設的基址也定義了(RCC外設是掛載在AHBPERIPH_BASE總線上的):

#define RCC_BASE (AHBPERIPH_BASE + 0x1000)

同時由於這七個口每個下面都有剛纔定義的7個寄存器(BSR,BSRR,ODR,IDR,…),而這7個寄存器都是被封裝在了結構體GPIO_TypeDef中,因此要能使用這7個寄存器,並能具體指明使用哪個,就必須把GPIOA-GPIOG對應的總線強制轉換爲GPIO_TypeDef類型的指針:

/*GPIO外設聲明*/
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)
#define GPIOG ((GPIO_TypeDef *) GPIOG_BASE)

這樣就把變量名與真實的寄存器的地址對應起來了。
同樣,也需要RCC外設的聲明:

//RCC外設的聲明
#define RCC ((RCC_TypeDef *) RCC_BASE)
//RCC的AHB1時鐘使能寄存器的地址,強制轉換成指針
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE + 0x18)

3.管腳定義
在之前定義管腳時,用的都是0x01左移若干位來操作的。這樣還是有些不方便,因此對管腳也來一個方便使用的定義。設置輸出高電平,我們用BSRR寄存器(也就是 端口位設置/清除寄存器),輸出低電平用的是BRR寄存器。看下BSRR寄存器的說明:
BSRR寄存器
可以看到BSRR寄存器的0-15這16位是設置端口位輸出電平的,而16-31這16位則是清除前面0-15這16位的。而BRR寄存器的高16位保留不可操作,低16位用於清除端口位,也就是設置爲低。因此只需要定義0-15號管腳這16個管腳就可以了,而且直接把1左移n位(n=0,1,2,…,15)的結果計算出來賦值給對應的管腳即進行宏定義,之後直接使用即可:

#define GPIO_Pin_0 ((uint16_t)0x0001)
#define GPIO_Pin_1 ((uint16_t)0x0002)
#define GPIO_Pin_2 ((uint16_t)0x0004)
#define GPIO_Pin_3 ((uint16_t)0x0008)
#define GPIO_Pin_4 ((uint16_t)0x0010)
#define GPIO_Pin_5 ((uint16_t)0x0020)
#define GPIO_Pin_6 ((uint16_t)0x0040)
#define GPIO_Pin_7 ((uint16_t)0x0080)
#define GPIO_Pin_8 ((uint16_t)0x0100)
#define GPIO_Pin_9 ((uint16_t)0x0200)
#define GPIO_Pin_10 ((uint16_t)0x0400)
#define GPIO_Pin_11 ((uint16_t)0x0800)
#define GPIO_Pin_12 ((uint16_t)0x1000)
#define GPIO_Pin_13 ((uint16_t)0x2000)
#define GPIO_Pin_14 ((uint16_t)0x4000)
#define GPIO_Pin_15 ((uint16_t)0x8000)
#define GPIO_Pin_ALL ((uint16_t)0xFFFF)

2.工作模式與速率的配置

1.說明:
輸出速率有三種(輸入不講速率),分別是2MHz、10MHz和50MHz;工作模式有多種,先分輸入和輸出,輸入又分爲模擬輸入、浮空輸入、上拉輸入和下拉輸入,輸出分爲開漏輸出、推輓輸出、複用開漏輸出和複用推輓輸出。在選用模式和速率時,這些有多種搭配,逐一列出來就很麻煩,因此同樣將它們分別封裝成結構體,採用枚舉類型,也就是將所有的速率封裝、所有的模式封裝,這樣就有兩個結構體,最後再在一個新的結構體中定義前兩種結構體類型的變量作爲分別的工作模式與速率的選擇,再定義一個選擇管腳的變量即可。由於管腳數並沒那麼多,因此定義其變量類型爲無符號short型就可以了。
2.代碼實現
(1)速率結構體配置
速率的配置可以在數據手冊中查到,如下圖:
速率配置
對照着上表可以,同時爲了見名知意,方便起見,寫出GPIOSpeed_TypeDef結構體如下:

typedef enum
{
	GPIO_Speed_10MHz = 0x01,   //10MHz,  (01)B
	GPIO_Speed_2MHz = 0x02,    //2MHz,   (10)B
	GPIO_Speed_50MHz = 0x03    //50MHz,  (11)B
}GPIOSpeed_TypeDef;

(2)工作模式的配置(8種)
工作模式有8種好理解,主要是其取值有些不好看,如下表:
工作模式配置
從上表可以看到如下幾點:

  • 工作模式有8個bit位
  • bit4決定輸入還是輸出,寫0輸入,寫1輸出
  • bit3和bit2對應的是CNF[1:0]位,是真正要寫入到CRH和CRL寄存器中的值。爲輸入模式時,bit3和bit2分別爲00、01則分別爲模擬輸入和浮空輸入。
  • bit1和bit0應的是MODE[1:0]位,暫時不用理會。
  • bit6和bit5用於區分上、下拉輸入,這個取值是可以自擬的,爲了區分,以01表示下拉輸入,10表示上拉輸入。

因此,就可以寫出定義工作模式的結構體GPIOMode_TypeDef:

typedef enum
{
	GPIO_Mode_AIN = 0X00,    //模擬輸入
	GPIO_Mode_IN_FLOATING = 0x04,   //浮空輸入
	GPIO_Mode_IPD = 0X28,       //下拉輸入
	GPIO_Mode_IPU = 0X48,      //上拉輸入
	
	GPIO_Mode_Out_OD = 0X14,   //開漏輸出
	GPIO_Mode_Out_PP = 0X10,   //推輓輸出
	GPIO_Mode_AF_OD = 0X10,    //複用開漏輸出
	GPIO_Mode_AF_PP = 0X18     //複用推輓輸出
}GPIOMode_TypeDef;

(3)結構體GPIO_InitTypeDef:

typedef struct
{
	uint16_t GPIO_Pin;      //管腳
	GPIOSpeed_TypeDef GPIO_Speed;   //速率
	GPIOMode_TypeDef GPIO_Mode;     //工作模式
}GPIO_InitTypeDef;

在此定義的管腳,剛有說過了。之後如果再定義一個GPIO_InitTypeDef類型的結構體變量,就可以調用GPIO_InitTypeDef這個結構體的各個屬性,然後就可以把與之對應的枚舉類型的結構體的成員進行“使用”。比如:

GPIO_InitTypeDef GPIO_InitStructure;   //定義結構體類型的變量
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;   //速率爲10MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //開漏輸出

這是使用的一個例子,有註釋很詳細,也不難理解,不再解釋了。

3.操作函數

操作函數有三個,分別是高電平輸出函數、低電平輸出函數和GPIO初始化函數(初始化包括管腳選擇、工作模式選擇等)。前面寫的內容都是寫在stm32f10x_gpio.h文件中的初始定義,下來纔是真正的對單片機操作的函數,而這裏的內容有了之前的初始定義後就相對好多了,這部分的內容全部寫在stm32f10x_gpio.c文件中,具體如下。
1.高電平輸出函數
具體直接看代碼就可以了,有的地方如果不明白可以翻回去再看看之前的結構體定義:

/*
函數名:GPIO_SetBit(),Set就是設置的意思,Bit就是位
參數說明:
(1)GPIOx:GPIO_TypeDef類型的的指針,x可以爲A~G
(2)GPIO_Pin:GPIO管腳,可以取GPIO_Pin_0 ~ GPIO_Pin_15
*/
void GPIO_SetBit(GPIO_TypeDef* GPIOx, uint32_t GPIO_Pin)
{
	/*BSRR寄存器用來設置高電平*/
	GPIOx->BSRR = GPIO_Pin;
}

2.低電平輸出函數

/*
函數名:GPIO_ResetBit(),Reset就是重置的意思,認爲其爲0
*/
void GPIO_ResetBit(GPIO_TypeDef* GPIOx, uint32_t GPIO_Pin)
{
	/*BRR寄存器用來設置低電平*/
	GPIOx ->BRR = GPIO_Pin;
}

3.GPIO初始化函數
這個函數十分重要,是整個程序的核心。在此要設置的是,CRH和CRL兩個寄存器,在之前我們也看過了,配置其輸出時主要就是這兩個寄存器。簡單概括的說,前面做好了寄存器等的定義,在這裏就要把這些定義和配置統統利用起來並燒錄到板子裏面去,而這個就是讓板子對這一切做一個初始化的準備的過程。
CRH和CRL寄存器的配置幾乎一樣,主要不同在於一個是低位,一個是高位,只要注意位的高低與對應的寄存器L、H即可了。
下面是代碼,有詳細的註釋,死磕是一定可以理解的:

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
	uint32_t currentmode = 0x00, currentpin = 0x00,pinpos=0x00,pos=0x00;
	uint32_t temreg=0x00,pinmask=0x00;
	
	/*----------------GPIO模式配置---------------------*/
	
	//將已有狀態的低四位保存到currentmode中
	currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & (uint32_t)(0x0F);
	
	//先判斷是輸入還是輸出,即判斷bit4是1還是0
	if((((uint32_t)GPIO_InitStruct->GPIO_Mode) & (uint32_t)(0x10)) != 0)
	{
		//如果爲輸出就配置輸出速度
		currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
	}

	/*-------------配置GPIO_CRL寄存器,即配置低八位------------*/
	
	if(((uint32_t)GPIO_InitStruct->GPIO_Pin & 0x00FF) != 0x00)
	{
		temreg = GPIOx->CRL;   //先讀取原來低八位的狀態並暫存
		//逐位匹配來找到是哪個管腳
		for(pinpos=0x00;pinpos<0x08;pinpos++)
		{
			pos = (uint32_t)0x01 << pinpos;
			currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
			if(currentpin == pos)
			{
				pos = pinpos<<2; //相當於乘以4,因爲每個管腳對應四位
				
				//將這四位清零,其他位狀態保留
				pinmask = ((uint32_t)0x0F) >> pos;
				temreg &= ~pinmask;
				
				//給這四位寫入模式配置,保留其他位原先的設置
				temreg |= (currentmode << pos);
				
				/*是否爲下拉輸入*/
				if(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)  
				{
					//爲下拉輸入則將BRR寄存器寫1,使對應位置0
					GPIOx->BRR = (uint32_t)0x01 << pinpos;
				}
				else
					/*是否爲上拉輸入*/
					if(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)  
					{
						//爲上拉輸入則將BSRR寄存器寫1,使對應位置1
						GPIOx->BSRR = (uint32_t)0x01 << pinpos;
					}
			}
		}
	}
	//將處理後的狀態寫入到CRL寄存器當中
	GPIOx->CRL = temreg;
	
	/*-----------配置GPIO_CRH寄存器,即配置高八位---------------*/
	if(GPIO_InitStruct->GPIO_Pin > 0x00FF)
	{
		temreg = GPIOx->CRH;   //先讀取原來的高八位的狀態並暫存
		
		//逐位匹配,找到具體的Pin
		for(pinpos=0x00;pinpos<0x08;pinpos++)
		{
			pos = (((uint32_t)0x01) << (pinpos+0x08));
			currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
			if(currentpin == pos)
			{
				pos = pinpos << 2;
				
				//把這四位清零,其他位保留不變
				pinmask = ((uint32_t)0x0F) << pos;
				pos &= ~pinmask;
				
				temreg |= currentmode << pos;
				
				//是否爲下拉輸入
				if(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)  
				{
					GPIOx->BRR = (uint32_t)0x01 << (pinpos + 0x08);
				}
				else
					/*是否爲上拉輸入*/
					if(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)  
					{
						GPIOx->BSRR = (uint32_t)0x01 << (pinpos+0x08);
					}
			}
		}
		GPIOx->CRH = temreg;
	}
}

至此,就把GPIO初始化函數寫完了,所有的宏定義呀、配置函數等等的,全部都寫完了。最後就是具體的利用這些函數來實現點亮LED的功能了。
4.主函數main()
在主函數裏,完成我們想要實現的功能就可以了。這裏實現的是點亮LED,在上一次看過的原理圖就知道是低有效。如果是綠色的,對應Pin0管腳;如果是紅色,對應的是Pin5管腳。在主函數之外,還需要一個SystemInit()函數來“騙過”編譯器不報錯,具體原因上次說過了,這次就不說啦。下面是主函數和SystemInit()中的代碼:

int main(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;   //定義GPIO初始化結構體變量
	
	//開啓外設時鐘
	RCC_APB2ENR |= (1<<3);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;      //0號管腳
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //工作模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; //輸出速率
	
	GPIO_Init(GPIOB, &GPIO_InitStructure);   //GPIO初始化工作
	GPIO_ResetBit(GPIOB, GPIO_Pin_0);   //讓GPIOB的0號管腳輸出低電平
	
	while(1);
}
void SystemInit()
{
}

4.全部代碼

由於代碼從Keil5複製過來後中文部分會亂碼,所以我把註釋刪除了。這部分內容看了挺久了,真的不想再去重複做這個工作了,有點懶,但不要怪我。剛好要是有人看下面的,還可以自己給自己解釋。
工程文件結構如下圖所示:
The Structure Of The Project

:其中的stm32f103.h和stm32f10x_gpio.h其實就是我說的stm32f10x_gpio.h文件,我開始時比較生疏,所以就分開寫了,不過是可以放在一起的。stm32f10x_gpio.h和stm32f10x_gpio.c這兩者是需要自己寫的,如下是全部的代碼。

(1)stm32f10x_gpio.h文件

#define  __IO volatile
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;

typedef struct
{
	__IO uint32_t CRL;   
	__IO uint32_t CRH;   
	__IO uint32_t IDR;   
	__IO uint32_t ODR;   
	__IO uint32_t BSRR;  
	__IO uint32_t BRR;  
	__IO uint32_t LCKR; 
}GPIO_TypeDef;

typedef struct
{
	__IO uint32_t APB2ENR;
}RCC_TypeDef;

#define PERIPH_BASE ((unsigned int)0x40000000)
	
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)


#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
#define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00)
#define GPIOG_BASE (APB2PERIPH_BASE + 0x2000)


#define RCC_BASE (AHBPERIPH_BASE + 0x1000)


#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)
#define GPIOG ((GPIO_TypeDef *) GPIOG_BASE)

#define RCC ((RCC_TypeDef *) RCC_BASE)
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE + 0x18)

#define GPIO_Pin_0 ((uint16_t)0x0001)
#define GPIO_Pin_1 ((uint16_t)0x0002)
#define GPIO_Pin_2 ((uint16_t)0x0004)
#define GPIO_Pin_3 ((uint16_t)0x0008)
#define GPIO_Pin_4 ((uint16_t)0x0010)
#define GPIO_Pin_5 ((uint16_t)0x0020)
#define GPIO_Pin_6 ((uint16_t)0x0040)
#define GPIO_Pin_7 ((uint16_t)0x0080)
#define GPIO_Pin_8 ((uint16_t)0x0100)
#define GPIO_Pin_9 ((uint16_t)0x0200)
#define GPIO_Pin_10 ((uint16_t)0x0400)
#define GPIO_Pin_11 ((uint16_t)0x0800)
#define GPIO_Pin_12 ((uint16_t)0x1000)
#define GPIO_Pin_13 ((uint16_t)0x2000)
#define GPIO_Pin_14 ((uint16_t)0x4000)
#define GPIO_Pin_15 ((uint16_t)0x8000)
#define GPIO_Pin_ALL ((uint16_t)0xFFFF)

typedef enum
{
	GPIO_Speed_10MHz = 0x01,
	GPIO_Speed_2MHz = 0x02,
	GPIO_Speed_50MHz = 0x03
}GPIOSpeed_TypeDef;

typedef enum
{
	GPIO_Mode_AIN = 0X00,
	GPIO_Mode_IN_FLOATING = 0x04,
	GPIO_Mode_IPD = 0X28,
	GPIO_Mode_IPU = 0X48,
	
	GPIO_Mode_Out_OD = 0X14,  
	GPIO_Mode_Out_PP = 0X10,   
	GPIO_Mode_AF_OD = 0X10,    
	GPIO_Mode_AF_PP = 0X18    
}GPIOMode_TypeDef;


typedef struct
{
	uint16_t GPIO_Pin;
	GPIOSpeed_TypeDef GPIO_Speed;
	GPIOMode_TypeDef GPIO_Mode;
}GPIO_InitTypeDef;

(2)stm32f10x_gpio.c文件

#include"stm32f10x_gpio.h"

void GPIO_SetBit(GPIO_TypeDef* GPIOx, uint32_t GPIO_Pin)
{
	GPIOx->BSRR = GPIO_Pin;
}

void GPIO_ResetBit(GPIO_TypeDef* GPIOx, uint32_t GPIO_Pin)
{
	GPIOx ->BRR = GPIO_Pin;
}

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
	uint32_t currentmode = 0x00, currentpin = 0x00,pinpos=0x00,pos=0x00;
	uint32_t temreg=0x00,pinmask=0x00;

	currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & (uint32_t)(0x0F);
	
	if((((uint32_t)GPIO_InitStruct->GPIO_Mode) & (uint32_t)(0x10)) != 0)
	{
		currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
	}


	if(((uint32_t)GPIO_InitStruct->GPIO_Pin & 0x00FF) != 0x00)
	{
		temreg = GPIOx->CRL;  
		for(pinpos=0x00;pinpos<0x08;pinpos++)
		{
			pos = (uint32_t)0x01 << pinpos;
			currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
			if(currentpin == pos)
			{
				pos = pinpos<<2; 
				
				pinmask = ((uint32_t)0x0F) >> pos;
				temreg &= ~pinmask;
				
				temreg |= (currentmode << pos);
				
				if(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)  
				{

					GPIOx->BRR = (uint32_t)0x01 << pinpos;
				}
				else
					if(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)  
					{
						GPIOx->BSRR = (uint32_t)0x01 << pinpos;
					}
			}
		}
	}

	GPIOx->CRL = temreg;
	
	if(GPIO_InitStruct->GPIO_Pin > 0x00FF)
	{
		temreg = GPIOx->CRH;  
		
		for(pinpos=0x00;pinpos<0x08;pinpos++)
		{
			pos = (((uint32_t)0x01) << (pinpos+0x08));
			currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
			if(currentpin == pos)
			{
				pos = pinpos << 2;
				
				pinmask = ((uint32_t)0x0F) << pos;
				pos &= ~pinmask;
				
				temreg |= currentmode << pos;
				
				if(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)  
				{
					GPIOx->BRR = (uint32_t)0x01 << (pinpos + 0x08);
				}
				else
					if(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)   
					{
						GPIOx->BSRR = (uint32_t)0x01 << (pinpos+0x08);
					}
			}
		}
		GPIOx->CRH = temreg;
	}
}

int main(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2ENR |= (1<<3);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
	
	GPIO_Init(GPIOB, &GPIO_InitStructure);   
	GPIO_ResetBit(GPIOB, GPIO_Pin_0);    
	while(1);
}
void SystemInit()
{
}

三.結語

看了上面沒有註釋的代碼,我承認我看了我也想打人。但是我就懶這麼一下,真的累了,也想着急去看下來的新的內容。這部分看懂用了兩三天,這個博客斷斷續續也寫了兩三天,一下子就是一個周啊!下來得趕緊抓緊時間,提高自己的效率,畢竟還得複習準備考研。就這樣吧,本次拖拖拉拉,但是總算有個頭兒了。
本次內容就到這裏,完結!
(Tip:文首有STM32F10x的中英文數據手冊的百度雲鏈接哦)

發佈了11 篇原創文章 · 獲贊 13 · 訪問量 5614
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章