Bài 6: Bật tắt đèn tự động bằng cảm biến ánh sáng sử dụng Arduino

From MakerLab Wiki
Jump to navigation Jump to search

Mục tiêu

Qua chuỗi 5 bài trước, các bạn đã cùng mình đi qua từng bước tiếp cận những kiến thức Điện tử và kỹ thuật Lập trình Arduino cơ bản nhất rồi.

Từ bài này, chúng ta hãy thử vận dụng những gì đã học được để làm những dự án nhỏ thật tế nhé.
Mục tiêu bài này là làm một "Bộ bật tắt đèn tự động" đơn giản, có thể lắp đặt ở nhiều nơi, như: cầu thang, tủ quần áo, phòng ngủ, bàn làm việc, ...
Các bạn đã sẵn sàng chưa, cùng đi nào!

Kiến thức cơ bản

Cảm biến Quang trở?

Quang trở
Quang trở
Quang trở (Photoresistor) là một loại linh kiện có chức năng khá giống Biến trở. Nó có thể thay đổi giá trị Trở kháng (Ω) theo Cường độ ánh sáng chiếu vào nó.
Nó có thiết kế "Hình đĩa" và ra hai đầu dẫn, được cấu tạo chủ yếu từ thành phần chính là "Cadmium Sulfide" (một chất bán dẫn). Nên khi có ánh sáng chiếu vào bề mặt đĩa, chất này tiếp xúc với ánh sáng làm cho nhiều hạt Electron bị kích thích chuyển sang trạng thái tự do và có thể tham gia vào quá trình dẫn điện. → Kết quả là Trở kháng giữa hai đầu dẫn cảm biến sẽ giảm đi.
Về nguyên tắc, bất kỳ Điện trở nào trong mạch đều có thể được thay thế bằng Quang trở. Vậy nên để biến đổi cường độ ánh sáng thành Điện áp cho Vi điều khiển đọc được dưới dạng tín hiệu Analog. Một Quang trở có thể mắc nối tiếp với một Điện trở thông thường, tạo thành một Bộ phân áp.
2 cách để thực hiện việc này theo hình dưới đây. Sơ đồ bên trái, khi chiếu ánh sáng vào sẽ làm điện áp đầu ra tăng. Còn sơ đồ bên phải, khi chiếu ánh sáng vào sẽ làm điện áp đầu ra giảm.
2 cách sử dụng Quang trở
2 cách sử dụng Quang trở
Để dễ hiểu, các bạn hãy xem Quang trở như Nút nhấn. Khi có ánh sáng chiếu vào sẽ làm nó giảm Trở kháng và dễ dẫn điện hơn, khi ấy ta có thể xem như đang NHẤN NÚT. Cho nên ngược lại, khi không có ánh sáng chiếu vào, ta có thể xem như đang NHẢ NÚT.

Serial Plotter?

Serial Plotter là một trong những công cụ trong Arduino IDE. Nó có thể nhận dữ liệu từ bo Arduino và hiển thị lên màn hình máy tính dưới dạng Sóng (Wave) thay vì văn bản thuần như Serial Monitor.
Serial Plotter
Serial Plotter
Nó có thể trực quan hóa không chỉ một dữ liệu đơn lẻ mà còn nhiều dữ liệu trong cùng một đồ thị. Trong đó, Trục tung (X) thể hiện "biên độ" dữ liệu, còn Trục hoành (Y) cập nhập dữ liệu liên tục theo "thời gian".
Và để Serial Plotter biểu diễn đồ thị đúng ý mình, ta sẽ cần tuân theo một số quy tắc trong việc gửi dữ liệu từ bo Arduino lên máy tính, để phần mềm có thể diễn giải đúng được. Bài hướng dẫn chi tiết, mình có để link ở mục Tìm hiểu thêm!

Phần mềm

Arduino

Icon-Info-White.png Trước khi bắt đầu:

  • Yêu cầu đã cài phần mềm Arduino IDE (nên cài phiên bản mới nhất đã ổn định).
  • Các bạn có thể xem các bài hướng dẫn cơ bản về cách cài, cách sử dụng IDE này tại đây nhé.

Phần cứng

Danh sách thiết bị

