繼上一篇文章ARDUINO nano + 旋轉編碼器控制介紹如何利用Arduino Nano和旋轉編碼器進行基本控制後,這次我們將進一步探討如何運用這些工具來控制OLED顯示螢幕的選單。這種設置非常適合需要用戶介面的各種項目,例如家用電器、實驗室設備或者任何需要選單控制的裝置。
材料清單
- Arduino Nano/Uno
- 旋轉編碼器
- 0.96吋 I2C OLED 顯示螢幕
- 麵包板和連接線
- 共陰RGBLED
硬件連接
首先,我們需要將硬件組件正確連接:
1.旋轉編碼器連接到Arduino Nano:- CLK接到PIN2
- DT接到PIN3
- SW接到PIN4
- 正極(+)接到VCC
- 負極(GND)接到GND
- SCL接到A5
- SDA接到A4
- VCC接到5V
- GND接到GND
3.共陰RGBLED
- R接到PIN9
- B接到PIN10
- G接到PIN11
程式編寫
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 定義引腳配置和常量定義 | |
#define SERIAL_BAUDRATE 9600 | |
#define CLK_PIN 2 | |
#define DT_PIN 3 | |
#define SW_PIN 4 | |
#define LED_R_PIN 9 | |
#define LED_G_PIN 11 | |
#define LED_B_PIN 10 | |
#define LED 13 | |
#define interruptA 0 // nano腳位2是interrupt 0 | |
// 全局變數 | |
int count = 0; //旋轉編碼器 | |
int lastCLK = 0; | |
int cR = 0, cG = 0, cB = 0; //RGBLED | |
int menuLength1 = 0, menuCounter1 = 0; //主選單 | |
int menuLength2 = 0, menuCounter2 = 0; //次選單 | |
unsigned long buttonPressTime = 0; //按鈕 | |
const unsigned long longPressTime = 2000; //長按2s | |
bool UpdateDisplayPress = false; //按壓旗標 | |
bool UpdateDisplayRotary = false; //旋鈕旗標 | |
unsigned long lastRotaryChange = 0; //去抖動 | |
const unsigned long debounceTime = 10; | |
// 選單項目和功能指標 | |
const char* menuItems[] = {"0. ", "1.LED ", "2.RGB LED ", "3. ", "4. ", "5. ", "6. ", "7. ", "8. "}; | |
const int F_DHT = 0, F_LED = 1, F_RGBLED = 2, F_Buzzer = 3, F_supersonic = 4, F_motor = 5, F_Photoresistor = 6; | |
// OLED | |
#define OLED_RESET -1 | |
#include <SPI.h> | |
#include <Wire.h> | |
#include <Adafruit_GFX.h> | |
#include <Adafruit_SSD1306.h> | |
Adafruit_SSD1306 display(OLED_RESET); | |
// 函式原型 | |
void rotaryEncoderChanged(); | |
void handleButton(); | |
void processEncoder(); | |
void displayMenu(); | |
void functionLED(); | |
void functionRGBLED(); | |
void setup() { | |
Serial.begin(SERIAL_BAUDRATE); | |
Serial.println("START"); | |
pinMode(LED, OUTPUT); | |
pinMode(LED_R_PIN, OUTPUT); | |
pinMode(LED_G_PIN, OUTPUT); | |
pinMode(LED_B_PIN, OUTPUT); | |
attachInterrupt(interruptA, rotaryEncoderChanged, FALLING); | |
pinMode(CLK_PIN, INPUT_PULLUP); | |
pinMode(DT_PIN, INPUT_PULLUP); | |
pinMode(SW_PIN, INPUT_PULLUP); | |
// OLED 初始化 | |
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); | |
display.display(); | |
display.clearDisplay(); | |
display.setTextColor(WHITE); | |
display.setCursor(0,0); | |
display.setTextSize(1); | |
display.print("orangeV TCJHS.lab V3"); | |
display.display(); | |
delay(1500); | |
display.clearDisplay(); | |
displayMenu(); | |
} | |
void loop() { | |
handleButton(); | |
processEncoder(); | |
} | |
//按鈕 | |
void handleButton() { | |
if (digitalRead(SW_PIN) == LOW) { | |
if (buttonPressTime == 0) { // 按下按鈕時記錄時間 | |
buttonPressTime = millis(); | |
} | |
} else { | |
if (buttonPressTime != 0) { | |
if (millis() - buttonPressTime >= longPressTime) { | |
// 長按回原始選單 | |
menuCounter2 = 0; | |
digitalWrite(LED,LOW); | |
resetRGBLED(); | |
} else { | |
// 短按進入各功能 | |
menuCounter2 += 1; | |
if(menuCounter2 > menuLength2) menuCounter2 = 1; | |
if(menuCounter1 > menuLength1) menuCounter1 = 0; | |
} | |
count = 0; | |
UpdateDisplayPress = true; // 按壓才輸出 | |
buttonPressTime = 0; // 重置按鈕時間 | |
} | |
} | |
} | |
//執行功能 | |
void processEncoder() { | |
if(menuCounter2 == 0){ | |
displayMenu(); | |
} else { | |
if (UpdateDisplayPress || UpdateDisplayRotary) { | |
display.clearDisplay(); | |
display.setCursor(0, 0); | |
if(menuCounter1 == F_LED) { | |
if(UpdateDisplayPress) functionLED(); | |
} | |
else if(menuCounter1 == F_RGBLED) functionRGBLED(); | |
else displayMenu(); | |
} | |
} | |
} | |
//旋轉編碼器旋轉 | |
void rotaryEncoderChanged() { | |
//去抖動 | |
unsigned long currentTime = millis(); | |
if (currentTime - lastRotaryChange < debounceTime) { | |
return; | |
} | |
int clkValue = digitalRead(CLK_PIN); | |
int dtValue = digitalRead(DT_PIN); | |
if (lastCLK != clkValue) { | |
lastCLK = clkValue; | |
if (clkValue != dtValue) { | |
count++; | |
} else { | |
count--; | |
} | |
// 限制 count 的範圍,防止溢出 | |
count = constrain(count, -3, 3); | |
//旋轉才輸出 | |
UpdateDisplayRotary = true; | |
} | |
} | |
//初始選單 | |
void displayMenu() { | |
display.clearDisplay(); | |
display.setCursor(0, 0); | |
display.println("PHYduino by orangeV"); | |
menuLength1 = sizeof(menuItems) / sizeof(char*); | |
int startMenuIndex = (menuCounter1 + menuLength1 - 1) % menuLength1; // 計算起始項目 | |
if (count >= 3) { | |
menuCounter1 = (menuCounter1 + 1) % menuLength1; | |
count = 0; | |
} else if (count <= -3) { | |
menuCounter1 = (menuCounter1 - 1 + menuLength1) % menuLength1; | |
count = 0; | |
} | |
//顯示選單項目 | |
for (int i = 0; i < 3; i++) { | |
int menuIndex = (startMenuIndex + i) % menuLength1; | |
if (i == 1) { | |
display.print("> "); | |
} else { | |
display.print(" "); | |
} | |
display.println(menuItems[menuIndex]); | |
} | |
display.display(); | |
} | |
void functionLED() { | |
//思考有幾個模式,短按更換,每個function都要有menuLength2設定,LED分成開關,1開2關 | |
menuLength2=2; | |
digitalWrite(LED, menuCounter2 % menuLength2 ? HIGH : LOW); | |
display.println(menuItems[F_LED]); | |
Serial.print(menuItems[F_LED]); | |
display.println(menuCounter2 % menuLength2 ? "LED ON" : "LED OFF"); | |
Serial.println(menuCounter2 % menuLength2 ? "LED ON" : "LED OFF"); | |
display.display(); | |
//有改變按鈕狀態才重複輸出 | |
UpdateDisplayPress = false; | |
} | |
void functionRGBLED(){ | |
//短按更換,RGB_LED分成R,G,B三色控制功能 | |
menuLength2=3; | |
display.print(menuItems[F_RGBLED]); | |
Serial.print(menuItems[F_RGBLED]); | |
if(menuCounter2==1){ | |
display.println(" R"); | |
adjustColorValue(cR); | |
}else if(menuCounter2==2){ | |
display.println(" G"); | |
adjustColorValue(cG); | |
}else if(menuCounter2==3){ | |
display.println(" B"); | |
adjustColorValue(cB); | |
}else{ | |
display.println(" clear"); | |
resetRGBLED(); | |
} | |
display.print("R="); | |
display.println(cR); | |
display.print("G="); | |
display.println(cG); | |
display.print("B="); | |
display.println(cB); | |
display.display(); | |
display.clearDisplay(); | |
Serial.print("R=,"); | |
Serial.print(cR); | |
Serial.print(",G=,"); | |
Serial.print(cG); | |
Serial.print(",B=,"); | |
Serial.println(cB); | |
//調弱輸出電壓,保護LED燈跟眼睛 | |
analogWrite(LED_R_PIN, cR*0.4); | |
analogWrite(LED_G_PIN, cG*0.55); | |
analogWrite(LED_B_PIN, cB*0.6); | |
//有改變旋鈕按鈕狀態才重複輸出 | |
UpdateDisplayPress = false; | |
UpdateDisplayRotary = false; | |
} | |
void adjustColorValue(int &colorValue) { | |
colorValue += 5 * count; | |
colorValue = constrain(colorValue, 0, 255); | |
count = 0; | |
} | |
void resetRGBLED() { | |
analogWrite(LED_R_PIN, 0); | |
analogWrite(LED_G_PIN, 0); | |
analogWrite(LED_B_PIN, 0); | |
} |
目前程式功能說明
這次項目中的程式主要實現以下功能:
短按操作:
在主選單時:短按按鈕進入選中的功能選單。
在功能選單時:短按按鈕切換至下一功能。
長按操作:
不論在哪個選單,長按按鈕都將返回到主選單。
LED 控制:
控制位於Arduino板上13腳位的LED燈,可通過選單開啟或關閉。
RGB LED 控制:
調整連接到Arduino的共陰RGB LED的顏色輸出。在RGB LED功能選單中,用戶可以調整
紅色、綠色和藍色的亮度,從而創造出各種顏色。
應用展望
若程式能夠順利運作,我們可以將此功能擴展應用於需要同時監測數值變化和按鈕操作的其他儀器上,如家用智慧裝置、實驗室測量工具等。這種互動式介面提升了使用者體驗,使得操作更加直觀和便捷。
沒有留言:
張貼留言