Keyboard from Scratch: Prototype

Công Nghệ
Keyboard from Scratch: Prototype

Bài viết được sự cho phép của tác giả Huy Trần

Là một lập trình viên, bàn phím là một vật dụng bạn phải sờ vào hằng ngày, thậm chí số lần bạn sờ nó còn nhiều hơn số lần bạn sờ vào vợ hoặc bạn gái. Chính vì vậy, chúng ta phải đầu tư cho nó một cách xứng đáng, bằng 2 cách:

  1. Mua một cái bàn phím cơ
  2. Tự làm một cái

Và, với những ai tự gọi mình là kĩ sư (software engineer, backend engineer, frontend engineer, hay copy-pasta engineer, stackoverflow engineer,… nói chung là mọi thể loại engineer), chẳng có lý do gì để không tự làm một cái cho riêng mình, để tự mình quyết định bố cục (layout), màu sắc (keycaps), và tốc dộ gõ (key switches, scanning time).

Xem thêm việc làm JavaScript hấp dẫn trên Station D

Suy cho cùng, tự mình build một cái gì đó, và tự tay giải quyết những vấn đề hóc búa trong quá trình build, học hỏi và thu lại được kinh nghiệm cho bản thân, cũng có thể gọi là cái raison d’être của một engineer . Hay nói cách khác, như vậy mới gọi là dân chơi đúng nghĩa .

Hình ảnh sẽ xuất hiện trong bài sau, không phải bài này =)))

Đó cũng là lý do mà mình quyết định tự build một cái bàn phím 40% cho riêng mình. Tuy nhiên, làm việc gì cũng có thử nghiệm, thất bại, rút kinh nghiệm,… để hạn chế những vấn đề đó, chúng ta sẽ bắt đầu với một bản prototype đơn giản nhưng đủ phức tạp để thấy được các vấn đề trong thực tế.

1. Nguyên vật liệu

Đối với bản prototype này, chúng ta cần chuẩn bị:

  • 4 x Cherry MX Brown Switches (chọn switch nào là sở thích cá nhân thôi, hè hè)
  • 4 x Keycap tùy ý
  • 4 x Diode 1N4148
  • 1 x Teensy 3.2 (hoặc Arduino Pro Micro)

Hoặc nếu máu thì các bạn có thể tự làm một con Teensy cho riêng mình 

2. Bố cục bàn phím

Đa phần các bàn phím tên tuổi thường chỉ khác nhau về bố cục (layout), và đây là phần bất biến, sau khi sản xuất, còn lại những thứ khác (case, plate, key mapping…) thì đều có thể được custom tùy ý.

Đối với bản prototype này, chúng ta sẽ thiết kế một layout vô cùng phức tạp, như thế này:

Quá phức tạp!   

Sau khi đã thiết kế xong bố cục thì chúng ta có thể move sang bước tiếp theo đó là thiết kế và cắt tấm đệm (plate).

Trong thiết kế của bàn phím cơ, có 2 cách lắp ghép (mount) swtiches, là Plate Mount và PCB Mount.

PCB mount bên trái. Plate mount bên phải.
Nguồn: https://www.mouser.com/new/Cherry-Electrical/cherry-mx-keyswitch/

PCB Mount là cách lắp các switches trực tiếp trên board mạch. Ưu điểm của thiết kế này là bàn phím nhẹ hơn, cảm giác gõ sâu hơn, có thể cảm nhận rõ độ nẩy và lún của switch. Có khá ít bàn phím thiết kế theo dạng này, có thể kể đến Minvan, KBC Poker,… là các bàn phím như vậy.

Nguồn: https://www.extremetech.com/electronics/255783-tiny-keyboard-experiment-living-minivan

Plate Mount là cách lắp các switches trên một tấm nền thường là bằng kim loại, plate thường có độ dày khoảng 1.5mm (rất quan trọng nếu bạn tự làm plate), trên thân của switch cũng có các khớp để “móc” vừa vào plate. Sau đó là đến PCB nằm bên dưới.

Nguồn: https://medium.com/@armno/building-my-own-mechanical-keyboard-6903b887b93d

Ưu điểm của cách bố trí này là bàn phím sẽ rất cứng cáp, cảm giác gõ rất chắc chắn, nhưng độ gõ không sâu.

Hầu hết bàn phím cơ trên thị trường được thiết kế dùng plate mount.

