1. 程式人生 > >關於stm32的GPIO的操作

關於stm32的GPIO的操作

 

首先先了解一下輸出的模式

比較常用的是 推輓輸出

1)GPIO_Mode_AIN 模擬輸入 

(2)GPIO_Mode_IN_FLOATING 浮空輸入

​(3)GPIO_Mode_IPD 下拉輸入

(4)GPIO_Mode_IPU 上拉輸入

​(5)GPIO_Mode_Out_OD 開漏輸出

​(6)GPIO_Mode_Out_PP 推輓輸出

​(7)GPIO_Mode_AF_OD 複用開漏輸出

​(8)GPIO_Mode_AF_PP 複用推輓輸出
 

首先簡述一下stm3的gpio

介面(interface):主機(CPU)與外部裝置(指MCU片上外設)之間緩衝電路。它用於完成主機與外部裝置設間速度匹配、訊號轉換,並完成某些控制功能。按資料的傳輸方式可分為並行介面和序列介面,並行介面指一般I/O介面或通用I/O介面,而序列介面有I2C/SPI/UART等等。

埠(port):I/O介面電路中已經編址並能進行讀寫操作的暫存器。埠分為資料埠、狀態埠及控制埠,普遍存在於各個介面電路中。每個介面電路中都包含一組暫存器,CPU與外部裝置進行資訊交換時,各類資訊在介面中存入不同的暫存器,這些暫存器就是I/O埠,簡稱I/O口,也稱為I/O埠暫存器。

引腳(pin):積體電路與外圍電路連線的管腳。

介面(埠)概念是對並行介面和序列介面(I2C/SPI/UART等片上外設)而言的,MCU中大多數的功能模組都有介面電路。狹義上,埠概念往往特指I/O並行介面電路中的暫存器。此外,通常我們所說的“I/O口”指的就是“I/O埠”。

一、GPIO的模式選擇

通過GPIO模式暫存器GPIOx_MODER(x是埠名稱,x=A…I/J/K)來設定GPIO埠位的方向: 
1、輸入模式(復位狀態) 
2、GPIO輸出模式 
3、複用功能模式 
4、模擬功能模式 
GPIOx_MODER的設定方法,詳見技術參考手冊TRM。

二、GPIO埠暫存器

每個I/O埠均有下列暫存器,每個埠位均可自由程式設計,但I/O埠暫存器必須按32位字、半字或位元組被訪問。其中,GPIOx_BSRR暫存器旨在實現對GPIOx_ODR暫存器進行原子讀取/修改訪問,具有對GPIOx_ODR按位寫許可權。

1、4個32位配置暫存器:GPIOx_MODER、GPIOx_OTYPER、GPIOx_OSPEEDR、GPIOx_PUPDR,這些暫存器位可通過軟體寫入。其中,輸出型別暫存器GPIOx_OTYPER是用1個暫存器位設定1個I/O位,其他配置暫存器均是用2個暫存器位設定1個I/O位。

GPIOx_MODER:選擇I/O埠方向為 輸入/通用輸出/AF/模擬,復位狀態為輸入。

GPIOx_OTYPER:選擇輸出型別為 推輓/開漏,復位狀態為推輓輸出。

GPIOx_OSPEEDR:選擇I/O輸出驅動電路的響應速度為 低速/中速/快速/高速,用於噪聲控制。(由下面Table 22. Port bit configuration table 可知,這個速度暫存器只對輸出模式和AF起作用)。 
注意:GPIO的引腳速度是指I/O口驅動電路的響應速度而不是輸出訊號的速度,輸出訊號的速度與程式有關。此外,如果較高頻率的訊號經過較低頻率的驅動電路輸出,那麼輸出的訊號就會產生失真,所以驅動電路的頻率和訊號的頻率之間滿足取樣定理的要求。驅動電路的頻率應該適當不能過大(建議10~20倍於訊號的頻率),以便降低噪聲、功耗和電磁輻射。

GPIOx_PUPDR:選擇I/O埠為 無上拉或下拉/上拉/下拉/保留(與IO埠方向無關)。

