Giới thiệu
Thông thường, đối với một ứng dụng nhỏ chẳng hạn như bạn muốn điều khiển 8 đèn LED với sự trợ giúp của Arduino (hoặc bất kỳ vi điều khiển nào). Ứng dụng này, mặc dù rất cơ bản và đơn giản, sẽ yêu cầu bạn sử dụng 8 trong số các chân Input / Output có sẵn trên board Arduino: mỗi chân cho một đèn LED.
Bây giờ hãy xem xét một ứng dụng phức tạp hơn, với yêu cầu điều khiển 8 đèn LED giống nhau, đồng thời làm các công việc khác như hiển thị thông báo hoặc bất kỳ thông tin nào trên màn hình LCD 16 × 2 hoặc giao tiếp với một thiết bị Bluetooth để điều khiển đèn LED thông qua điện thoại thông minh !!!
Loại ứng dụng lớn hơn này sẽ tiêu thụ rất nhiều chân I/O của bạn trên board Arduino và có thể không còn đủ chân để giao tiếp các thiết bị bổ sung.
Trên thực tế chúng ta có IC thanh ghi dịch để giải quyết tình huống này.
Thanh ghi dịch là gì?
Thanh ghi dịch (Shift Register) về cơ bản là một vi mạch chuyển đổi nối tiếp song song. Về cơ bản nó nhận dữ liều đầu vào nối tiếp thông qua một chân (về mặt kỹ thuật bạn cần ít nhất 3 chân, tôi sẽ nói vấn đề này sau) và chuyển đổi dữ liệu vào nối tiếp thành đầu ra song song 8 bit, do đó làm giảm số chân giao diện giữa vi điều khiển và các thiết bị đầu ra.
Có nhiều loại thanh ghi dịch như vào nối tiếp ra song song, vào nối tiếp ra nối tiếp, vào song song ra nối tiếp và vào song song ra song song.
Trong bài hướng dẫn này, tôi sẽ sử dụng một IC thanh ghi dịch VÀO nối tiếp RA song song gọi là 74HC595.
Giới thiệu IC ghi dịch 74HC595
74HC595 là IC ghi dịch (shift register) 8 bit kết hợp chốt dữ liệu, đầu vào nối tiếp, đầu ra song song.
IC này thường dùng trong các mạch quét led 7, led ma trận …để tiết kiệm số chân cho vi điều khiển. Có thể mở rộng số chân vi điều khiển bao nhiêu tùy thích mà không IC nào có thể làm được bằng cách mắc nối tiếp ngõ vào dữ liệu các IC với nhau.
Sơ đồ chân IC
Giải thích ý nghĩa các chân
Chân | Ký hiệu | Giải thích |
1 | Q1 | Ngõ ra dữ liệu song song (bit 1) |
2 | Q2 | Ngõ ra dữ liệu song song (bit 2) |
3 | Q3 | Ngõ ra dữ liệu song song (bit 3) |
4 | Q4 | Ngõ ra dữ liệu song song (bit 4) |
5 | Q5 | Ngõ ra dữ liệu song song (bit 5) |
6 | Q6 | Ngõ ra dữ liệu song song (bit 6) |
7 | Q7 | Ngõ ra dữ liệu song song (bit 7) |
8 | GND | Chân nối đất |
9 | Q7′ | Ngõ ra dữ liệu nôí tiếp. Khi dùng nhiều 74HC595 mắc nối tiếp nhau thì chân này đưa vào đầu vào (DS) của IC tiếp theo khi đã dịch đủ 8 bit |
10 | /MR | Master Reset (tích cực mức thấp) |
11 | SH_CP | Ngõ vào xung clock. Khi có 1 xung clock tích cực ở sườn dương (từ 0 lên 1) thì 1 bit được dịch vào IC. |
12 | ST_CP | Xung clock chốt dữ liệu. Khi có 1 xung clock tích cực ở sườn dương (từ 0 lên 1) thì cho phép xuất dữ liệu trên các chân output. |
13 | /OE | Chân cho phép tích cực ở mức thấp (0). Khi ở mức cao, tất cả các đầu ra của 74HC595 trở về trạng thái tổng trở cao, không có ngõ ra nào được cho phép. |
14 | DS | Ngõ vào dữ liệu nối tiếp. Tại 1 thời điểm xung clock chỉ đưa vào được 1 bit. |
15 | Q0 | Ngõ ra dữ liệu song song (bit 8) |
16 | VCC | Chân cấp nguồn |
Hoạt động
Ta đặt dữ liệu vào chân DS, và tạo một xung SHCP thì dữ liệu tại chân DS sẽ được dịch vào thanh ghi 8-STAGE SHIFT REGISTER.
Lần lượt làm như trên 8 lần (dịch bit cao trước), thì ta được 8 bit trong thanh ghi 8-STAGE SHIFT REGISTER.
Sau đó ta tạo một xung STCP thì 8 bit trong thanh ghi 8-STAGE SHIFT REGISTER sẽ được sao chép sang thanh ghi 8-BIT STORAGE REGISTER. Lúc này nếu chân OE ở mức thấp thì ngõ ra sẽ bằng với giá trị thanh ghi 8-BIT STORAGE REGISTER, còn nếu chân OE ở mức cao thì ngõ ra ở trạng thái tổng trở cao (Hi-Z).
Chú ý:
- Khi dịch dữ liệu vào thanh ghi 8-STAGE SHIFT REGISTER, và chưa tạo xung STCP thì thanh ghi 8-BIT STORAGE REGISTER sẽ giữ nguyên trạng thái và ngõ ra cũng giữ nguyên trạng thái.
- Khi chân MR ở mức 0 thì dữ liệu trên thanh ghi 8-STAGE SHIFT REGISTER sẽ bị xóa, còn thanh ghi 8-BIT STORAGE REGISTER sẽ giữ nguyên trạng thái và ngõ ra cũng giữ nguyên trạng thái.
Chuẩn bị
Phần cứng
Tên linh kiện | Số lượng |
Arduino Uno | 1 |
IC 74HC595 | 1 |
Điện trở 220 Ω | 8 |
LED | 8 |
Breadboard | 1 |
Dây cắm breadboard |
Phần mềm: Arduino IDE
Sơ đồ mạch 1
Hình ảnh sau đây cho thấy sơ đồ mạch giao tiếp IC ghi dịch 74HC595 với Arduino UNO.
Thực hiện kết nối Arduino với IC 74HC595 theo bảng hướng dẫn dưới đây
Arduino | IC 74HC595 |
5 | DS |
6 | ST_CP |
7 | SH_CP |
Lưu ý: để IC hoạt động được thì
|
Với sơ đồ mạch được kết nối như bên trên, các bạn thấy rằng tôi sẽ chỉ sử dụng ba chân của Arduino UNO để điều khiển cho 8 đèn LED. Điều này đã giảm đi số chân Arduino được sử dụng rất nhiều.
Chương trình mẫu 1
// Chuong trinh mau 1 – Hien thi so dem nhi phan voi LED
#define DATA 5
#define LATCH 6
#define CLOCK 7
void setup()
{
pinMode(LATCH, OUTPUT);
pinMode(CLOCK, OUTPUT);
pinMode(DATA, OUTPUT);
}
void loop()
{
int i;
for (int i = 0; i < 256; i++)
{
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, LSBFIRST, i);
digitalWrite(LATCH, HIGH);
delay(200);
}
}
Giải thích
Trong chương trình này, chúng ta thiết lập ba chân Arduino kết nối với IC ghi dịch là chân xuất tín hiệu ra (OUTPUT) trong void setup() và sau đó thêm một vòng lặp trong void loop() đếm từ 0 đến 255 và lặp lại. Điều thú vị nằm bên trong vòng lặp này. Khi chúng tôi gửi một byte dữ liệu (ví dụ, 240 hoặc 11110000B) tới thanh ghi thay đổi trong vòng lặp for, có ba điều sẽ xảy ra:
- Chân 12 (Chân chốt – Latch) của IC 74HC595 được tích cực mức THẤP (tín hiệu mức thấp này được cung cấp từ chân số 6 của Arduino ). Đây là sự chuẩn bị cho việc thiết lập ngõ ra chân 12 lên mức cao, chốt dữ liệu vào các chân đầu ra sau khi lệnh shiftOut đã hoàn thành nhiệm vụ của mình.
- Chúng ta gửi byte dữ liệu (ví dụ: 11110000B) từ chân 5 của Arduino đến IC ghi dịch và cho hàm shiftOut biết hướng của byte dữ liệu sẽ dịch chuyển. Ví dụ: nếu bạn chọn lệnh LSBFIRST thì đèn LED 1 đến 4 sẽ sáng còn các đèn LED khác tắt. Nếu bạn sử dụng lệnh MSBFIRST thì các đèn LED 5 đến 8 sẽ sáng còn các đèn LED khác sẽ tắt.
- Cuối cùng, chân 12 của IC 74HC595 được đưa lên mức CAO. Điều này cho thanh ghi dịch biết rằng tất cả các bit đã được dịch chuyển vào và sẵn sàng xuất ra. Tại thời điểm này IC ghi dịch thay đổi đầu ra của nó để phù hợp với dữ liệu nhận được.
Chương trình mẫu 2
// Chuong trinh mau 2 – Hien thi so dem nhi phan voi LED
#define DATA 5
#define LATCH 6
#define CLOCK 7
void setup()
{
pinMode(LATCH, OUTPUT);
pinMode(CLOCK, OUTPUT);
pinMode(DATA, OUTPUT);
}
void loop()
{
int i;
for (int i = 1; i < 256; i = i << 1)
{
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, LSBFIRST, i);
digitalWrite(LATCH, HIGH);
delay(1000);
}
}
Giải thích
Với chương trình này, tôi không dịch các con số từ 1 -> 256.
Ở đây, tôi cho con số i ban đầu là 1 – 0000 0001. Sau mỗi vòng lặp i sẽ dịch bit sang trái 1 lần, vậy tức là với một con số 8 bit, i lần lượt có các giá trị:
- 0000 0001 – 1
- 0000 0010 – 2
- 0000 0100 – 4
- 0000 1000 – 8
- 0001 0000 – 16
- 0010 0000 – 32
- 0100 0000 – 64
- 1000 0000 – 128
Vậy tôi sẽ giới hạn vòng lặp khi i đạt đến giá trị 256 thì dừng.
Sơ đồ mạch 2
Như tôi đã giới thiệu lúc đầu, IC 74HC595 vẫn còn 1 chân là Q7′ là chân đưa ra các bit bị tràn. Vậy dựa vào điều này, ta có thể mở rộng được thêm chân nữa tức là 1 con số 16 bit nếu ghép thêm 1 IC nữa.
Việc ghép nhiều IC ghi dịch lại với nhau rất đơn giản, bạn còn có thể ghép nhiều IC hơn nữa theo thứ tự : IC 2 lấy dữ liệu từ Q7′ của IC 1, IC 3 lấy dữ liệu từ Q7′ của IC 2, IC 4 lấy dữ liệu từ Q7′ của IC 3, ….
Ở đây, các chân CLOCK và chân LATCH của IC 2 vẫn phải được đảm bảo có giá trị tương đương với các chân CLOCK và chân LATCH của IC1. Ta kết nôí mạch như sau :
Chương trình
#define DATA 5
#define LATCH 6
#define CLOCK 7
#define HC595_count 2
void setup()
{
pinMode(LATCH, OUTPUT);
pinMode(CLOCK, OUTPUT);
pinMode(DATA, OUTPUT);
}
void loop()
{
char* temp;
unsigned int i;
temp = (char*) &i;
for( i = 1 ; i < 32768 ; i = i << 1)
{
digitalWrite(LATCH, LOW);
for (int j = 0; j < HC595_count; j++)
{
shiftOut(DATA, CLOCK, LSBFIRST, *(temp + j));
}
digitalWrite(LATCH, HIGH);
delay(1000);
}
digitalWrite(LATCH, LOW);
for (int j = 0; j < HC595_count; j++)
{
shiftOut(DATA, CLOCK, LSBFIRST, *(temp + j));
}
digitalWrite(LATCH, HIGH);
delay(1000);
}
Giải thích
HC595_count chính là số lượng IC 74HC595 đang dùng.
Hàm shiftOut() chỉ có thể dịch 1 lần 8bit mà thôi. Ở đây ta đang dùng đến 16 bit, tức là một biến 2 byte, nên ở đây tôi dùng unsigned int là một biến 2 byte không dấu. Khi i đạt đến giá trị 16 384 – 0100 0000 0000 0000 thì thoát vòng lặp, nên bạn để ý bên dưới tôi tiếp tục dịch i qua trái thêm một lần nữa để có giá trị là 32 768 – 1000 0000 0000 0000, để có thể hiển thị đèn LED cuối cùng.