/* 学长代码调整,调整内容如下:
* 1.移除不需要功能。简化代码复杂度。
* 2.优化代码逻辑,降低Mega负载。
* 3.增加基础功能,简化设置。
* 4.预留串口通信空间。
*/
#include <Wire.h>
#include "mode.h"
#include "calculate.h"
#include "OLED_config.h"
Adafruit_SSD1306 OLED(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// button
const int numButtons = 10;
// 2 ~ 5: 數值調整,6 ~ 7: rate,vol,8模式,9是啟用,13是設置,44方向
const int buttonPins[] = {2, 3, 4, 5, 6, 7, 8, 9, 13, 44};
// led
const int ledPin[] = {46, 48, 50, 52, 51, 53, 47, 49};
// motor
const int dirPin = 22;
const int stepPin = 24;
const int enablePin = 26;
// other
int button_mode = -1;
bool button_click[10] = {false};
unsigned long pressStartTime = 0;
bool isButtonPressed = false;
const unsigned long DEBOUNCE_DELAY = 50; // 標準防抖延遲 (50毫秒)
const unsigned long PRESS_TIME = 1000;
void setup() {
Serial.begin(9600);
// pinMode
pinMode(dirPin, OUTPUT);
pinMode(stepPin, OUTPUT);
pinMode(enablePin, OUTPUT);
for (int i = 0; i < numButtons; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
}
// 初始化 OLED 顯示屏
OLED_init();
clearDisplay();
}
void loop() {
// 保留原有Pin9常按啟用、流速ul、流量vol、模式設置(快速模式、總量/流速設置)
// ==========================================================
// A. 按鈕按下與計時開始偵測 (無阻塞)
// ==========================================================
for (int i = 4; i <= 9; i++) {
int buttonState = digitalRead(buttonPins[i]);
unsigned long currentTime = millis();
// 1. 偵測 按下邊緣 (LOW & 尚未標記按下)
if (buttonState == LOW && button_click[i] == false) {
// 如果是 Pin 7 (Pin 9) 則開始計時
if (i == 7 && !isButtonPressed) {
pressStartTime = currentTime;
isButtonPressed = true;
}
button_click[i] = true;
}
// 2. 偵測 釋放邊緣 (HIGH & 上次標記為按下)
else if (buttonState == HIGH && button_click[i] == true) {
// 如果在長按時間到達前鬆開 Pin 7,則觸發短按
if (i == 7 && isButtonPressed) {
unsigned long pressDuration = currentTime - pressStartTime;
// 檢查是否是短按 (在 PRESS_TIME 內鬆開,且長於防抖時間)
if (pressDuration < PRESS_TIME && pressDuration >= DEBOUNCE_DELAY) {
button_mode = i; // 7 代表 Pin 9 短按
}
// 清除 Pin 7 的計時狀態
isButtonPressed = false;
pressStartTime = 0;
} else if (i != 7) {
// 其他按鈕 (4, 5, 6, 8, 9) 釋放:觸發單次事件
button_mode = i;
}
button_click[i] = false;
if (button_mode != -1) break;
}
}
// ==========================================================
// B. 長按持續觸發偵測 (僅針對 Pin 7)
// ==========================================================
// 如果 Pin 7 已經被按下,且計時時間超過 PRESS_TIME,立即觸發長按
if (digitalRead(buttonPins[7]) == LOW && isButtonPressed == true) {
if (millis() - pressStartTime >= PRESS_TIME) {
button_mode = 107; // 設置長按模式
// 重要:觸發長按後,立即將 isButtonPressed 設為 false,
// 避免在 keep_motion() 退出後,loop() 再次誤判為長按。
isButtonPressed = false;
}
}
// 如果 button_mode 已經被設置為長按,則跳過 switch 之前的其他邏輯
if (button_mode == 107) {
goto execute_mode;
}
execute_mode:
if (button_mode != -1) {
switch (button_mode) {
// 進入 rate 模式
case 4:
Serial.println("rate");
break;
// 進入 volum 模式
case 5:
Serial.println("volum");
break;
// 進入 mode 模式
case 6:
Serial.println("mode");
break;
// 進入 start 模式
case 7:
Serial.println("start");
break;
// 進入 set 模式(暫時不用)
case 8:
break;
// 進入 dir 模式
case 9:
dir_change();
break;
// 進入 set 模式(暫時不用)
case 107:
Serial.println("Pin 9 【長按】:進入阻塞模式,變更馬達方向/快速設置...");
keep_motion();
isButtonPressed = false;
pressStartTime = 0;
// 2. 清除按鈕按下標記 (防止誤判為新的按下邊緣)
// Pin 9 的索引是 7
button_click[7] = false;
break;
}
}
// 默認為-1
button_mode = -1;
}