2、2個32位資料暫存器:GPIOx_IDR、GPIOx_ODR

GPIOx_IDR:這些暫存器位為只讀 形式,並且只能在字模式下訪問。

GPIOx_ODR:這些暫存器位可通過軟體讀取和寫入。

3、1個32位置位復位暫存器:GPIOx_BSRR

GPIOx_BSRR低半字用來置位GPIOx_ODR,即寫入“1”,而高半字用來複位GPIOx_ODR,即寫入“0”。GPIOx_BSRR旨在對GPIOx_ODR暫存器進行原子讀寫操作,它只能在字、半字、位元組模式下被訪問對GPIOx_ODR進行原子操作。

4、1個32位鎖定暫存器:GPIOx_LCKR

鎖定暫存器GPIOx_LCKR的每個鎖定位用於鎖定埠位的配置。凍結的暫存器包括:GPIOx_MODER、GPIOx_OTYPER、GPIOx_OSPEEDR、GPIOx_PUPDR、GPIOx_AFRH、GPIOx_AFRL,它只能以字的方式被訪問。鎖定暫存器鎖定配置後,就會避免因意外改寫埠暫存器配置造成大電流損壞晶片的故障或其他故障。

5、2個32位複用功能選擇暫存器:GPIOx_AFRH、GPIOx_AFRL

GPIOx_AFRL:用四位暫存器位選擇一個對應的複用功能。該暫存器用於選擇AF0~AF7。

GPIOx_AFRH:用四位暫存器位選擇一個對應的複用功能。該暫存器用於選擇AF8~AF15。

複用功能選擇暫存器只能通過字被訪問。

三、GPIO的工作模式

通過對4種埠配置暫存器進行程式設計,可將GPIO口的各個埠位配置成以下8種工作模式:

輸入+懸空 
輸入+上拉 
輸入+下拉 
模擬(用作ADC輸入、DAC輸出或者捕獲輸入情況下) 
輸出+開漏+上拉/下拉(輸出模式時GPIO的輸出速度是可配置的) 
輸出+推輓+上拉/下拉(輸出模式時GPIO的輸出速度是可配置的) 
複用功能+推輓+上拉/下拉(複用功能時速度是可配置的) 
複用功能+開漏+上拉/下拉(複用功能時速度是可配置的)


● I/O輸入通道有個TTL施密特觸發器,它用於將變化緩慢的輸入訊號整形成邊沿陡峭的矩形脈衝。同時,施密特觸發器利用其回差電壓提高了電路的抗干擾能力; 
● 所有的I/O口均相容TTL電平和CMOS電平; 
● 大多數I/O是5V電壓容限(FT 結構的I/O是5V容限,其他結構的I/O不是。詳細情況請參見相應的STM32F4資料手冊); 
● 當GPIO被配置為模擬功能時,I/O不再是5V電壓容限,這時以VDDA為電壓容限; 
● 除了埠A和B(主要是PA13/PA14/PA15/PB3/PB4這5個埠位復位後專門用於片上除錯模組,不受4個GPIO控制暫存器控制),其他埠的所有埠位復位期間或者復位後都是懸空輸入狀態; 
● 輸出通道中,輸出資料暫存器和複用功能輸出接到多路複用器,再經過輸出控制連線到推輓電路的門極。值得注意的是輸出控制會將輸出資料暫存器和複用功能輸出的電平進行反轉(即’1’變’0’,’0’變’1’)。仔細觀察會發現P-MOS管的門極有個小圈“。”,它表示P-MOS的門極為低電平’0’時,P-MOS導通。反之,N-MOS是門極為高電平’1’時導通; 
● 推輓輸出的驅動能力強,並且推輓輸出時,若P-MOS導通,引腳上的電壓不會因為外部器件或裝置(即引腳帶負載)而有所降低; 
● I/O埠位的最大狀態切換頻率為90MHZ。
● 輸出緩衝器被禁止; 
● 施密特觸發輸入被啟用; 
● 根據暫存器GPIOx_PUPDR中的值選擇引腳為弱上拉或弱下拉或懸空輸入; 
● I/O引腳上的資料在每個AHB1時鐘週期被取樣到輸入資料暫存器; 
● 對輸入資料暫存器的讀訪問可獲得I/O狀態。


● 輸出緩衝器被啟用 
─ 開漏模式:輸出暫存器上的 ‘0’ 啟用N-MOS,而輸出暫存器上的 ‘1’ 將埠置於高阻狀態(PMOS從不被啟用); 
─ 推輓模式:輸出暫存器上的 ‘0’ 啟用N-MOS,而輸出暫存器上的 ‘1’ 將啟用P-MOS; 
● 施密特觸發器輸入被啟用; 
● 選擇引腳為弱上拉或弱下拉輸出或懸空; 
● I/O腳上的資料在每個AHB1時鐘週期被取樣到輸入資料暫存器; 
● 對輸入資料暫存器的讀訪問可得到I/O狀態; 
● 對輸出資料暫存器的讀訪問得到最後一次寫的值。

由圖4可以看出,當I/O埠被配置為複用功能AF(Alternate Function)時: 
● 輸出緩衝器可以被配置成開漏或推輓; 
● 輸出緩衝器被片上外設訊號驅動; 
● 施密特觸發器輸入被啟用; 
● 根據暫存器GPIOx_PUPDR中的值選擇引腳為弱上拉或弱下拉或懸空輸出; 
● I/O腳上的資料在每個AHB1時鐘週期被取樣到輸入資料暫存器; 
● 對輸出資料暫存器的讀訪問得到最後一次寫的值。

 


● 輸出緩衝器被禁止; 
● 施密特觸發器輸入被暫停,0功耗,並且輸出一直維持在0值狀態; 
● 管腳的弱上拉和下拉被禁止; 
● 訪問輸入資料暫存器得到的數值為0;

五、GPIO引腳作為一般IO輸入時,引腳的狀態和埠輸入暫存器GPIOx_IDR的狀態是否一致?

在學習51核微控制器時,由於51微控制器I/O介面電路結構的原因,I/O輸入時,I/O的引腳狀態會出現與鎖存器不一樣的情況。所以,往往在I/O上拉輸入前,提前向鎖存器寫入“1”,指令上也分為讀引腳和讀鎖存器指令。

那麼,基於Cortex-M核心的MCU的I/O引腳輸入時是否也有與51微控制器同樣的問題呢??

答案是否定的!因為Cortex-M核心的MCU的GPIO引腳在被配置為I/O輸入時,其輸出電路是斷開的。這樣,輸出電路就不會影響到引腳的狀態。所以,引腳上的狀態和輸入暫存器GPIOx_IDR中的資料始終一致。
 

 

為什麼要配置埠?

因為GPIO中埠的作用很多,沒有固定的一種模式,因此需要配置.

每個GPI/O埠有兩個32位配置暫存器(GPIOx_CRL,GPIOx_CRH),兩個32位資料暫存器(GPIOx_IDR,GPIOx_ODR),一個32位置位/復位暫存器(GPIOx_BSRR),一個16位復位暫存器(GPIOx_BRR)和一個32位鎖定暫存器(GPIOx_LCKR)。

本文引用地址:http://www.eepw.com.cn/article/201611/318989.htm

GPIO埠的每個位可以由軟體分別配置成多種模式。每個I/O埠位可以自由程式設計,然而I/0埠暫存器必須按32位字被訪問(不允許半字或位元組訪問)。GPIOx_BSRR和GPIOx_BRR暫存器允許對任何GPIO暫存器的讀/更改的獨立訪問;這樣,在讀和更改訪問之間產生IRQ時不會發生危險。

配置為輸出模式 , 驅動led , 配置思路是什麼樣的?

使能埠時鐘;
選定需要配置的管腳;
配置埠的模式;
初始化埠; 
程式碼如下:

#include "led.h"
#include "sys.h"
void LED_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;//結構體變數定義

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能GPIOF時鐘

  GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_9|GPIO_Pin_10); //LED0=PF9,LED1=PF10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//輸出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推輓輸出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50M
  GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化GPIOF
}
以下是配置按鍵的介面

