Robomaster電控培訓(二) GPIO


RM電控入門(二) GPIO

   GPIO(General-purpose input/output),中文名叫通用型輸入輸出,是STM32可控制的引腳,最基本的功能就是控制輸出高低電平以及檢測輸入電平高低,是非常重要的一個外設。在講GPIO之前,我們先來了解一下端口和引腳的相關定義。

 

端口與引腳

  端口(Port)是單片機內部(CPU單元)和外部IO的接口組 ,以PA端口為例,PA是PortA的縮寫,除了PA端口之外還有PB~PH一共8個端口。每個端口有8到16個引腳(以芯片為准):PA有PA0到PA15。引腳(又稱管腳,Pin)是芯片外接的一個個管腿,引腳有特殊的引腳比如電源,地引腳,晶振引腳,復位引腳,BOOT引腳之外,其余都可以看作是GPIO引腳,那么GPIO引腳有些是模塊引腳,當定義為模塊管腳時,PIN起模塊中定義的功能。比如定義成SPI模塊的管腳,那就按照具體芯片的規定,或者定義成MOSI,或者定義成MISO,或者定義成SCLK,這些不是任意的。那剩下的就是普通元器件接的GPIO,沒有特殊化引腳。具體可參考下圖。

image-20210810122716889

image-20210810122721469

 

GPIO模式配置

  GPIO可以由軟件配置成8種模式:

  1. 輸入浮空 2.輸入上拉 3.輸入下拉 4.模擬輸入 5.開漏輸出 6.推挽輸出 7.推挽式復用 8.開漏式復用

 

  想理解好這些模式,我們需要重點分析下面的GPIO框圖

image-20210810124551858

 

保護二極管、上下拉電阻

  先看圖片右側的1部分,這部分是輸入輸出共有的部分,包括兩個保護二極管和上下拉電阻。

  保護二極管作為與IO口最近的元件,起到保護內部芯片的作用。當引腳外部輸入過高或是過低的電壓時,保護二極管都會生效。當引腳電壓高於VDD_FT 時, 上方的二極管導通,當引腳電壓低於 VSS 時,下方的二極管導通,防止不正常電壓引入芯片導致芯片燒毀。盡管有這樣的保護,並不意味着 STM32 的引腳能直接外接大功率驅動器件。

  上下拉電阻允許用戶配置相應開關控制引腳的默認電平狀態,當我們開啟上拉開關時,IO引腳默認接在VDD上,開啟下拉時,IO引腳默認接在VSS低電平。通過上下拉電阻的配置,我們可以消除引腳狀態不確定的影響。只要引腳沒有接入外部器件,或是已知外部設備不會干擾引腳電平時,我們可以確定當前引腳的電平狀態。那如果我們將兩個開關都斷開,選擇”既不上拉也不下拉模式“,我們稱這種狀態叫浮空模式,在這種模式下我們用電壓表測引腳電壓會得到不確定的電壓值。我們一般情況下會選擇上拉或是下拉來保證引腳有默認的電平狀態。還要強調一點是,在芯片內部的上拉是弱上拉,即通過此上拉輸出的電流是很弱的 ,也就是說配置成上拉之后並不會影響輸出的結果。

  上下拉電阻的作用:

 - 在芯片上電后和引腳配置之前消除引腳不確定的狀態
 - 提高驅動能力,輸出能力(上拉)
 - 可代替跳線帽,選擇BOOT模式啟動
 - 提高遠距離信號線的抗干擾能力
 - 配合開漏輸出模式輸出高電平

 