Vì bản prototype này chúng ta tự hàn mạch bằng tay chứ chưa thiết kế PCB, nên chúng ta sẽ chọn cách plate mount. Và tùy vào độ khéo tay cũng như vật liệu mà bạn kiếm được, mình suggest dùng giấy bìa cứng =)) cắt một tấm hình vuông nhỏ nhắn xinh xinh kiểu này:

Mấy cái ô trống thì cắt hình vuông là được rồi, không cần phải phức tạp như trong hình kia đâu. Căn cứ vào kích thước của switch (ở đây là Cherry MX), mỗi ô trên plate sẽ có kích thước tầm 15mm - 15.6mm

Nguồn: https://www.mouser.com/new/Cherry-Electrical/cherry-mx-keyswitch/

3. Mạch điện

Tiếp đến là bước nối mạch điện. Sau khi lắp xong swtich vào plate thì lật ngửa nó ra, các bạn sẽ thấy bố trí như hình bên dưới, với mỗi switch gồm 2 chân, các chân bên trái nằm cao hơn bên phải. Nối diode vào chân bên trái, và nối lại với nhau để tạo thành một hàng, đồng thời, nối các chân bên phải lại với nhau tạo thành các cột.

Sơ đồ mạch điện trên lý thuyết

Và thực tế 

Cách mắc mạch điện như trên cũng là cách mắc phổ biến trong các loại bàn phím cơ, các switch tạo thành một mam trận nhiều hàng nhiều cột, cách mắc này có ưu điểm là tiết kiệm được số cổng kết nối trên board điều khiển, trong bản prototype này chúng ta không thể thấy rõ điều đó, nhưng giả sử với một bàn phím 60%, thường sẽ có 5 hàng và 15 cột, như vậy ta chỉ cần 20 cổng kết nối trên board điều khiển, nhưng vẫn có thể xử lý được từ 60 đến 65 phím.

Nếu các bạn thắc mắc tại sao phải lắp thêm diode vào các switch thì có thể tham khảo thêm về vấn đề Ghosting.

Sau khi hoàn tất công đoạn hàn mạch, thì chúng ta sẽ nối mạch này vào Teensy, chúng ta gọi các dây xanh là hàng (row), và dây đỏ là cột (column), mạch của chúng ta gồm có 2 hàng và 2 cột, tiến hành nối các hàng và cột này vào 4 cổng digital của Teensy, cổng nào là tùy ý các bạn chọn.

Trong hình trên, mình nối các cột vào các chân số 2 và 3. Các hàng vào các chân số 6 và 7.

4. Thiết kế Firmware

Khi mình bắt đầu phần này thì khá là nhiều người trên Reddit và Geekhack khuyên mình đừng nên tự viết firmware riêng mà hãy dùng các firmware có sẵn như TMK hoặc QMK. Tuy nhiên khi thử build hai loại firmware trên thì rất may là mình dùng Teensy 3.2, board này xài chip ARM 32-bit (Cortex-M4), chưa được support tốt lắm trên cả 2 firmware trên, nên build không chạy được . Thế nên mình quyết định là tự viết riêng cho mình một bản firmware riêng.

Để cho đơn giản, thì mình sẽ sử dụng Teensyduino để lập trình. Đây là một add-on của Arduino IDE, cho phép chúng ta lập trình trên Teensy bằng bộ thư viện của Arduino, và sử dụng cấu trúc chương trình của Arduino.

Một firmware cơ bản sẽ là một event loop thực hiện các công việc sau:

  • Scan: quét liên tục để tìm ra các phím được nhấn
  • Processing: xây dựng một buffer chứa keycode của các phím đang được nhấn xuống, dựa trên keymap mà chúng ta đã thiết lập.
  • Output: Gửi buffer này về máy tính thông qua cổng USB.

Trước khi bắt tay vào thực hiện code logic trên, chúng ta cần phải khai báo một vài thông số liên quan:

#include <Keyboard.h>

const byte ROWS = 2;
const byte COLS = 2;

char keys[ROWS][COLS] = {
  { 'A', 'B' },
  { 'C', 'D' }
};

const byte rowPins[ROWS] = { 6, 7 };
const byte colPins[COLS] = { 2, 3 };

Ở trên, chúng ta include thư viện Keyboard.h (đi kèm theo SDK của Arduino), chỉ vì chúng ta muốn sử dụng hàm Keyboard.print() có trong thư viện này để gửi phím được nhấn về cho máy tính.

