Tangwx

Tangwx

博客网站

03.STM32 GPIO通用輸入輸出口

3 GPIO 通用輸入輸出口#

3.1 GPIO 簡介#

GPIO(General Purpose Input Output)通用輸入輸出口

可配置為 8 種輸入輸出模式

引腳電平:0V~3.3V,部分引腳可容忍 5V

輸出模式下可控制端口輸出高低電平,用以驅動 LED、控制蜂鳴器、模擬通信協議輸出時序等

輸入模式下可讀取端口的高低電平或電壓,用於讀取按鍵輸入、外接模塊電平信號輸入、ADC 電壓採集、模擬通信協議接收數據等

3.2 GPIO 基本結構#

在 STM32 中,所有的 GPIO 都是掛載在 APB2 外設總線上的,其中 GPIO 的名稱是按照 GPIOA、GPIOB、GPIOC 等來命名的,每個 GPIO 外設都有 16 個引腳,編號是從 0 到 15,再每個 GPIO 模塊內,主要包含了寄存器和驅動器這些東西,寄存器就是一段特殊的存儲器,內核可以通過 APB2 總線對寄存器進行讀寫,這樣就可以完成輸出電平和讀取電平的功能了。這個寄存器的每一位對應一個引腳,其中輸出寄存器寫 1,對應的引腳就會輸出高電平,寫 0 就會輸出低電平。輸入寄存器讀取為 1 說明對應的端口目前是高電平,讀取為 0 說明是低電平。因為 STM32 是 32 位的單片機,所以 STM32 內部的寄存器都是 32 位的,但端口只有 16 位,所以這個寄存器只有低 16 位對應的有端口,高 16 位沒有用到。這個驅動器是用來增加信號的驅動能力的,寄存器只負責存儲數據,如果要進行點燈這樣的操作的話,還是需要驅動器來負責增大驅動能力,這些就是 GPIO 的整體基本結構了。

image-20220821193133744

3.3 GPIO 位結構#

GPIO 中每一位的具體電路結構,下圖為 STM32 參考手冊中的 GPIO 位結構的電路圖,左邊 3 個是寄存器,中間這部分是驅動器,右邊是某一個 IO 口的引腳。整體結構可以分為兩部分,上半部分為輸入部分,下半部分為輸出部分。

3.3.1 輸入部分#

引腳處接了兩個保護二極管,對輸入電壓進行限幅,上面二極管接 VDD-3.3V,下面接 VSS-0V。若輸入電壓比 3.3V 高,則上方這個二極管導通,輸入電壓產生的電流就會直接流入 VDD 而不流入內部電路,這樣就可以避免過高的電壓對內部這些電路產生傷害。若輸入電壓比 0V 低,這個電壓是相對於 VSS 的電壓,所以是可以有負電壓的,此時下方這個二極管導通,電流從 VSS 直接流出去,不會從內部電路汲取電流,這樣也是可以保護內部電路的。若輸入的電壓在 0~3.3V 之間,此時兩個二極管均不導通,二極管對電路沒有影響,這就是保護二極管的用途。電流經過上拉電阻和下拉電阻,上拉電阻至 VDD,下拉電阻至 VSS,這個開關是可以通過程序進行配置的,如果上面導通、下面斷開,就是上拉輸入模式;如果下面導通、上面斷開,就是下拉輸入模式;如果兩個都斷開,就是浮空輸入模式。上拉和下拉是為了給輸入提供一個默認的輸入電平,對於一個數字端口,輸入不是高電平就是低電平,如果輸入啥都不接,這時輸入就會處於一種浮空狀態,引腳的輸入電平極易受外界干擾而改變,所以為了避免引腳懸空導致的輸入數據不確定,我們就需要在這裡加上上拉或下拉電阻。若接入上拉電阻,當引腳懸空時還有上拉電阻來保證引腳的高電平,所以上拉輸入又可以稱為默認高電平的輸入模式;下拉也是同理,默認為低電平的輸入方式。上拉電阻和下拉電阻的阻值都是比較大的,是一種弱上拉和弱下拉,目的是儘量不影響正常的輸入操作。TTL 肖特基觸發器這裡應該是施密特觸發器,作用是對輸入電壓進行整形,他的執行邏輯是,當輸入電壓大於某一閾值,輸出就會瞬間升為高電平,當輸入電壓小於某一閾值,輸出就會瞬間降為低電平。對於施密特觸發器來說,只有高於上限或低於下限輸出才會變化。經過施密特觸發器整型的波形就可以直接寫入數據寄存器內,我們再用程序讀取輸入數據寄存器對應某一位的數據,就可以知道端口的輸入電平了。模擬輸入是連接到 ADC 上的,因為 AD 需要接收模擬量,所以這根線需要接到施密特觸發器前面的,另一個是復用功能輸入,這個是連接到其他需要讀取端口外設上的,例如串口的輸入引腳等,這根線接收的是數字量,所以跟在施密特觸發器後面