輸出模式

  再來看看圖片下半部分,也就是輸出的相關結構。我們從左往右看

  可以看到控制輸出的高低電平信號由兩部分構成,一部分是芯片直接控制輸出高低電平,這一部分操作是由兩個寄存器完成:GPIOx_ODR寄存器和GPIOx_BSRR寄存器,另一部分輸出為復用功能輸出,所謂:“復用”功能,指的是片上外設對GPIO引腳進行控制,此時GPIO 引腳用作該外設功能的一部分,算是第二用途。 例如串口通訊時我們可以用某個GPIO引腳用作串口的發送引腳或是接收引腳,此時只需要將引腳配置成復用成串口功能即可,在原理圖上我們看到一個引腳往往有許多功能,但是同時一個引腳只能使用一種功能,當引腳被復用為其他功能時,引腳的高低電平控制就不受ODR寄存器和BSRR寄存器控制了,同時也要注意,不是所有的引腳都可以復用成任意一種功能,即使是復用也是芯片合理分配的引腳,復用前要查閱原理圖看該引腳是否有對應復用功能。

  那不論哪種方式得到的輸出信號,進入輸出控制后,就有兩種輸出模式可以選擇,而這兩種輸出模式則是通過兩個MOS管P-MOS和N-MOS來進行輸出。

  首先是推挽輸出(Pull-Push Mode 簡稱PP Mode),當輸入高電平時,上方P-MOS管導通,下方N-MOS管關閉,對外輸出高電平;當輸入低電平時,N-MOS 管導通, P-MOS 關閉,對外輸出低電平。 這樣通過兩個MOS管來進行高低電平的切換,使得負載能力和開關速度都很大的提高。推挽輸出的低電平為0v,高電平為3.3v。

  然后是開漏輸出(Open Drain Mode 簡稱OD Mode),當引腳配置為開漏輸出模式后,上方的 P-MOS 管完全不工作。如果我們控制輸出為 0,低電平,則 P-MOS 管關閉, N-MOS 管導通,使輸出接地,若控制輸出為 1 (它無法直接輸出高電平)時,則 P-MOS 管和 N-MOS 管都關閉,所以引腳既不輸出高電平,也不輸出低電平,為高阻態。 高阻態意思就是電阻值很高,既不是低電平也不是高電平,對外像斷路一樣,不被任何東西驅動也不能驅動任何東西,如果高阻態再輸入下一級電路的話,對下級電路無任何影響,和沒接一樣。因為這個原因,所以單獨的開漏模式下,並不能輸出高電平,而是一定要搭配一個外部上拉才能輸出高電平。因此開漏輸出具有“線與”特性:當很多引腳都配置成開漏模式接在一起,那么只有當所有引腳都輸出高阻態時,才能由外部上拉將電平拉高,一旦有一個引腳輸出低電平,則整個線路相當於短路接地,輸出低電平。IIC就是利用了開漏模式下的線與特性判斷總線的占用狀態。

  還可以看到有一類輸出它並不經過雙MOS管結構,就是右下角的模擬信號輸出,此時GPIO引腳用於DAC作為模擬電壓輸出通道,模擬信號直接輸出到引腳,當GPIO用於模擬功能時(包括輸入輸出),引腳的上、下拉電阻是不起作用的,這個時候即使在寄存器配置了上拉或下拉模式,也不會影響到模擬信號的輸入輸出。

image-20210810151623840

 

                         推挽輸出有P-MOS和N-MOS控制,而開漏輸出只有N-MOS有作用

  總的來說,大多數情況下我們會選擇推挽輸出,其負載能力強且高低電平切換速度快。只有某些特殊情況下,我們才會選擇開漏模式,例如I2C、 SMBUS 通訊等需要“線與”功能的總線電路中。 而且開漏模式具有推挽模式不具備的優點,由於推挽模式下電平只有0~3.3v,但是開漏輸出的高電平取決於上拉電源,可以在外部上拉一個5v電源,這樣開漏模式下的IO口可以輸出5v的高電平。

 

輸入模式

  最后我們來看看上半部分的輸入結構。從右往左看框圖。

  在輸入模式下,輸出被禁止。最終的數據寄存器每隔一個AHB1時鍾周期更新一次當前引腳的電平狀態。IO口的引腳在經過上下拉電阻引入后,如果有復用功能輸入,則該引腳的電平狀態不會經過施密特觸發器直接由復用的外設讀取。若是取消復用輸入,則引入的電平會經過施密特觸發器作用。簡單的來說模擬量的電壓信號經過施密特觸發器后會變成0、1的數字信號。具體原理是當輸入電壓高於正向閾值電壓,輸出為高;當輸入電壓低於負向閾值電壓,輸出為低;當輸入在正負向閾值電壓之間,輸出不改變。經過施密特觸發器后的數字信號直接由輸入數據寄存器(GPIOx_IDR)儲存以供讀取。如果GPIO 引腳用於 ADC 采集電壓的輸入通道時,用作“模擬輸入”功能,此時信號是不經過施密特觸發器的,因為經過施密特觸發器后信號只有 0、 1 兩種狀態,所以 ADC 外設要采集到原始的模擬信號,信號源輸入必須在施密特觸發器之前。與模擬輸出一樣,上下拉電阻也是不起作用的。

 

