KeyPad

( 30 Votes )

Nội dung Các bài cần tham khảo trước
  1. Keypad 4x4.
  2. Đọckeypad 4x4 bằng AVR.
Download ví dụ

 

I. Keypad 4x4.

       Keypad là một "thiết bị nhập" chứa các nút nhấn cho phép người dùng nhập các chữ số, chữ cái hoặc ký hiệu vào bộ điều khiển. Keypad không chứa tất cả bảng mã ASCII như keyboard và vì thế keypad thường được tìm thấy trong các thiết bị chuyên dụng. Các nút nhấn trên các máy tính điện tử cầm tay là một ví dụ về keypad. Số lượng nút nhấn của một keypad thay đổi phụ thuộc vào yêu cầu ứng dụng. Trong bài này tôi giới thiệu cách điều khiển của một loại keypad đơn giản, keypad 4x4.

       Gọi là keypad 4x4 vì keypad này có 16 nút nhấn được bố trí dạng ma trận 4 hàng và 4 cột. Cách bố trí ma trận hàng và cột là cách chung mà các keypad sử dụng. Cũng giống như các ma trận LED, các nút nhấn cùng hàng và cùng cột được nối với nhau, vì thế với keypad 4x4 sẽ có tổng cộng 8 ngõ ra (4 hàng và 4 cột). Mô hình Keypad 4x4 được thể hiện trong hình 1.

a)                                                                 b)

Hình 1. Keypad 4x4.

       Hình 1b là mô hình thật của 1 keypad 4x4 và hình 1a là cấu hình bên trong của nó. Bốn hàng của keypad được đánh dấu là A, B, C và D trong khi 4 cột được gọi là 1, 2, 3 và 4.

       Hoạt động của keypad: Giả sử nhút '2' được nhấn, khi đó đường C và 2 được nối với nhau. Giả sử đường 2 được nối với GND (mass, 0V) thì C cũng sẽ là GND. Tuy nhiên, câu hỏi đặt ra là bằng cách kiểm tra trạng thái đường C chúng ta sẽ có kết luận nút '2' được nhấn? Giả sử tất cả các đường 1, 2, 3, 4 đều nới với GND, nếu C= GND thì rõ ràng chúng ta không thể kết luận nút '1',= hay nút '2' hay nút '3' hay nút  '-' được nhấn. Kỹ thuật để khắc phục vấn đề này chính là kỹ thuật "quét" keypad. Kỹ thuật quét keypad bằng AVR được trình bày như sau:

- Nối tất cả 8 chân của keypad với 1 PORT của AVR, ví dụ PORTB theo thứ tự bên dưới:


       - Các chân 1, 2, 3, 4 được set như các chân Output và giữ ở mức cao, các chân A, B, C, D là Input và có điện trở kéo lên. Lần lượt kéo chân 1, 2, 3, 4 xuống thấp (lần lượt xuất giá trị 0 ra từng chân), đọc trạng thái các chân A, B, C, D để kết luận nút nào được nhấn. Ví dụ như trong hình 1, nút '2' được nhấn thì quá trình quét sẽ cho kết quả như sau:

  • Bước 1: kéo chân 1 xuống 0 (các chân 2,3,4 vẫn ở mức cao), kiểm tra 4 chân A, B, C, D thu được kết quả D=1, C=1, B=1, A=1. (giá trị đọc về của PINB là 00001111 nhị phân)
  • Bước 2: kéo chân 2 xuống 0, kiểm tra lại A, B, C, D, kết quả thu được D=1, C=0, B=1, A=1 (giá trị đọc về của PINB là 0b00001011 nhị phân). Chân C=0 tức có 1 nút ở hàng thứ 3 được nhấn, chúng ta lại đang ở Bước thứ 2 tức nút nhấn thuộc cột thứ 2. Chúng ta có thể dừng quá trình quét tại đây và kết quả thu về nút ở hàng 3, cột 2 (tức nut '2' được) được nhấn.

       Quá trình quét cho các nút khác cũng xảy ra tương tự. Chú ý, nếu có 1 nút nào đó được nhấn thì có 4 khả năng cò thể đọc về từ 4 A,B,C,D đó là:

  • D=1, C=1, B=1, A=0: nút ở hàng A được nhấn, giá trị đọc về là 0x0E (các đường A,B,C,D được nối với 4 bit thấp của PORT trên AVR).
  • D=1, C=1, B=0, A=1: nút ở hàng B được nhấn, giá trị đọc về là 0x0D .
  • D=1, C=0, B=1, A=1: nút ở hàng C được nhấn, giá trị đọc về là 0x0B .
  • D=0, C=1, B=1, A=1: nút ở hàng D được nhấn, giá trị đọc về là 0x07 .

       Để tiện lợi khi so sánh kết quả đọc về, khi lập trình đọc keypad chúng ta nên lập 1 mảng 4 phần tử chứa 4 số có thể đọc về từ keypad. Ví dụ uint8_t  scan_code[4]={0x0E,0x0D,0x0B,0x07};

       Trong phần tiếp theo chúng ta sẽ khảo sát cách đọc keypad 4x4 bằng 1 chip AVR Atmega32. 

II. Đọc Keypad 4x4 bằng AVR.

       Chúng ta sẽ mô phỏng cách đọc và hiển thị giá trị từ keypad 4x4 bằng phần mêm Proteus. Các mã đọc được từ keypad sẽ hiễn thị lên 1 Text LCD 16x2. Thư viện myLCD.h được dùng để hiển thị lên LCD (xem lại bài Text LCD). Mạch điện mô phỏng thể hiện trong hình 2. 

Hình 2. Đọc và hiển thị từ Keypad 4x4.

       Hãy tạo 1 Project bằng WinAVR với tên gọi KEYPAD, tạo file main.c và add vào Project, tạo Makefile, đồng thời copy file myLCD.h từ bài học Text LCD vào thư mục chứa Project KEYPAD. Mở file myLCD.h và sửa phần khai báo PORT như List0. 

List 0. Khai báo PORT trong file myLCD.h

01
02
03
04
05
06
07
08

....
#define CTRL                       PORTC
#define DDR_CTRL             DDRC

#define DATA_O                  PORTC
#define DATA_I                    PINC
#define DDR_DATA             DDRC
....

     Viết đoạn code trong List1 vào file main.c

List 1. Nội dung file main.c


       Ở dòng 3 chúng ta include file myLCD.h để sử dụng các hàm thao tác Text LCD. Trong các dòng 5, 6 và 7 chúng ta định nghĩa PORT giao tiếp với Keypad, theo đó PORTB được dùng cho Keypad. Dòng 9 khai báo một mảng 4 phần tử chứa mã đọc về từ Keypad như đã thảo luận trong phần trên. Các dòng code từ 10 đến 13 khai báo một mảng 2 chiều có 16 phần tử chứa mã ASCII của các ký tự đại diện cho các Button, tôi sắp xếp các ký tự dạng ma trận để dễ dàng tương ứng với các nút trên keypad. Dòng 14 khai báo biến key loại 8 bit không dấu, đây là biến chứa mã ascii khi đọc keypad. Dòng 15 khai báo hàm quét Keypad có tên checkpad(). Tất cả giải thuật quét và đọc keypad đều năm trong hàm này, giá trị trả về của hàm là mã ascii của nút được nhấn.

       Trước khi khảo sát đoạn code trong chương trình main, chúng ta sẽ tìm hiểu chương trình con checkpad(). Ở dòng 31 trong chương trình con checkpad, chúng ta khai báo 3 biến phụ 8 bit không dấu, i là biến đại diện cho cột của keypad và j là hàng, keyin là giá trị đọc về từ các chân A, B, C, D. Vòng lặp for 4 lần trong dòng 32 của biến i chính là 4 bước quét mà tôi đã trình bày trong ví dụ trên. Ở bước 1, biến i=0, nếu chúng ta dịch trái số 1 như (1<<(4+i)) thì giá trị thu được là (1<<(4+i))=0b00010000, kết hợp với dòng code 33: KEYPAD_PORT=0xFF-(1<<(4+i)); chúng ta thu được KEYPAD_PORT=0xEF. Số 4 trong phép dịch xuất hiện vì các cột của Keypad được nối với 4 bit cao của PORT trên AVR. Tóm lại, sau bước đầu tiên cột thứ nhất của Keypad được kéo xuống mức 0, sẵn sàng cho quá trình kiểm tra các hàng A,B,C,D trong các dòng tiếp theo. Dòng 35 đọc giá trị từ Keypad về biến keyin, vì chúng ta kết nối các chân A,B,C,D của Keypad với 4 bit thấp của PORT nên chúng ta chỉ quan tâm đến giá trị của 4 bit thấp này, việc AND (&) giá trị đọc về với 0x0F cho phép chúng ta bỏ qua 4 bit cao. Trong dòng 36, chúng ta kiểm tra xem nếu giá trị đọc về khác 0x0F thì thực hiện các dòng tiếp theo. Nếu keyin =0x0F nghĩa là không có bất kỳ nút nào trên cột 1 được nhấn, các dòng tiếp theo không thực hiện, vòng lặp for cho  biến i được tiếp tục giá trị tiếp theo. Nếu biến keyin khác 0x0F thì chúng ta biết rằng có 1 nút nào đó trên cột i được nhấn, các dòng tiếp theo sẽ xác định chính xác nút nào được nhấn. Dòng 37 cho biến hàng j chạy từ 0 đến 4, dòng 38 kiểm tra giá trị keyin, nếu keyin bằng phần tử thứ j trong mảng scan_code mà chúng ta đã định nghĩa trước đó thì nút trên hàng j đã được nhấn, tóm lại nút được nhấn là nút hàng j và cột i, chúng ta trả về giá trị mã ascii của nút này bằng cách lấy giá trị tương ứng của mảng ascii_code được định nghĩa trước đó: return ascii_code[j][i]. Nếu quá trình quét thất bại chúng ta trả về giá trị 0.

       Nội dung của chương trình chính là khởi động chip và thực hiện demo quá trình đọc Keypad, Dòng 19 chúng ta khai báo sử dụng 4 bit thấp của KEYPAD_PORT làm input (các chân A,B,C,D là input) và 4 bit cao làm output. Dòng 18 khởi động các điện trở kéo lên cho 4 bit thấp. Hai dòng 21 và 22 khởi động và xóa Text LCD. Trong vòng lặp vô tận while(1), chúng ta quét keypad ở dòng 24 và hiển thị lên LCD ở dòng 25 (chỉ hiển thị nếu quá trình quét thành công).

       Trong ví dụ này tôi chỉ trình bày giải thuật quét Keypad cơ bản, vẫn còn một số vấn đề khác như kiểm tra sự kiện nhấn (key down), thả (key up)...bạn đọc hãy tự giải tuyết theo cách của riêng mình.