Tên sản phẩm Số lượng
Mạch Vietduino Uno (Arduino Uno Compatible) 1
Mạch Arduino MakerEDU Shield 1
Cảm biến ánh sáng quang trở MKL-S02 LDR light sensor 1
Mạch led đơn MKL-M01 10mm single LED module [Trắng (White)] 1
Cáp Micro USB 1
Cáp Kết Nối MakerEDU XH2.54 3Wires 20cm Cable [XH2.54 - XH2.54] 2

Hướng dẫn kết nối

  1. Gắn Shield "Arduino MakerEDU" lên bo Vietduino.
  2. Kết nối Module Quang trở với Shield bằng dây "XH2.54 3Wires" vào Port A1.
  3. Kết nối Module LED với Shield bằng dây "XH2.54 3Wires" vào Port D9.
  4. Kết nối bo Vietduino với máy tính thông qua cáp MicroUSB.

Code

  1. Mở Arduino IDE.
  2. Vào File -> New (hoặc Ctrl+N) tạo 1 file Arduino mới và đặt tên là ...\Smart_Light.ino
  3. Vào Tool để cấu hình Board:...Port:... đúng tương ứng với bo Arduino bạn đang dùng.
  4. Copy đoạn Code sau và nhấp vào Verify (Ctrl+R) để IDE kiểm tra lỗi cú pháp.
  5. Sau khi IDE kiểm tra không có lỗi trong Code, lúc này bạn có thể nhấp Upload (Ctrl+U) để nạp Code vào bo Arduino.

Code Example

Template:Kxncode

Giải thích Code

#define /*** TIỀN XỬ LÝ ***/

Chức năng:

  • Đây cũng là 1 lệnh chỉ thị dành cho Tiền xử lý.
    Nó cho phép lập trình viên đặt tên (MACRO) cho một Giá trị không đổi (Constant) trước khi chương trình được biên dịch. Và khi bắt đầu quá trình biên dịch, trước tiên Tiền xử lý sẽ thực hiện "ánh xạ" (làm thay đổi văn bản Code) trên các MACRO này bằng các giá trị được xác định trước.
Icon-Info-White.png MACRO?

  • MACRO hiểu đơn giản là một quy tắc "ánh xạ" một giá trị đầu vào thành một giá trị đầu ra theo một quy trình đã được xác định.

Cú pháp:

  • #define Constant_Name Value

Tham số:

  • Constant_Name - tên của MACRO được xác định.
  • Value - giá trị để "gán" cho MACRO đó.
const /*** ĐỊNH TÍNH ***/

Chức năng:

  • Là một Định tính (Qualifier) cho biến, làm sửa đổi hành vi của biến.
    Nó làm cho một biến trở thành loại "chỉ đọc", như Hằng số (Constant).
    Điều này có nghĩa là biến có thể được sử dụng giống như bất kỳ biến nào khác cùng loại, nhưng giá trị của nó không thể thay đổi. Trình biên dịch sẽ báo lỗi nếu phát hiện bạn cố gắng thay đổi giá trị của biến trong chương trình.

Cú pháp:

  • const type var = val;

Tham số:

  • type - các "kiểu dữ liệu".
  • var - tên biến.
  • val - giá trị bạn "gán cố định luôn" cho biến đó.




Icon-Info-White.png #define và const:

  • Tuy cả 2 có chức năng nhìn giống như nhau, đều cho phép ta đặt tên cho một giá trị hằng số để sử dụng cái tên đó trong Code. Nhưng giữa chúng vẫn có điểm khác nhau.
  • Đó là các MACRO chỉ đơn thuần là một giá trị Literal được thay thế (không phải là Biến). Chính vì vậy nó có thể được sử dụng ở bất kỳ đâu trong chương trình hoặc trong các tệp khác, mà không có sự ràng buộc hay kiểm soát.
  • Còn const là một từ khóa được dùng cho Biến. Nên nó sẽ được kiểm soát bởi những thuộc tính của Biến đó, như: Phạm vi sử dụng, Thời gian tồn tại, ... cũng như bởi Trình biên dịch




byte /*** KIỂU DỮ LIỆU ***/

Chức năng:

  • Tạo một biến có kiểu dữ liệu là SỐ NGUYÊN KHÔNG DẤU để lưu trữ.
    KHÔNG DẤU (Unsigned) nghĩa là biến này chỉ có thể lưu trữ Số Nguyên Dương.
    Với 1 Byte = 8 bit, nó có thể lưu trữ một Số Nguyên trong phạm vi từ 0 đến 255 (28-1).