寄存器

  關於寄存器,在本文中,與GPIO相關的寄存器我只提及了名字,並沒有強調其用法,是因為在初步的學習中我們通過調用庫函數可以暫時忽略其底層的寄存器操作,但是了解寄存器的具體功能也是非常有必要的,那了解寄存器一定要查閱《STM32F4xx 參考手冊》中對應外設的寄存器說明。

 

外設介紹

 

發光二極管

發光二極管image-20210812150042181

  發光二極管簡稱為LED,長腳為正極,短腳為負極。右圖中二極管帶有發光剪頭的圖標就是LED在原理圖中的符號。當 LED 內有電流通過時會發光,在安全電流范圍內,電流越大,亮度越亮。

 

按鍵

2018111622073416image-20210812150713410

  按鍵簡稱KEY,分為獨立按鍵和矩陣鍵盤,在這里我們只介紹獨立按鍵。獨立按鍵有四個針腳,其中有兩對引腳是默認導通的,所以對外可以看作只有兩個引腳,有些原理圖中KEY也只有兩個引腳。按鍵的一段接在芯片的IO口上,另一端要么接在VCC上要么接在GND上,這對我們配置按鍵有影響,需要我們查看原理圖。

  由於按鍵是機械彈性開關,當機械觸點斷開、閉合時,由於機械觸點的彈性作用,一個按鍵開關在閉合時不會馬上穩定地接通,在斷開時也不會一下子斷開。 因而在閉合及斷開的瞬間均伴隨有一連串的抖動,如下圖所示。

 

 

  這些忽高忽低的電平也會被單片機IO口捕獲到,那這對我們的邏輯判斷是非常不利的,所以我們要消除這些抖動,保留穩定的電平狀態。按鍵消抖有硬件方案也有軟件方案:硬件方案是在按鍵上並聯一個電容,利用電容的充放電特性對抖動過程產生的電壓毛刺進行平滑處理實現消抖。軟件方案目前也有兩種,因為人為按下或者松開開關,穩定的電平持續時間在100ms左右,抖動的時間一般不會超過10ms,所以我們的思路就是在檢測到按鍵按下/松開時,等待10ms再進行檢測,如果檢測結果一致,則判斷按鍵按下/松開。這種方法叫延時重采樣法,具體有兩種實現方法,這兩種方法分別對應按鍵作為GPIO輸入和GPIO作為外部中斷(這個之后會講到)。另一種方法叫持續采樣法,也就是在檢測到某個電平時對之后的一段時間周期進行持續檢測,如果在采樣周期內電平保持不變則確認按鍵按下/松開。

延時重采樣法

  • 優點:操作簡單

  • 缺點

    • 如果延時太短,有可能兩次采樣時都處於抖動時間,因此可能引起誤判;

    • 如果延時太長,可能檢測不出按鍵變換

持續采樣法

  • 優點:樣本足夠多,減少誤判的可能性。

  • 缺點:持續檢測的時間太長(大於按鍵按下和釋放的時間差),則可能無法檢測按鍵的變換

     

按鍵檢測完的輸出有兩種形式

一種像撥碼開關或是台燈開關一樣是電平輸出,只要按下,輸出的電平改變后就保持,如key_out1

另一種是像門鈴一樣的脈沖輸出,每按下一次按鍵就輸出一個脈沖信號 如key_out2

img

Key_out1的輸出與Key_in的變換趨勢相同,只是濾除了抖動成分;

Key_out2則是每當按鍵按下后輸出一個高電平脈沖。在大多數的應用中會用到Key_out2所示功能。

雖然按鍵硬件上按下就是按下,松開后信號就馬上斷開,但是我們可以在軟件上利用一個變量和非運算符 !來實現台燈一樣的開關效果

實際操作

  我們打開STM32CubeMX,選擇MCU為STM32F427IIHx

image-20210812152859178

  再打開《Robomaster開發板用戶手冊》可以看到下方列表中10處有8個LED,13為自定義按鍵,18還有兩個紅綠LED

image-20210812153144861

 

image-20210812153254482

  然后我們在A型板原理圖pdf中搜索(Ctrl+F)LED和KEY,得到他們的引腳。這里可以看出,LED是一端是接在VCC也就是高電平上的,那么如果引腳輸入高電平,發光二極管兩邊沒有電勢差,自然也就不會亮,如果引腳輸入低電平,發光二極管就會依據電流大小發光。按鍵也是連在VCC上的,那相應地我們要給PB2配一個下拉電阻,如果浮空不能確定引腳的電平狀態。

