2:06 PM
0

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




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

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

Đâ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é)
Vi deo hướng dẫn:



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 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 giaiphaptt.vn! 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.
  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:
#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ạ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é.
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.
Video thành quả:



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é.
#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.

0 comments:

Post a Comment

 

Lập trình

-

Arduino Hải Phòng

,