Tiếp theo, chúng ta khai báo 2 hằng ROWS và COLS quy định số hàng và số cột của bàn phím, mảng keys chính là keymap, là mảng quy ước các kí tự nào thuộc về phím nào trên bàn phím của chúng ta, ở đây khi nhấn các phím 1, 2, 3, 4 thì bàn phím sẽ gửi về máy tính các kí tự A, B, C, D.

Hai mảng rowPins và colPins lưu vị trí các chân cắm trên board điều khiển, theo như cách chúng ta đã nối dây ở phần trước.

Đến đây, nếu tinh ý thì các bạn sẽ nhận ra, là ở bài viết tiếp theo khi chúng ta xây dựng firmware cho một cái bàn phím thực sự, thì chỉ cần thay đổi các thông số ở trên là xong.

Bây giờ đến phần implement event loop cho firmware của chúng ta, đầy đủ 3 bước scanprocess và output:

void loop() {
    char code = scan();
    if (code !== -1) {
        char keyCode = process(code);
        output(keyCode);
    }
    delay(50);
}

4.1. Vấn đề #1: Quét tín hiệu

Hàm scan() của chúng ta sẽ có nhiệm vụ quét tất cả các hàng và các cột của mạch điện, kiểm tra xem phím nào được nhấn xuống và trả về một giá trị kiểu byte chứa thông tin các phím được nhấn.

C không có kiểu byte nên chúng ta dùng kiểu char để thay thế.

Để cho đơn giản, thì chúng ta chỉ support việc nhấn một phím một lần, ở bài sau chúng ta sẽ cải tiến firmware để xử lý việc nhấn tổ hợp phím, macro,…

Việc quét phím được thực hiện thông qua thuật toán sau:

1: Đưa tất cả các chân về trạng thái INPUT, mang giá trị HIGH
2: Lần lượt đưa từng hàng (row) về trạng thái OUTPUT, giá trị LOW
3:  Trên mỗi hàng, lần lượt đọc trạng thái của từng cột (col)
4:   Nếu phím K[r][c] tại hàng r cột c được nhấn, cột c sẽ mang giá trị LOW
5:   Ghi nhận giá trị r và c.
6:  Trả lại trạng thái ban đầu cho hàng hiện tại.
7: Trả về giá trị r và c

Nếu cảm thấy khó hiểu ở bước 3 và 4, bạn có thể đọc thêm cách hoạt động của các chân digital tại đây.

Vì mạch của chúng ta chỉ đơn giản gồm có 4 nút, mỗi hàng và mỗi cột chỉ có nhiều nhất là 2 phàn tử (index là 0 hoặc 1), vậy nên ta có thể “gói” hai giá trị hàng cột này vào cho một số kiểu byte, bằng phương pháp dịch bit.

Giả sử chúng ta đang ở hàng r = 0 và cột c = 1, chúng ta có thể chèn giá trị r vào bit thứ nhất, và c vào bit thứ 2:

n = (r << 0) | (c << 1)

Khi cần đọc ngược lại thì cũng rất đơn giản:

r = (n >> 0) & 1c = (n >> 1) & 1
char scan() {
    char code = -1;

    // Đưa tất cả các pin về trạng thái INPUT/HIGH
    for (int i = 0; i < ROWS; i++) {
        pinMode(rowPins[i], INPUT_PULLUP);
        digitalWrite(rowPins[i], HIGH);
    }
    for (int i = 0; i < COLS; i++) {
        pinMode(colPins[i], INPUT_PULLUP);
        digitalWrite(colPins[i], HIGH);
    }

    // Đưa từng hàng về trạng thái OUTPUT/LOW và quét
    for (int row = 0; row < ROWS; row++) {
        pinMode(rowPins[row], OUTPUT);
        digitalWrite(rowPins[row], LOW);
        for (int col = 0; col < COLS; col++) {
            if (!digitalRead(colPins[col])) {
                // Lưu giá trị hàng và cột thành một số int
                code = (row << 0) | (col << 1);
            }
        }
        pinMode(rowPins[row], INPUT_PULLUP);
        digitalWrite(rowPins[row], HIGH);
    }
    return code;
}

4.2. Vấn đề #2: Gửi tín hiệu về máy tính

Tiếp theo, chúng ta cần chuyển thông tin về hàng/cột nhận được thành kí tự đã được khai báo trong keymap.

Bước này khá là đơn giản, chỉ cần đọc giá trị trả về từ hàm scan() và trả về giá trị tương ứng từ mảng keys :

char process(char code) {
    return keys[(code >> 0) & 1][(code >> 1) & 1];
}

