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