자작 정수기용 컨트롤러 5, 초기 화면 및 메뉴 구성
이제 메뉴를 만들 차례입니다. 필요한 메뉴는 실제 사용량과 유효정수량을 확인하는 부분과 흐름센서(Flow meter)의 정밀도를 수정(Calibration)할 수 있는 부분입니다. 그 외 필요한 메뉴는 그때그때 추가할 예정이구요!
우선, 메뉴 작성에 앞서서 초기 대기화면을 먼저 만들었습니다. 소스는 이전글에서 테스트한 예제를 그대로 가져와서 왔고, standby_message(); 함수를 만들어서 처음 부팅 후 초기화면을 표시하도록 했습니다.
void standby_message()
{
display.fillScreen(BLACK); // 화면 전체를 검정색으로 채운다. 화면 지움 효과
display.setTextSize(2); // 글자 크기 지정, 한 화면에 4줄 들어가는 크기입니다. 64/4해서 16픽셀 정도.
display.setCursor(0,0); // 처음부터 입력되도록 커서를 옮깁니다.
display.setTextColor(GREEN); // 글자 색상 변경, 전체를 검정색으로 채웠기 때문에 배경색은 생략.
display.print("Push for");
display.setTextColor(BLUE);
display.print("Water");
display.setTextColor(GREEN);
display.print(" or");
display.print("press ");
display.setTextColor(RED);
display.print("OK");
display.setTextColor(GREEN);
display.print("for");
display.setTextColor(YELLOW);
display.print("Setup");
}
대기 화면을 출력하는 함수입니다. 색상을 몇가지 조합했습니다. setup() 함수 내에서 호출하여 초기 구동시 표시합니다.
대기화면이 출력된 모습입니다. 대기 화면에서 리모컨의 "OK"버튼을 누르면 셋업 메뉴로 들어갑니다. EnterSetup() 함수를 만들어서 처리했으며, "#"키를 누르면 다시 대기화면으로 빠져 나옵니다. 메뉴속에선 좌, 우 화살표키를 이용해 이동을 합니다. 이를 위해서 menu, selected 두 개의 변수를 두어 구현했습니다. 현재 총 4개의 메뉴가 있는데, 왼쪽 화살표를 누르면 이전 메뉴로, 오른쪽 화살표는 다음 메뉴로 이동합니다.
첫번째 메뉴에서 왼쪽 화살표를 누를 경우 더 이상의 이전 메뉴는 없기 때문에 메뉴 출력을 안하고 화면을 그대로 두도록 처리했습니다. 마찬가지로 4번째 메뉴 보다 다음 메뉴는 없기에 동일한 처리를 했습니다.
void EnterSetup() // 셋업 메뉴 구현
{
int menu = 0; // 현재 선택된 메뉴
int selected = 1; // 좌, 우 화살표키를 이용해 이동한 값
boolean looping = true; // "#"키를 이용해 메뉴를 탈출하기 위한 체크 변수
while(looping) { // "#"키를 누르기 전까지 반복
if ( menu != selected ) // 키 입력이 있고 현재 메뉴가 아닐 경우
{
switch(selected) // 키 입력이 있으나
{
case 0: // 오른쪽 화살표 입력시
selected = selected + 1; // 첫번째 메뉴보다 이전 메뉴는 없으므로
break;
case 1:
mainMenu(selected); // 해당 메뉴를 표시하는 함수 호출
menu = 1; // 다음 값 비교를 위해 현재 메뉴값 저장
break;
case 2:
mainMenu(selected);
menu = 2;
break;
case 3:
mainMenu(selected);
menu = 3;
break;
case 4: // 네번째 메뉴보다 이후 메뉴는 없으므로
selected = selected - 1;
break;
}
}
irrecv.resume(); // 다음 IR 키값을 입력 받을 준비를 합니다
delay(500);
if (irrecv.decode(&results)) // IR 입력값이 있을 경우 처리합니다.
{
switch(results.value)
{
case 0xFF22DD: // 왼쪽 화살표
selected = selected - 1; // 현재보다 이전 메뉴 표시하도록
break;
case 0xFFC23D: // 오른쪽 화살표
selected = selected + 1; // 현재보다 이후 메뉴 표시
break;
case 0xFF02FD: // "OK" 키, 현재 메뉴로 이동(메인에서 서브로...)
subMenu(menu);
break;
case 0xFF52AD: // "#" 키, 대기화면 출력 후, 반복문을 빠져나간다
standby_message();
looping = false;
break;
}
}
}
}
위 소스에서 if (menu != selected ) 비교문은 키 값이 입력되더라도 메뉴 이동이 없으면 화면 출력을 다시 하지 않도록 처리하기 위함입니다. 즉, 첫번째 메뉴에서 왼쪽 화살표 입력시, 마지막 네번째 메뉴에서 오른쪽 화살표 입력시 아무 일도 안하도록 합니다.
void mainMenu(int Sel)
{
display.fillScreen(BLACK);
display.setTextSize(2);
display.setCursor(0,0);
display.setTextColor(GREEN);
display.print(mainMenuList[Sel]);
display.setTextColor(BLUE);
display.print("--------");
display.print("<-OK-> #");
}
void subMenu(int SelMenu)
{
switch(SelMenu)
{
case 1:
break;
case 2:
break;
case 3:
break;
}
메뉴 출력 함수와 해당 메뉴 선택시 호출되는 서브메뉴 함수입니다. 서브 메뉴는 아직 구현하지 않았습니다.
메뉴 작동 화면은 아래 동영상 참고하시고, 전체 소스는 그 아래 있습니다.
#define sclk 13
#define mosi 11
#define cs 10
#define rst 9
#define dc 8
// Color definitions
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1331.h>
#include <SPI.h>
#include <IRremote.h>
Adafruit_SSD1331 display = Adafruit_SSD1331(cs, dc, rst);
int RECV_PIN = 12;
IRrecv irrecv(RECV_PIN);
decode_results results;
#define MaxMenu 3
char* mainMenuList[] = {"",
"MaxValueSetting ",
"Used Info ",
"FlowRateAdjust "};
void setup(void) {
Serial.begin(9600);
display.begin();
standby_message();
irrecv.enableIRIn(); // Start the receiver
delay(1000);
}
void loop() {
display.setTextColor(BLUE);
display.setTextSize(2);
if (irrecv.decode(&results)) {
if (results.value == 0xFF02FD) EnterSetup();
irrecv.resume(); // Receive the next value
}
delay(100);
}
void standby_message()
{
display.fillScreen(BLACK);
display.setTextSize(2);
display.setCursor(0,0);
display.setTextColor(GREEN);
display.print("Push for");
display.setTextColor(BLUE);
display.print("Water");
display.setTextColor(GREEN);
display.print(" or");
display.print("press ");
display.setTextColor(RED);
display.print("OK");
display.setTextColor(GREEN);
display.print("for");
display.setTextColor(YELLOW);
display.print("Setup");
}
void EnterSetup()
{
int menu = 0;
int selected = 1;
boolean looping = true;
while(looping) {
if ( menu != selected )
{
switch(selected)
{
case 0:
selected = selected + 1;
break;
case 1:
mainMenu(selected);
menu = 1;
break;
case 2:
mainMenu(selected);
menu = 2;
break;
case 3:
mainMenu(selected);
menu = 3;
break;
case 4:
selected = selected - 1;
break;
}
}
irrecv.resume();
delay(500);
if (irrecv.decode(&results))
{
switch(results.value)
{
case 0xFF22DD:
selected = selected - 1;
break;
case 0xFFC23D:
selected = selected + 1;
break;
case 0xFF02FD:
subMenu(menu);
break;
case 0xFF52AD:
standby_message();
looping = false;
break;
}
}
}
}
void mainMenu(int Sel)
{
display.fillScreen(BLACK);
display.setTextSize(2);
display.setCursor(0,0);
display.setTextColor(GREEN);
display.print(mainMenuList[Sel]);
display.setTextColor(BLUE);
display.print("--------");
display.print("<-OK-> #");
}
void subMenu(int SelMenu)
{
switch(SelMenu)
{
case 1:
break;
case 2:
break;
case 3:
break;
}
}