---
# System prepended metadata

title: '[STM32] GPIO(LED 蜂鳴器 按鍵輸入)'
tags: [stm32]

---

# [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燈按照順序跑動，按鈕按下時跑馬燈會有變化且蜂鳴器發出聲響
:::
![S__255696902_0](https://hackmd.io/_uploads/H1qNfddt1e.jpg)
![S__255696900_0](https://hackmd.io/_uploads/SyqVMdOYJe.jpg)
{%youtube XHtZdKsiiWc%}
## STM32CubeIDE設定
### 點選 File -> New -> STM32 Project
![image](https://hackmd.io/_uploads/SkfRDudt1g.png)

---
### 選取開發板型號：STM32F411E-DISCO
![image](https://hackmd.io/_uploads/S18wFO_tye.png)


---
### 建立專案
![image](https://hackmd.io/_uploads/SkFkBKOK1e.png)


---
### Pinout -> Clear Pinouts 移除不需要的Pin腳設置
![image](https://hackmd.io/_uploads/SkDmytuKkx.png)
![image](https://hackmd.io/_uploads/rJeByKuFkx.png =30%x)


---
### 設定 RCC 時鐘源
![image](https://hackmd.io/_uploads/HJtTpuOYyg.png)


---
 ### Debug 設定
![image](https://hackmd.io/_uploads/Bk5kC__Kyx.png)


---
### Pin腳啟用 

**按鈕1、2**：
PD1、PD2 (GPIO_Input)
**蜂鳴器**：
PD6 (GPIO_Output)
**LED**：
PD12、PD13、PD14、PD15 (GPIO_Output)

![image](https://hackmd.io/_uploads/ryP5LuOF1e.png =75%x)

---

### Pin腳設定 

![image](https://hackmd.io/_uploads/BkjYI_uFkl.png)


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

![image](https://hackmd.io/_uploads/B11qzFOFkl.png)

---
### Nucleo_Pinout  
![nucleo_pinout_13](https://hackmd.io/_uploads/BJz_JYHiyl.png)

---
### 電路圖  
![GPIO](https://hackmd.io/_uploads/Hkk5kKHiyl.png)

## 程式碼

::: 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 */
```
:::

---
