Hải Đăng PPK gửi vào
- 24525 lượt xem
Dự án này mình đã hoàn thiện vào cuối năm 2015. Tuy nhiên bây giờ mới có thời gian giới thiệu tới các bạn. Gia đình bạn có sử dụng wifi và những lúc không sử dụng bạn muốn tắt nó đi để tránh ảnh hưởng của sóng wifi tới sức khỏe, đặc biệt là với trẻ nhỏ. Dựa trên lí do đó mình đã làm 1 thiết bị có khả năng tự bật tắt wifi theo thời gian định sẵn, có thể điều khiển từ xa và học lệnh các loại điều khiển. Qua bài viết này, hi vọng nhận được nhiều ý kiến đóng góp từ các bạn đồng thời nâng cấp thêm nhiều tính năng cho thiết bị.
1. Chuẩn bị
- 1 Arduino Nano
- 1 LCD 5510
- 1 Module Relay
- 1x module Realtime Clock DS1307 + datasheet DS1307
- 1x Dây cắm breadboard
- 1 LED thu hồng ngoại
- 1 Remote bất kỳ nhé
2. Bắt đầu
Phần cứng các bạn kết nối như sau:
Arduino | DS1307 | LCD5510 | IR LED | NÚT NHẤN | RELAY |
3 | SCLK | ||||
4 | DIN | ||||
5 | DC | ||||
6 | CS | ||||
7 | RST | ||||
10 | DATA | ||||
11 | DATA | ||||
12 | LIGHT | ||||
A0 | DOWN | ||||
A1 | UP | ||||
A2 | SETUP | ||||
SDA | SDA | ||||
SCL | SCL | ||||
GND | GND | GND | GND | GND | |
5V | VCC | VCC | VCC | VCC |
Đừng vội hoang mang nhé, các bạn chỉ cần nối chân lần lượt từng module với arduino theo thứ tự trên thôi !
3. Các thư viện có liên quan
- <SPI.h> Thư viện giao tiếp SPI giữa Arduino với LCD 5510 (đã có mặc định trong Library)
- <Adafruit_GFX.h> Thư viện đồ họa
- <Adafruit_PCD8544.h> Thư viện điều khiển LCD 5510
- <Wire.h> Thư viện giao tiếp với module thời gian thực DS1307 (đã có mặc định trong Library mặc định của Arduino)
- <IRremote.h> Thư viện cho IR LED
- <IRremoteInt.h> Thư viện cho IR LED
- <string.h> Thư viện xử lý chuỗi (dùng cho việc xử lý chuỗi khi học mã IR từ Remote) (đã có mặc định trong Library)
- <EEPROM.h> Thư viện EEPROM để thao tác lưu mã IR vào bộ nhớ (đã có mặc định trong Library)
Các bạn có thể down các thư viện chưa có tại đây (mirror), sau đó giải nén và đưa vào thư mục C:\Program Files\Arduino\libraries\
Có 1 lưu ý nho nhỏ đó là thư viện IRremote, IRremoteInt ở trong thư mục library mặc định của arduino nó không hoạt động được theo cách của mình, vì vậy trước khi copy thư viện của mình vào mục thư viện của các bạn thì các bạn xóa thư viện IRremote mặc định đi nhé
4. Lập trình
Trước khi đến phần lập trình, mình xin diễn giải sơ bộ như sau:
Arduino được kết nối với module thời gian thực DS1307 để có được thông số thời gian chính xác, sau đó hiển thị lên LCD 5510, Căn cứ vào thời gian đó, Arduino sẽ điều khiển cho Module Relay bật hoặc tắt.
Các bạn có thể tham khảo thêm về việc sử dụng module DS1307 trong vài viết của bác NTP_PRO
Và bài viết về cách sử dụng LCD 5510 của bác ksp nhé
Led Thu hồng ngoại (IR LED) được kết nối với arduino có tác dụng nhận tín hiệu hồng ngoại từ điều khiển từ xa (Remote), điều khiển từ xa sẽ truyền 1 chuỗi tín hiệu, led thu đọc được và arduino sẽ xử lý tín hiệu. Mình lấy ví dụ đơn giản đối với điều khiển tivi: khi nhấn nút nguồn trên điều khiển, led phát trên điều khiển sẽ gửi 1 chuỗi tín hiệu dạng : XXXXXXXXXX (x là các kí tự bất kì). Và tất nhiên với mỗi 1 nút trên điều khiển sẽ tương ứng với 1 chuỗi cố định. Led thu nhận được chuỗi XXXXXXXXX đó truyền cho arduino và arduino sẽ thực hiện xử lý theo chương trình. Các bạn cũng có thể tham khảo thêm phần giao tiếp với IR LED trong bài viết nữa của bác NTP_PRO
ok, giờ thì làm tách cafe và bắt đầu thôi!!!
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <Wire.h>
#include <IRremote.h>
#include <IRremoteInt.h>
#include <string.h>
#include <EEPROM.h>
int RECV_PIN = 10; // gán giá trị chân của IR LED là 10
int IRLength=0; // Gán độ dài của chuỗi kí tự
String IRCode, ReadIR[12],CodeRemote;// mã IRCode: giá trị IR đọc từ EEPROM, ReadIR: Đọc IR từ Led thu, CodeRemote giá trị IR từ Led thu
String StrCode[12]=""; // Giới hạn độ dài chuỗi
int StringLength=0;
int i=0,CountSET=0;
IRrecv irrecv(RECV_PIN); // Khai báo chân của IR LED
/* Địa chỉ của DS1307 */ const byte DS1307 = 0x68; /* Số byte dữ liệu sẽ đọc từ DS1307 */ const byte NumberOfFields = 7; /* khai báo các biến thời gian */ int second, minute, hour, day, wday, month, year, count=0, countT=0; long TimeBD=0,TimeHT=0,Time=0; int StateWifi=0; // Trạng thái của relay int StateCurent=0; int CountWF =0, CountIF=0,CountClear=0,value=0; // các biến đếm char* State; char* thu; Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 6, 7); const int SETUP =A2; // nút Setup const int UP =A1; // nút up const int DOWN =A0; // nút down int StateSETUP=0,StateUP=0,StateDOWN=0; // trạng thái các nút void setup() { pinMode(12, OUTPUT); // khai báo chân 12 là chân out (chân LIGHT của LCD) dùng để điều khiển bật tắt đèn nền LCD pinMode(11, OUTPUT); // Chân của relay pinMode(DOWN, INPUT_PULLUP); pinMode(UP, INPUT_PULLUP); pinMode(SETUP, INPUT_PULLUP); display.begin(); // Bắt đầu hiển thị LCD display.clearDisplay(); // Xóa màn hình Wire.begin(); //Khởi tạo kết nối với DS1307 irrecv.enableIRIn(); // Băt đầu nhận tín hiệu từ remote /* cài đặt thời gian cho module */ //setTime(12, 30, 45, 1, 8, 2, 15); // 12:30:45 CN 08-02-2015 Phần này các bạn xem trong mục chú thích IRLength=EEPROM.read(50); // Đọc dữ liệu trong eeprom } void loop() { readDS1307(); // đọc thời gian trong ds1307 Check_State(); // kiểm tra lại trạng thái của relay Hen_Gio(); // hàm hẹn giờ bật - tắt WIFI(); // hàm hiện thỉ trạng thái hiện tại của wifi đang bật hay tắt StateSETUP= digitalRead(SETUP); StateUP= digitalRead(UP); StateDOWN= digitalRead(DOWN); // nhấn là 0(LOW), bình thường là 1(HIGH) if(StateSETUP==0) // khi nút setup được nhấn giữ { digitalWrite(12, LOW); // đèn nền sáng SetTime(); // hàm chỉnh sửa thời gian hiện tại } else { digitalWrite(12, HIGH); // đèn nền tắt } //////////////// if(StateSETUP!=0) { Button_ON_OFF();// nếu nút setup không được nhấn, hàm kiểm tra trạng thái nút on - off sẽ khởi chạy } else { } if (irrecv.decode(&results)) { RemoteIR(); IRrecord(); irrecv.resume(); // Receive the next value } if (StateWifi!=StateCurent) // Nếu trạng thái của relay hiện tại khác với trạng thái relay ban đầu { LED_LCD();// Hàm tự đông tắt đèn nền của LCD sau 10 giây. Điều này có nghĩa là cứ có 1 thay đổi trạng thái relay thì đèn nền sẽ sáng, sau 10 giây tự động tắt } HienThiGio();// Hàm hiển thị thời gian Clear_Display(); // Xóa màn hình để cập nhật thời gian liên tục lên LCD } void readDS1307() // Hàm xử lý thời gian { Wire.beginTransmission(DS1307); Wire.write((byte)0x00); Wire.endTransmission(); Wire.requestFrom(DS1307, NumberOfFields); second = bcd2dec(Wire.read() & 0x7f); minute = bcd2dec(Wire.read() ); hour = bcd2dec(Wire.read() & 0x3f); // chế độ 24h. wday = bcd2dec(Wire.read() ); day = bcd2dec(Wire.read() ); month = bcd2dec(Wire.read() ); year = bcd2dec(Wire.read() ); year += 2000; } /* Chuyển từ format BCD (Binary-Coded Decimal) sang Decimal */ int bcd2dec(byte num) { return ((num/16 * 10) + (num % 16)); } /* Chuyển từ Decimal sang BCD */ int dec2bcd(byte num) { return ((num/10 * 16) + (num % 10)); } void HienThiGio() { display.setTextSize(2); display.setTextColor(BLACK); display.setCursor(15,10); display.print(hour); display.print(":"); display.print(minute); display.setTextSize(1); display.setTextColor(BLACK); display.setCursor(2,0); display.print(thu); if (thu!="CN") { display.print(wday); } display.print(":"); display.print(day); display.print(":"); display.print(month); display.print(":"); display.print(year); display.display(); if (second==59) { display.clearDisplay(); } if (wday==1) { thu="CN"; } else { thu="T"; } } /* cài đặt thời gian cho DS1307 */ void setTime(byte hr, byte min, byte sec, byte wd, byte d, byte mth, byte yr) { Wire.beginTransmission(DS1307); Wire.write(byte(0x00)); // đặt lại pointer Wire.write(dec2bcd(sec)); Wire.write(dec2bcd(min)); Wire.write(dec2bcd(hr)); Wire.write(dec2bcd(wd)); // day of week: Sunday = 1, Saturday = 7 Wire.write(dec2bcd(d)); Wire.write(dec2bcd(mth)); Wire.write(dec2bcd(yr)); Wire.endTransmission(); } void Hen_Gio() { // Mình đặt thời gian để relay ngắt là từ 22h đêm đến 4h59 if (((hour==22) ||(hour==23) ||(hour==0) ||(hour==1) ||(hour==2) ||(hour==3) ||(hour==4)) && (count==0)) { digitalWrite(11, LOW); //relay ngắt StateWifi=0; // gán trạng thái của wifi =0 count=1;// đặt biến đếm =1 } if (((hour==5) ||(hour==6) ||(hour==7)) && (count==1)) // thời gian mở lại relay là từ 5h đến 7h59 { digitalWrite(11, HIGH); // relay đóng StateWifi=1; // gán trạng thái wifi = 1 count=0; // đặt biến đếm =0 } if (((hour==8)|| (hour==9)||(hour==10)) && (count==0)&& ( (wday==2)||(wday==3)||(wday==4)||(wday==5)||(wday==6))) { digitalWrite(11, LOW); StateWifi=0; count=1; } if (((hour==11)||(hour==12)||(hour==13)) && ( (wday==2)||(wday==3)||(wday==4)||(wday==5)||(wday==6)) && (count==1)) { digitalWrite(11, HIGH); StateWifi=1; count=0; } if (((hour==14)||(hour==15)||(hour==16))&& ( (wday==2)||(wday==3)||(wday==4)||(wday==5)||(wday==6)) && (count==0)) { digitalWrite(11, LOW); StateWifi=0; count=1; } if (((hour==17)||(hour==18)||(hour==19)||(hour==20)||(hour==21)) && ( (wday==2)||(wday==3)||(wday==4)||(wday==5)||(wday==6)) && (count==1)) { digitalWrite(11, HIGH); StateWifi=1; count=0; } } void LED_LCD() { digitalWrite(12, LOW); // đèn nền sáng if (countT==0) // nếu biến countT=0 { TimeBD= ((hour*3600) + (minute*60) + second); // Thời gian ban đầu = tổng số giây tại thời điểm hiện tại countT=1; // gán biến đếm =1 để đảm bảo nó sẽ không thực hiện lại dòng lệnh bên trên quá 1 lần } TimeHT=abs(((hour*3600) + (minute*60) + second) - TimeBD); // thời gian hiện tại = tổng số giây tại thời điểm hiện tại - thời gian ban đầu if (TimeHT>=10) // nếu thời gian hiện tại >= 10 { digitalWrite(12, HIGH); // đèn nền tắt countT=0; // gán biến đếm CountT=0 StateCurent=StateWifi; // Gán trạng thái wifi } } void WIFI() { display.setTextSize(1); display.setTextColor(BLACK); display.setCursor(0,30); display.print("WiFi"); display.print(":"); display.setTextSize(2); display.setTextColor(BLACK); if (StateWifi==1) { digitalWrite(11, HIGH); State="ON"; //display.clearDisplay(); } if (StateWifi==0) { digitalWrite(11, LOW); State="OFF"; // display.clearDisplay(); } display.println(State); display.display(); if ((second==59) || (second==0)) // hàm này có tác dụng cập nhật lại trạng thái wifi trên màn hình { display.clearDisplay(); } } void Check_State() // hàm này để kiểm tra lại trạng thái relay { if ((hour==5) ||(hour==6) ||(hour==7) ||(hour==11) ||(hour==12) ||(hour==13) ||(hour==17)||(hour==18)||(hour==19)||(hour==20) ||(hour==21)) { if (CountIF==0) { StateCurent=0; StateWifi=1; count=1; CountIF=1; } } if ((hour==22) ||(hour==23) ||(hour==0) ||(hour==1) ||(hour==2) ||(hour==3) ||(hour==4)||(hour==8)||(hour==9)||(hour==10) ||(hour==14)||(hour==15)||(hour==16)) { if (CountWF==0) { count=0; StateCurent=1; StateWifi=0; CountWF=1; } } } void Clear_Display() { if (CountClear==0) { display.clearDisplay(); CountClear=1; } } void RemoteIR() // hàm xử lý tín hiệu hồng ngoại { for (i=0;i<IRLength;i++) { ReadIR[i]=EEPROM.read(i)-48; // đọc giá trị đã được lưu trong eeprom sau đó - 48 để delay(10); } IRCode=ReadIR[0]; // gán giá trị đã đọc được vào biến IRCode for(i=1;i<IRLength;i++) { IRCode+=ReadIR[i]; delay(10); } if(StateSETUP!=0) // nếu nút setup không được nhấn { CodeRemote=(results.value); // gán giá trị hồng ngoại nhận được vào CodeRemote if (CodeRemote==IRCode) // nếu giá trị nhận được = giá trị đã lưu trong eeprom { if (StateWifi==1) // nếu trạng thái wifi đã gán =1 tức là relay đang đóng { StateWifi=0; // thì sẽ chuyển trạng thái wifi = 0 đồng thời relay mở display.clearDisplay(); // xóa màn hình để cập nhật trạng thái trên màn hình } else if (StateWifi==0) { StateWifi=1; display.clearDisplay(); } } } } void IRrecord() // hàm học mã hồng ngoại và lưu vào eeprom { if(StateSETUP==0) // nếu nhấn giữ nút setup { StrCode[12]=(results.value); // gán giá trị nhận được vào mảng StrCode StringLength=StrCode[12].length(); // Đọc độ dài mảng EEPROM.write(50,StringLength);// ghi giá trị đọc được và eeprom for(i=0;i<StringLength;i++) { EEPROM.write(i,StrCode[12].charAt(i)); delay(10); } } } void SetTime() // hàm điều chỉnh thời gian { readDS1307(); display.clearDisplay(); if(StateUP==0) // nếu nút up được nhấn { minute=minute+1; if(minute>59) { minute=0; hour=hour+1; } if ((hour==0) && (minute==1)) { wday=wday+1; if (wday>7) { wday=1; } day=day+1; } Wire.begin(); setTime(hour, minute, 00, wday, day, month, 15); delay(10); } if(StateDOWN==0) { minute=minute-1; if(minute<0) { minute=59; hour=hour-1; } if ((hour<0) && (minute==59)) { wday=wday-1; hour=23; if (wday<1) { wday=7; } day=day-1; } Wire.begin(); delay(10); } } void Button_ON_OFF() { if(StateUP==0) { StateWifi=0; display.clearDisplay(); } if(StateDOWN==0) { StateWifi=1; display.clearDisplay(); } }
5. Chú thích
Phần code có đoạn:
//setTime(12, 30, 45, 1, 8, 2, 15); // 12:30:45 CN 08-02-2015
Minh để sau dấu chú thích là bởi vì khi nạp chương trình, thời gian sẽ được set theo giá trị 12:30:45 CN 08-02-2015 . và những lần chạy tiếp theo nó sẽ liên tục set lại giá trị cũ.
Vì vậy chỉ trong lần nạp chương trình đầu tiên mình mới để hàm setTime. sau đó để hàm settime vào sau dấu chú thích "//" rồi nạp lại lần nữa
6. Sử dụng thế nào?
Khi cần thay đổi thời gian.
Nhấn và giữ nút setup sau đó nhấn nút Up, Down để tăng, giảm thời gian.
Khi cần học mã điều khiển.
Nhấn và giữ nút setup, sau đó nhấn nút bạn cần học mã trên điều khiển (nhớ phải quay điều khiển về hướng IR LED nhé)
khi cần bật tắt bằng tay.
Nhấn nút up để bật, nhấn nút down để tắt.
Hiện tại mình mới chỉ dừng lại ở mức nạp code mặc định khoảng thời gian hẹn để bật tắt.
Cuối cùng, các bạn chỉ cần nối dây nguồn của moderm wifi vào relay và mắc nguồn cho arduino là xong. Bạn nào chưa hiểu có thể liên hệ trực tiếp với mình qua mục tin nhắn hoặc bình luận dưới bài viết nhé. Chúc các bạn thành công!