Hàm gửi tín hiệu output() sẽ sử dụng hàm Keyboard.print của bộ thư viện Keyboard.h và truyền thông tin sang máy tính:

void output(char c) {
    Keyboard.print(c);
}

Đến bước này, bạn có thể compile và upload firmware vào Teensy để test thử.

Máy tính đã nhận diện được bàn phím mới, và gõ thì có ra được nội dung thật. Tuy nhiên sẽ có một vấn đề đó là hiện tượng nhấn một nút, máy tính sẽ in ra rất nhiều lần phím được nhấn. Đây gọi là hiện tượng key chatter.

Ở bài viết tiếp theo, chúng ta sẽ tìm hiểu sâu hơn về hiện tượng này, và implement kĩ thuật debounce để giải quyết nó.

Bài viết gốc được đăng tải tại thefullsnack.com

Có thể bạn quan tâm:

Xem thêm công việc công nghệ hấp dẫn trên Station D

Bài viết liên quan

Bộ cài đặt Laravel Installer đã hỗ trợ tích hợp Jetstream

Bộ cài đặt Laravel Installer đã hỗ trợ tích hợp Jetstream

Bài viết được sự cho phép của tác giả Chung Nguyễn Hôm nay, nhóm Laravel đã phát hành một phiên bản chính mới của “ laravel/installer ” bao gồm hỗ trợ khởi động nhanh các dự án Jetstream. Với phiên bản mới này khi bạn chạy laravel new project-name , bạn sẽ nhận được các tùy chọn Jetstream. Ví dụ: API Authentication trong Laravel-Vue SPA sử dụng Jwt-auth Cách sử dụng Laravel với Socket.IO laravel new foo --jet --dev Sau đó, nó sẽ hỏi bạn thích stack Jetstream nào hơn: Which Jetstream stack do you prefer? [0] Livewire [1] inertia > livewire Will your application use teams? (yes/no) [no]: ... Nếu bạn đã cài bộ Laravel Installer, để nâng cấp lên phiên bản mới bạn chạy lệnh: composer global update Một số trường hợp cập nhật bị thất bại, bạn hãy thử, gỡ đi và cài đặt lại nha composer global remove laravel/installer composer global require laravel/installer Bài viết gốc được đăng tải tại chungnguyen.xyz Có thể bạn quan tâm: Cài đặt Laravel Làm thế nào để chạy Sql Server Installation Center sau khi đã cài đặt xong Sql Server? Quản lý các Laravel route gọn hơn và dễ dàng hơn Xem thêm Tuyển dụng lập trình Laravel hấp dẫn trên Station D

By stationd
Principle thiết kế của các sản phẩm nổi tiếng

Principle thiết kế của các sản phẩm nổi tiếng

Tác giả: Lưu Bình An Phù hợp cho các bạn thiết kế nào ko muốn làm code dạo, design dạo nữa, bạn muốn cái gì đó cao hơn ở tầng khái niệm Nếu lập trình chúng ta có các nguyên tắc chung khi viết code như KISS , DRY , thì trong thiết kế cũng có những nguyên tắc chính khi làm việc. Những nguyên tắc này sẽ là kim chỉ nam, nếu có tranh cãi giữa các member trong team, thì cứ đè nguyên tắc này ra mà giải quyết (nghe hơi có mùi cứng nhắc, mình thì thích tùy cơ ứng biến hơn) Tìm các vị trí tuyển dụng designer lương cao cho bạn Nguyên tắc thiết kế của GOV.UK Đây là danh sách của trang GOV.UK Bắt đầu với thứ user cần Làm ít hơn Thiết kế với dữ liệu Làm mọi thứ thật dễ dàng Lặp. Rồi lặp lại lần nữa Dành cho tất cả mọi người Hiểu ngữ cảnh hiện tại Làm dịch vụ digital, không phải làm website Nhất quán, nhưng không hòa tan (phải có chất riêng với thằng khác) Cởi mở, mọi thứ tốt hơn Bao trừu tượng luôn các bạn, trang Gov.uk này cũng có câu tổng quát rất hay Thiết kế tốt là thiết kế có thể sử dụng. Phục vụ cho nhiều đối tượng sử dụng, dễ đọc nhất nhất có thể. Nếu phải từ bỏ đẹp tinh tế – thì cứ bỏ luôn . Chúng ta tạo sản phẩm cho nhu cầu sử dụng, không phải cho người hâm mộ . Chúng ta thiết kế để cả nước sử dụng, không phải những người đã từng sử dụng web. Những người cần dịch vụ của chúng ta nhất là những người đang cảm thấy khó sử dụng dịch...

