/************************************
OLED製作功能表選單控制LED
可控制4LED。具按鈕開關防彈跳處理
************************************/
#include <Wire.h> //I2C介面
#include <Adafruit_GFX.h> //文字圖形
#include <Adafruit_SSD1306.h> //驅動
// 設定OLED
#define SCREEN_W 128 // OLED 寬度像素
#define SCREEN_H 64 // OLED 高度像素
#define OLED_RESET -1 //與晶片共用重置
Adafruit_SSD1306 ssd(SCREEN_W, SCREEN_H, &Wire, -1);
//button
const byte up = 33; //上
const byte down = 13; //下
const byte ok = 26; //執行
//LED
const byte red = 4; //LED接腳
const byte green = 15;
const byte yellow = 18;
const byte blue = 5;
//LED state
bool red_state ; //記錄LED顯示狀態
bool green_state;
bool yellow_state;
bool blue_state;
//初值設定
int sel = 1; //第1選項
int layer = 0; //層級0, 1
void setup() {
Serial.begin(115200);
pinMode(up, INPUT_PULLUP); //按鈕使用上拉電阻
pinMode(down, INPUT_PULLUP);
pinMode(ok, INPUT_PULLUP);
pinMode(red, OUTPUT); //LED為輸出埠
pinMode(green, OUTPUT);
pinMode(yellow, OUTPUT);
pinMode(blue, OUTPUT);
// 偵測是否安裝好SSD1306了,位址都是0x3C
if (!ssd.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;) //死迴圈
;
}
initSetting(); //偵測正常,初值設定
}
void loop() {
if(!digitalRead(up)) { //是否向上?
delay(20); //開關彈跳時間20ms,延遲後再讀取。
while(!digitalRead(up)); //按鈕未鬆開,等待…
sel--; //向上sel-1
if(sel<1)sel=1; //已到頂
display(layer,sel); //顯示現在狀態
}else
if(!digitalRead(down)) { //是否向下?
delay(20);
while(!digitalRead(down));
sel++; //向下+1
if(sel>3)sel=3; //已到底
display(layer,sel); //顯示現在狀態
}else
if(!digitalRead(ok)) { //是否確定執行?
delay(20);
while(!digitalRead(ok));
action(layer,sel); //依選項執行
}
delay(100); //緩衝時間
}
//初始化顯示-----------------------------------
void initSetting() {
ssd.clearDisplay(); //清除oled
ssd.setTextSize(2); // 設定文字大小
ssd.setTextColor(1); // 1:OLED預設的顏色
display(layer,sel); //依層數選項顯示
}
//依層級、選項來顯示選單-----------------------------
void display(int _layer,int _sel) {
ssd.clearDisplay(); //清除OLED
Serial.print("layer,sel="); //顯示現在的層級選項
Serial.println(String(_layer)+","+String(_sel));
switch(_layer){ //判斷層級
case 0: //最上層
ssd.setCursor(0, 0); //定位與顯示資訊
ssd.print(" Red");
ssd.setCursor(0, 20);
ssd.print(" Green");
ssd.setCursor(0, 40);
ssd.print(" More");
break;
case 1: //第1層
ssd.setCursor(0, 0); //定位與顯示資訊
ssd.print(" Yellow");
ssd.setCursor(0, 20);
ssd.print(" Blue");
ssd.setCursor(0, 40);
ssd.print(" Back");
break;
} //以下依選項值_sel, 與顯示座標連動變化
ssd.setCursor(0, (_sel-1)*20); //=0,20,40
ssd.print(">"); //箭頭表示現在的選項sel
ssd.display(); //把設定的值一次顯示出來
}
//按執行時的判斷程式(層級,選項)----------------------------
void action(int _layer,int _sel){
Serial.print("Action:"); //顯示現在的層級、選項
Serial.println(String(_layer)+","+String(_sel));
switch(_layer){
case 0: //第0層
if(_sel==1){ //第1選項,反相顯示
red_state=!red_state; //由state決定亮滅
digitalWrite(red, red_state ? 1 : 0 );
}else
if(_sel==2){ //第2選項,反相顯示
green_state=!green_state; //由state決定亮滅
digitalWrite(green, green_state ? 1 : 0 );
}else
if(_sel==3){
layer=1;sel=1;
display(layer,sel); //顯示下一層1
}
break;
case 1: //第1層
if(_sel==1){ //判斷方式同上,控制黃、藍燈
yellow_state=!yellow_state ;
digitalWrite(yellow, yellow_state ? 1 : 0 );
}else
if(_sel==2){
blue_state=!blue_state ;
digitalWrite(blue, blue_state ? 1 : 0 );
}else
if(_sel==3){ //按back
layer=0;sel=1;
display(layer,sel); //回上一層0
}
break;
} }