Thiết bị bật tắt Moderm Wifi tự động - Một dự án về việc hẹn giờ

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.enlightened 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ị.wink

1. Chuẩn bị

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 wink!

 mặt saumặt trước

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 yes

Và bài viết về cách sử dụng LCD 5510 của bác ksp nhé yes

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 yes

ok, giờ thì làm tách cafe và bắt đầu thôi!!! wink

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

Những hình ảnh về dự án: 
lên
26 thành viên đã đánh giá bài viết này hữu ích.
Chuyên mục: 
Các dự án được truyền cảm hứng

Select any filter and click on Apply to see results

Các bài viết cùng tác giả

Giao tiếp I2C với nhiều module

Nhiều bạn khi mới tiếp cận với thế giới điện tử và bắt đầu làm quen với arduino không khỏi bỡ ngỡ khi nhận thấy trên Arduino Uno chỉ có 2 chân A4,A5 để giao tiếp I2C. Rồi chợt đặt câu hỏi. Có mỗi 1 cổng I2C thế kia thì làm sao có thể giao tiếp với nhiều thiết bị cũng sử dụng giao tiếp I2C? Bài viết này mình sẽ hướng dẫn các bạn cách giao tiếp I2C với nhiều thiết bị.

lên
34 thành viên đã đánh giá bài viết này hữu ích.

Giao tiếp giữa 2 boad Arduino ở cự li xa 1000m bằng chuẩn giao tiếp RS-485

Mình đã có 1 bài viết hướng dẫn về cách giao tiếp giữa 2 arduino bằng i2c, 1 câu hỏi đặt ra "Đối với trường hợp 2 arduino cách xa nhau 50-100m thì sẽ thế nào?", Tất nhiên đối với cự ly như vậy, giao tiếp i2c vẫn có thể thực hiện được nhưng với yêu cầu sử dụng cáp kết nối và nhiều vấn đề phức tạp khác để đối phó với vấn đề sụt giảm điện áp trên đường truyền tải tín hiệu.

Bài viết này mình xin đề cập đến chuẩn giao tiếp RS-485,giúp giao tiếp 2 boad arduino ở cự ly 1000m thậm chí có thể lên tới 1200m (4000feet)

lên
23 thành viên đã đánh giá bài viết này hữu ích.