image-20210812153555543

image-20210812153621031

  這些引腳在芯片原理圖上也有標注(上圖是片上外設原理圖)

image-20210812153933080

image-20210812154001366

  那個8XLED的沒有直接注明是LED搜索不到,但是可以通過LED的符號查出他們的引腳

image-20210812154130382

  知道引腳之后我們在STM32CubeMX上進行配置

image-20210812154419426

image-20210812160510687

  再配置LED的引腳

image-20210812161349702

image-20210812172726500

image-20210812173056791

image-20210812174728873

image-20210812174844124

image-20210812175153760

image-20210812175428342

  最后點擊右上角的GENERATE CODE 生成代碼

image-20210812175941686

  進入MDK-ARM文件夾,找到以uvprojx結尾的文件,雙擊我們會用keil打開它。可以在左側的工程目錄里看到Application/User/Core文件夾中除了默認的main.c外,STM32CubeMX還生成了gpio.c,接下來我們打開gpio.c來對比一下,看看CubeMX到底幫我們做了些什么工作。

image-20210813101957801

image-20210812182453224

image-20210812181739396

image-20210812181859531

image-20210812181956480

  可以看出,在STM32CubeMX中配置的代碼都在keil中生成了本應該由用戶自己寫的配置代碼,並且代碼量也不小,因此ST公司才大力推行與STM32CubeMX配套使用的HAL庫。

接下來就是我們開始編寫代碼了,那看先本次任務涉及的函數,之前談到在function窗口內我們可以看到各個.c文件里有哪些函數。

  我們今天重點學習以下三個GPIO相關的函數。

  • HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

  • HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);

  • HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

image-20210812191550537

image-20210812191700160

  先看HAL庫中的ReadPin函數,HAL庫中每個函數上方都有函數的相關說明,我們來一一解釋一下:

  • brief:簡要說明一下這個函數的作用,此處表明ReadPin函數可以讀取某個特殊的引腳的輸入電平狀態

  • param:是參數parameter的縮寫,說明中一共有兩個@param說明這個函數有兩個參數。

    • 參數一:GPIOx,說明中說GPIOx,x可以是A~I(429是A到K)中任意一個來選中GPIO的端口

    • 參數二:GPIO_Pin,GPIO_Pin可以選中端口中一個具體的引腳,x可以0~15

  • retval:是return value的縮寫,此處說明ReadPin函數的返回值是讀取到的電平狀態

  到此就介紹完了ReadPin函數,也就是說ReadPin函數只要我們能選中我們想要讀取的引腳的端口和引腳號,ReadPin函數就能返回其當前的電平狀態。那如果你還不知道應該怎么填寫參數,或是不知道其返回值返回什么,那可以用一個keil中非常好用的功能:go to definition of,通俗地說如果你不知道一個函數、變量、宏定義、類型的定義是什么,你可以將鼠標懸停在其上方,右鍵然后go to definition of ,軟件會自動跳轉到相應的定義處。

image-20210812193020128

image-20210812193252539

  那么類似地,我們來看看WritePin函數和TogglePin函數

image-20210812193358011

image-20210812193450069

  如果你完全理解了上面的函數解讀的話,你應該也能理解這兩個函數的用法,這里我就不在像之前一樣詳細解釋了。

  • WritePin函數:輸入三個參數:引腳端口號,引腳號,電平狀態,沒有返回值。執行該函數,單片機會將你所選的引腳和電平狀態將 該引腳的電平拉高或拉低。

  • TogglePin函數:輸入兩個參數:引腳端口號,引腳號。執行該函數單片機會將你所選的引腳電平狀態反轉,如果之前是高電平則置 低成低電平,如果之前是低電平則拉高成高電平。

  最后我們介紹一個制作流水燈必要的函數:延時函數 HAL_Delay函數,這是一個毫秒級的延時函數。在stm32f4xx_hal.c里

image-20210812195925880

  用法也非常簡單,如果你想延時1s,也就是1000ms,寫成函數為HAL_Delay(1000);

  接下來是代碼實現,可以看到我所有的代碼都是寫在begin和end之間,防止被擦除。同時我的函數都放在while(1)的死循環中,在裸機開發過程中,所有的程序都在main()里面執行,

  main函數中有while(1)的死循環,里面存放一些需要一直執行的操作,在while循環外存放的就是一些初始化的語句,這些語句只需要執行一遍就行了。

