자작 정수기용 컨트롤러 7, 메뉴 구조 변경 및 유량센서(Flowmeter)

2015. 10. 7. 12:53

Project/Water Purifier

자작 정수기용 컨트롤러 7, 메뉴 구조 변경 및 유량센서(Flowmeter)







  이제 유량센서(Flowmeter)를 적용할 차례인데 우선 그에 앞서 메뉴 구조를 변경했습니다. 경험도 없이 처음부터 너무 무리하게 진행했는 지, 시행착오가 계속이네요!^^ OLED로 메뉴를 구성하려니 그래픽 방식이라 좀 힘이 듭니다. 숫자 하나 출력하려해도 일일이 좌표값 따져가며 해야 되니, 메뉴 구성에만 너무 많은 시간이 들 것 같아 답답해 지네요! 우선 메뉴를 다시 변경했습니다. 단계별로 서브 메뉴가 많아질수록 코딩이 복잡해져서 서브 메뉴를 들어가지 않고 설정값을 변경하도록 했습니다. 


  메뉴 흐름은 오른쪽으로만 가능하도록 했습니다. 한쪽 방향으로만 진행하고 마지막에선 다시 처음으로 돌아가도록 해서 코딩 수를 줄였습니다. 해당 메뉴에선 서브메뉴 화면 호출이 없고 카테고리 구분없이 모든 항목이 순서대로 나오도록 구성할 생각입니다. 그렇게 해도 메뉴 항목이 많지 않아서 괜찮을 듯 싶습니다.


  우선, 유효정수량과 현재까지의 실제 정수량을 필터별로 표시하도록 하고, 실제 정수량을 "0"으로 리셋 하는 기능만 구현했습니다. 대기화면에서 리모컨의 "OK" 버튼을 누르면 메뉴로 들어가고, "오른쪽" 화살표 키로 메뉴간 이동을 합니다. "*" 키를 누르면 실제 정수량이 0으로 표시만 되고 저장은 "OK" 버튼을 누르면 실행됩니다. "*" 키를 눌렀어도 "OK" 버튼을 누르지 않으면 적용되지 않고 리셋할 때와 저장할 때의 글자색상을 구별해서 표시합니다. 어느 단계에서든 "#"키를 누르면 대기화면으로 나가게 됩니다.


  아래 동영상을 참고하세요! 동영상 내용은

  - 처음에는 대기화면에서 메뉴로 들어가고 오른쪽 키로 메뉴 전환하다가 처음으로 다시 돌아간 후 "#"키로 대기화면으로 나가는 동작

  - 그 다음에는 메뉴에서 "*"키를 눌러 실제 정수량을 초기화 하지만 "OK"키를 누르지 않아 저장되지 않는 화면

  - 마지막으로 초기화를 저장까지 완료하는 화면입니다.







  아래는 전체 소스코드입니다. resetValue() 함수는 메뉴화면에서 "*"키가 입력될 경우, 단순히 화면상 실제 정수량을 숫자 "0"으로 표시합니다. 아직 저장은 되지 않습니다. saveValue() 함수는 "OK" 키가 입력될 때 리셋된 값을 변수 및 EEPROM에 저장합니다.



#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>

#include <EEPROM.h>


Adafruit_SSD1331 display = Adafruit_SSD1331(cs, dc, rst);


int RECV_PIN = 12;


IRrecv irrecv(RECV_PIN);


decode_results results;


char* mainMenuList[] = {"Filter 1",

                        "Filter 2",

                        "Filter 3",

                        "Filter 4",

                        "Filter 5"};


  int maxWater[5];

  int useWater[5];

  float flowrate;


void setup(void) {

  Serial.begin(9600);

  display.begin();

  initValue();   

  standby_message();

  irrecv.enableIRIn(); // Start the receiver

  delay(1000);

}


void loop() {


  if (irrecv.decode(&results)) {

    if (results.value == 0xFF02FD) EnterSetup();

    irrecv.resume(); // Receive the next value

  }

  delay(100);

}


void EnterSetup()

