Cách làm đồng hồ đếm ngược, và bật mí cách làm nó để tỏ tình!

17/06/2019
cach-lam-dong-ho-dem-nguoc-va-bat-mi-cach-lam-no-de-to-tinh

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 devil, 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)
  • 3 x button
  • 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! heart

Thứ nhất: Bạn hãy xem hôm nay chúng ta sẽ làm gì!

Đây là chiếc đồng hồ của tôi, bạn sẽ cải tiến nó đẹp hơn chứ smiley?

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ì:

  1. 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 wink)
  2. 1 biến trở có nhiệm vụ sẽ thay đổi độ sáng của Module 4 LED nói trên
  3. 1 cái loa để phát ra tiếng báo động là đã hết "Quỹ thời gian"
  4. 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 devil 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 giaiphapchung.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 smiley.

  1. 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)
  2. Mở Arduino IDE và dán vào đoạn mã sau:
  3. #include "SevSeg.h" //Include thư viện SevSeg
  4.  
  5. SevSeg myDisplay; // Khai báo biến myDisplay là đối tượng của thư viện SegSev
  6.  
  7. void setup() { //Hàm Setup
  8.  
  9. 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!
  10. int digit1 = 8; //Pin 12 led 7 đoạn
  11. int digit2 = 12; //Pin 9 led 7 đoạn
  12. int digit3 = 13; //Pin 8 led 7 đoạn
  13. int digit4 = 2; //Pin 6 led 7 đoạn
  14.  
  15. int segA = 9; //Pin 11 led 7 đoạn
  16. int segB = 11; //Pin 7 led 7 đoạn
  17. int segC = 4; //Pin 4 led 7 đoạn
  18. int segD = 6; //Pin 2 led 7 đoạn
  19. int segE = 7; //Pin 1 led 7 đoạn
  20. int segF = 10; //Pin 10 led 7 đoạn
  21. int segG = 3; //Pin 5 led 7 đoạn
  22. int segDP= 5; //Pin 3 led 7 đoạn
  23.  
  24. int numberOfDigits = 4; // số dấu chấm
  25.  
  26. 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
  27.  
  28. myDisplay.SetBrightness(100); //điều chỉnh độ sáng của Module LED
  29.  
  30.  
  31. }
  32.  
  33. void loop(){
  34.  
  35. 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
  36.  
  37. }

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ạn gắn Module 4 LED số 8 vào bread board, những số màu đỏ là thứ tự chân của Module LED

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:

  1. Chân số 12 --> điện trở 560 Ohm --> Digital 8
  2. Chân số 11 --> Digital 9
  3. Chân số 10 --> Digital 10
  4. Chấn số 9 --> điện trở 560 Ohm --> Digital 12
  5. Chân số 8 --> điện trở 560 Ohm --> Digital 13
  6. Chân số 7 --> Digital 11
  7. Chân số 6 --> điện trở 560 Ohm --> Digital 2
  8. Chân số 5, 4, 3, 2, 1 lần lượt nối với chân Digital 3, 4, 5, 6, 7

Sau khi upload code trên, bạn sẽ được thành quả như thế này. Thật đáng 45 phút bạn chứ?

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:

 
  1. #include "SevSeg.h" //Include thư viện SevSeg
  2.  
  3. SevSeg myDisplay; // Khai báo biến myDisplay là đối tượng của thư viện SegSev
  4.  
  5. int bientro = A0;
  6. void setup() { //Hàm Setup
  7. Serial.begin(9600);//Bật cổng Serial ở mức Baudrate là 9600
  8. Serial.println("Ready");
  9. 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!
  10. int digit1 = 8; //Pin 12 led 7 đoạn
  11. int digit2 = 12; //Pin 9 led 7 đoạn
  12. int digit3 = 13; //Pin 8 led 7 đoạn
  13. int digit4 = 2; //Pin 6 led 7 đoạn
  14.  
  15. int segA = 9; //Pin 11 led 7 đoạn
  16. int segB = 11; //Pin 7 led 7 đoạn
  17. int segC = 4; //Pin 4 led 7 đoạn
  18. int segD = 6; //Pin 2 led 7 đoạn
  19. int segE = 7; //Pin 1 led 7 đoạn
  20. int segF = 10; //Pin 10 led 7 đoạn
  21. int segG = 3; //Pin 5 led 7 đoạn
  22. int segDP= 5; //Pin 3 led 7 đoạn
  23.  
  24. int numberOfDigits = 4; // số dấu chấm
  25.  
  26. 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
  27.  
  28. myDisplay.SetBrightness(100); //điều chỉnh độ sáng của Module LED
  29.  
  30.  
  31. }
  32.  
  33. void loop(){
  34.  
  35. 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
  36. myDisplay.SetBrightness(getBrightness()); //độ sáng
  37. }
  38.  
  39. int getBrightness() { // Hàm đọc giá trị độ sáng từ biến trở
  40. int value = analogRead(bientro); // Đọc giá trị biến trở và đưa vào biến value
  41. value = map(value,0,1023,0,100); // Chuyển đổi giá trị trong thang đo 0-1023 về thang đo 0 - 180
  42. return value; // Trả về giá trị độ sáng
  43. }