3.3.2 輸出部分#

數字部分由輸出數據寄存器或片上外設控制,通過數據選擇器接到輸出控制部分,如果選擇通過輸出數據寄存器進行控制,就是普通的 IO 口輸出,寫這個數據寄存器的某一位就可以操作對應的某個端口。左邊還有一個位設置 / 清除寄存器,用來單獨操作輸出數據寄存器的某一位而不影響其他位,這個輸出數據寄存器同時控制 16 個端口,並且這個寄存器只能整體讀寫,若想單獨控制其中某一個端口而不影響其他端口的話,需要一些特殊的操作方式。第一種操作方式是先讀出這個寄存器,然後用按位與&=和按位或|=的方式來更改某一位,最後再將更改後的數據寫回去。這種方法比較麻煩且效率不高,對於 IO 口的操作而言不太合適。第二種方式就是通過設置這個位設置 / 清除寄存器,如果我們要對某一位進行置一的操作,在位設置寄存器的對應位寫一即可,剩下不需要操作的位寫 0,這樣它內部就會有電路自動將輸出數據寄存器中對應位置為 1,其他寫 0 的位置保持不變。這樣就保證了只操作其中一位而不影響其它位,並且這是一部到位的操作。如果想對某一位進行清零的操作,就在位清除寄存器的對應位寫 1 即可,這樣內部電路就會把這一位清零了。另外還有第三種操作方式,就是讀寫 STM32 中的位帶區域,這个位帶的作用就跟 51 單片機的位尋址作用差不多,在 STM32 中,專門分配的有一段地址區域,這段地址映射了 RAM 和外設寄存器的所有位,讀寫這段地址中的數據就相當於讀寫所映射位置的某一位,這就是位帶的操作方式,這個方式我們本課程暫不使用,我們主要使用庫函數來操作,庫函數使用的就是讀寫位設置 / 清除寄存器的方法。輸出控制之後就接到了兩個 MOS 管,上面是P-MOS,下面是N-MOS,這個 MOS 管就是一種電子開關,我們的信號來控制開關的導通和關閉,開關負責將 IO 口接到VDDVSS,在這裡可以選擇推挽、開漏或者關閉三種輸出方式。在推挽輸出下,P-MOSN-MOS均有效,數據寄存器為 1 時,上管導通,下管斷開,輸出直接接到 VDD,就是輸出高電平;數據寄存器為 0 時,上管斷開,下管導通,輸出直接接到 VSS,就是輸出低電平。這個模式下,高低電平均有較強的驅動能力,所以推挽輸出模式也可以叫強推輸出模式。在推挽輸出模式下,STM32 對 IO 口具有絕對的控制權,高低電平都由 STM32 說了算。在開漏輸出模式下,P-MOS無效,只有N-MOS在工作,數據寄存器為 1 時,下管斷開,此時輸出相當於斷開,也就是高阻模式;數據寄存器為 0 時,下管導通,輸出直接接到 VSS,輸出低電平。這種模式下,只有低電平有驅動能力,高電平是沒有驅動能力的。開漏模式可以作為通信協議的驅動方式,比如 I2C 通信的引腳就是使用的開漏模式,在多機通信的情況下,這個模式可以避免各個設備的相互干擾,此外開漏模式還可以用於輸出 5V 的電平信號,在 IO 口外接一個上拉到 5V 的電源,當輸出低電平時,內部的 N-MOS 直接接 VSS,當輸出高電平時,由外部的上拉電阻拉高至 5V,這樣就可以輸出 5V 的電平信號,用於兼容一些 5V 電平的設備,這就是開漏輸出的主要用途。剩下的一種狀態是關閉,這是當引腳配置成輸入模式的時候,這兩個 MOS 管都無效,也就是輸出關閉,端口的電平由外部信號來控制,以上就是 GPIO 位結構的全部介紹。

image-20220821193240193

3.4 GPIO 的 8 種工作模式#

通過配置 GPIO 的端口配置寄存器,端口可以配置成以下 8 種模式