By stationd
Hiểu về trình duyệt – How browsers work

Hiểu về trình duyệt – How browsers work

Bài viết được sự cho phép của vntesters.com Khi nhìn từ bên ngoài, trình duyệt web giống như một ứng dụng hiển thị những thông tin và tài nguyên từ server lên màn hình người sử dụng, nhưng để làm được công việc hiển thị đó đòi hỏi trình duyệt phải xử lý rất nhiều thông tin và nhiều tầng phía bên dưới. Việc chúng ta (Developers, Testers) tìm hiểu càng sâu tầng bên dưới để nắm được nguyên tắc hoạt động và xử lý của trình duyệt sẽ rất hữu ích trong công việc viết code, sử dụng các tài nguyên cũng như kiểm thử ứng dụng của mình. Cách để npm packages chạy trong browser Câu hỏi phỏng vấn mẹo về React: Component hay element được render trong browser? Khi hiểu được cách thức hoạt động của trình duyệt chúng ta có thể trả lời được rất nhiều câu hỏi như: Tại sao cùng một trang web lại hiển thị khác nhau trên hai trình duyệt? Tại sao chức năng này đang chạy tốt trên trình duyệt Firefox nhưng qua trình duyệt khác lại bị lỗi? Làm sao để trang web hiển thị nội dung nhanh và tối ưu hơn một chút?… Hy vọng sau bài này sẽ giúp các bạn có một cái nhìn rõ hơn cũng như giúp ích được trong công việc hiện tại. 1. Cấu trúc của một trình duyệt Trước tiên chúng ta đi qua cấu trúc, thành phần chung và cơ bản nhất của một trình duyệt web hiện đại, nó sẽ gồm các thành phần (tầng) như sau: Thành phần nằm phía trên là những thành phần gần với tương tác của người dùng, càng phía dưới thì càng sâu và nặng về xử lý dữ liệu hơn tương tác. Nhiệm...

By stationd
Thị trường EdTech Vietnam- Nhiều tiềm năng nhưng còn bị bỏ ngỏ tại Việt Nam

Thị trường EdTech Vietnam- Nhiều tiềm năng nhưng còn bị bỏ ngỏ tại Việt Nam

Lĩnh vực EdTech (ứng dụng công nghệ vào các sản phẩm giáo dục) trên toàn cầu hiện nay đã tương đối phong phú với nhiều tên tuổi lớn phân phối đều trên các hạng mục như Broad Online Learning Platforms (nền tảng cung cấp khóa học online đại chúng – tiêu biểu như Coursera, Udemy, KhanAcademy,…) Learning Management Systems (hệ thống quản lý lớp học – tiêu biểu như Schoology, Edmodo, ClassDojo,…) Next-Gen Study Tools (công cụ hỗ trợ học tập – tiểu biểu như Kahoot!, Lumosity, Curriculet,…) Tech Learning (đào tạo công nghệ – tiêu biểu như Udacity, Codecademy, PluralSight,…), Enterprise Learning (đào tạo trong doanh nghiệp – tiêu biểu như Edcast, ExecOnline, Grovo,..),… Hiện nay thị trường EdTech tại Việt Nam đã đón nhận khoảng đầu tư khoảng 55 triệu đô cho lĩnh vực này nhiều đơn vị nước ngoài đang quan tâm mạnh đến thị trường này ngày càng nhiều hơn. Là một trong những xu hướng phát triển tốt, và có doanh nghiệp đã hoạt động khá lâu trong ngành nêu tại infographic như Topica, nhưng EdTech vẫn chỉ đang trong giai đoạn sơ khai tại Việt Nam. Tại Việt Nam, hệ sinh thái EdTech trong nước vẫn còn rất non trẻ và thiếu vắng nhiều tên tuổi trong các hạng mục như Enterprise Learning (mới chỉ có MANA), School Administration (hệ thống quản lý trường học) hay Search (tìm kiếm, so sánh trường và khóa học),… Với chỉ dưới 5% số dân công sở có sử dụng một trong các dịch vụ giáo dục online, EdTech cho thấy vẫn còn một thị trường rộng lớn đang chờ được khai phá. *** Vừa qua Station D đã công bố Báo cáo Vietnam IT Landscape 2019 đem đến cái nhìn toàn cảnh về các ứng dụng công...

By stationd