[STM32] 03-GPIO _Output

Morgan Ting
閱益如美
Published in
19 min readJun 19, 2021
Photo by Anthony Indraus on Unsplash

使用 STM32CubeIDE 開發 STM32 專案不只有圖形化設定並且能使用官方函式庫,可以說是相當方便。本文章將使用搭載 STM32F103C8T6 的 Blue pill 開發板演示 I/ O 腳位的輸出點亮 LED 燈。

文章內容

  1. Blue pill 開發板
  2. GPIO 輸出模式
  3. 相關暫存器
  4. 建立專案與設定
  5. 使用 HAL 函式庫撰寫程式
  6. Debug 設定
  7. Live Expressions
  8. 成果展示
  9. 總結

材料

  1. STM32 Blue pill 開發板 *1
  2. ST-LINK v2 燒錄器 *1
  3. LED 燈 *1
  4. 220 Ω 電阻 *1
  5. 麵包板與單芯線

Blue pill 開發板

作為一款入門級開發板 Blue pill 相當受歡迎,小小一片確有大大功能。Blue pill 主要是由 Cortex-M3 的STM32F103C8T6 獨挑大樑,該開發板上設計成最小系統也就是說除了讓微處理器運作的必要元件之外沒有任何擴充,搭配 ST-LINK v2 燒錄器透過 SWD 介面與電腦端連結便可以進行學習旅程了。這次使用的 ST-LINK v2 如下:

Blue Pill board
Blue Pill board

GPIO 輸出模式

Blue Pill 開發板是 LQFP48封裝共有 37 個 I / O 腳位,而General Purpose I / O , GPIO Port分別是 GPIOA、GPIOB,因封裝而異每一組 Port 的 I / O 腳位數量不等而完整的 GPIOA 有 16 支 I / O 腳位。詳細要看開發板上實際的設置。

Ref. STM32F103xx data sheet

GPIO 共有以下輸出模式

  • Output open-drain 開洩極輸出。
  • Output push-pull 推挽輸出。
  • Alternate function open-drain 多用途開洩極輸出。
  • Alternate function push-pull 多用途推挽輸出。

這裡說的 alternate fuction 是指該 I / O 有其他硬體功能,例如 USART、SPI …. 等。

從手冊上可以了解有兩大輸出方式:open-drain 與 push-pull 。

GPIO 設定成輸出模式時有以下特性

  • 輸出緩衝器被開啟,這裡面包含了 open-drain 與 push-pull 輸出模式,採用 open-drain 輸出時若輸出暫存器輸出資料 「0」則啟動 NMOS ( PMOS 無動作),輸出端形成高阻抗狀態。採用 push-pull 時輸出暫存器輸出資料「0」則啟動 NMOS,輸出資料「1」則啟動 PMOS。
  • 開啟TTL Schimitt trigger 樞密特觸發器。
  • 關閉弱上拉與弱下拉電阻功能。
  • I / O 輸出資料隨著 APB2 時脈被採樣到輸入資料暫存器中。
  • Open-drain 模式下,讀取輸入資料暫存器可以得知 I / O 狀態。
  • Push-pull 模式下,讀取輸出資料暫存器可以得知最後一次輸出狀態。
Ref. STM32F103xx data sheet

相關暫存器

GPIO 相關暫存器

  • Port configuration register Low , GPIOx_CRL。輸出入模式與頻率設定。
  • Port configuration register High , GPIOx_CRH。輸出入模式與頻率設定。
  • Port Input data register , GPIOx_IDR。輸入資料暫存器。
  • Port output data register , GPIOx_ODR。輸出資料暫存器。
  • Port bit set / reset register , GPIOx_BSRR。位元設置 / 清除暫存器。
  • Port bit reset register , GPIOx_BRR。位元清除暫存器。
  • Port configuration lock register , GPIOx_LCKR 。鎖定暫存器。

Port configuration register Low , GPIOx_CRL

x 為 Port 名稱 A、B、C

GPIOx_CRL 與 GPIOx_CRH 分別用來設定 Port 上所有 I / O 腳位的輸出與輸入模式及頻率,GPIOx_CRL 用來設定 Port 第 0 至 第 7 個 I / O 腳位,GPIOx_CRH 用來設定 Port 第 8 至 第 15 個 I / O 腳位 其暫存器如下所示。

GPIOx_CRH Ref. STM32F103xx datasheeet
GPIOx_CRL Ref. STM32F103xx datasheeet

每一個 I / O 腳位由 CNF 與 MODE 兩個暫存器進行設定。

GPIO Mode

Port Input data register , GPIOx_IDR

輸入資料暫存器,讀取此暫存器可以知道輸出狀態。

共 16 位元,每一個位元表示一個 I / O 狀態。讀取資料時必須一次讀取 16 位元資料。

GPIOx_IDR Ref. STM32F103xx datasheet