Và sau khi upload đoạn code mới lên, bạn sẽ có mạch của riêng bạn

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:

  1. time = time - 1 ( time-- ) --> xuất ra đồng hồ --> delay(1000) --> quay trở về (time--) cho đến khi nào mà time = 0
  2. 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é.

 
  1. #include "SevSeg.h" //Include thư viện SevSeg
  2.  
  3. SevSeg myDisplay; // Khai báo biến myDisplay là đối tượng của thư viện SegSev
  4.  
  5. int bientro = A0;
  6. /* NEW */
  7.  
  8. int maxTime = 60 * 60 - 1; // 59 phút 59 giây.
  9. int time; // Biến "Quỹ thời gian".
  10. int defaultTime = 90; // Mặc định tôi đặt là 90 giây
  11. int second, minute; // Biến giây và biến phút sẽ được tính từ biến "Quỹ thời gian"
  12. 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
  13. boolean startCounting = false; // Biến này dùng để. Mặc định là chưa đếm
  14. 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
  15.  
  16. 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
  17. int button[3]; // Mảng lưu giá trị các button (HIGH, LOW)
  18.  
  19. 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
  20. /* Hết NEW */
  21. void setup()
  22. { //Hàm Setup
  23. Serial.begin(9600); //Bật cổng Serial ở mức Baudrate là 9600
  24. Serial.println("Ready");
  25. 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!
  26. int digit1 = 8; //Pin 12 led 7 đoạn
  27. int digit2 = 12; //Pin 9 led 7 đoạn
  28. int digit3 = 13; //Pin 8 led 7 đoạn
  29. int digit4 = 2; //Pin 6 led 7 đoạn
  30.  
  31. int segA = 9; //Pin 11 led 7 đoạn
  32. int segB = 11; //Pin 7 led 7 đoạn
  33. int segC = 4; //Pin 4 led 7 đoạn
  34. int segD = 6; //Pin 2 led 7 đoạn
  35. int segE = 7; //Pin 1 led 7 đoạn
  36. int segF = 10; //Pin 10 led 7 đoạn
  37. int segG = 3; //Pin 5 led 7 đoạn
  38. int segDP = 5; //Pin 3 led 7 đoạn
  39.  
  40. int numberOfDigits = 4; // số dấu chấm
  41.  
  42. 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
  43.  
  44. myDisplay.SetBrightness(100); //điều chỉnh độ sáng của Module LED
  45.  
  46. /* NEW */
  47. // pinMode các chân của button là INPUT
  48. for (int i = 0; i < 3; i++) { //Chạy từ 0 --> 2
  49. pinMode(buttonPin[i], INPUT);
  50. }
  51. milli = milli2 = millis(); // Cập nhập cả 2 thời điểm
  52. time = defaultTime;
  53. /* hết NEW */
  54. }
  55.  
  56. void loop()
  57. {
  58. myDisplay.SetBrightness(getBrightness()); //độ sáng
  59.  
  60. /* NEW */
  61. if (millis() - milli2 > 300) { //Cứ sau mỗi 300 mili giây là đọc tất cả giá trị button
  62. for (int i = 0; i < 3; i++) {
  63. button[i] = digitalRead(buttonPin[i]);
  64. Serial.print(button[i]); //Debug
  65. }
  66. Serial.println();
  67. /*
  68. 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
  69. Tôi đặt mặc định như sua:
  70. - 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
  71. - 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
  72. - Nhấn button[0] để giảm "Quỹ thời gian" đi 10 giây
  73. - Nhấn button[2] để tăng "Quỹ thời gian" thêm 10 giây
  74. */
  75. if (button[0] && button[2]) {
  76. startCounting = !startCounting; //Thay đổi trạng thái kiểu toogle giữa HIGH và LOW
  77. delay(500);
  78. }
  79. else if (button[1]) {
  80. time = defaultTime; // Đặt mặc định
  81. startCounting = false;
  82. delay(500);
  83. }
  84. else if (button[0]) {
  85. time = max(0, time - 10);
  86. }
  87. else if (button[2]) {
  88. time = min(maxTime, time + 10);
  89. }
  90.  
  91. milli2 = millis(); //Cập nhập lại thời điểm
  92. }
  93. second = time % 60;
  94. minute = time / 60;
  95. 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
  96. 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
  97. if (startCounting && time > 0 && (millis() - milli) > 1000) {
  98. /*
  99. Còn đếm ngược khi:
  100. 1. Được phép đếm
  101. 2. Quỹ thời gian lớn hơn 0
  102. 3. Cách 1 giây từ THỜI ĐIỂM VỪA THỰC HIỆN LỆNH XUẤT RA ĐỒNG HỒ
  103. */
  104. milli = millis();
  105. time -= 1;
  106. }
  107.  
  108. if (time == 0) { // Quỹ thời gian đã cạn, bây giờ boom sẽ nổ! (đùa thôi, loa sẽ kêu)
  109. 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.
  110. }
  111. else {
  112. noTone(speakerPin); // Tắt loa vì Quỹ thời gian vẫn còn
  113. }
  114.  
  115. delay(5);
  116. /* hết NEW */
  117. }
  118.  
  119. int getBrightness()
  120. { // Hàm đọc giá trị độ sáng từ biến trở
  121. int value = analogRead(bientro); // Đọc giá trị biến trở và đưa vào biến value
  122. value = map(value, 0, 1023, 0, 100); // Chuyển đổi giá trị trong thang đo 0-1023 về thang đo 0 - 180
  123. /* NEW */
  124. Serial.println(value);
  125. /* hết NEW*/
  126. return value; // Trả về giá trị độ sáng
  127. }

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ứ devil 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!

Bình luận
Nội dung này chưa có bình luận, hãy gửi bình luận đầu tiên của bạn.
VIẾT BÌNH LUẬN CỦA BẠN