# [STM32] GPIO(LED 蜂鳴器 按鍵輸入)
## GPIO 簡介
### 什麼是GPIO(general purpose input output)
GPIO代表通用輸入/輸出。它是集成電路上一種沒有特定功能的引腳。雖然大多數 Pin 腳都有專用用途,例如向某個元件發送訊號,但 GPIO Pin 腳的功能是可自訂的,可以由軟體控制。
### 功能模式:
#### General Purpose(通用功能):
一般的控制模式,由使用者透過程式碼直接控制該 Pin 腳要輸出 High 還是 Low,也可以由程式碼直接讀取該 Pin 腳的值。
#### Alternate Function(復用功能):
使用該 Pin 腳所擁有的特殊功能(例如:UART、PWM、I2C),使用者沒辦法用程式碼直接控制該 Pin 腳的 High 或 Low,而是由指定的特殊功能來控制。
### 輸出電路組態:
#### Push-Pull(推挽):
由一對互補的電晶體組成,可以直接輸出 High 或 Low 電位。
#### Open-Drain(汲極開路):
FET 版的 Open-Collector。由一個 N 通道 FET 構成,只能輸出 Low(GND) 或 Open(開路)狀態,因此要外加一上拉電阻才能使其輸出的 Open 狀態變成 High,而 High 狀態的實際電壓根據上拉電阻所接的電源而定,可以高或低於 IC 本身的電壓值。擁有線接及閘(Wired AND)的特性。
### 輸入模式:
#### Analog(類比):
用於使用 ADC 讀取類比的數值時。需要分配爲 ADC Channel 的 Pin 腳上才能正常使用。
#### Floating(浮接):
一般的讀取模式。若不啓用 STM32 內部的上/下拉電阻,使用時外部電路應要有上/下拉電阻,否則該 Pin 腳浮空時可能無法正確讀值。
## Demo
:::success
功能:讓LED燈按照順序跑動,按鈕按下時跑馬燈會有變化且蜂鳴器發出聲響
:::


{%youtube XHtZdKsiiWc%}
## STM32CubeIDE設定
### 點選 File -> New -> STM32 Project

---
### 選取開發板型號:STM32F411E-DISCO

---
### 建立專案

---
### Pinout -> Clear Pinouts 移除不需要的Pin腳設置


---
### 設定 RCC 時鐘源

---
### Debug 設定

---
### Pin腳啟用
**按鈕1、2**:
PD1、PD2 (GPIO_Input)
**蜂鳴器**:
PD6 (GPIO_Output)
**LED**:
PD12、PD13、PD14、PD15 (GPIO_Output)

---
### Pin腳設定

---
### 設置完成 點選齒輪生成程式碼

---
### Nucleo_Pinout

---
### 電路圖

## 程式碼
::: spoiler main.c
```c=
/* USER CODE BEGIN PD */
#define BUTTON1_PIN GPIO_PIN_1 // 按鈕1的GPIO引腳
#define BUTTON1_PORT GPIOD // 按鈕1的GPIO端口
#define BUTTON2_PIN GPIO_PIN_2 // 按鈕2的GPIO引腳
#define BUTTON2_PORT GPIOD // 按鈕2的GPIO端口
#define BUTTON1 HAL_GPIO_ReadPin(BUTTON1_PORT, BUTTON1_PIN) // 讀取按鈕1狀態
#define BUTTON2 HAL_GPIO_ReadPin(BUTTON2_PORT, BUTTON2_PIN) // 讀取按鈕2狀態
#define BEEPON HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_SET) //開啟蜂鳴器
#define BEEPOFF HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_RESET) //關閉蜂鳴器
/* USER CODE END PD */
/*---------------------------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint16_t led_pins[] = {LD1_Pin, LD2_Pin, LD3_Pin, LD4_Pin}; // LED燈的引腳陣列
int num_leds = sizeof(led_pins) / sizeof(led_pins[0]); // 計算LED數量
/* USER CODE END PV */
/*---------------------------------------------------------------------------*/
/* USER CODE BEGIN 2 */
void LED()
{
static int delay = 300, direction = 1; // 設定初始延遲與方向
// 根據按鈕狀態調整LED跑馬燈速度與方向
if (BUTTON1 == 0 && BUTTON2 == 1) delay /= 1.1; // 按鈕1按下,變快
else if (BUTTON1 == 1 && BUTTON2 == 0) delay *= 1.1; // 按鈕2按下,變慢
else if (BUTTON1 == 1 && BUTTON2 == 1) direction *= -1;// 按鈕同時按下,反轉
// 根據方向執行跑馬燈效果
for (int i = (direction == 1 ? 0 : num_leds - 1);
(direction == 1 ? i < num_leds : i >= 0);
i += direction) {
HAL_GPIO_WritePin(GPIOD, led_pins[i], GPIO_PIN_SET); // 點亮當前LED
HAL_Delay(delay);
HAL_GPIO_WritePin(GPIOD, LD1_Pin | LD2_Pin | LD3_Pin | LD4_Pin,
GPIO_PIN_RESET); // 關閉所有LED
}
// 當按鈕被按下時,蜂鳴器響100毫秒
if (BUTTON1 || BUTTON2) {
BEEPON;
HAL_Delay(100);
BEEPOFF;
}
}
/* USER CODE END 2 */
/*---------------------------------------------------------------------------*/
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
LED(); // 執行LED
}
/* USER CODE END 3 */
```
:::
---