一、變量定義部分(理解程序的 "記憶")
c
運行
/* USER CODE BEGIN PV */
static uint8_t last_button_state = 1; // 初始為高電平(未按下)
static uint8_t device_mode = 0; // 設備模式:0=LD1, 1=LD3, 2=蜂鳴器, 3=全部關閉
static uint8_t device_state[3] = {0, 0, 0}; // 設備狀態:0=關, 1=開
/* USER CODE END PV */
這部分定義了程序運行中需要 "記住" 的變量,就像人的短期記憶:
last_button_state
:記錄上一次按鍵的狀態(1 = 未按下,0 = 按下),用于檢測按鍵的 "變化"(從按下到松開或反之)。初始值為 1,因為按鍵未按下時默認是高電平(硬件上拉)。device_mode
:記錄當前操作的設備模式(0-3 分別對應不同設備),類似遙控器的 "模式切換"。device_state[3]
:數組,分別記錄 3 個設備的開關狀態(索引 0=LD1,1=LD3,2 = 蜂鳴器),0 表示關,1 表示開。
二、函數聲明(提前 "告知" 程序要用到的功能)
c
運行
/* USER CODE BEGIN PFP */
void beep_short(void);
/* USER CODE END PFP */
這行代碼是函數聲明,告訴編譯器:后面會定義一個叫beep_short
的函數,無參數、無返回值。作用是提前 "報備",避免編譯器在遇到函數調用時不認識該函數。
三、初始化代碼(程序啟動時的 "準備工作")
c
運行
/* USER CODE BEGIN 2 */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_RESET); // LD1關閉
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); // LD3關閉
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET); // 蜂鳴器關閉// 開機提示音
beep_short();
HAL_Delay(200);
beep_short();
/* USER CODE END 2 */
這部分是程序啟動后首先執行的初始化操作:
- 關閉所有外設:通過
HAL_GPIO_WritePin
函數將 3 個設備的引腳設為低電平(GPIO_PIN_RESET
),確保程序啟動時所有設備都是關閉狀態。- LD1 接在 GPIOC 的 Pin4
- LD3 接在 GPIOC 的 Pin13
- 蜂鳴器接在 GPIOA 的 Pin15
- 開機提示音:調用
beep_short
函數讓蜂鳴器短響兩次(間隔 200ms),提示程序已正常啟動。
四、主循環邏輯(程序的 "核心動作",反復執行)
這部分在while(1)
循環中,是程序運行時一直在重復做的事情,就像人反復 "觀察→判斷→行動" 的過程。
1. 讀取當前按鍵狀態
c
運行
uint8_t current_button_state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_9);
- 通過
HAL_GPIO_ReadPin
函數讀取按鍵引腳(GPIOC 的 Pin9)的當前狀態(1 = 未按下,0 = 按下),并存在current_button_state
變量中。
2. 檢測按鍵 "按下" 動作(下降沿檢測)
c
運行
if (last_button_state == 1 && current_button_state == 0) {// 按鍵從"未按下"變為"按下"(下降沿)HAL_Delay(20); // 防抖延時current_button_state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_9);if (current_button_state == 0) { // 確認按鍵確實按下// 按鍵處理邏輯...}
}
這是按鍵檢測的核心邏輯,作用是準確識別一次有效的按鍵按下:
- 條件
last_button_state == 1 && current_button_state == 0
:判斷按鍵是否從 "未按下"(1)變為 "按下"(0),這種變化叫 "下降沿"。 HAL_Delay(20)
:延時 20ms,是為了 "消抖"—— 按鍵機械結構會導致按下瞬間有微小抖動(狀態快速變化),延時后再讀一次狀態,避免誤判。- 再次判斷
current_button_state == 0
:確認按鍵確實處于按下狀態,排除抖動干擾。
3. 按鍵按下后的處理
當確認按鍵按下后,執行以下操作:
(1)按鍵提示音
c
運行
beep_short(); // 調用蜂鳴器短響函數,反饋按鍵已被按下
(2)切換設備模式
c
運行
device_mode = (device_mode + 1) % 4;
device_mode
從 0 開始,每次按鍵加 1,通過%4
(取余 4)實現循環:0→1→2→3→0→...,對應 4 種模式的切換。
(3)根據模式控制外設(核心邏輯)
通過switch-case
語句,根據當前device_mode
執行不同操作:
c
運行
switch(device_mode) {case 0: // 控制LD1device_state[0] = !device_state[0]; // 取反:0→1(開),1→0(關)// 控制LD1引腳狀態(開=高電平,關=低電平)HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, device_state[0] ? GPIO_PIN_SET : GPIO_PIN_RESET);// 關閉其他設備,確保每次只控制一個設備HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);device_state[1] = 0; // 同步更新其他設備的狀態記錄device_state[2] = 0;break;// case 1(控制LD3)、case 2(控制蜂鳴器)邏輯與case 0類似,只是操作的引腳不同case 3: // 全部關閉模式// 關閉所有設備引腳HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);// 同步更新所有設備狀態為0(關)device_state[0] = 0;device_state[1] = 0;device_state[2] = 0;break;
}
邏輯要點:
- 每個模式只控制一個設備,同時關閉其他設備(避免多個設備同時工作)。
- 用
device_state
數組記錄設備狀態,方便下次切換時判斷當前狀態(開 / 關)。 - 通過三元運算符
device_state[0] ? GPIO_PIN_SET : GPIO_PIN_RESET
快速設置引腳狀態(開 = 高電平,關 = 低電平)。
4. 等待按鍵釋放并更新狀態
c
運行
// 等待按鍵釋放
while (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_9) == 0) {// 空循環,直到按鍵松開(狀態變為1)
}
HAL_Delay(20); // 釋放時的防抖延時
- 這部分確保一次按鍵只觸發一次模式切換,避免按鍵長按導致多次切換。
- 按鍵松開后再延時 20ms,進一步消除釋放時的機械抖動。
5. 更新按鍵狀態記錄
c
運行
last_button_state = current_button_state;
- 將當前按鍵狀態保存到
last_button_state
,為下一次循環的 "狀態變化檢測" 做準備。
五、蜂鳴器短響函數(封裝重復功能)
c
運行
/* USER CODE BEGIN 4 */
void beep_short(void)
{HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET); // 蜂鳴器開啟(高電平)HAL_Delay(100); // 持續100msHAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET); // 蜂鳴器關閉(低電平)
}
/* USER CODE END 4 */
- 這是一個封裝好的函數,實現蜂鳴器短響 100ms 的功能。
- 好處:避免重復寫相同代碼,需要蜂鳴器提示時直接調用
beep_short()
即可,讓程序更簡潔。
總結:程序的整體流程
- 初始化:關閉所有設備,蜂鳴器響兩次提示啟動。
- 循環檢測:反復讀取按鍵狀態,判斷是否有有效按下。
- 按鍵處理:確認按鍵按下后,切換模式→控制對應設備(開 / 關)→關閉其他設備→等待按鍵釋放。
- 狀態記錄:通過變量記錄按鍵狀態和設備狀態,實現 "記憶" 功能。
關鍵思路提煉(自己寫時可復用)
- 按鍵檢測:通過 "上一次狀態 + 當前狀態" 判斷按鍵變化(下降沿),加延時消抖。
- 狀態管理:用變量 / 數組記錄設備狀態,方便切換時判斷當前狀態。
- 模式切換:用
switch-case
或數組索引實現多模式循環。 - 功能封裝:重復使用的功能(如蜂鳴器提示)寫成函數,簡化代碼。
理解這些邏輯后,你可以嘗試修改設備引腳、增加更多模式(如控制 4 個設備),或者改用中斷方式檢測按鍵,逐步掌握 STM32 的 GPIO 控制編程。