image-20210813101626240

  流水燈的思路就是將一個LED亮100ms然后滅緊接着下一個LED亮100ms,當然100ms只是測試效果比較好的一種,你也可以試試延時不同時長達到不同效果的流水燈,但是必須要有延時,因為芯片內部執行代碼的速度相當快,如果你將一個IO口電平拉高后馬上置低,肉眼觀察LED是不會亮的,那我是用A型板的8×自定義LED,如果真要寫流水燈的話要寫8×3也就是24行代碼,這有些冗雜,那可以看到我用了6行代碼就實現了流水燈,是因為我把我住了這些IO口的特點,我們在原理圖上可以看到這8個IO口是PG1~PG8,所以他們的端口都是GPIOG,所以我自己宏定義了一個LED_GPIO_Port代表GPIOG,當然也可以直接用GPIOG,只是這樣代碼可讀性高一些,在看看Pin1到Pin8,我們利用go to definition of 可以查到如下結果:

image-20210813103241123     

   為了更好地展示原理,我將16進制數在右側寫成二進制,可以很明顯的看到這些pin口地址是獨立而且相鄰的,也就是說如果我對地址0000 0011進行拉低電平,那么0腳和1腳的燈會同時亮,可以看到在宏定義的下方有個GPIO_PIN_ALL 的值為0xFFFF,轉換為二進制就是每一位都是1,也就是選中了0~15中所有的pin口,那現在思路可以轉換成0000 0001如何轉換到0000 0010一直轉換到1000 0000,我們可以以十進制作為對比,如果你有數 1,那你要得到10 ,100, 1000,……1000 0000,你的想法自然是×10,×10²,……,那現在是二進制,你要從1轉換到 10,自然要×2,轉換到100,要×2²,轉換到1000 0000,就要×2⁷。可以看到我的程序中,對pin的判斷是pin>128在重新歸零,保證乘數pin從1到128都取得到。如果有學會位操作的,可以嘗試用左移運算符來重寫該功能,這里不做演示。

image-20210813105941812

  按鍵輸入的代碼就比較簡單了,主要就是一個按鍵消抖,具體做法就是延時后再檢測。

  寫好程序之后呢,我們就要將程序從電腦下載到開發板上,這涉及到單片機仿真器,也被叫做下載器或者調試器。市面上常用的調試器除了J-Link ,ST-Link還有CMSIS-DAP(有時簡稱DAP:Debug Access Port 即調試訪問端口)。他們都兼容SWD模式和JTAG模式,DAP還有虛擬串口的功能,可以當做USB轉TTL用。但三者中只有DAP是電腦免驅的,stlink和jlink都需要安裝驅動,關於安裝驅動網上的教程也非常多,可以自行安裝。

 

stlink jlink image-20210813144055723

            ST-LINK V2                             J-LINK                     CMSIS-DAP

 

J-TAG接口:JTAG(Joint Test Action Group,聯合測試行動小組)是一種國際標准測試協議。

標准的JTAG接口是6線:VCC、GND、TMS、TCK、TDI、TDO,分別為電源線兩根、模式選擇、時鍾、數據輸入和數據輸出線

SWD接口:串行調試(Serial Wire Deb 、CLK、DIO,分別是電源信號線兩根、串行時鍾輸入、串行數據輸入輸出

 

  A型開發板留了SWD接口可供我們下載調試。接線就是一一對應。 計算機—USB接口—調試器—SWD接口—單片機。

 

 

 

 

image-20210813154551412

  如果VCC和GND都接正確的話,那么開發板上電后,配對的一對無線調試器的指示燈就會常亮,這時候我們再打開keil,點開魔術棒按鈕

image-20210813151812628

img

image-20210813152450756

  至此,全部的准備工作都已經完成,我們只需要點擊燒錄按鈕觀察流水燈效果和測試按鍵即可。學會原理之后,可以嘗試各種燈效。

 

總結

  本次課程我們需要重點掌握以下幾點:

  • GPIO輸入輸出框圖、GPIO的8種模式以及GPIO的三個函數

  • 查看開發板手冊查閱外設種類,以及通過芯片原理圖查找外設相應引腳

  • STM32CubeMX的使用

  • 如何利用keil中Function窗口來查閱函數用法

  • keil中 go to definition of 的功能


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM