Ma trận LED

( 91 Votes )

Nội dung Các bài cần tham khảo trước
  1. Ma trận LED.
  2. AVR và ma trận LED.
Download ví dụ

 

 I. Ma trận LED. 

       Ma trận LED tức Dot Matrix LED là tập hợp nhiều đèn LED được bố trí thành dạng “ma trận” hình chữ nhật hoặc vuông với số hàng là a và số cột là b. Ma trận LED được dùng rất nhiều trong các ứng dụng hiển thị như các biển quảng cáo, hiển thị thay thế LCD hoặc thậm chí dùng hiển thị video…Để giảm số lượng các đường điều khiển, trong các ma trận LED các LED được nối chung với nhau theo hàng và cột. Số lượng LED trên ma trận LED là axb trong khi số lượng ngõ ra bằng tổng số hàng và cột: a + b. Việc điều khiển 1 ma trận LED kích thước lớn đòi hỏi thiết kế một mạch driver và điều khiển rất phức tạp. Với mục đích giúp bạn đọc làm quen khái niệm ma trận LED, trong phạm vi bài này tôi chỉ trình bày thao tác với 1 ma trận LED có kích thước 7x5 (7 hàng, 5 cột). ma trận LED 7x5 thường được dùng để hiển thị các ký tự trong bảng mã ASCII thay cho Text LCD. Tuy nhiên, bạn có thể ghép các ma trận LED này lại để hiển thị các loại hình ảnh bất kỳ có độ phân giải thấp. Hình 1 mô tả một cấu trúc của một ma trận LCD 7x5 với 12 ngõ ra được đặt tên từ C0…C4 và D0…D6 (C đại diện cho Control line và D là Data line).

Hình 1. Ma trận LED 7x5.

       Bên trong các ô của ma trận LED là các LED phát sang. Trong mô hình trên, Cathod (cực âm) của các LED trên mỗi hàng được nối chung với nhau và ngõ ra chung là các ngõ D (Data). Các Anod của các LED trên mỗi cột được nối chung tạo thành các đường C (Control). Thông thường, các đường D và C được chọn sao số số lượng đường D nhiều hơn đường C hoặc sao cho số lương các đường D gần nhất với số 8, 16, 32…(lũy thừa của 2). Lý do của việc chọn này nhằm giảm kích thước bộ font chứa các ký tự hoặc hình ảnh hiển thị lên ma trận LED, bạn sẽ hiểu rõ hơn khi tìm hiểu các điều khiển ma trận LED 7x5 bên dưới.

a)                                                             b)

Hình 2 mô tả cách mà ma trận LED 7x5 được dùng để hiển thị số 4. 

       Trước hết chúng ta sẽ khảo cách cho sang các LED mà không cần quan tâm đến bảng font. Quan sát cột thứ nhất (cột C0) trong hình 2a, trong cột này chỉ có 2 LED ở hàng D2 và D3 là sang, các LED còn lại tắt. Điều này được thực hiện bằng cách kích chân C0 (Anod) lên mức cao, kéo các chân D2, D3 xuống mức 0 trong khi các chân Data khác được giữ ở mức cao. Các cột khác được thực hiện tương tự. Tuy nhiên, câu hỏi ở đây là làm sao hiển thị các cột với các đèn LED sáng khác nhau trong khi các ngõ Cathod của chúng đều được nối chung (thành các chân D). Ví dụ một người kéo tất cả 5 chân C0…C4 lên mức cao vào xuất tín hiệu ra các chân D, khi đó tất cả các LED trên dùng một hàng sẽ sáng hoặc tắt như nhau. “Bí quyết” ở đây chính là kỹ thuật “quét”, chúng ta sẽ hiển thị tuần tự các cột với các giá trị tương ứng của chúng chứ không hiển thị đồng thời. Trong ví dụ hiển thị số ‘4’, trước hết hãy kích chân C0 lên cao trong khi các chân C1…C4 ở mức thấp, xuất tín hiệu ra các chân D để hiển thị lên cột C0. Tiếp theo kéo chân C1 lên cao và các chân Control khác ở mức thấp, xuất dữ liệu ra các chân D để hiển thị cột C1…Cứ như thế cho đến khi hiển thị hết các cột thì quay lại cột C0. Quá trình này gọi là “quét LED”. Do tốc độ “quét” rất cao nên chúng ta sẽ không có cảm giác “nhấp nháy”, các cột của ma trận như được hiển thị đồng thời. Chú ý là độ sáng của LED phụ thuộc vào số cột LED, nếu bạn “quét” quá nhiều cột LED, tỉ lệ thời gian “ON”  của mỗi cột sẽ rất nhỏ so với thời gian “OFF” vì phải chờ quét các cột khác. Vì thế nếu ma trận LED có nhiều cột hoặc khi ghép nhiều ma trận, các mạch driver cần được sử dụng để đảm bảo độ sáng của LED.

       Giả sử mỗi LED đại diện cho 1 bit và các LED sáng đại diện cho giá trị nhị phân 1 trong khi các LED tắt là số 0. Hình 2b thể hiện mô hình số nhị phân cho trường hợp hiển thị số 4 trên ma trận LED 7x5. Nếu xem mỗi cột của ma trận là 1 con số 7 bit thì 5 giá trị cần thiết để hiền thị số ‘4’ là: 0x0C, 0x14, 0x24, 0x7F, 0x04. Bộ 5 giá trị này tạo thành mã font cho ký tự ‘4’, chúng sẽ được định nghĩa trước và lưu trong bộ nhớ của chip điều khiển (AVR), mỗi lần một ký tự được yêu cầu hiển thị, bộ font tương ứng của ký tự đó sẽ được “load” ra và xuất lần lượt trên các đường Data, đây chính là lý do tại sao chúng ta gọi các đường D là các đường Data. Cách “quét” LED tôi vừa trình bày là cách “quét ngang”, bạn có thể thực hiện “quét dọc” nếu ứng dụng yêu cầu. Trong phương pháp quét dọc, các chân hàng chung sẽ được dùng để chọn hàng cần hiển thị, dữ liệu sẽ xuất ra theo từng hàng trên 5 cột và lần lượt thay đổi hàng (hàng 0 trước, đến 1…và cuối cùng là 6). So sánh 2 cách quét cho trường hợp ma trận LED 7x5, rõ ràng trong cách quét ngang chúng ta chỉ cần quet 5 cột cho mỗi lần LED nên tỉ lệ thời gian ON sẽ cao hơn (1/5 so với 1/8 của cách quét dọc). Mặt khác, nếu thực hiện quét dọc chúng ta cần 8 số số để tạo thành 1 bộ font cho một ký tự và vì thế tốn nhiều bộ nhớ hơn cho việc lưu trữ bảng font. Trong bài học này tôi thực hiện theo cách quét ngang và bảng font cũng được xây dựng cho cách quét này.

II. AVR và Ma trận LED.

       Phần này tôi minh họa cách hiển thị ma trận LED 7x5 bằng AVR. Chúng ta sẽ thực hiện trên duy nhất một ma trận LED, cho các ứng dụng cần nhiều LED bạn đọc hãy tự phát triển từ ý tưởng trong phần này. Hãy vẽ một mạch điện mô phỏng bằng phần mềm Proteus như trong hình 3.

Hình 3. Hiển thị ma trận LED bằng AVR.

       Các chân C của ma trận được nối với các chân trên PORTC của chip AVR ATmega32, và các chân D được nối với PORTD. Hãy tạo 1 Project bằng Programmer Notepad tên DotMatrix và tạo 2 file tên font.h cùng dotmatrix.c trong Project này. File font.h chứa bảng font của các ký tự và file dotmatrix.c là file chính cho chương trình demo. List 1 trình là một phần nội dung của file font.h và List 2 là nội dung file dotmatrix.c.

List 1. Bảng font.


List 2. Chương trình demo.


       Điều cần quan tâm đầu tiên là kích thước bảng font, trong ví dụ này bảng font được xây dụng cho 223 symbol có mã ASCII từ 32 đến 255 (do các mã ASCII trước 32 không có symbol tương ứng nên có thể bỏ qua để tiết kiệm bộ nhớ), mỗi symbol cần 5 số 8 bits, như thế chúng ta cần tổng cộng 1115 byte cho bảng font trong khi kích thước SRAM của chip ATmega32 chỉ là 2KB (2048 byte). Nếu dùng SRAM chứa bảng font sẽ rất phí phạm vì đây là 1 bảng tĩnh, giá trị trong bảng hoàn toàn không thay đổi mà chỉ được truy xuất đọc. Vì thế chúng ta có thể tận dụng bộ nhớ chương trình (Flash) để lưu bảng font này. Dòng đầu tiên trong List 1 chúng ta include header “pgmspace.h” để sử dụng các thao tác trên bộ nhớ chương trình. Tiếp theo chúng ta khai báo 1 mảng tĩnh có tên font7x5 với kiểu dữ liệu là prog_char tức là kiểu char nhưng chứa trong bộ nhớ chương trình (Program memory). Giá trị chứa trong mảng font7x5 chính là dữ liệu của bảng font, thực chất mảng font7x5 là mảng 1 chiều liên tục, việc tách ra trên nhiều dòng có mục đích giúp người đọc dễ hình dung khi truy cập các giá trị của mảng để xuất ra sau này. Bạn hãy hiểu rằng cứ một tổ hợp 5 số sẽ tạo thành một symbol hiển thị cho ma trận LED. Dữ liệu trong bảng font được sắp xếp theo trình tự ASCII và để tạo điều kiện thuận lợi khi truy xuất bảng font theo mã ASCII của ký tự cần hiển thị. Tuy nhiên cần chú ý là bảng font được bắt đầu cho symbol có mã ASCII là 32 chứ không bắt đầu từ mã ASCII 0, vì thế khi truy cận bảng font từ mã ASCII chúng ta cần lấy mã ASCII trừ đi 32 để được vị trí chính xác trong bảng.

       Tiếp theo chúng ta sẽ tìm hiểu chương trình chính, dòng 3 trong list 2 include file font.h để sử dụng bảng font trong chương trình chính. Các dòng từ 5 đến 9 định nghĩa các PORT kết nối với ma trận LED, PORTD là Data bus trong khi PORTC là control lines. Chương trình con void DOTputChar75(uint8_t chr) trong dòng 11 là thủ tục đọc dữ liệu từ bảng font và hiển thị trên ma trận LED. Tham số chr của chương trình này chính là mã ASCII của ký tự cần hiển thị trên ma trận LED. Dòng 12 khai báo 2 biến phụ, trong đó biến line chứa tín hiệu điều khiển cho các đường Control. Dòng 13 khai báo một biến tạm tchr dùng chứa địa chỉ dữ liệu cần lấy ra từ bảng font để xuất ra các đường Data, vì mã ASCII là một số 8 bit trong khi số lượng dữ liệu trong bảng font lớn gấp 5 lần số lương ký tự, vì thế cần khai báo biến tchr có kiểu dữ liệu 16 bit. Nội dung chính của đoạn chương trình này nằm trong vòng lặp for, biến i đại diện cho số thứ tự của các chân Control được cho chạy từ 0 đến 4, trong dòng 15 “CTRL_PORT=line;” xuất tín hiệu điều khiển ra CTRL_PORT tức ra các chân C. Do biến line được khởi tạo bằng 1 nên ở lần lặp đầu tiên giá trị CTRL_PORT=0b00000001, tức chân C0 ở mức cao trong khi các chân còn lại ở mức thấp, cột đầu tiên được chọn. Sau khi 1 cột đã được chọn, dòng 16 “DATA_PORT=~pgm_read_byte(&font7x5[((tchr - 32) * 5) + i]);” đọc và xuất dữ liệu từ bảng font ra các chân Data. Trước hết là cách tính địa chỉ của dữ liệu trong bảng font. Như trình bày trong phần giải thích cho bảng font, bảng này được chúng ta bắt đầu từ ký tự có mã 32 nên chúng ta cần trừ đi 32 để tham chiếu đến vị trí chính xác trong bảng font: tchr-32. Ví dụ muốn hiển thị ký tự có mã chr = 48 (mã của ký tự ‘0’), vị trí của tổ hợp dữ liệu tạo nên số ‘0’ được chứa trong bảng font ở vị trí 16, giá trị này được tính 48-32=16. Tiếp theo, do mỗi ký tự được tạo thành từ 5 số nên địa chỉ thực chất của số đầu tiên trong tổ hợp sẽ là (tchr-32)*5. Để di chuyển trong phạm vi 5 dữ liệu ứng với 6 cột của ma trận LED, biến i được cộng dồn vào địa chỉ này và chúng ta có: tchr - 32) * 5) + i. Để đọc dữ dữ liệu dạng byte từ bộ nhớ chương trình, chúng ta cần dùng hàm pgm_read_byte, hàm này được định nghĩa trong header pgmspace.h được khai báo trong file font.h.  Như vậy saiu khi thực hiện “pgm_read_byte(&font7x5[((tchr - 32) * 5) + i])” chúng ta thu được dữ liệu 1 byte tương ứng với cột thứ i của ký tự chr từ bảng font, việc cuối cùng có thể là xuất giá trị này ra DATA_PORT. Tuy nhiên, trước khi xuất byte đọc được ra DATA_PORT, chúng ta cần đảo các bit của byte này bằng toán tử “~”, lý do được giải thích là do các LED trong ma trận trong ví vụ này có các hàng nối với cực âm Cathode, để một LED sáng thì giá trị cần cấp cho bit D tương ứng là 0 nghĩa là ngược lại so với cách chúng ta tạo bảng font (sáng là 1). Chỉ bằng một thao tác đơn giản là toán tử “~” chúng có thể dễ dàng vượt qua trở ngại này. Trong trường hợp ma trận LED có các hàng nối với cực dương Anode thì chúng ta không cần đảo giá  trị đọc về. Dòng 17 thực hiện dịch chuyển giá trị của biến line sang trái 1 vị trí, việc làm có tác dụng chuẩn bị cho lần kế tiếp chân C kế tiếp sẽ được kích. Hàm delay trong dòng 18 giúp các LED trong cột hiện tại sáng trong 1 khoảng thời gian trước khi chuyển qua cột khác.

       Chương trình chính trong ví dụ này thật sự rất đơn giản, chúng ta trước hết cần khởi động hướng xuất nhập cho các PORT và sau đó gọi hàm DOTputChar75() trong vòng lặp vô tận while(1). Ở ví dụ trên, ký tự ‘4’ được xuất ra và kết quả hiển thị như trong hình 3. Chú ý là hàm DOTputChar75() chỉ “quét” qua các cột 1 lượt, vì thế muốn hiển thị một ký tự trong một khoảng thời gian chúng ta cần gọi hàm DOTputChar75() lặp lại trong khoảng thời gian đó.