{

  int menu = 0;

  int selected = -1;

  int digit = 0;

  boolean looping = true;

  boolean reset = false;


  irrecv.resume(); // Receive the next value

  delay(300);

  

  while( looping ) 

  {

    if ( menu > 4 ) menu = 0;

    

    if ( menu != selected )

    {

      showMenu(menu);

      selected = menu;

    }

    

    if (irrecv.decode(&results))

    {

      switch(results.value)

      {

        case 0xFFC23D: // right

          menu = menu + 1;

          reset = false;

          break;

        case 0xFF02FD: // ok

          if ( reset ) saveValue(menu);

          reset = false;

          selected = -1;

          break;

        case 0xFF42BD: //*

          resetValue();

          reset = true;

          break;

        case 0xFF52AD: //#

          standby_message();

          looping = false;

          break;

      }   

    }

    irrecv.resume();

    delay(300);

  }

}


void showMenu(int Sel)

{

  display.fillScreen(BLACK);

  display.setTextSize(2);

  display.setCursor(0,0);

  

  display.setTextColor(YELLOW);

  display.print(mainMenuList[Sel]);


  display.setTextColor(RED);

  display.println(maxWater[Sel], DEC);

  display.setTextColor(GREEN);

  display.println(useWater[Sel], DEC);

  

  display.setTextColor(BLUE);

  display.print("OK-> * #");

}


void saveValue( int Sel )

{

  useWater[Sel] = 0;

  EEPROM.write(Sel + 10, 0);

  EEPROM.write(Sel + 15, 0);

}


void resetValue()

{

  display.setCursor(0,32);

  display.fillRect(0, 32, 64, 16, BLACK);

  display.setTextColor(CYAN);

  display.print("0");

}


void initValue()

{

  int i, value;

  float val1, val2;


  for ( i = 0; i < 5 ; i++ )

  {

    value = (EEPROM.read(i) * 100) + EEPROM.read(i + 5);

    maxWater[i] = value;

    

    value = (EEPROM.read(i + 10) * 100) + EEPROM.read(i + 15);

    useWater[i] = value;

  }

  

  val1 = EEPROM.read(20);

  val2 = EEPROM.read(21);

  flowrate = val1 + ( val2 / 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");

}





유량센서(Flow meter, Flow sensor) 적용



우선 유량센서 사진 부터 보세요!!





  알리나 구글에서 flow sensor, flow meter로 검색하시면 가장 많이 보실 수 있는 제품입니다. 아두이노(arduino)와 연결한 프로젝트도 많이 나오고, 또 판매하는 곳도 많습니다. 국내 오픈 마켓에서도 구입하실 수 있고, 알리에서 저렴하게 구입하셔도 됩니다. Adafruit 에서도 판매하는데 여기는 관련 예제까지 제공합니다. 저도 Adafruit 예제를 조금 고쳐서 사용했습니다. 인터페이스는 3핀이고, +, -, data 이렇게 구성됩니다. 노란색이 데이터선이고 빨간색이 전원이며, 전압은 12V까지 허용되고 아두이노 핀 출력으로도 잘 작동합니다.





  뒷면에 흐름 방향이 표시되어 있습니다. 꼭 맞게 설정하시고, 피팅(휘팅, fitting) 연결을 위한 나사홈은 G1/2 규격으로, 국내 오픈마켓이나 정수기 필터 판매 사이트 가시면 정수기 부품쪽에 맞는게 있습니다. 저도 그곳에서 구입했구요!




  원터치 피팅(plug-in fitting)입니다. 반대쪽은 G1/2사이즈로 플로우미터랑 딱 맞습니다. 고무오링이 안쪽에 있어서 테프론 테이프는 필요없으며 호스 규격은 정수기에서 주로 사용하는 외경 6.5mm 사이즈입니다. 정수기 필터 및 부품 판매하는 사이트나 오픈마켓에서 쉽게 구할 수 있으나, 만약 다른 규격의 수로에 적용하시려면 국내에선 온라인으로는 좀 힘들 듯 합니다.




  피팅 장착 완료한 모습입니다. 호스 규격에 비하면 좀 크네요!^^; 플로우미터에 대한 자세한 사항은 아래 링크에서 확인하세요!


  Liquid Flow Meter - Plastic 1/2" NPS Threaded (https://www.adafruit.com/products/828)


 길어지는 관계로 실제 소스코드 부분은 다음 글에서 설명하겠습니다.


  이상입니다.


Comments