Cú pháp:

  • byte var = val;
  • byte var;

Tham số:

  • var - tên biến.
  • val - giá trị bạn "gán" cho biến đó.
if(condition)
{
  // statement(s)
}
else
{
  // statement(s)
}

Chức năng:

  • Câu lệnh if kiểm tra một Điều kiện (Condition) và thực hiện một câu lệnh hoặc tập hợp các câu lệnh của nó, nếu điều kiện là true.
    Ngược lại, điều kiện là false thì sẽ thực hiện một câu lệnh hoặc tập hợp các câu lệnh của phần mở rộng else.

Tham số:

  • condition - một biểu thức Boolean (có thể là true hoặc false).
Serial.print(); /*** HÀM ***/

Chức năng:

  • In dữ liệu vào cổng Serial Port dưới dạng văn bản ASCII mà con người có thể đọc được.
    Lệnh này có thể nhận nhiều định dạng kiểu dữ liệu (như: kí tự, chuỗi, số nguyên, số thực, ...) tương tự giống với lệnh Serial.println().

Cú pháp:

  • Serial.print(val);

Tham số:

  • val - giá trị để in (cho phép bất kì kiểu dữ liệu nào).

Kiểu dữ liệu trả về:

  • Trả về số Byte được in ra (kiểu dữ liệu size_t).
    Chức năng này là tùy chọn, bạn có thể đọc hoặc không đọc cũng được.
>  /*** TOÁN TỬ ***/
>= /*** TOÁN TỬ ***/
<= /*** TOÁN TỬ ***/
<  /*** TOÁN TỬ ***/

Chức năng:

  • Là các Toán tử So sánh2 Toán hạng.
    Nó giúp "so sánh" Biến ở bên trái với Biến hoặc Hằng số ở bên phải của toán tử.

Cú pháp:

  • x > y; // kết quả là true nếu x lớn hơn y và false nếu x nhỏ hơn bằng y
  • x >= y; // kết quả là true nếu x lớn hơn bằng y và false nếu x nhỏ hơn y
  • x <= y; // kết quả là true nếu x nhỏ hơn bằng y và false nếu x lớn hơn y
  • x < y; // kết quả là true nếu x nhỏ hơn y và false nếu x lớn hơn bằng y

Tham số: → cả 2 toán hạng đều có thể là bất kì kiểu dữ liệu nào.

  • x - là Biến (toán hạng bên phải).
  • y - là Biến hoặc Hằng số (toán hạng bên trái).
?: /*** TOÁN TỬ ***/

Chức năng:

  • Là một Toán tử Điều kiện có tận 3 Toán hạng.
    Nó có chức năng tương tự như câu lệnh if-else nhưng lại chiếm ít không gian hơn và giúp viết câu lệnh if-else theo cách ngắn nhất có thể.

Cú pháp:

  • var = exp1 ? exp2 : exp3; // tương tự cấu trúc if (exp1) {var = exp2} else {var = exp3}
  • exp1 ? exp2 : exp3; // tương tự cấu trúc if (exp1) {exp2} else {exp3}

Tham số:

  • var - tên biến.
  • exp1 - là biểu thức được đánh giá.
  • exp2 - là biểu thức trả về hoặc câu lệnh được thực hiện nếu exp1 đánh giá là true.
  • exp3 - là biểu thức trả về hoặc câu lệnh được thực hiện nếu exp1 đánh giá là false.

Lưu đồ (Flow Chart)

FlowChartB6.png

Chương trình này hoạt động như thế nào?

Trước khi thật sự bắt đầu hoạt động.

  • Ta sẽ cần đọc giá trị Analog từ cảm biến Quang trở lần đầu tiên để lấy mẫu.
  • Từ giá trị Analog đọc được, ta chuyển đổi sang thang đo mới, với đơn vị (%).
  • Và lần nữa chuyển đổi tiếp sang thang đo khác, chỉ còn 2 giá trị là HIGHLOW. Nhờ giá trị (%) nên ta dễ dàng xác định trạng thái của Quang trở qua điểm SetPoint.
  • Sau khi đã xác định được trạng thái của Quang trở rồi, ta có thể quyết định bật LED hay tắt LED tùy theo nhu cầu sử dụng.