Port output data register , GPIOx_ODR

輸出資料暫存器。

要輸出的資料放在 ODR 裡面,必須以 16 位元形式操作。

GPIOx_ODR Ref. STM32F103xx datasheet

Port bit set / reset register , GPIOx_BSRR

位元設置 / 清除暫存器。

共有 32 位元,前 16 位元 BRy ( y = [15:0] ) 是清除位元功能,BR 是 Bit Reset 之意,對 BR 暫存器寫入 「1」會清除ODR暫存器對應的位元為「0」,後 16 位元 BSy ( y = [15:0] ) 是設置位元功能,BS 是 Bit Set 之意,對 BS 暫存器寫入「1」會設置 ODR 暫存器對應的位元為「1」,每一個位元代表每一支 I / O 腳位。

GPIOx_BSRR Ref. STM32F103xx datasheet

Port bit reset register , GPIOx_BRR

位元清除暫存器。

對 BR 暫存器寫入 「1」會清除ODR暫存器對應的位元為「0」。

GPIOx_BSRR 可以設置 ODR 暫存器為「1」,或清除為「0」。

GPIOx_BRR 只能清除 ODR 暫存器為「0」。

GPIOx_BRR Ref. STM32F103xx datasheet

Port configuration lock register , GPIOx_LCKR

鎖定暫存器。

對 LCKK 進行鎖定程序後會鎖定 LCK [ 15:0 ] 設定的狀態。被鎖定的 I / O 腳位在系統重置之前都不能對其改變狀態。

設定 LCK [15:0 ] 時必須在 LCKK 為「0」時進行設定,LCK 設置「1」表示鎖定該位元,「0」表示不鎖定,LCK 每一個位元進行鎖定時對應 CRL 或 CRH 兩個暫存器 上4 個位元 ( 每一個 I / O 腳位組態由 CRL 或 CRH 的 CNF [ 1:0 ] 與 MODE [ 1:0 ] 共 4 位元組成 )。

LCKK 鎖定程序 : 對 LCKK 寫「1」==> 寫「0」==> 寫「1」==> 讀「0」==> 讀「1」。

進行鎖定程序時不可操作 LCK 。

GPIOx_LCKR Ref. STM32F103xx datasheet

建立專案與設定

打開 STM32CubeIDE 後我們首先要建立一個專案,在歡迎頁面上點擊 「Start New STM32 Project」。

start new project

接著在 Target Selection頁面要選擇開發板,由於 Blue pill 不是官方推出的開發板因此我們要選擇的是晶片型號,因產品眾多所以利用搜尋鍵入 STM32F103 便會出現對應型號,我們要選 STM32F103C8 。

target selection

右下方會出現相關的晶片型號我們要選擇 「STM32F103C8Tx」。這裡讓使用者感到方便的是有提供產品的資料與訂購資訊,是不是相當貼心呢。確定後就可以往下一步進行。

target selection

接著會出現輸入專案名稱的畫面由於最後要點亮 LED 燈所以命名為 LED,讀者可以自行命名。

輸入專案名稱後按下 「Finish」便完成了。

project name

接下來就要來設定晶片的腳位資料方向、系統時脈等參數。

setting

在頁面的左手邊是專案內容,我們可以看到最上層的資料夾就是專案名稱,底下有很多檔案。中間有 「Catagories」字樣的就是用來設定系統時脈、中斷、計時器…等,右手邊有一個大大的晶片就是用來設定腳位狀態,筆者標註數字的部分就是待會兒我們要設定的順序,依序設定 「 Pinout & Configuration 」、「 Clock Configuration 」、「 Project Manager 」。上述設定只需要滑鼠動作便能完成了,這也是專案開發必經程序。

  1. Pinout & Configuration :我們選定 PA1 這一支腳位來點亮 LED 燈,滑鼠點一下 PA1 會出現小選單,選擇 「GPIO_Output」設定 PA1 作為輸出腳。
pinout setting
  • Catagories :因為用到的功能不多只需要設定 「 SYS 」與 「 RCC 」。

點擊「 SYS 」有一個 「 Debug 」設定,因為是用 ST-LINK v2 所以選擇「 Serial Wire 」,「 RCC 」是用來設定系統時脈來源由於 Blue pill 開發板上有一個外接震盪器作為晶片時脈來源,所以在 Hi Speed Clock ( HSE ) 選擇 「 Crystal / Ceramic Resonator 」。最後可以看看 「 GPIO 」裡面顯示 PA1 腳位的初始狀態,這裡不作設定。

debug configuration
RCC configuration
GPIO configuration

2. 「 Clock Configuration 」這邊會出現一張圖是有關於系統時脈來源以及除頻等設定,因為來源是外接震盪器因此在「 System Clock Mux 」選 「HSE 」便完成時脈來源設定。

