?GPIO
GPIO:通用輸入輸出口;可配置8種輸入輸出模式
引腳電平:0V-3.3V,部分引腳可容忍5V也可認為高電平,但是對于輸出而言,最大就只能輸出3.3V,因為供電就只有3.3V,
能容忍5v的在以下的引腳定義下,I/O電平含FT的可以
輸出模式下可控制端口輸出高低電平,用以驅動LED、控制蜂鳴器、模擬通信協議輸出時序等
輸入模式下可讀取端口的高低電平或電壓,用于讀取按鍵輸入(最常用)、外接模塊電平信號輸入、ADC電壓采集、模擬通信協議接收數據等
GPIO的基本結構:GPIO掛載在APB2上的
總共有16個引腳,一般稱為PA0~PA15
GPIO分為不同的模塊:用GPIOA、GPIOB來表示,主要包含了寄存器(是一段特殊的存儲器,內核可以通過APB2總線對寄存器進行讀寫,從而完成對于的輸入輸出功能)和驅動器。
在模塊內每一個位對于一個引腳,其中輸出寄存器寫1,對于的引腳就會輸出高電平,寫0就輸出低電平,輸入同理。
STM32為32位的寄存器,但是模塊中的端口只有16位,所有這個寄存器只有低16位的端口
GPIO的電路圖:
輸入部分
引腳部分
這接入了兩個保護二極管,目的是保護電路的:
? 上面的二極管接VDD,3.3V:如果輸入電壓比3.3V還要高,則上方會被導通,輸入電壓產生的電流會流入VDD,從而保護電路;
下面的二極管接VSS,0V:同理;
補:VDD:代表總正極,常用于現代電子
? ? ? ? VCC:代表總正極,常用于三極管等
? ? ? ? VSS:代表總負極,在MOS管電路中更常用。
? ? ? ? GND:所有電路的公共回路
如果電流在0-3.3V中則兩邊都不接通,正常流入到電路中來
這里連接一個上拉電阻(連至VDD)和下拉電阻(連至VSS),這個開關是可以通過程序進行配置的:如果上面導通,下面斷開,就是上拉輸入模式(高電平模式),反之;如果兩個都斷開則為浮空模式;如果兩者都接入,并不會同時生效,相互存在互斥,為了防止電源短路風險。
作用:為了給輸入提供一個默認的輸入電平,因為當輸入電平時沒有讓引腳的輸入為低電平或者是高電平時,電路也不知道它是什么狀態,則會被其他外界的環境所干擾;目的是不影響正常的輸入操作。
補:電路:由電子元器件(電阻、電容、晶體管等)和導線組成的閉合路徑,用于傳輸電能或處理電信號
? ? ? ? 電壓:電勢差(單位:伏特?V),表示電場中兩點之間的能量差,驅動電流流動。
? ? ? ? 電平:表示數字信號的狀態(高電平或低電平),通常對應特定的電壓范圍。
????????電流:電荷的定向流動(單位:安培?A),由電壓驅動。
? ? ? ? 電平信號:用電壓表示的離散信號,通常用于數字通信。
電壓是電流的原因,電流是電壓的結果。
電壓是“推力”,電流是“流量”。
開路(斷路)時:電壓可以存在(如電池兩極),但電流為零。 短路時:電流可以很大,但電壓可能接近零。
1.在電源(如電池)內部,化學反應將正電荷推到正極(+),負電荷推到負極(-),從而在兩極之間建立一個靜電場。
2.沒有閉合回路,電子無法流動
斷路:斷路是指電路中的某處斷開,導致電流無法流通,但電源電壓仍然存在。
短路:短路是指電路中兩點之間出現極低電阻(接近0Ω)的連接,導致電流極大,電壓驟降。
肖特基(施密特)觸發器:
對輸入電壓進行整形:如果是輸入電壓大于某一個閾值,輸出就會瞬間變為高電平,反之;
例如:通常的引腳輸入的模擬信號為波形模擬信號:
會通過施密特觸發器對信號進行整形,中間留有流動范圍,可以有效地避免因信號波動造成的是輸出抖動現象
之后就可以通過輸入寄存器輸入數據了,我們再用程序去讀取輸入數據寄存器對于某一位的數據,就可以知道端口的輸入電平;
是連接片上外設的一些端口:
模擬輸入:連至ADC(模擬到數字轉換器),因為它需要接受模擬數據量,所以接入在觸發器之前的
復用功能輸入:連接到其他需要讀取端口的外設上的
輸出部分
數字部分可以由輸出寄存器和片上外設控制,兩者方式通過數據選擇器接到輸出控制部分;
輸出寄存器:
為普通IO輸出,寫數據寄存器的某一位就可操作對于的某個端口;同時控制低16位端口,并且只能整體讀寫,
????????所以如果想控制一個端口而不影響其他端口的話,需要特殊操作:
????????????????????????1.先讀出這個寄存器,然后按位與&=和按位或|=的方式更改某一位。最后將更改的數據寫回去;
????????????????????????2. (主要)設置位設置/清楚寄存器(可以單獨拿操作輸出數據寄存器的某一位,而不影響其他位),在位設置寄存器上的對于的位上修改為1即可,不修改的位置寫0。如果想對一位進行清0的操作,在位清除寄存器上對應位寫1即可;
????????????????????????3.讀寫STM32的位帶區域(這段地址映射了RAM和外設寄存器所有的位);
兩個Mos管,上面是P-MOS,下面N-MOS
MOS管就是一種電子開關,信號來控制開關的導通或關閉,開關負責將IO口接到VDD或者VSS。
推挽、開漏、關閉三種輸出方式:
1.推挽
P-MOS和N-MOS均有效,數據寄存器為1時,上管導通,下官斷開,輸出直接接到VDD,輸出高電平,反之;這種模式,高低電平均有較強的驅動能力,所以推挽模式也叫強輸出模式。在此模式下STM32對IO口有著絕對的控制權。
2.開漏
P-MOS無效,N-MOS有效,數據寄存器為1時,下官斷開,這是輸出相當于斷開,屬于高阻模式;為0時,則是輸出低電平;這種模式下只有低電平有驅動能力,作為通訊協議的模式。同時還可以用于輸出5V電平信號
3.關閉
P-MOS和N-MOS均無效:當引腳配置為輸入模式的時候,端口的電平由外部設備進行控制;
GPIO的8種工作模式:通過配置端口的配置寄存器
1.
電路結構基本一樣,區別在與上拉電阻和下拉電阻的連接。在浮空輸入模式下,端口一定要接一個連續的驅動源,從而不出現浮空的狀態。
VDD 3.3V端口和VDD_FT 容忍5V端口
2.
ADC模數轉換器的專屬:
只有這個模式會關閉數字的輸入功能
3.
區別是在高電平下的狀態
可以發現輸出情況下,輸入是存在的,因為一個端口只有一個輸出,可以有多個輸入
4.
更多內容參考STM32F10xxx參考手冊(中文)-第8章
GPIO的寄存器
每個端口的模式由4位進行配置
由端口配置低寄存器和端口配置高寄存器,具體配置在參考手冊中
端口輸入數據寄存器:
,只用低16位
端口輸出數據寄存器
,同理
端口位設置/清除寄存器
端口位清除寄存器:為了與端口位設置/清除寄存器進行區別,此寄存器只進行位清除
端口位設置/清除寄存器,對端口的配置進行鎖定,防止被更改
GPIO的外部設備和電路
LED和蜂鳴器:
LED:
發光二級管,正向通電點亮,反向通電不亮,
長腳為正極,內部里較小的是正極。
STM32的GPIO口驅動LED的電路
低電平驅動的電路
LED正極接入3.3V,負極通過一個限流電阻接到PA0上,當PA0輸出低電平時,LED兩端會產生電壓差就會形成正向導通的電流,這樣LED就點亮了。當PA0輸出高電平時,因為LED兩端都是3.3V電壓,不會形成電流;限流電阻:防止LED電流過大而燒毀和調整LED的亮度;
補:此時的電壓差解釋:本質電壓差:電路中兩點之間的電壓之差(即電勢差);當PA0為低電平時,電壓差=V正極??V負極?=3.3V?0V=3.3V(不考慮電阻),故燈亮;當PA0為高電平時,電壓差=V正極??V負極?=3.3V?3.3V=0V,故燈滅
高電平驅動的電路
LED負極接入GND,正極通過一個限流電阻接到PA0上,反之;
至于這兩種接入的選擇,需靠考慮輸入輸出的驅動器,正如我們的STM32的GPIO的推挽模式下,低電平和高電平都具有較高的驅動能力,所以都可以使用,而對單片機或部分芯片中,都使用了高電平弱驅動,低電平高驅動的方法。
有源蜂鳴器:
內部自帶振蕩源,將正負極接上直流電壓即可持續發聲,頻率固定。
電路中用了個三極管開關進行驅動,在VCC和GND上分別接上正負極的供電,中間的引腳2接入低電平,蜂鳴器就會響,高電平停止。
無源蜂鳴器:內部不帶振蕩源,需要控制器提供振蕩脈沖才可發聲,調整提供振蕩脈沖的頻率,可發出不同頻率的聲音
三極管可防止IO驅動使STM32負擔過重:左邊的是基極,帶箭頭的是發射極,剩下的是集電極
PNP三極管的驅動電路
電流方向:電流從發射極(E)流向集電極(C),基極(B)控制導通
基極給低電平,三極管則會導通,通過3.3V和GND可以給蜂鳴器提供驅動電流
基極給高電平,三極管停止,蜂鳴器沒有電流
NPN三極管的驅動電路
電流方向:電流從集電極(C)流向發射極(E),基極(B)控制導通。
驅動邏輯與上分之
注:PNP的三極管最好接在上邊,NPN的三極管最好接在下邊:“上邊”通常指靠近電源(VCC)的一側,“下邊”指靠近地(GND)的一側。
??? 因為三級管的通斷,是需要在發射極和基極產生一定的開啟電壓
面包板
當把元件的引腳插入面包板的孔里后,面包板內部的金屬爪就會夾住引腳。
如果需要供電,就從上下的孔位,用跳線引出來即可;
如果中間部分的面包板,沒有連接需要用跳線進行連接
點亮LED電路
操作GPIO,需要使用三個步驟:
- 使用RCC開啟GPIO的時鐘
- 使用GPIO_Init函數初始化GPIO
- 使用輸出或輸入的函數控制GPIO口
從庫函數中找到RCC和GPIO兩個外設相關的函數庫:
stm32f10x_rcc和stm32f10x_gpio,通過查看其頭文件。來找到我們需要的庫函數stm32f10x_rcc:void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);//RCC AHB外設時鐘控制void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState); //RCC APB2外設時鐘控制void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState); //RCC APB1外設時鐘控制
跳到對應的函數里,查看調用信息:
注釋上有對此函數的相關說明,以及相關參數:
stm32f10x_gpio.h:
void GPIO_DeInit(GPIO_TypeDef* GPIOx); //所指定的GPIO外設就會被復位void GPIO_AFIODeInit(void); //可以復位AFIO外設void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);//用結構體的參數來初始化GPIO口,需要手動配置一個結構體變量并賦值。void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);? //把結構體變量賦值為一個默認值//以下四個為GPIO的讀取函數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);//以下四個為GPIO的寫入函數: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);? ?//可以同時對16個端口進行寫入操作
接線圖:
LED閃爍
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//定義結構體變量GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//對其成員工作模式進行配置:推挽模式//GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;//開漏輸出模式GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//GPIO的引腳位置配置為我們接入的A0引腳GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//默認為50mhzGPIO_Init(GPIOA,&GPIO_InitStructure);//注意此函數調用的是結構體指針,所以使用此函數時需要傳遞地址//輸出函數//GPIO_ResetBits(GPIOA,GPIO_Pin_0);//向PA0輸出低電壓,燈亮(默認是低電平)GPIO_SetBits(GPIOA,GPIO_Pin_0);//反之//GPIO_WriteBit(GPIOA,GPIO_Pin_0, Bit_SET);//實現LED閃爍,新建System文件夾,相關配置之后,引入延時文件Delaywhile(1){//GPIO_SetBits(GPIOA,GPIO_Pin_0);//Delay_ms(500);//GPIO_ResetBits(GPIOA,GPIO_Pin_0);//Delay_ms(500);}
}
LED流水燈
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(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_0 |GPIO_Pin_1|GPIO_Pin_2 |GPIO_Pin_3|GPIO_Pin_4 |GPIO_Pin_5|GPIO_Pin_6 |GPIO_Pin_7;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_All;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_SetBits(GPIOA,GPIO_Pin_0);while(1){/*使用GPIO_Write,同時設置GPIOA所有引腳的高低電平,實現LED流水燈,Write直接寫入OCD寄存器中*/GPIO_Write(GPIOA, ~0x0001); //0000 0000 0000 0001,PA0引腳為低電平,其他引腳均為高電平,注意數據有按位取反Delay_ms(100); //延時100msGPIO_Write(GPIOA, ~0x0002); //0000 0000 0000 0010,PA1引腳為低電平,其他引腳均為高電平Delay_ms(100); //延時100msGPIO_Write(GPIOA, ~0x0004); //0000 0000 0000 0100,PA2引腳為低電平,其他引腳均為高電平Delay_ms(100); //延時100msGPIO_Write(GPIOA, ~0x0008); //0000 0000 0000 1000,PA3引腳為低電平,其他引腳均為高電平Delay_ms(100); //延時100msGPIO_Write(GPIOA, ~0x0010); //0000 0000 0001 0000,PA4引腳為低電平,其他引腳均為高電平Delay_ms(100); //延時100msGPIO_Write(GPIOA, ~0x0020); //0000 0000 0010 0000,PA5引腳為低電平,其他引腳均為高電平Delay_ms(100); //延時100msGPIO_Write(GPIOA, ~0x0040); //0000 0000 0100 0000,PA6引腳為低電平,其他引腳均為高電平Delay_ms(100); //延時100msGPIO_Write(GPIOA, ~0x0080); //0000 0000 1000 0000,PA7引腳為低電平,其他引腳均為高電平Delay_ms(100); //延時100ms}
}
蜂鳴器
#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_0 |GPIO_Pin_1|GPIO_Pin_2 |GPIO_Pin_3|GPIO_Pin_4 |GPIO_Pin_5|GPIO_Pin_6 |GPIO_Pin_7;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_12);while(1){GPIO_ResetBits(GPIOB,GPIO_Pin_12);Delay_ms(100);GPIO_SetBits(GPIOB,GPIO_Pin_12);Delay_ms(100);GPIO_ResetBits(GPIOB,GPIO_Pin_12);Delay_ms(100);GPIO_SetBits(GPIOB,GPIO_Pin_12);Delay_ms(700);}
}