浮空輸入、上拉輸入、下拉輸入的電路結構基本是樣的,區別就是上拉電阻和下拉電阻的連接,他們都屬於數字輸入口,都可以讀取端口高低電平。當引腳懸空時,上拉輸入默認是高電平,下拉輸入默認是低電平,而浮空輸入的電平是不確定的,所以在使用浮空輸入時,端口一定要接上一个連續的驅動源,不能出現懸空的狀態。

模擬輸入特徵是 GPIO 無效,引腳直接接入內部 ADC,是 ADC 模數轉換器的專屬配置

開漏輸出與推挽輸出這兩個電路的結構也基本一樣,都是數字輸出端口,用於輸出高低電平,區別就是開漏輸出的高電平呈現的是高阻態,沒有驅動能力,而推挽輸出的高低電平都是具有驅動能力的。

復用開漏輸出和復用推挽輸出與普通的開漏輸出和推挽輸出差不多,是復用的輸出,引腳電平由片上外設控制。

在 GPIO 的這 8 種模式中,除了模擬輸入這個模式會關閉數字的輸入功能,在其他 7 個模式中輸入都是有效的

模式名稱** 性 質 **特徵
浮空輸入數字輸入可讀取引腳電平,若引腳懸空,則電平不確定
上拉輸入數字輸入可讀取引腳電平,內部連接上拉電阻,懸空時默認高電平
下拉輸入數字輸入可讀取引腳電平,內部連接下拉電阻,懸空時默認低電平
模擬輸入模擬輸入GPIO 無效,引腳直接接入內部 ADC
開漏輸出數字輸出可輸出引腳電平,高電平為高阻態,低電平接 VSS
推挽輸出數字輸出可輸出引腳電平,高電平接 VDD,低電平接 VSS
复用开漏输出数字输出由片上外设控制,高电平为高阻态,低电平接 VSS
复用推挽输出数字输出由片上外设控制,高电平接 VDD,低电平接 VSS

3.5 GPIO 輸入浮空 / 上拉 / 下拉配置#

在輸入模式下,輸出驅動器是斷開的,端口只能輸入而不能輸出。上面兩個電阻可以選擇為上拉工作或下拉工作或不工作,對應是上拉輸入、下拉輸入和浮空輸入。輸入通過施密特觸發器進行波形整型後,連接到輸入數據寄存器。右邊輸入保護上面寫的是 VDD 或 VDD_FT,這是 3.3V 端口和 5V 端口的區別。容忍 5V 的引腳它的上邊保護二極管要做一下處理,不然這裡直接接 VDD3.3V 的話,外部再接入 5V 電壓就會導致上邊二極管開啟,並且產生較大的電流。

image-20220821193727313

3.6 GPIO 高阻抗的模擬輸入配置#

模擬輸入的輸出也是斷開的,輸入的施密特觸發器也是關閉無效的狀態,GPIO 的絕大部分都是沒用的,只剩下從引腳直接接入片上外設,也就是 ADC,因此當我們使用 ADC 的時候,將引腳配置為模擬輸入即可,其他時候一般用不到模擬輸入。

image-20220821193914682

3.7 GPIO 開漏 / 推挽輸出配置#

輸出由輸出數據寄存器控制,P-MOS如果無效,就是開漏輸出,如果P-MOSN-MOS都有效,就是推挽輸出。另外在輸出模式下,輸入模式也是有效的。一个端口只能有一个输出,但可以有多个输入,当配置成输出模式的时候,内部也可以顺便输入一下。

image-20220821193955149

3.8 复用开漏 / 推挽输出#

輸出控制左邊通用的輸出這裡是斷開的,引腳的控制權轉移到了片上外設,由片上外設來控制,在輸入部分,片上外設也可以讀取引腳的電平,同時普通的輸入也是有效的,順便接收一下電平信號。

image-20220829075654841

3.9 GPIO 控制 LED 和有源蜂鳴器#

image-20220829084106943

USE使用 STD標準 PERIPH外設 DRIVER驅動

3.9.1 LED 閃爍#

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//RCC開啟GPIO時鐘 打開C口時鐘並使能
	GPIO_InitTypeDef GPIO_InitStructure;//定義GPIO結構體變量
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//通用推挽輸出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;//PC13口
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz速度
	GPIO_Init(GPIOC, &GPIO_InitStructure);//GPIO_Init初始化GPIO 配置端口模式
    //輸出或輸出 SetBits設置為高電平 ResetBits設置為低電平