Kể từ lần lấy mẫu đầu tiên, chương trình mới thực sự bắt đầu hoạt động.

  • Từ những lần sau quá trình cứ lặp lại như trên. Nhưng sẽ có thêm một quy tắc để tránh trường hợp mỗi khi giá trị đọc từ cảm biến dao động nhỏ quanh điểm SetPoint, làm đèn LED bật tắt liên tục.
  • Để khắc phục ta sử dụng thêm giá trị Delta kết hợp với luật: "Là chỉ chấp nhận trạng thái mới của Quang trở (tức thay đổi trạng thái LED) chỉ khi giá trị (%) vượt quá khoảng Delta của ngưỡng trên hoặc dưới tính từ điểm SetPoint".
Icon-Info-White.png Tip:

  • Điểm tiện lợi của SetPointDelta là ta dễ dàng tinh chỉnh lại trong code cho phù hợp với vùng ánh sáng xung quanh ở môi trường hiện tại.
  • Ngoài ra, các bạn có thể bật đồ thị Serial Plotter để xem trực quan quá trình thiết bị hoạt động như thế nào. Bấm vào Tool -> Serial Plotter, hoặc nhấn phím tắt Ctrl+Shift+L (nhớ chọn đúng Baudrate theo code).

Kết quả Demo

Icon-Warning-White.png Vấn đề nguồn:

  • Các bạn lưu ý, bất cứ ứng dụng nào chúng ta có dùng đến hàm analogRead(), để kết quả chạy đúng theo Code. Ta phải cấp nguồn riêng cho các board Arduino ở jack DC, hoặc chí ít phải đảm bảo nguồn cấp qua cổng USB đúng 5V!
  • Vì thực tế hàm này trả về giá trị MAX 1.023 bằng với giá trị điện áp đang cấp nuôi cho Vi Điều Khiển trên bo Arduino, chứ không phải là 5V.
  • Nên khi nguồn điện áp này không đúng 5V có thể làm chương trình trả về kết quả sai số nhỏ, hay xuất hiện những lỗi không mong muốn, thậm chí hoạt động sai!

Nếu mình đã cấp đủ nguồn rồi, thì ...

Icon-Done-White.png Successful:

  • Đèn LED chỉ thay đổi từ OFF sang ON, khi ánh sáng môi trường xung quanh giảm đi, và chạm ngưỡng dưới điểm (SetPoint - Delta).
  • Còn ngược lại, khi ánh sáng môi trường xung quanh nhiều, làm chạm qua ngưỡng (SetPoint + Delta).

Các bạn có thể xem chương trình sẽ hoạt động như thế nào theo video dưới đây nhé.

!!! nhúng 1 clip youtube, để xem video trực tiếp trên trang này. Dùng extension <iframe> cho MediaWiki.

Gợi ý mở rộng

_ Ta có thể thay đèn LED bằng Relay → để bật tắt các bóng đèn điện hay các thiết bị điện trong nhà.
_ Kết hợp thêm Module RealTime → để tự động tinh chỉnh thông số sao cho hoạt động phù hợp với từng khung giờ sinh hoạt trong ngày.
_ Kết hợp các thiết bị như Dimmer -> để theo dõi độ sáng của đèn bàn học hay góc làm việc từ đó điều chỉnh độ sáng đèn tự động ở một mức độ ổn định → giúp mắt mình đỡ mỏi, dễ chịu hơn.
_ Làm ứng dụng theo dõi cường độ ánh sáng trong phòng → từ đó điều chỉnh rèm cửa tự động hay cửa miệng giếng trời → giúp luôn duy trì một lượng ánh sáng ổn định cho cả căn nhà.
_ Làm hệ thống ánh sáng sân vườn tự động → bật đèn dần khi trời tối và tắt đèn dần khi trời sáng.
_ Làm hệ thống theo dõi hướng mặt trời, để điều chỉnh hướng nhận được ánh sáng nhiều nhất có thể → cho các tấm pin năng lượng mặt trời, từ đó giúp tối ưu hiệu suất tạo năng lượng. Hay điều chỉnh hướng thấu kính tự động → để làm bộ đun nước nóng bằng mặt trời.
_ ...

Tìm hiểu thêm

Về Quang trở và các Cảm biến tương tự khác: | Photoresistor VS Photodiode VS Phototransistor.

Về cách sử dụng đồ thị Serial Plotter: | Arduino - Serial Plotter.

Ngôn ngữ lập trình Arduino: | Language - Arduino Reference.