上篇針對GPIO做了詳細的說明,沒看過的先去[Day 7]-【STM32系列】淺入淺出之 General Purpose Input/Output 介紹 (上)再來
今天要來實作在CubeMX上我們是如何設置GPIO PIN腳以及設定開漏(open-drain,漏極開路)和推輓(push-pull)等等功能,還有修改暫存器的數值,函數的調用等等。那廢話不多說直接開始吧。
因為控制IO搭配LED觀察HIGH、LOW比較方便
所以我用麵包板接了一排LED出來
今日目標就是它!
圖中沒有標示出來,但兩邊的接地端(Gnd)要接在一起哦,
所以最下面的GND還要拉一條線到STM32 Board 的 GND,
驅動LED時接地才有電流流回形成迴路。
接著將 GPIOB 的 0 ~ 15 pin,與 LED 對接,
當pin腳輸出HIGH,LED為ON,當pin腳輸出LOW,LED為OFF。
對!你沒聽錯!你要一條一條線拉出來排成 PB0 ~ PB15
光是查接腳圖就快死了,誰叫這顆接腳也不是按照順序啊
重點是這拉完之後很亂很醜啊!!
懶得花錢買點電路板的我於是決定自行土炮了一個
(不喜勿噴XD
:-此系列由STM32CUBEIDE編寫。如果你是使用其他任何的IDE,程式仍然可以運行。但是你必須自行編寫一些項目
開啟CubeMX並新建專案.
選擇上次已經加到我的最愛裡的晶片,滑鼠連按兩下LQFP64包裝的晶片,進入設定頁面
想要控制GPIO首先要先選擇要使用的IO腳和IO腳將要配置的功能
個別點選PA0~PA7,設置GPIO_Output,並打開外部Clock、debug功能
設定MCU速度32MHz
打開GPIO項,選擇任一Pin腳配置
生成文件
1.專案名稱
2.存放路徑
3.用來撰寫的IDE
4.按ok生成並直接open project
怕大家忘記再提醒一下在 按右鍵選Add New Item to Group 'Application/User'
選擇 C File
Name 輸入: mycodes.c
Location 選擇 Src
按 Add 按鍵
接著在main.c定義void mycodes(void);
函式
main主程式中相同的位置加入mycodes();
當初始化完成就會執行我們的程式
// 複製程式碼
#include "main.h"
#include "stm32l0xx_hal.h"
void mycodes(void){
while(1){
}
}
我們自己的code就寫在這個mycodes.c裡面,這樣寫的好處不僅程式碼方便觀看,也不怕重新生成後因為忘記沒寫在begin end裡面被消失
編譯燒錄吧!
0 Error(s), 0 Warning(s)
接下來要說說HAL庫裡提供了甚麼函數供我們使用~
一共有8種方法可以讓我們做使用,
這裡控制LED只介紹兩種~~(好偷懶~~
常用的Write、Toggle:
1.) -Write Pin - 控制單一 GPIO Pinout 為 HIGH or LOW
HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
GPIOx:可以是GPIOA、GPIOB、GPIOC
GPIO_Pin:GPIO_PIN_0、GPIO_PIN_1、GPIO_PIN_3...以此類推,最多看GPIOx支援到多少
PinState:GPIO_PIN_RESET為Low、GPIO_PIN_SET為High
我們將 PB5 為 HIGH 維持 5 秒鐘,LOW 維持 5 秒鐘
這裡需要用到 Delay 函式
void HAL_Delay(__IO uint32_t Delay)
HAL_Delay(x):延遲x毫秒,32位正整數寬
//GPIOB LED(HAL_GPIO_WritePin)
#include "main.h"
#include "stm32l0xx_hal.h"
void mycodes(void){
while(1){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET); //PA5 High
HAL_Delay(500);// Delay 500ms
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);//PA5 Low
HAL_Delay(500);// Delay 500ms
}
}
可以看到PB5 HIGH、LOW的變化在LED上囉!
2.) -Toggle Pin - 切換 GPIO 目前的狀態。如果目前為HIGH則轉為LOW、為LOW則轉為HIGH
HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
GPIOx:可以是GPIOA、GPIOB、GPIOC
GPIO_Pin:GPIO_PIN_0、GPIO_PIN_1、GPIO_PIN_3...以此類推,最多看GPIOx支援到多少
一樣讓 LED 為 HIGH、LOW 間隔500ms
//GPIOB LED閃爍電路(HAL_GPIO_TogglePin)
#include "main.h"
#include "stm32l0xx_hal.h"
void mycodes(void){
while(1){
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5); //PA5 High
HAL_Delay(500);// Delay 500ms
}
}
結果應該是一樣滴!
但是你知道,一條指令就那麼長,有沒有辦法把它縮短呢?
當然有!這裡用一個小技巧,用#define來對函數進行“定義”,舉例來說:
#define 為定義,
定義HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
為 PB5_H
定義HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
為 PB5_L
代表以後如果我們需要PB5為HIGH,不用再打一長串的指令,事先定義好就可以使用自己的命名:
#define
PB5_H
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
#definePB5_L
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
//GPIOB LED閃爍電路(#define 縮短指令)
#include "main.h"
#include "stm32l0xx_hal.h"
#define PB5_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
#define PB5_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
void mycodes(void){
while(1){
PB5_H //PB5 High
HAL_Delay(500);// Delay 500ms
PB5_L //PB5 Low
HAL_Delay(500);// Delay 500ms
}
}
照著個方式把所有的GPIOB 0~15定義出來:
#define PB0_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
#define PB0_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
#define PB1_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
#define PB1_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
#define PB2_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
#define PB2_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
#define PB3_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
#define PB3_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
·
·
·
#define PB15_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_SET);
#define PB15_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET);
來實際做一些變化~
#include "main.h"
#include "stm32l0xx_hal.h"
#define PB0_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
#define PB0_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
·
·
·
#define PB15_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_SET);
#define PB15_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET);
void mycodes(void){
while(1){
PB0_H; PB1_H; PB2_H; PB3_H; //PB0 ~ PB3 HIGH
HAL_Delay(500); // Delay 500ms
PB4_H; PB5_H; PB6_H; PB7_H; //PB4 ~ PB7 HIGH
HAL_Delay(500); // Delay 500ms
PB8_H; PB9_H; PB10_H; PB11_H; //PB8 ~ PB11 HIGH
HAL_Delay(500); // Delay 500ms
PB12_H; PB13_H; PB14_H; PB15_H; //PB12 ~ PB15 HIGH
HAL_Delay(500); // Delay 500ms
PB0_L; PB1_L; PB2_L; PB3_L; //PB0 ~ PB3 LOW
HAL_Delay(500); // Delay 500ms
PB4_L; PB5_L; PB6_L; PB7_L; //PB4 ~ PB7 LOW
HAL_Delay(500); // Delay 500ms
PB8_L; PB9_L; PB10_L; PB11_L; //PB8 ~ PB11 LOW
HAL_Delay(500); // Delay 500ms
PB12_L; PB13_L; PB14_L; PB15_L; //PB12 ~ PB15 LOW
HAL_Delay(500); // Delay 500ms
}
}
接續亮下去,然後再暗回來,差不多做到這裡,大家應該有些概念了吧!
可是你說,每次控制IO都要先#define會不會太麻煩
整體控制來很沒有效率,一整個是土法煉鋼,有沒有更好的辦法呢?
當然有!這樣說當然就是有啦~XD
還記得昨天我們說過,GPIOx的每一組暫存器都是32位寬,每個GPIO底下都有自己的多組暫存器來記錄當前的值,例如IDR、ODR、BSRR、BRR...等等。用法也非常簡單如下:
//GPIOB LED(控制暫存器)
#include "main.h"
#include "stm32l0xx_hal.h"
void mycodes(void){
while(1){
GPIOB->BSRR = (1<<5);
HAL_Delay(500);
GPIOB->BRR = (1<<5);
HAL_Delay(500);
}
}
GPIOB->BSRR:控制GPIOB的BSRR暫存器,BSRR可以針對某一個pin腳改動它的值為High
GPIOB->BRR:控制GPIOB的BRR暫存器,BRR可以針對某一個pin腳改動它的值為Low
(1<<5)
:1左移5位,所以是從PB0 --> PB5,PB5為High
這裡要注意一點,BRR、BSRR只會針對單一pin腳更動它的HIGH、LOW,並不會影響其他未被配置的值
甚麼意思?假如今天你塞了GPIOB->BSRR = 5
,以二進制來說它是0101,所以PB0和PB2會被點亮,其餘IO不論原先是HIGH或LOW會保持原先的狀態,並不會被影響。這種特性在BRR上也是如此。
//GPIOB LED(控制暫存器)
#include "main.h"
#include "stm32l0xx_hal.h"
void mycodes(void){
int i;
while(1){
for(i=0;i<16;i++){
GPIOB->BSRR = (1<<i);
HAL_Delay(50);
}
for(i=0;i<16;i++){
GPIOB->BRR = (1<<i);
HAL_Delay(50);
}
}
}
我這裡寫了一個for迴圈,隨著變數 i 的增加,GPIO會逐一被點亮,點滅。
//GPIOB LED(控制暫存器)
#include "main.h"
#include "stm32l0xx_hal.h"
void mycodes(void){
int i;
while(1){
for(i=0;i<=15;i++)
{
GPIOB -> ODR = (1<<i);
HAL_Delay(50);
}
for(b=14;b>=1;b--)
{
GPIOB -> ODR = (1<<i);
HAL_Delay(50);
}
}
}
一樣的方法,只是換成丟給 ODR ,像這樣亮過去亮回來,會更動暫存器整個的值。
以上這些是基本GPIO使用LED的方法與技巧,
剛開始就這樣會不會太難XDD,
可以試試看用不同的方式會有不同的結果
請熟悉以上這些方法,之後會有更多應用哦!
- STM32 Nucleo-64 boards (MB1136)資料手冊
https://www.st.com/resource/en/user_manual/dm00105823-stm32-nucleo-64-boards-mb1136-stmicroelectronics.pdf- STM32L053R8 datasheet
https://www.st.com/resource/en/datasheet/stm32l053r8.pdf- RM0367 Reference manual Ultra-low-power STM32L0x3 advanced Arm®-based 32-bit MCUs
https://www.st.com/resource/en/reference_manual/dm00095744-ultra-low-power-stm32l0x3-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf- ARM Mbed官網介紹 - NUCLEO-L053R8
https://os.mbed.com/platforms/ST-Nucleo-L053R8/- STM32 官網介紹 - STM32L053R8
https://www.st.com/en/microcontrollers-microprocessors/stm32l053r8.html#overview
- 此開發板售價在臺幣1000元以下,讀者可於以下網站購得:
https://www.mouser.tw/
https://www.digikey.tw/
實在是想不到甚麼文案啊...
請問
在pinout 那邊 設定PA0-~PA7
但是在程式碼都是控制GPIOB,為什麼不是控制GPIOA呢
謝謝~