程式如下:

/按鍵初始化函式
void KEY_Init(void) //IO初始化

     GPIO_InitTypeDef GPIO_InitStructure;
 
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);//使能PORTA,PORTE時鐘

    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;//KEY0-KEY2
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //設定成上拉輸入
     GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE2,3,4

    //初始化 WK_UP-->GPIOA.0      下拉輸入
    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0設定成輸入,預設下拉      
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0

}

 

以下是配置ds18b20的介面

//IO方向設定
#define DS18B20_IO_IN()  {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=8<<12;}
#define DS18B20_IO_OUT() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=3<<12;}
////IO操作函式                                               
#define    DS18B20_DQ_OUT PGout(11) //資料埠    PA0 
#define    DS18B20_DQ_IN  PGin(11)  //資料埠    PA0 


//////IO方向設定  gpio13  每4個位控制1個IO。
//#define DS18B20_IO_IN()  {GPIOG->CRH&=0XFFF0FFFFF;GPIOG->CRH|=8<<20;}
//#define DS18B20_IO_OUT() {GPIOG->CRH&=0XFFF0FFFFF;GPIOG->CRH|=3<<20;}
//////IO操作函式                                               
//#define    DS18B20_DQ_OUT PGout(13) //資料埠    PA0 
//#define    DS18B20_DQ_IN  PGin(13)  //資料埠    PA0 
 

 

 

再看GPIO功能很強大:

1.通用I/O(GPIO):最最基本的功能,可以驅動LED、可以產生PWM、可以驅動蜂鳴器等等;

2.單獨的位設定或位清除:方便軟體作業,程式簡單。埠配置好以後只需GPIO_SetBits(GPIOx, GPIO_Pin_x)就可以實現對GPIOx的pinx位為高電平;

3.外部中斷/喚醒線:埠必須配置成輸入模式時,所有埠都有外部中斷能力;

4.複用功能(AF):複用功能的埠兼有IO功能等。復位期間和剛復位後,複用功能未開啟,I/O埠被配置成浮空輸入模式:(CNFx[1:0]=01b,MODEx[1:0]=00b)。

5.軟體重新對映I/O複用功能:為了使不同器件封裝的外設I/O功能的數量達到最優,可以把一些複用功能重新對映到其他一些腳上。這可以通過軟體配置相應的暫存器來完成。這時,複用功能就不再對映到它們的原始引腳上了;

6.GPIO鎖定機制:主要針對復位設定的,當某埠位lock後,復位後將不改變的此埠的位配置。

GPIO基本設定

GPIOMode_TypeDef GPIO mode定義及偏移地址

GPIO_Mode_AIN = 0x0,//模擬輸入

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 = 0x1C,//開漏複用

GPIO_Mode_AF_PP = 0x18//推輓複用

GPIO輸入輸出速度選擇:

typedef enum

{

GPIO_Speed_10MHz = 1,

GPIO_Speed_2MHz,

GPIO_Speed_50MHz

}

GPIOSpeed_TypeDef;

#define IS_GPIO_SPEED(SPEED) ((SPEED == GPIO_Speed_10MHz) || (SPEED == GPIO_Speed_2MHz) ||(SPEED == GPIO_Speed_50MHz))

做一個GPIO輸出的試驗

當I/O埠被配置為推輓模式輸出時:輸出暫存器上的0啟用N-MOS,而輸出暫存器上的1將啟用P-MOS。

用這段程式實現:GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

int main(void)

{

#ifdef DEBUG

debug();

#endif

RCC_Configuration();

NVIC_Configuration();

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOC, &GPIO_InitStructure);

while (1)

{

GPIO_SetBits(GPIOC, GPIO_Pin_4); //設定PC.04 pin為高電平,點亮LED1

Delay();

GPIO_ResetBits(GPIOC, GPIO_Pin_4); //設定PC.04 pin為低電平,熄滅LED1

Delay();

}

}