ksp gửi vào
- 73906 lượt xem
Nội dung chính, cần nắm
Hôm nay chúng ta sẽ cùng tham gia làm một dự án nho nhỏ cùng với tôi để thiết kế một mạch đồng hồ đếm ngươc nhé! Vậy mạch này dùng để làm gì nhỉ? Có nhiều ứng dụng lắm, ví dụ như bạn có thể nâng cấp để ghi âm lại lời thoại của mình vào một thẻ nhớ, sau đó dùng module thẻ nhớ (sẽ có hướng dẫn sau) để làm một mạch tự động phát ra lời tỏ tình với người mà bạn yêu thương !
Và nếu có một tâm hồn , bạn sẽ có thể làm một mạch tự động phát ra tiếng kêu beep beep thật to để phá một ai đó (trong lúc họ đang ngủ,...)! Đùa thôi, không nên quậy như vậy!
Phần cứng
- Arduino Uno
- 1 x biến trở (1kOhm hoặc 10kOhm) (nếu bạn chưa biết về biến trở, có thể tham khảo thêm tại đây)
- 3 x button (bạn có thể tham khảo về button tại đường dẫn này)
- Module 4 LED số 8 (hoặc module 4 LED 7 đoạn)
- 1 x Loa (bạn có thể lấy từ thùng loa cũ hoặc từ đồ chơi có nhạc, loại nào cũng được)
- 3 điện trở 10kOhm
- 4 điện trở 560 Ohm (hoặc 220 Ohm hoặc 1kOhm)
- Breadboard
- Dây cắm breadboard
Lắp mạch
Hôm nay, sẽ là một ngày vất vả đấy, vì vậy các bạn nên chọn thời gian rãnh rỗi (khoảng 1 tiếng 30 phút để làm nhé). Bây giờ, còn chần chừ gì nữa, tiến hành cùng với tôi thôi!
Thứ nhất: Bạn hãy xem hôm nay chúng ta sẽ làm gì!
Các bạn thấy đấy, mô hình của tôi chưa đẹp, vậy sau khi làm xong ví dụ mẫu này, hãy hàn mạch và gửi bài về cho chúng tôi nhé! (bạn không biết gửi bài? hãy chú ý đến menu đang chạy theo con chuột của bạn và kích vào mục Đăng bài nhé)
Bây giờ, tôi sẽ phân tích bộ đồng hồ có những phần (sau này trong các bài viết sau tôi sẽ gọi là module) gì:
- Module 4 LED số 8 tôi dùng để hiển thị thời gian, tôi chỉ cho đặt tối đa là 59 phút 59 giây. (vì nhiều quá thì cũng không biết làm gì, các bạn có thể đặt cho cao hơn, nhưng cũng chỉ tối đa là 99 phút 59 giây mà thôi )
- 1 biến trở có nhiệm vụ sẽ thay đổi độ sáng của Module 4 LED nói trên
- 1 cái loa để phát ra tiếng báo động là đã hết "Quỹ thời gian"
- 3 cái button nho nhỏ để điều chỉnh cái đồng hồ
Thứ hai: Thực hiện Module 4 LED số 8 (khoảng 45 phút)
Đây là module tốn thời gian nhất, vì bạn biết đấy, module này nhiều chân nhất và nó cùng có khá là mới mẻ với những bạn nào chưa từng làm, còn những module khác trong bài, chúng ta có thể dễ dàng tham khảo trên arduino.vn đúng không nào! Tuy nhiên, Cộng đồng Arduino Việt Nam của chúng ta luôn có những suy nghĩ cực kỳ đơn giản cho những việc khó, vì vậy bạn chỉ cần làm theo từng bước dưới đây để hoàn thiện module này. Và tất nhiên, bạn sẽ hiểu được cách để sử dụng chúng sau này, cho những dự án khác của bạn .
- Tải về thư viện SegSev ( sau đó giải nén và chép vào thư mục libraries trong thư mục cài đặt Arduino IDE của bạn)
- Mở Arduino IDE và dán vào đoạn mã sau:
#include "SevSeg.h" //Include thư viện SevSeg SevSeg myDisplay; // Khai báo biến myDisplay là đối tượng của thư viện SegSev void setup() { //Hàm Setup int displayType = COMMON_ANODE; // CÁI NÀY VÔ CÙNG QUAN TRỌNG, nếu người ta bán cho bạn một Module LED 8 đoạn chung cực dương thì bạn không cần thay đổi dòng này. Còn nếu họ bán một Module LED 8 đoạn chung cực âm cho các bạn thì bạn cần thay đổi là COMMON_CATHODE. Và nếu người bán không nói cho bạn hoặc bạn quên không hỏi thì cũng không sao, cứ đặt như thế này và lắp mạch nếu không chạy đúng như những gì đoạn code này cần thực hiện thì bạn chỉ cần thay nó là COMMON_CATHODE thôi! int digit1 = 8; //Pin 12 led 7 đoạn int digit2 = 12; //Pin 9 led 7 đoạn int digit3 = 13; //Pin 8 led 7 đoạn int digit4 = 2; //Pin 6 led 7 đoạn int segA = 9; //Pin 11 led 7 đoạn int segB = 11; //Pin 7 led 7 đoạn int segC = 4; //Pin 4 led 7 đoạn int segD = 6; //Pin 2 led 7 đoạn int segE = 7; //Pin 1 led 7 đoạn int segF = 10; //Pin 10 led 7 đoạn int segG = 3; //Pin 5 led 7 đoạn int segDP= 5; //Pin 3 led 7 đoạn int numberOfDigits = 4; // số dấu chấm myDisplay.Begin(displayType, numberOfDigits, digit1, digit2, digit3, digit4, segA, segB, segC, segD, segE, segF, segG, segDP); // Bắt đầu cho phép giao tiếp Module LED 7 đoạn với Arduino myDisplay.SetBrightness(100); //điều chỉnh độ sáng của Module LED } void loop(){ myDisplay.DisplayString("abcd", 0b00001000); // Thể hiện chữ AbcD ra bảng LED, và dãy số 0b00001000 là vị trí dấu chấm. Bạn hãy thử thay những số 0 bằng số 1 hoặc ngược lại để kiểm nghiệm }
Bây giờ, bạn hãy lắp mạch như sau (kích vào hình để xem ảnh lớn)
Nếu không rõ, bạn có thể thực hiện theo từng bước như sau:
Bây giờ, bạn sẽ thực hiện lắp ghép chân của module này như hướng dẫn sau:
- Chân số 12 --> điện trở 560 Ohm --> Digital 8
- Chân số 11 --> Digital 9
- Chân số 10 --> Digital 10
- Chấn số 9 --> điện trở 560 Ohm --> Digital 12
- Chân số 8 --> điện trở 560 Ohm --> Digital 13
- Chân số 7 --> Digital 11
- Chân số 6 --> điện trở 560 Ohm --> Digital 2
- Chân số 5, 4, 3, 2, 1 lần lượt nối với chân Digital 3, 4, 5, 6, 7
Thứ ba: Dùng biến trở để chỉnh độ sáng của Module đèn LED (khoảng 15 phút)
Bạn hãy lắp thêm một biến trở vào chân A0 nhé, để biết cách sử dụng biến trở, xem bài hướng dẫn sau.
Hãy theo từng bước của tôi, bạn nhé.
Đầu tiên, bạn cần khai báo biến bientro là A0 để sử dụng trong việc đọc giá trị biến trở, bạn đặt dòng code này trước hàm setup:
int bientro = A0;
Sau đó, chúng ta cần khởi tạo một cổng Serial để xem giá trị của biến trở, và sau này là để xem giá trị của các nút bấm (button) bạn thêm vào trong hàm setup những dòng code sau:
Serial.begin(9600);//Bật cổng Serial ở mức Baudrate là 9600 Serial.println("Ready");
Khi sử dụng hàm analogRead, nó sẽ trả về một giá trị trong khoảng từ 0 đến 1023, mà giá trị độ sáng của đèn (được thiết đặt tại myDisplay.SetBrightness(100);) chỉ nằm trong khoảng từ 0 đến 100. Vì vậy, chúng ta sẽ sử dụng hàm map để đổi thang đo. Vì vậy, ta sẽ xây dựng một hàm kiểu int để trả về giá trị độ sáng màn hình! Bạn thêm đoạn code này nằm ngoài hàm loop hoặc hàm setup.
int getBrightness() { // Hàm đọc giá trị độ sáng từ biến trở int value = analogRead(bientro); // Đọc giá trị biến trở và đưa vào biến value value = map(value,0,1023,0,100); // Chuyển đổi giá trị trong thang đo 0-1023 về thang đo 0 - 180 return value; // Trả về giá trị độ sáng }
Để thay đổi độ sáng của Module 4 LED số 8 thời gian thực (ngay lập tức) chúng ta cần thêm dòng này vào hàm loop, lúc này độ sáng sẽ được cập nhập liên tục:
myDisplay.SetBrightness(getBrightness()); //độ sáng
Lúc bấy giờ, toàn bộ chương trình của ta sẽ như thế này:
#include "SevSeg.h" //Include thư viện SevSeg SevSeg myDisplay; // Khai báo biến myDisplay là đối tượng của thư viện SegSev int bientro = A0; void setup() { //Hàm Setup Serial.begin(9600);//Bật cổng Serial ở mức Baudrate là 9600 Serial.println("Ready"); int displayType = COMMON_ANODE; // CÁI NÀY VÔ CÙNG QUAN TRỌNG, nếu người ta bán cho bạn một Module LED 8 đoạn chung cực dương thì bạn không cần thay đổi dòng này. Còn nếu họ bán một Module LED 8 đoạn chung cực âm cho các bạn thì bạn cần thay đổi là COMMON_CATHODE. Và nếu người bán không nói cho bạn hoặc bạn quên không hỏi thì cũng không sao, cứ đặt như thế này và lắp mạch nếu không chạy đúng như những gì đoạn code này cần thực hiện thì bạn chỉ cần thay nó là COMMON_CATHODE thôi! int digit1 = 8; //Pin 12 led 7 đoạn int digit2 = 12; //Pin 9 led 7 đoạn int digit3 = 13; //Pin 8 led 7 đoạn int digit4 = 2; //Pin 6 led 7 đoạn int segA = 9; //Pin 11 led 7 đoạn int segB = 11; //Pin 7 led 7 đoạn int segC = 4; //Pin 4 led 7 đoạn int segD = 6; //Pin 2 led 7 đoạn int segE = 7; //Pin 1 led 7 đoạn int segF = 10; //Pin 10 led 7 đoạn int segG = 3; //Pin 5 led 7 đoạn int segDP= 5; //Pin 3 led 7 đoạn int numberOfDigits = 4; // số dấu chấm myDisplay.Begin(displayType, numberOfDigits, digit1, digit2, digit3, digit4, segA, segB, segC, segD, segE, segF, segG, segDP); // Bắt đầu cho phép giao tiếp Module LED 7 đoạn với Arduino myDisplay.SetBrightness(100); //điều chỉnh độ sáng của Module LED } void loop(){ myDisplay.DisplayString("abcd", 0b00001000); // Thể hiện chữ AbcD ra bảng LED, và dãy số 0b00001000 là vị trí dấu chấm. Bạn hãy thử thay những số 0 bằng số 1 hoặc ngược lại để kiểm nghiệm myDisplay.SetBrightness(getBrightness()); //độ sáng } int getBrightness() { // Hàm đọc giá trị độ sáng từ biến trở int value = analogRead(bientro); // Đọc giá trị biến trở và đưa vào biến value value = map(value,0,1023,0,100); // Chuyển đổi giá trị trong thang đo 0-1023 về thang đo 0 - 180 return value; // Trả về giá trị độ sáng }
Và sau khi upload đoạn code mới lên, mạch của bạn sẽ như thế này.
Thứ tư: Xây dựng bộ đếm ngược thời gian với các button và phát ra loa (khoảng 30 phút)
Để xây dựng một bộ đếm thời gian thì chúng ta cần hiểu được quy trình nó như thế nào, và trước tiên phải đề xuất ra những ý tưởng, với tôi, tôi có 2 ý tưởng cho việc này:
Gọi biến time là Quỹ thời gian còn lại của đồng hồ, ta có 2 cách:
- time = time - 1 ( time-- ) --> xuất ra đồng hồ --> delay(1000) --> quay trở về (time--) cho đến khi nào mà time = 0
- Nếu thời điểm kể từ lúc bắt đầu chạy chương trình đến bây giờ trừ đi THỜI ĐIỂM VỪA THỰC HIỆN LỆNH XUẤT RA ĐỒNG HỒ mà lớn hơn 1 giây thì
- time = time - 1 ( time-- )
- Cập thời THỜI ĐIỂM VỪA THỰC HEIẸN LỆNH XUẤT RA ĐỒNG HỒ lời thời điểm hiện tại
Qua quá trình so sánh giữa 2 cách, tôi nhận thấy. Cách 2 có nhiều ưu điểm vượt trội, như là:
- Chương trình không bị dừng hẳn (delay) nên vẫn tiếp tục tính toán được ==> tôi có thể gắn được các button
- Cập nhập thời gian liên tục không gián đoạn
- Còn cách 1 làm cho đồng hồ bị dừng (sử dụng hàm delay) làm cho việc gia công các button là không thể thực hiện được
Bây giờ, bạn hãy lắp thêm 3 button như sau bạn nhé:
Chúng ta sẽ mắc 3 điện trở button kiểu PULL DOWN và pinMode cho chúng là INPUT. Thứ tự của 3 button từ trái qua phải lần lượt là 1, 2, 3 và 3 button này được mắc lần lượt với chân Analog A3, Analog A2, Analog A1. Tiếp theo chúng ta sẽ gắn loa theo sơ đồ sau, nếu các bạn không phân biệt được cực âm cực dưong của loa thì cũng không sao cả, chúng ta chỉ việc chọn đại một chân nào đó để làm cực âm thôi (chân còn lại nối vào Analog A4).
Cuối cùng, bạn upload đoạn code sau đây và "enjoy" dự án đồng hồ của mình thôi! Trong đoạn code mình đã chủ thích khá rõ ràng, bạn hãy đọc trong đó để hiểu hơn nhé! Để debug xem các button và biến trở có hoạt động hay không thì sau khi upload thành công bạn nhấn tổ hợp phím Ctrl+Shift+M nhé.
#include "SevSeg.h" //Include thư viện SevSeg SevSeg myDisplay; // Khai báo biến myDisplay là đối tượng của thư viện SegSev int bientro = A0; /* NEW */ int maxTime = 60 * 60 - 1; // 59 phút 59 giây. int time; // Biến "Quỹ thời gian". int defaultTime = 90; // Mặc định tôi đặt là 90 giây int second, minute; // Biến giây và biến phút sẽ được tính từ biến "Quỹ thời gian" unsigned long milli, milli2; // Biến milli dùng để lưu lại THỜI ĐIỂM VỪA THỰC HIỆN LỆNH XUẤT RA ĐỒNG HỒ. Biến milli2 dùng để lưu lại THỜI ĐIỂM CUỐI CÙNG NHẤN NÚT BẤM boolean startCounting = false; // Biến này dùng để. Mặc định là chưa đếm char buf[5]; //Chuỗi buf có độ dài tối đa là 4 (xem bài char để rõ). Chuỗi buf có nhiệm vụ là nhận giá trị cuối cùng (Đã được định dạng thời gian) trước khi chuyển cho đối tượng SegSev để xuất ra Module 4 LED số 8 int buttonPin[3] = { A3, A2, A1 }; // Mảng lưu chân các button. Do 12 chân digital đã được sử dụng để xử lý Module 4 LED nên mình mới sử dụng chân Analog, ngoài ra bạn có thể sử dụng chân Digital cho việc này int button[3]; // Mảng lưu giá trị các button (HIGH, LOW) int speakerPin = A4; // Chân nối tới 1 chân của loa. Do 12 chân digital đã được sử dụng để xử lý Module 4 LED nên mình mới sử dụng chân Analog, ngoài ra bạn có thể sử dụng chân Digital cho việc này /* Hết NEW */ void setup() { //Hàm Setup Serial.begin(9600); //Bật cổng Serial ở mức Baudrate là 9600 Serial.println("Ready"); int displayType = COMMON_ANODE; // CÁI NÀY VÔ CÙNG QUAN TRỌNG, nếu người ta bán cho bạn một Module LED 8 đoạn chung cực dương thì bạn không cần thay đổi dòng này. Còn nếu họ bán một Module LED 8 đoạn chung cực âm cho các bạn thì bạn cần thay đổi là COMMON_CATHODE. Và nếu người bán không nói cho bạn hoặc bạn quên không hỏi thì cũng không sao, cứ đặt như thế này và lắp mạch nếu không chạy đúng như những gì đoạn code này cần thực hiện thì bạn chỉ cần thay nó là COMMON_CATHODE thôi! int digit1 = 8; //Pin 12 led 7 đoạn int digit2 = 12; //Pin 9 led 7 đoạn int digit3 = 13; //Pin 8 led 7 đoạn int digit4 = 2; //Pin 6 led 7 đoạn int segA = 9; //Pin 11 led 7 đoạn int segB = 11; //Pin 7 led 7 đoạn int segC = 4; //Pin 4 led 7 đoạn int segD = 6; //Pin 2 led 7 đoạn int segE = 7; //Pin 1 led 7 đoạn int segF = 10; //Pin 10 led 7 đoạn int segG = 3; //Pin 5 led 7 đoạn int segDP = 5; //Pin 3 led 7 đoạn int numberOfDigits = 4; // số dấu chấm myDisplay.Begin(displayType, numberOfDigits, digit1, digit2, digit3, digit4, segA, segB, segC, segD, segE, segF, segG, segDP); // Bắt đầu cho phép giao tiếp Module LED 7 đoạn với Arduino myDisplay.SetBrightness(100); //điều chỉnh độ sáng của Module LED /* NEW */ // pinMode các chân của button là INPUT for (int i = 0; i < 3; i++) { //Chạy từ 0 --> 2 pinMode(buttonPin[i], INPUT); } milli = milli2 = millis(); // Cập nhập cả 2 thời điểm time = defaultTime; /* hết NEW */ } void loop() { myDisplay.SetBrightness(getBrightness()); //độ sáng /* NEW */ if (millis() - milli2 > 300) { //Cứ sau mỗi 300 mili giây là đọc tất cả giá trị button for (int i = 0; i < 3; i++) { button[i] = digitalRead(buttonPin[i]); Serial.print(button[i]); //Debug } Serial.println(); /* Bây giờ chúng ta sẽ thiết đặt các lệnh, gợi ý, các bạn đặt những lệnh nào sử dụng nhiều nút bấm lên trước Tôi đặt mặc định như sua: - Nhấn cả 2 phím button[0] và button[2] sẽ ngừng/tiếp tục đếm ngược --> delay(500) miligiây để tạo hiệu ứng - Nhấn button[1] sẽ reset về giá trị ban đầu và ngừng đếm ngược --> delay(500) miligiây để tạo hiệu ứng - Nhấn button[0] để giảm "Quỹ thời gian" đi 10 giây - Nhấn button[2] để tăng "Quỹ thời gian" thêm 10 giây */ if (button[0] && button[2]) { startCounting = !startCounting; //Thay đổi trạng thái kiểu toogle giữa HIGH và LOW delay(500); } else if (button[1]) { time = defaultTime; // Đặt mặc định startCounting = false; delay(500); } else if (button[0]) { time = max(0, time - 10); } else if (button[2]) { time = min(maxTime, time + 10); } milli2 = millis(); //Cập nhập lại thời điểm } second = time % 60; minute = time / 60; sprintf(buf, "%02d%02d", minute, second); // Hàm sprintf là một hàm của C, bạn tham khảo địa chỉ http://www.cplusplus.com/reference/cstdio/sprintf/ Tôi dùng nó để định dạng lại giá trị trước khi xuất ra màn hình. Bởi vì các biến minute và second là các biến kiểu số nguyên => không thể xuất được. Vì vậy tôi định dạng lại nó để có được mạng chuỗi dạng (mmss) (mm = minute, ss = second) để xuất ra được Module 4 LED số 8 myDisplay.DisplayString(buf, 0b00000010); // Thể hiện chữ AbcD ra bảng LED, và dãy số 0b00001000 là vị trí dấu chấm. Bạn hãy thử thay những số 0 bằng số 1 hoặc ngược lại để kiểm nghiệm if (startCounting && time > 0 && (millis() - milli) > 1000) { /* Còn đếm ngược khi: 1. Được phép đếm 2. Quỹ thời gian lớn hơn 0 3. Cách 1 giây từ THỜI ĐIỂM VỪA THỰC HIỆN LỆNH XUẤT RA ĐỒNG HỒ */ milli = millis(); time -= 1; } if (time == 0) { // Quỹ thời gian đã cạn, bây giờ boom sẽ nổ! (đùa thôi, loa sẽ kêu) tone(speakerPin, 3200); //Phát ra âm thanh ở tần số 3200 Hz, bạn có thể thay đổi nó, miễn nó nằm trong ngưỡng nghe được của tai. } else { noTone(speakerPin); // Tắt loa vì Quỹ thời gian vẫn còn } delay(5); /* hết NEW */ } int getBrightness() { // Hàm đọc giá trị độ sáng từ biến trở int value = analogRead(bientro); // Đọc giá trị biến trở và đưa vào biến value value = map(value, 0, 1023, 0, 100); // Chuyển đổi giá trị trong thang đo 0-1023 về thang đo 0 - 180 /* NEW */ Serial.println(value); /* hết NEW*/ return value; // Trả về giá trị độ sáng }
Ngoài ra, bạn có thể download đoạn code trên tại đây.
Lời kết
Bạn và tôi đã trải qua 1h30 phút căng thẳng đúng không nào? Vậy bây giờ ra ngoài tiệm tạp hóa gần nhất mua một chai Mountain Dew để thưởng thức vị ngọt đậm đà và lên kế hoạch cho cái đồng hồ chứ khàkhà
Và trong bài sau, tôi sẽ hướng dẫn bạn sử dụng module thẻ nhớ để lưu lại những gì mình muốn nói và phát ra lời bạn muốn tỏ tình hehe!
Thôi, không phải đợi lâu, bạn chỉ cần làm như bài hướng dẫn sau thôi, hehe. Bài 12: Phát nhạc bằng Arduino với một cái loa hoặc buzzer