//	GPIO_SetBits(GPIOC, GPIO_Pin_13);
	GPIO_ResetBits(GPIOC, GPIO_Pin_13);
	while (1)
	{
        GPIO_SetBits(GPIOC, GPIO_Pin_13);//SetBits設置為高電平
        Delay_ms(500);
		GPIO_ResetBits(GPIOC, GPIO_Pin_13); //ResetBits設置為低電平
        Delay_ms(500);
        
		GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);//低電平
		Delay_ms(500);
		GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);//高電平
		Delay_ms(500);
        
        GPIO_WriteBit(GPIOC,GPIO_Pin_13,{BitAction}0);//低電平
		Delay_ms(500);
		GPIO_WriteBit(GPIOC,GPIO_Pin_13,{BitAction}1);//高電平
		Delay_ms(500);
	}
}

3.9.2 LED 流水燈#

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

/************************************************************************************************************************
* GPIO(General Purpose Input Output)通用輸入輸出口
* 可配置為8種輸入輸出模式
* 引腳電平:0V~3.3V,部分引腳可容忍5V FT的
* 輸出模式下可控制端口輸出高低電平,用以驅動LED、控制蜂鳴器、模擬通信協議輸出時序等
* 輸入模式下可讀取端口的高低電平或電壓,用於讀取按鍵輸入、外接模塊電平信號輸入、ADC電壓採集、模擬通信協議接收數據等
* GPIO端口圖片裡的ttl肖特基觸發器應該是施密特觸發器
* 施密特觸發器只有在高於上限或低於下限電平才會變化,很好的消抖
* 推挽輸出 開漏輸出 關閉 三種狀態
* 推挽輸出 P-MOS 和 N-MOS均有效 這種模式下,高低電平均有較強的驅動能力,所以推挽輸出又叫強推輸出模式
* 在推挽輸出模式下,STM32對IO口具有絕對的控制權,高低電平都由STM32說了算
* 開漏輸出 P-MOS輸出是無效的,只有N-MOS在工作 這種模式下,只有低電平有驅動能力.高電平是沒有驅動能力的
* 開漏模式可以作為通信協議的驅動方式,如I2C通信的引腳就是使用的開漏模式,多機通信下這個模式可以避免多個設備相互干擾
* 另外開漏模式還可以用於輸出5V的電平信號,
* 關閉 當引腳配置為輸入模式時,P-MOS和N-MOS都無效,輸出關閉,端口的電平信號都由外部信號來控制
************************************************************************************************************************/

/************************************************************************************************************************
* | **模式名稱** | **性質** | ************************特徵***********************|
* | ------------ | -------- | -------------------------------------------------- |
* | 浮空輸入     | 數字輸入 | 可讀取引腳電平,若引腳懸空,則電平不確定           |
* | 上拉輸入     | 數字輸入 | 可讀取引腳電平,內部連接上拉電阻,懸空時默認高電平 |
* | 下拉輸入     | 數字輸入 | 可讀取引腳電平,內部連接下拉電阻,懸空時默認低電平 |
* | 模擬輸入     | 模擬輸入 | GPIO無效,引腳直接接入內部ADC                      |
* | 開漏輸出     | 數字輸出 | 可輸出引腳電平,高電平為高阻態,低電平接VSS        |
* | 推挽輸出     | 數字輸出 | 可輸出引腳電平,高電平接VDD,低電平接VSS           |
* | 复用开漏输出 | 数字输出 | 由片上外设控制,高电平为高阻态,低电平接VSS        |
* | 复用推挽输出 | 数字输出 | 由片上外设控制,高电平接VDD,低电平接VSS           |
* 浮空輸入 上拉輸入 下拉輸入 這三種模式的電路結構基本一致,區別是上下拉電阻的連接
* 開漏輸出 推挽輸出 這兩種電路結構也基本一致 區別在於開漏輸出的高電平呈現的是高阻態,沒有驅動能力
* 复用开漏输出 复用推挽输出 這兩種模式和普通的差不多,只不過復用的輸出,引腳電平是由片上外設控制的
* 只有模擬輸入會關閉數字的輸入功能,其他模式數字輸入都是有效的
************************************************************************************************************************/ 


