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 的整體基本結構了。
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 口接到VDD
或VSS
,在這裡可以選擇推挽、開漏或者關閉三種輸出方式。在推挽輸出下,P-MOS
和N-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 位結構的全部介紹。
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 電壓就會導致上邊二極管開啟,並且產生較大的電流。
3.6 GPIO 高阻抗的模擬輸入配置#
模擬輸入的輸出也是斷開的,輸入的施密特觸發器也是關閉無效的狀態,GPIO 的絕大部分都是沒用的,只剩下從引腳直接接入片上外設,也就是 ADC,因此當我們使用 ADC 的時候,將引腳配置為模擬輸入即可,其他時候一般用不到模擬輸入。
3.7 GPIO 開漏 / 推挽輸出配置#
輸出由輸出數據寄存器控制,P-MOS
如果無效,就是開漏輸出,如果P-MOS
和N-MOS
都有效,就是推挽輸出。另外在輸出模式下,輸入模式也是有效的。一个端口只能有一个输出,但可以有多个输入,当配置成输出模式的时候,内部也可以顺便输入一下。
3.8 复用开漏 / 推挽输出#
輸出控制左邊通用的輸出這裡是斷開的,引腳的控制權轉移到了片上外設,由片上外設來控制,在輸入部分,片上外設也可以讀取引腳的電平,同時普通的輸入也是有效的,順便接收一下電平信號。
3.9 GPIO 控制 LED 和有源蜂鳴器#
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 輸入#
按鍵抖動
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);