byte _pins[] = { 21, 20, 19, 18, 17, 16, 15, 14, 2, 3, 4, 5 };
class Port {
byte length;
byte* pins;
byte level;
public:
Port(byte length, byte level) : length(length), level(level) {}
// length: xác định số chân điều khiển
// level: xác định trạng thái hoạt động của chân (0: catot chung, 1: anot chung)
/*
Lí do hàm constructor không có tham số pins: giúp linh hoạt hơn
VD: có thể thay đổi các chân điều khiển sau khi khởi tạo chúng
*/
void Connect(byte* pins, byte mode){
this->pins = pins;
// gán con trỏ mảng chân điều khiển từ tham số truyền vào cho biến thành viên
for(int i = 0; i < length; i++){
pinMode(pins[i], mode);
}
// chế độ OUTPUT giúp xuất tín hiệu điện áp tới thiết bị như đèn LED,...
// chế độ INPUT giúp thu tín hiệu điện áp từ thiết bị như nút nhấn, cảm biến,...
}
void Write(int value) {
if (level == 0) value = ~value;
for(int i = 0; i < length; i++){
digitalWrite(pins[i], (value >> i) & 1);
// ghi giá trị 0 hoặc 1 của bit thứ i của value vào chân pins[i]
}
}
// bật chân điều khiển dig thứ index
void Set(int index) { digitalWrite(pins[index], level ? 1 : 0); }
// tắt chân điều khiển dig thứ index
void Reset(int index) { digitalWrite(pins[index], level ? 0 : 1); }
};
// Điều khiển 1 chân điều khiển Led 7 đoạn hiển thị các đoạn A, B, C, D, E, F, G
class Led7Seg : Port {
public:
Led7Seg(byte* pins, bool anode = true) : Port(7, anode ? 0 : 1) {
Connect(pins, OUTPUT);
// thiết lập các đoạn A, B, C, D, E, F, G là đầu ra
}
// pins: 1 mảng chứa các đoạn A, B, C, D, E, F, G
// 7 là số lượng các đoạn
void Display(int d) {
static byte code[] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F };
Port::Write(code[d]);
}
};
int nled = 4;
Led7Seg data(_pins);
Port control(nled, 1);
// control là đối tượng điều khiển 4 chân điều khiển
void setup() {
// thiết lập các chân điều khiển ở chế độ OUTPUT
control.Connect(_pins + 8, OUTPUT);
}
void Display(int digit, int index) {
data.Display(digit); // Hiển thị chữ số 'digit' trên các đoạn của màn hình LED 7 đoạn.
control.Set(index); // Bật chân điều khiển của chữ số tại vị trí 'index'.
delay(5);
// Tạm dừng một khoảng thời gian ngắn để chữ số có thể hiển thị rõ ràng.
// Càng tăng thì bật tắt các chân điều khiển các lâu
control.Reset(index); // Tắt chân điều khiển của chữ số tại vị trí 'index'.
}
int v = 0; // Giá trị số hiển thị
int ms = 0; // Biến đếm thời gian
void loop() {
int a = v; // Lưu giá trị số hiển thị hiện tại
control.Write(0); // Xóa màn hình bằng cách ghi 0 vào tất cả các chân điều khiển
for (int i = nled; i > 0; ) {
int d = a % 10; // Trích xuất chữ số cuối cùng của giá trị số hiển thị
a /= 10; // Loại bỏ chữ số cuối cùng khỏi giá trị số hiển thị
Display(d, --i); // Hiển thị chữ số 'd' tại vị trí 'i'
if (++ms == 100) { // Tăng giá trị đếm mỗi 100 mili giây
// Càng tăng thì giá trị v tăng càng lâu
// = delay() của Display * mức của ms
++v; // Tăng giá trị đếm
ms = 0; // Đặt lại biến đếm thời gian
}
}
}