int main(void)
{
	/***********************************************************************************
		GPIO輸出
	***********************************************************************************/
	uint16_t i=0;//定義循環變量
	//開啟對應時鐘
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //打開A口時鐘並使能
	//定義一個構造體
	GPIO_InitTypeDef GPIO_InitStructure;
	//配置端口模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //通用推挽輸出
	/**********************************************************
	GPIO8種工作模式
	GPIO_Mode_AIN 模擬輸入(analog in)
	GPIO_Mode_IN_FLOATING 浮空輸入(in floating)
	GPIO_Mode_IPD 下拉輸入(in pull down)
	GPIO_Mode_IPU 上拉輸入(in pull up)
	GPIO_Mode_Out_OD 開漏輸出(out open drain)
	GPIO_Mode_Out_PP 推挽輸出(out push pull)
	GPIO_Mode_AF_OD 复用开漏输出(alt open drain)
	GPIO_Mode_AF_PP 复用推挽输出(alt push pull)
	**********************************************************/
	//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // A4號引腳
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; //A口所有引腳
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50MHz速度
	//端口初始化
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//設置端口高低電平
	/********************************************************************
	void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//設置引腳為高電平
	void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//設置引腳為低電平
	void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);//BitAction BitVal值為Bit_RESET和Bit_SET
	void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);//PortVal:指定要寫入端口輸出數據寄存器的值 
	*********************************************************************/
	//GPIO_SetBits(GPIOC, GPIO_Pin_13);//高電平
	//GPIO_ResetBits(GPIOC, GPIO_Pin_13);//低電平
	//GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);//低電平
	//GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);//高電平
	//GPIO_Write(GPIOC, 0x0001); //0000 0000 0000 0001 對應PC0~PC15共16個引腳
	while(1)
	{
		/*
		//LED閃爍
		GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_RESET);//低電平
		Delay_ms(500);
		GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_SET);//高電平
		Delay_ms(500);
		*/
		//流水燈
		for(i=0;i<16;i++)
		{
			GPIO_Write(GPIOA, ~0x0001);//0000 0000 0000 0001 按位取反 低電平點亮
			Delay_ms(500);
			GPIO_Write(GPIOA, ~0x0002);//0000 0000 0000 0010
			Delay_ms(500);
			GPIO_Write(GPIOA, ~0x0004);//0000 0000 0000 0100
			Delay_ms(500);
			GPIO_Write(GPIOA, ~0x0008);//0000 0000 0000 1000
			Delay_ms(500);
			GPIO_Write(GPIOA, ~0x0010);//0000 0000 0001 0000
			Delay_ms(500);
			GPIO_Write(GPIOA, ~0x0020);//0000 0000 0010 0000
			Delay_ms(500);
			GPIO_Write(GPIOA, ~0x0040);//0000 0000 0100 0000
			Delay_ms(500);
			GPIO_Write(GPIOA, ~0x0080);//0000 0000 1000 0000
			Delay_ms(500);
			//GPIO_Write(GPIOA, 0x0001);//高電平亮
			//Delay_ms(500);
		}
	}

}

3.9.3 蜂鳴器#

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//通用推挽輸出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;//PB12口
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz速度
	GPIO_Init(GPIOB, &GPIO_InitStructure);//GPIO_Init初始化GPIO 配置端口模式

	while (1)
	{
        GPIO_SetBits(GPIOB, GPIO_Pin_12);//SetBits設置為高電平
        Delay_ms(500);
		GPIO_ResetBits(GPIOB, GPIO_Pin_12); //ResetBits設置為低電平
        Delay_ms(500);
	}
}

3.10 GPIO 輸入#

按鍵抖動

image-20220829223028287

3.10.1 按鍵控制 LED#

快捷鍵Ctrl+ALT+空格顯示代碼提示

main.c#
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"

/************************************************************************************************************************
* GPIO(General Purpose Input Output)通用輸入輸出口
* 可配置為8種輸入輸出模式
* 引腳電平:0V~3.3V,部分引腳可容忍5V FT的
* 輸出模式下可控制端口輸出高低電平,用以驅動LED、控制蜂鳴器、模擬通信協議輸出時序等
* 輸入模式下可讀取端口的高低電平或電壓,用於讀取按鍵輸入、外接模塊電平信號輸入、ADC電壓採集、模擬通信協議接收數據等
* GPIO端口圖片裡的ttl肖特基觸發器應該是施密特觸發器
* 施密特觸發器只有在高於上限或低於下限電平才會變化,很好的消抖
* 推挽輸出 開漏輸出 關閉 三種狀態
* 推挽輸出 P-MOS 和 N-MOS均有效 這種模式下,高低電平均有較強的驅動能力,所以推挽輸出又叫強推輸出模式
* 在推挽輸出模式下,STM32對IO口具有絕對的控制權,高低電平都由STM32說了算
* 開漏輸出 P-MOS輸出是無效的,只有N-MOS在工作 這種模式下,只有低電平有驅動能力.高電平是沒有驅動能力的
* 開漏模式可以作為通信協議的驅動方式,如I2C通信的引腳就是使用的開漏模式,多機通信下這個模式可以避免多個設備相互干擾
* 另外開漏模式還可以用於輸出5V的電平信號,
* 關閉 當引腳配置為輸入模式時,P-MOS和N-MOS都無效,輸出關閉,端口的電平信號都由外部信號來控制
************************************************************************************************************************/

