//**************************** Program ตั้งเวลา DS3231 ****************************//
//*************************** การทำงานแบบ Muti Task ****************************//
#include "Wire.h" //Libery I2C
#include "SPI.h" //Libery SPI
#include "EEPROM.h" //Libery EEPROM มีอยู่แล้วใน ATMEGA 328P ไม่ต้อง Add เพิ่ม
#include "RTClib.h" //Libery ของ RTC DS3231
#include "LiquidCrystal_I2C.h" //Libery ของจอ LCD
LiquidCrystal_I2C lcd(0x27, 16, 2); //IC PCF8574T จอ LCD //Set the LCD address 0x27 or 0x3F
RTC_DS3231 RTC;
//********** กำหนดการทำงานแบบ Muti Task แบบ milli() DS3231 ***********//
unsigned long lt_1 = 0; //task 1 (Last Time 1) DS3231
ี unsigned long lt_2 = 0; //task 2 (Last Time 2) ปุ่มเพิ่มค่า
ี unsigned long lt_3 = 0; //task 3 (Last Time 3) ปุ่มลดค่า
ีื unsigned long lt_4 = 0; //task 4 (Last Time 4) ปุ่มเมนู
ี unsigned long lt_5 = 0; //task 5 (Last Time 5) ปุ่มบันทึก
unsigned long pt_1 = 1000; //task 1 (preiod Time 1) DS3231 ทำงานทุกๆ 1000 ms
ี unsigned long pt_2 = 50; //task 2 (preiod Time 2) ปุ่มเพิ่มค่า ทำงานทุกๆ 50 ms
ี unsigned long pt_3 = 60; //task 3 (preiod Time 3) ปุ่มลดค่า
ี unsigned long pt_4 = 70; //task 4 (preiod Time 4) ปุ่มเมนู
ี unsigned long pt_5 = 100; //task 5 (preiod Time 5) ปุ่มบันทึก
//******************************* กำหนดขา *********************************//
byte led_1 = 13; //ไฟแสดงสถานะการบันทึก เมื่อกดปุ่มบันทึก
byte ry_1 = 2; //Relay ควบคุมอุปกรณ์ภายนอก
//******************************* ตัวแปร Menu ******************************//
int manu_Name = 0; //จำนวน menu เมื่อเปิดเครื่องให้เริ่มต้นที่ Menu 1
int manu_Paraameter = 0; //ค่าที่ปรับได้โดยการกดปุ่ม UP DOWN
//***************************** ตัวแปร การรับค่า *****************************//
int DAY ; //ค่าที่ตั้งไว้ของ " วัน "
int MONTH ; //ค่าที่ตั้งไว้ของ " เดือน "
int YEAR ; //ค่าที่ตั้งไว้ของ " ปี "
int HOUR ; //ค่าที่ตั้งไว้ของ " ชั่วโมง "
int MINUTE ; //ค่าที่ตั้งไว้ของ " นาที "
int SECOND ; //ค่าที่ตั้งไว้ของ " วินาที "
//**** ตัวแปรชนิด String แสดง วันที่ เวลา ชื่อ แต่ละ Menu จำนวน 6 Menu แบบ ARRAY ****//
String NAME[] = {"1.Set YEAR ","2.Set MONTH ","3.Set DAY ","4.Set HOUR ","5.Set MINUTE ","6.Set SECOND "}; //ชื่อ Menu ชนิด Array 1. Set Item
//**************** 0 (Menu 1) , 1 (Menu 2) , 2 (Menu 3) , 3 (Menu 4) , 4 (Menu 5) , 5 (Menu 6) ,
//***ตัวแปรแบบ Array ที่เก็บค่า วัน เดือน ปี ชั่วโมง นาที วินาที่ ที่ตั้งค่าไว้ จำนวน 6 Menu ***//
int parameter[] = {YEAR, MONTH, DAY, HOUR, MINUTE, SECOND};
//***************** { 0, 1, 2, 3, 4, 5 }
//****** ค่าคงที่ตัวแปรที่ไม่มีการเปลี่ยนแปลง (Constant Parameter Do not Change) ******//
const int M_button = 8; //ปุ่มกดเปลี่ยน Menu ต่อกับขา 8
const int Up_button = 9; //ปุ่มกดเพิ่มค่า UP ต่อกับขา 9
const int Down_button = 10; //ปุ่มกดลดค่า Down ต่อกับขา 10
const int Rec_button = 11; //ปุ่มกดบันทึกข้อมูลลงใน EEPROM (Record) ต่อกับขา 11
//*************************** ค่าตัวแปรสถานะการกดปุ่ม ****************************//
int M_bcs = 0; //สถานะปัจจุบันของปุ่ม Menu (Menu Button current State)
int M_bls = 0; //สถานะก่อนหน้าของปุ่ม Menu (Menu Button last State)
int Up_bcs = 0; //สถานะปัจจุบันของปุ่มเพิ่มค่า Up (Up Button current State)
int Up_bls = 0; //สถานะก่อนหน้าของปุ่มเพิ่มค่า Up (Up Button last State)
int Down_bcs = 0; //สถานะปัจจุบันของปุ่มลดค่า Down (Down Button current State)
int Down_bls = 0; //สถานะก่อนหน้าของปุ่มลดค่า Down (Down Button last State)
int Rec_bcs = 0; //สถานะปัจจุบันของปุ่มบันทึก Rec (Record Button current State)
int Rec_bls = 0; //สถานะก่อนหน้าของปุ่มบันทึก Rec (Record Button last State)
void setup() {
Serial.begin(115200);
Wire.begin(); //I2C เริ่มทำงาน
RTC.begin(); //RTC (real time clock) DS3231 เริ่มทำงาน
if (! RTC.isrunning()) {Serial.print("RTC is NOT running!");} //ถ้า RTC ไม่ทำงานให้แจ้ง "RTC is NOT running!"
DateTime now = RTC.now(); //Update เวลา
lcd.begin(); //จอ LCD เริ่มทำงาน
lcd.blacklight(); //เปิดหน้าจอ LCD
lcd.clear(); //Clear หน้าจอ LCD
lcd.setCursor(0, 0); //Set Cursor ไปบรรทัดที่ 1 ตัวอักษรที่ 1 (0, 0)
lcd.print(" Timer Control"); //แสดงผลคำว่า " Timer Control"
pinMode(led_1, OUTPUT);
pinMode(ry_1, OUTPUT);
pinMode(M_button, INPUT_PULLUP);
pinMode(Up_button, INPUT_PULLUP);
pinMode(Dowm_button, INPUT_PULLUP);
pinMode(Rec_button, INPUT_PULLUP);
//***** อ่านค่าตัวแปรจาก EEPROM ที่บันทึกไว้ *****//
parameter[0] = EEPROM.read(0); //อ่านค่าข้อมูลทั้งหมดใน EEPROM ในตำแหน่ง 0 เก็บไว้ในตัวแปร parameter [0] YEAR
parameter[1] = EEPROM.read(1); //อ่านค่าข้อมูลทั้งหมดใน EEPROM ในตำแหน่ง 1 เก็บไว้ในตัวแปร parameter [1] MONTH
parameter[2] = EEPROM.read(2); //อ่านค่าข้อมูลทั้งหมดใน EEPROM ในตำแหน่ง 2 เก็บไว้ในตัวแปร parameter [2] DAY
parameter[3] = EEPROM.read(3); //อ่านค่าข้อมูลทั้งหมดใน EEPROM ในตำแหน่ง 3 เก็บไว้ในตัวแปร parameter [3] HOUR
parameter[4] = EEPROM.read(4); //อ่านค่าข้อมูลทั้งหมดใน EEPROM ในตำแหน่ง 4 เก็บไว้ในตัวแปร parameter [4] MINUTE
parameter[5] = EEPROM.read(5); //อ่านค่าข้อมูลทั้งหมดใน EEPROM ในตำแหน่ง 5 เก็บไว้ในตัวแปร parameter [5] SECOND
}
void loop() {
rtc_DS3231();
manu();
add_1();
reduce();
record();
time_Step();
}
//************************ Function RTC DS3231 ************************//
void rtc_DS3231() {
//************ ส่วนของ Program Muti Task ************//
lt_1 = millis(); //กำหนดให้เวลาที่ผ่านมามีหน่วยเป็น ms
if (millis() - lt_1 >= pt_1) { //ถ้าเวลาที่ผ่านมา lt_1 (ซึ่งมีหน่วยเป็น ms) มีค่าเท่ากับหรือมากกว่าเวลาที่กำหนด pt_1 (1000 ms) เมื่อเป็นจริง
DateTime now = RTC.now(); //กำหนดตัวแปรประเภทเวลา (DateTime) มีค่าเท่ากับเวลาปัจุบัน ()
//*********** แสดงผล วัน เดือน ปี บนจอ LCD ***********//
lcd.setCursor(0, 0); //Set Cursor ไปเริ่มที่ ตัวอักษรที่ 1, บรรทัดที่ 1
lcd.print(now.day(), DEC); //แสดงผล "วันที่" เป็นเลขฐาน 10 (DEC)
lcd.print("/"); //แสดงผล "/"
lcd.print(now.month(), DEC); //แสดงผล "เดือน" เป็นเลขฐาน 10 (DEC)
lcd.print("/"); //แสดงผล "/"
lcd.print(now.year(), DEC); //แสดงผล "ปี" เป็นเลขฐาน 10 (DEC)
lcd.println(" "); //แสดงผล " " เพื่อลบข้อความ 1 ตัวอักษร
//********* แสดงผล ชั่วโมง นาที วินาที บนจอ LCD *********//
lcd.setCursor(8, 0); //Set Cursor ไปเริ่มที่ ตัวอักษรที่ 9, บรรทัดที่ 1
lcd.print(now.hour(), DEC); //แสดงผล "ชัวโมง" เป็นเลขฐาน 10 (DEC)
lcd.print(":"); //แสดงผล ":"
lcd.print(now.minute(), DEC); //แสดงผล "นาที" เป็นเลขฐาน 10 (DEC)
lcd.print(":"); //แสดงผล ":"
lcd.print(now.second(), DEC); //แสดงผล "วินาที" เป็นเลขฐาน 10 (DEC)
lcd.println(" "); //แสดงผล " " ลบข้อความ 1 ตัวอักษร
//************* แสดงผล อุณหภูมิ บนจอ LCD *************//
/* lcd.setCursor(8, 1); //Set Cursor ไปเริ่มที่ ตัวอักษรที่ 9, บรรทัดที่ 2
lcd.print("T=") //แสดงผล "T="
lcd.setCursor(10, 1); //Set Cursor ไปเริ่มที่ ตัวอักษรที่ 11, บรรทัดที่ 2
lcd.print(RTC.getTemperature); //แสดงผล อุณหภูมิ
lcd.setCursor(15, 1); //Set Cursor ไปเริ่มที่ ตัวอักษรที่ 16, บรรทัดที่ 2
lcd.println("C";) */
}
}
//************************ Function ปุ่มกด Menu ***********************//
void menu() { //Function Menu แบบกดปุ่มวน
if(millis() - lt_4 >= pt_4) { //Muti Task 4
lt_4 = millis();
//********************** แสดงชื่อ Menu บนจอ LCD **********************//
lcd.setCoursor(0, 1); //แสดงผลชือ Manu โดยเริ่มต้นที่อักษรตัวที่ 1 บรรทัดที่ 2
lcd.print(NAME[menu_NAME]); //แสดงผลบนจอ LCD ชื่อ Menu (YEAR, MONTH, DAY .... SECOND)
//**** แสดงชื่อ Parameter ที่รับได้ ****//
lcd.setCoursor(13, 1); //แสดงผลชือ Manu โดยเริ่มต้นที่อักษรตัวที่ 14 บรรทัดที่ 2
lcd.print(parameter[manu_parameter]); //แสดงค่า Parameter แต่ละ Manu ที่สามารถปรับค่าได้
lcd.print(" "); //ลบหน้าจอ LCD ออก 1 ตัวอักษร
M_bs = digitalRead(M_button); //อ่านค่าการกดปุ่ม มาเก็บไว้ที่ตัวแปร M_bs (Manu Buttom State)
if (M_bs != M_bls) { //ถ้าค่าของ M_bcs (Manu Button Curent State) มีค่าไม่เท่ากับ M_bls (Manu Buttom Last State)
if (M_ฺbs == LOW) { //ถ้ามีการกดปุ่ม M_button (pin 8) สถานะเป็น LOW
manu_NAME ++; //ให้ค่า manu_NAME เพิ่มขึ้นทีละ 1
manu_parameter ++; //ให้ค่า manu_parameter เพิ่มขึ้นทีละ 1
Serial.print(M_bs);
if ( (manu_NAME == 6) && (manu_parameter == 6)) { //ถ้าค่าของ manu_NAME = 6 และ manu_parameter = 6
manu_NAME = 0; //ให้ค่าของ menu_NAME = 0
manu_parameter = 0; //ให้ค่าของ menu_parameter = 0
} } }
}
}
//************************ Function ปุ่มกด UP ***********************//
void add_1() { //Function UP แบบกดปุ่มวน
if(millis() - lt_2 >= pt_2) { //Muti Task 2
lt_2 = millis();
//********************** แสดงผล บนจอ LCD **********************//
lcd.setCoursor(0, 1); //แสดงผลชือ Manu โดยเริ่มต้นที่อักษรตัวที่ 1 บรรทัดที่ 2
lcd.print(NAME[menu_NAME]); //แสดงผลบนจอ LCD ชื่อ Menu (YEAR, MONTH, DAY .... SECOND)
//**** แสดงชื่อ Parameter ที่ต้องการเพิ่มค่า ****//
lcd.setCoursor(13, 1); //แสดงผลชือ Manu โดยเริ่มต้นที่อักษรตัวที่ 14 บรรทัดที่ 2
lcd.print(parameter[manu_parameter]); //แสดงค่า Parameter แต่ละ Manu ที่สามารถปรับค่าได้
lcd.print(" "); //ลบหน้าจอ LCD ออก 1 ตัวอักษร
Up_bs = digitalRead(Up_button); //อ่านค่าการกดปุ่ม Up_button (pin 9) มาเก็บไว้ที่ Up_bs (Up Buttom State)
if (Up_bs != Up_bls) { //ถ้าค่าของ Up_bcs (Up Button Curent State) มีค่าไม่เท่ากับ Up_bls (Up Buttom Last State)
if ( (Up_ฺbs == LOW) && (manu_NAME == 0) ) { //ถ้ามีการกดปุ่ม Up_button สถานะเป็น LOW และ manu_NAME = 0
parameter[0] ++; } else //ให้ค่า parameter[0] "YEAR" เพิ่มขึ้นทีละ 1
if ( (Up_ฺbs == LOW) && (manu_NAME == 1) ) { //ถ้ามีการกดปุ่ม Up_button สถานะเป็น LOW และ manu_NAME = 1
parameter[1] ++; } else //ให้ค่า parameter[1] "MONTH" เพิ่มขึ้นทีละ 1
if ( (Up_ฺbs == LOW) && (manu_NAME == 2) ) { //ถ้ามีการกดปุ่ม Up_button สถานะเป็น LOW และ manu_NAME = 2
parameter[2] ++; } else //ให้ค่า parameter[2] "DAY" เพิ่มขึ้นทีละ 1
if ( (Up_ฺbs == LOW) && (manu_NAME == 3) ) { //ถ้ามีการกดปุ่ม Up_button สถานะเป็น LOW และ manu_NAME = 3
parameter[3] ++; } else //ให้ค่า parameter[3] "HOUR" เพิ่มขึ้นทีละ 1
if ( (Up_ฺbs == LOW) && (manu_NAME == 4) ) { //ถ้ามีการกดปุ่ม Up_button สถานะเป็น LOW และ manu_NAME = 4
parameter[4] ++; } else //ให้ค่า parameter[4] "MINUTE" เพิ่มขึ้นทีละ 4
if ( (Up_ฺbs == LOW) && (manu_NAME == 5) ) { //ถ้ามีการกดปุ่ม Up_button สถานะเป็น LOW และ manu_NAME = 5
parameter[5] ++; } } //ให้ค่า parameter[5] "SECOND" เพิ่มขึ้นทีละ 1
} }
//************************ Function ปุ่มกด DOWN ***********************//
void reduce() { //Function Down แบบกดปุ่มวน
if(millis() - lt_3 >= pt_3) { //Muti Task 3
lt_3 = millis();
//********************** แสดงผล บนจอ LCD **********************//
lcd.setCoursor(0, 1); //แสดงผลชือ Manu โดยเริ่มต้นที่อักษรตัวที่ 1 บรรทัดที่ 2
lcd.print(NAME[menu_NAME]); //แสดงผลบนจอ LCD ชื่อ Menu (YEAR, MONTH, DAY .... SECOND)
//**** แสดงชื่อ Parameter ที่ต้องการลดค่า ****//
lcd.setCoursor(13, 1); //แสดงผลชือ Manu โดยเริ่มต้นที่อักษรตัวที่ 14 บรรทัดที่ 2
lcd.print(parameter[manu_parameter]); //แสดงค่า Parameter แต่ละ Manu ที่สามารถปรับค่าได้
lcd.print(" "); //ลบหน้าจอ LCD ออก 1 ตัวอักษร
Down_bs = digitalRead(Down_button); //อ่านค่าการกดปุ่ม Up_button (pin 9) มาเก็บไว้ที่ Up_bs (Up Buttom State)
if (Down_bs != Down_bls) { //ถ้าค่าของ Up_bcs (Up Button Curent State) มีค่าไม่เท่ากับ Up_bls (Up Buttom Last State)
if ( (Down_ฺbs == LOW) && (manu_NAME == 0) ) { //ถ้ามีการกดปุ่ม Up_button สถานะเป็น LOW และ manu_NAME = 0
if (parameter[0] > 0) { //ค่าของ parameter[0] จะต้องมีค่ามากกว่า 0 ถึงจะลบได้
parameter[0] --; } } else //ให้ค่า parameter[0] "YEAR" ลดลงทีละ 1
if ( (Down_ฺbs == LOW) && (manu_NAME == 1) ) { //ถ้ามีการกดปุ่ม Up_button สถานะเป็น LOW และ manu_NAME = 1
if (parameter[1] > 0) { //ค่าของ parameter[1] จะต้องมีค่ามากกว่า 0 ถึงจะลบได้
parameter[1] --; } } else //ให้ค่า parameter[1] "MONTH" ลดลงทีละ 1
if ( (Down_ฺbs == LOW) && (manu_NAME == 2) ) { //ถ้ามีการกดปุ่ม Up_button สถานะเป็น LOW และ manu_NAME = 2
if (parameter[2] > 0) { //ค่าของ parameter[2] จะต้องมีค่ามากกว่า 0 ถึงจะลบได้
parameter[2] --; } } else //ให้ค่า parameter[2] "DAY" ลดลงทีละ 1
if ( (Down_ฺbs == LOW) && (manu_NAME == 3) ) { //ถ้ามีการกดปุ่ม Up_button สถานะเป็น LOW และ manu_NAME = 3
if (parameter[3] > 0) { //ค่าของ parameter[3] จะต้องมีค่ามากกว่า 0 ถึงจะลบได้
parameter[3] --; } } else //ให้ค่า parameter[3] "HOUR" ลดลงทีละ 1
if ( (Down_ฺbs == LOW) && (manu_NAME == 4) ) { //ถ้ามีการกดปุ่ม Up_button สถานะเป็น LOW และ manu_NAME = 4
if (parameter[4] > 0) { //ค่าของ parameter[4] จะต้องมีค่ามากกว่า 0 ถึงจะลบได้
parameter[4] --; } } else //ให้ค่า parameter[4] "MINUTE" ลดลงทีละ 1
if ( (Down_ฺbs == LOW) && (manu_NAME == 5) ) { //ถ้ามีการกดปุ่ม Up_button สถานะเป็น LOW และ manu_NAME = 5
if (parameter[5] > 0) { //ค่าของ parameter[5] จะต้องมีค่ามากกว่า 0 ถึงจะลบได้
parameter[5] --; } } //ให้ค่า parameter[5] "SECOND" ลดลงทีละ 1
} }
}
//************************ Function ปุ่มกด Record ***********************//
void record() { //Function Record (Save)
if(millis() - lt_5 >= pt_5) { //Muti Task 5
lt_5 = millis();
rec_bs = digitalRead(Rec_button); //อ่านค่าจาก Rec_button (pin 11) มาเก็บไว้ที่ค่าตัวแปร rec_bs (Record Button State)
if (rec_bs != rec_bls) {
if(rec_bs == LOW) {
//********** ปรับค่า วัน เดือน ปี และ เวลา RTC *****//
RTC.adjust(DateTime( parameter[0], parameter[1], parameter[2], parameter[3], parameter[4], parameter[5] ))
//************ บันทึกลงใน EEPROM **********//
EEPROM.put(0, parameter[0]); //บันทึกค่า parameter[0] ในตำแหน่ง 0 ของ EEPROM แบบ Update คือจะไม่บันทึกค่าเดิมซ้ำ "YEAR"
EEPROM.put(1, parameter[1]); //บันทึกค่า parameter[1] ในตำแหน่ง 1 ของ EEPROM แบบ Update คือจะไม่บันทึกค่าเดิมซ้ำ "MONTH"
EEPROM.put(2, parameter[2]); //บันทึกค่า parameter[2] ในตำแหน่ง 2 ของ EEPROM แบบ Update คือจะไม่บันทึกค่าเดิมซ้ำ "DAY"
EEPROM.put(3, parameter[3]); //บันทึกค่า parameter[3] ในตำแหน่ง 3 ของ EEPROM แบบ Update คือจะไม่บันทึกค่าเดิมซ้ำ "HOUR"
EEPROM.put(4, parameter[4]); //บันทึกค่า parameter[4] ในตำแหน่ง 4 ของ EEPROM แบบ Update คือจะไม่บันทึกค่าเดิมซ้ำ "MINUTE"
EEPROM.put(5, parameter[4]); //บันทึกค่า parameter[5] ในตำแหน่ง 5 ของ EEPROM แบบ Update คือจะไม่บันทึกค่าเดิมซ้ำ "SECOND"
digitalWrite(led_1, HIGH);
lcd.setCoursor(10, 1); //แสดงผลชือ Manu โดยเริ่มต้นที่อักษรตัวที่ 11 บรรทัดที่ 2
lcd.print(" "); //ลบหน้าจอ LCD ออก 16 ตัว
lcd.setCoursor(13, 1); //แสดงผลชือ Manu โดยเริ่มต้นที่อักษรตัวที่ 14 บรรทัดที่ 2
lcd.print(parameter[manu_parameter]); //แสดงค่า Parameter แต่ละ Manu ที่สามารถปรับค่าได้
lcd.print(" "); //ลบหน้าจอ LCD ออก 1 ตัวอักษร
} else { digitalWrite(led_1, LOW);} //ถ้าไม่กดปุ่ม rec ไฟ led ดับ
}
rec_bls = rec_bs; //update สถานะการกดปุ่มจาก LOW ให้เป็น HIGH พร้อมจะกดปุ่มครั้งต่อไป
}
}
//******************* Function Timer 2 Step ON-OFF *******************//
void timer_Step() {
//***************** การตั้งเวลาทำงาน 2 Step ON-OFF ****************//
//***** Step_01 Timer_01 สั่งเปิดเวลา 10:05:10 ปิดเวลา 10:05:25 *****//
if ( (now.hour() == 10) && (now.minute() == 5) && (now.second() == 10) ) { //Timer_01 เมื่อถึงเวลา 10:05:10
digitalWrite(ry_1, HIGH); } else //Timer_01 Relay ry_1 ทำงาน (ON)}
if ( (now.hour() == 10) && (now.minute() == 5) && (now.second >= 25) ) { //Timer_01 เมื่อถึงเวลา 10:05:25
digitalWrite(ry_1, LOW); } else //Timer_01 Relay ry_1 หยุดทำงาน (OFF)
//***** Step_02 Timer_02 สั่งเปิดเวลา 10:06:10 ปิดเวลา 10:07:15 *****//
if ( (now.hour() == 10) && (now.minute() == 6) && (now.second() == 10) ) { //Timer_02 เมื่อถึงเวลา 10:06:10
digitalWrite(ry_1, HIGH); } else //Timer_02 Relay ry_1 ทำงาน (ON)}
if ( (now.hour() == 10) && (now.minute() == 7) && (now.second >= 15) ) { //Timer_02 เมื่อถึงเวลา 10:07:15
digitalWrite(ry_1, LOW); } //Timer_02 Relay ry_1 หยุดทำงาน (OFF)
}