Clock Configuration

3. 「 Project Manager 」這裡有三個部分: 「 Project 」、「 Code Generator 」與 「 Advanced Settings 」。

「 Project 」列出一些專案資訊基本上不用做其他更改。

project manager

「 Code Generator 」第一個選項可以設定 「 Copy only the necessary library files 」只複製必要的函式庫到專案目錄底下。其餘可不用特別修改。

code generator

「 Advanced Settings 」會列出目前的設定狀況,可以了解是否有所遺漏例如少設定腳位之類的,右手邊是通訊界面因為此次專案沒用到任何通訊界面因此都顯示 「 DISABLE 」。

Advanced Settings

到這裡已經完成所有初始設定,在上方找到 「 Project 」 按下後選擇 「 Generate Code 」產生初始化的程式碼,儲存後完成階段工作。

generate code

最後就會出現撰寫程式的畫面裡面包含了初始設定所產生的程式碼。

initial code
                              看起來好麻煩呀 !

剛接觸都會有這種感覺但是初始設定過程也都是點點滑鼠就完成了,看到那一坨系統幫我們產生的初始化程式碼,我還是寧願戳滑鼠不想要自己寫。

使用 HAL 函式庫撰寫程式

Hardware Abstraction Layer , HAL,是一款函式庫讓使用者可以不需要操作底層暫存器實現硬體功能,透過HAL 函式庫我們可以輕鬆地對微處理器上的各式功能進行實作,以下我們會利用 HAL 函式庫來進行 I / O 的輸出功能。

我們在 PA1 上接了一個 LED 燈要令它發光就必須使得 PA1 呈現高電位方能驅動 LED 燈,HAL 函式庫提供了這個語法來驅動 I / O 腳位。

HAL_GPIO_WritePin(GPIOx, GPIO_Pin, PinState)

有三個參數要填入。

  • GPIOx :這是腳位所在的 PORT,x 代表埠號例如 A、B、C 等。
  • GPIO_Pin :這是腳位名稱,例如 GPIO_PIN_1 代表編號 1 腳位,這裡也可以填入別名。
  • PinState :這是輸出邏輯準位,填 GPIO_PIN_RESET 表示邏輯 Low ,GPIO_PIN_SET 表示邏輯 High。

我們打算讓 LED 燈一閃一閃,所以要先輸出 High 點亮 LED 燈,稍微延遲後再輸出邏輯 Low 關閉 LED 燈,最後再稍加延遲然後反覆動作。依照這樣的需求首先找到程式碼出現 while(1) 的地方,程式寫在這裡就會反覆運作。輸入 HAL_GPIO 這時不用急著打完整個函式,可以按下 「 Ctrl + 空白鍵 」( 注意輸入法必須在英文模式 ) ,這時會出現關於 HAL_GPIO 的所有函式並找到我們要的 HAL_GPIO_WritePin(GPIOx, GPIO_Pin, PinState) 。

HAL GPIO functions

再來就是要填入參數,由於 PA1 位於 GPIOA 因此第一個參數填入 GPIOA,第二個參數便是 PA1 腳位可是不能填 PA1 這樣會錯誤,不知道怎麼填可以在參數的位置上按下 「 Ctrl + 空白鍵 」依樣會出現選單,PA1 腳位就是 GPIO_PIN_1 ,第三個參數輸入 GPIO_PIN_SET。

形成

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);

表示對 GPIO_PIN_1 輸出高電位。

而延遲函式是

HAL_Delay(Delay);

參數 Delay 是延遲時間,單位是毫秒 ( ms ) ,如果要延遲 1 秒就填入 1000。

重複上述動作將 GPIO_PIN_1 輸出低電位,此階段我們所寫入的程式碼如下:

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);HAL_Delay(1000);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);HAL_Delay(1000);
GPIO output

Debug 設定

程式寫好了免不了要經過編譯與除錯,首先我們要先設定 Debug 組態。

在上方的命令列找到「 Run 」==> 「 Debug Configurations 」進入組態設定頁面。

debug configurations

找到底下 STM32 Cortex M C/C++ Application 滑鼠點兩下後,右手邊會出現設定頁面。

首先看到 「 main 」這個頁面,上面寫著 C/C++ Application 如過呈現空白就按下右邊的 「 Search Project 」按鈕選擇 LED.elf 。之後點選 「 Debugger 」頁面進行設定。

「 Debugger 」頁面第二項 interface 將 ST-LINK S/N 選項前面的方格打勾,此時若有接上 ST-LINK v2 燒錄器可以按一下右邊的 Scan 按鈕,空格內便會出現燒錄器的 ID 號碼。

往下看到 Serial Wire Viewer ( SWV ) 把 Enable 選項打勾,最後確認底下有一個選項 Enable live Expressions 是否有打勾,做完設定後可以按下 Apply 按鈕完成 Debug 設定。