/************************************************************************************************************************
* | **模式名稱** | **性質** | ************************特徵***********************|
* | ------------ | -------- | -------------------------------------------------- |
* | 浮空輸入     | 數字輸入 | 可讀取引腳電平,若引腳懸空,則電平不確定           |
* | 上拉輸入     | 數字輸入 | 可讀取引腳電平,內部連接上拉電阻,懸空時默認高電平 |
* | 下拉輸入     | 數字輸入 | 可讀取引腳電平,內部連接下拉電阻,懸空時默認低電平 |
* | 模擬輸入     | 模擬輸入 | GPIO無效,引腳直接接入內部ADC                      |
* | 開漏輸出     | 數字輸出 | 可輸出引腳電平,高電平為高阻態,低電平接VSS        |
* | 推挽輸出     | 數字輸出 | 可輸出引腳電平,高電平接VDD,低電平接VSS           |
* | 复用开漏输出 | 数字输出 | 由片上外设控制,高电平为高阻态,低电平接VSS        |
* | 复用推挽输出 | 数字输出 | 由片上外设控制,高电平接VDD,低电平接VSS           |
* 浮空輸入 上拉輸入 下拉輸入 這三種模式的電路結構基本一致,區別是上下拉電阻的連接
* 開漏輸出 推挽輸出 這兩種電路結構也基本一致 區別在於開漏輸出的高電平呈現的是高阻態,沒有驅動能力
* 复用开漏输出 复用推挽输出 這兩種模式和普通的差不多,只不過復用的輸出,引腳電平是由片上外設控制的
* 只有模擬輸入會關閉數字的輸入功能,其他模式數字輸入都是有效的
************************************************************************************************************************/


/************************************************************************************************************************
* uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
* GPIO_ReadInputDataBit這個函數是用來讀取輸入寄存器某一個端口的輸入值
* uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
* GPIO_ReadInputData這個函數是用來讀取整個輸入數據寄存器,返回值是uint16_t,是一個16位的數據,每一位代表一個端口值
* uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
* GPIO_ReadOutputDataBit這個函數是用來讀取輸出數據寄存器的某一位,原則上來說它並不是用來讀取端口的輸入數據的,這個函數一般用於輸出模式下,看一下自己輸出的是什么
* uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
* GPIO_ReadOutputData這個函數是用來讀取整個輸出寄存器的
************************************************************************************************************************/

uint8_t Key_Num;

int main(void)
{
	/***********************************************************************************
		GPIO輸入
	***********************************************************************************/
	LED_Init();
	Key_Init();
	
	while(1)
	{
		Key_Num = Key_GetNum();
		if(Key_Num == 1)
		{
			LED1_Turn();
		}
		if(Key_Num == 2)
		{
			LED2_Turn();
		}
		
	}

}

LED.c#
#include "stm32f10x.h"                  // Device header
#include "LED.h"

void LED_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);//設置為高電平
}

void LED1_ON(void)
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}

void LED1_OFF(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_1);
}

void LED1_Turn(void)
{
	if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == 0)
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_1);
	}
	else
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_1);
	}
}

void LED2_ON(void)
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}

void LED2_OFF(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_2);
}

void LED2_Turn(void)
{
	if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2) == 0)
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_2);
	}
	else
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);
	}
}


key.c#
#include "Key.h"

void Key_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉輸入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

uint8_t Key_GetNum(void)
{
	uint8_t KeyNum = 0;
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
	{
		Delay_ms(20);
		while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);
		Delay_ms(20);
		KeyNum = 1;
	}
	
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0)
	{
		Delay_ms(20);
		while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);
		Delay_ms(20);
		KeyNum = 2;
	}
	
	return KeyNum;
}

GPIO 使用方法總結

初始化時鐘
定義結構體
賦值結構體
GPIO_Init 函數將指定的 GPIO 外設初始化好
讀寫 GPIO 的 8 個主要函數

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。