到了這個階段我們已經寫好程式並且把電路與燒錄器都接上,這時我們可以按下快捷鍵 「 F11 」或 「 Run 」==> 「 Debug 」,程式便開始進行編譯若沒有出現錯誤訊息則會在編譯完成後燒錄程式到開發板上,底下會有 Download verified successfully 表示燒錄完成。這時需要按一下 Blue pill 開發板上的 Reset 按鈕便會執行我們的程式了。

Live Expressions

完成了上述動作已經可以運行程式了這裏我們進一步介紹在 Debug 運作當中如何追蹤變數狀態,這時會用到 Live Expressions 功能。

翻開 STM32F103C8T6 手冊可以了解到我們可以讀取 I / O 腳位輸出狀態,如此一來便可以確定 I / O 腳位是否真的輸出指定的狀態,讀取 I / O 狀態的函式如下:

GPIO_HAL_GPIO_ReadPin(GPIOx, GPIO_Pin)

因為要讀取 PA1 腳位的狀態所以第一個參數填入 GPIOA,第二個參數填入 GPIO_PIN_1。

這時還需要一個變數來接收讀取狀態,例如宣告一個變數 int LED_state = 0 ; 再把讀取結果指定給變數形成

LED_state = GPIO_HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) ;

在程式碼當中有許多系統寫的註解分別提醒我們應該把變數、巨集….等寫在指定位置,這裡我們將變數寫在程式前段形成全域變數。

declare variable

程式碼則改成

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);LED_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1);HAL_Delay(1000);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);LED_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1);HAL_Delay(1000);

完成程式修改後執行 「 Run 」==> 「 Debug 」將程式燒錄到開發版上。

接下來我們在頁面右上方找到一個放大鏡的圖示,按下放大鏡後會跳出一個視窗輸入 live expressions, 應該不用全部輸入就會出現 live expressions ( Debug ) 。

點擊該選項後頁面右方會出現 Live Expressions 表單,這時表單應該是空的,按下 「 Add new expression 」後輸入我們要觀察的變數 LED_state 按下 Enter 後即完成。

此時按下快捷鍵「 F8 」Resume ,此功能位於命令列「 Run 」下面一個綠色箭頭符號,執行 Resume 功能後可以看到 Live Expressions 表單內的 LED_state 變數狀態會跟著 LED 閃爍而改變。注意到 Resume 功能是在執行 Debug 模式下才會出現喔。

我們已經完成了 GPIO 的輸出與監測操作,是不是很簡 ( 崩 ) 單 ( 潰 ) 呢 ?

上述過程是每個專案都必須操作的只因為是用圖文說明所以感覺很瑣碎,相信各位冰雪聰明的讀者自行操作過一遍就能了解並不困難。

電路圖

成果展示

Result

總結

Blue pill 是一款搭載 STM32F103C8T6 的開發板搭配 ST-LINK v2 燒錄器可以做程式上傳與除錯,控制 I / O 狀態可以使用 HAL 函式庫的幫助省去自行設定暫存器的麻煩,HAL 函式庫提供眾多功能是學習 STM32 的好幫手。

參考資料

  1. STM32F103 手冊 [ 連結 ]
  2. STMicroelectronics 線上教學 [ 連結 ]

推廣與打賞

感謝讀者若文章有幫助到您可以拍手給我鼓勵,或是加入 Like Coin 帳戶並點擊下方拍手按鈕,免費支持我。

相關文章

  • [STM32] 00-Install STM32CubeIDE [連結]
  • [STM32] 01-ST-LINK [連結]
  • [STM32] 02-STM32F103C8T6 [連結]
  • [STM32] 03-GPIO-Output [連結]
  • [STM32] 04-GPIO-Input [連結]
  • [STM32] 05-Ext-Interrupt [連結]
  • [STM32] 06-Timer-Basic [連結]
  • [STM32] 07-Timer-Interrupt [連結]
  • [STM32] 08-Timer-Output_Compare [連結]
  • [STM32] 09-Timer-PWM [連結]
  • [STM32] 10-Timer-Input_Capture [連結]
  • [STM32] 11-RTC-Second-Interrupt [連結]
  • [STM32] 12-RTC-Alarm_Interrupt [連結]
  • [STM32] 13-Independent_Watch_Dog [連結]
  • [STM32] 14-Windows_Watch_Dog [連結]
  • [STM32] 15-ADC_Conversion [連結]
  • [STM32] 16-ADC_Conversion_Temperature_Sensor [連結]
  • [STM32] 17-ADC_Convversion_DMA [連結]
  • [STM32] 18-SPI [連結]
  • [STM32] 19-UART [連結]
  • [STM32] 20-I2C [連結]

--

--

Morgan Ting
閱益如美

用好奇心探索世界。喜愛學習樂於分享。