- vừa được xem lúc

Keyboard from Scratch: Từ A tới Z

0 0 27

Người đăng: Huy Tran

Theo The Full Snack

Keyboard from Scratch: Từ A tới Z

Sau khi kết thúc hai phần trước, chúng ta đã có những kiến thức cơ bản về chiếc bàn phím cơ, không để các bạn đợi lâu, ở phần này chúng ta sẽ thực sự bắt tay vào làm một chiếc bàn phím hoàn chỉnh.

TL;DR: Các bước để build một chiếc bàn phím cơ

  1. Tham khảo thật nhiều layout, thiết kế của cộng đồng
  2. Thiết kế cho mình một layout hợp lý
  3. Đặt mua linh kiện, keycaps, switches, cắt plate nếu cần thiết
  4. Hàn mạch bằng tay, hoặc thiết kế mạch in rồi mới hàn
  5. Hàn controller, viết firmware hoặc modify từ các firmware có sẵn như QMK hay TMK
  6. Done

Trước khi bắt đầu thì các bạn hãy để mình khoe hàng tí đã, chiếc bàn phím bốn chấm không, à nhầm 40% mang tên SnackyMini Keyboard một sản phẩm kết tinh của tinh thần bốn chấm không, của trí tuệ Việt và nền công nghệ tiên tiến của Đế quốc Tư bản Huê Kỳ, cộng với nguồn cung cấp thiết bị kĩ thuật, linh kiện bán dẫn phong phú của người anh lớn Trung Hoa, một sản phẩm của người Việt, dành cho cả người Việt lẫn người không Việt, được nghiên cứu, thiết kế và tối ưu dành riêng cho các software developer, một... ấy ấy ấy, thôi các bạn đừng tắt mà, ở lại đọc tiếp đi mà, mình im rồi đây

và cuối cùng thì bản này bị vứt xó.

. Đặc biệt là trên macOS. Đó là chưa kể cơ chế quản lý thư viện footprint và component của nó khá rối. Trước khi bắt tay vào làm thì các bạn nên đọc qua bài hướng dẫn sử dụng của Deskthority, đây là bài viết dễ hiểu nhất mà mình có thể tìm thấy, mặc dù hơi cũ.

Cái khó thứ hai, là bắt đầu như thế nào? một cái switch có những chân nào, cần đục những lỗ nào? khoảng cách giữa các switch là bao xa? để nắm được các thông tin này thì bạn cần phải bới tung các wiki và các diễn đàn về phím cơ lên. Ở đây mình sẽ nói sơ qua, vì các bạn có đọc trước cũng không thể nhớ được cho tới khi các bạn bắt tay vô làm và tự mình đụng phải các vấn đề đó

  • Về chân switch (footprint) và các linh kiện khác, các bạn có thể tải thư viện hỗ trợ cho KiCad tại đây https://github.com/tmk/keyboard_parts.pretty và đây https://github.com/tmk/kicad_lib_tmk. Đồng thời tham khảo bài viết này để biết cách import https://github.com/ruiqimao/keyboard-pcb-guide.

  • Về khoảng cách giữa các chân switch, thì theo tài liệu của hãng Cherry, mỗi switch có kích thước 15.6mm x 15.6mm, keycaps có kích thước tầm 18mm x 18mm nữa, theo matt3o, khi kết hợp lại thì mỗi một switch 1u nên chiếm một ô có kích thước 19.05mm x 19.05mm.

    nếu các bạn sử dụng controller khác, có thể các bạn sẽ compile được và không cần phải đâm đầu vào con đường đen tối này. Suy cho cùng, tự viết firmware cũng có cái hay của nó, và mình học được rất nhiều từ việc này. Dưới đây là một vài ghi chép của mình trong quá trình viết, nếu không thực sự quan tâm, các bạn có thể bỏ qua cũng được.

    Mãi cho đến khi hoàn thành xong phần hardware thì mình mới bắt tay vào viết firmware hoàn chỉnh (chứ không phải là cái firmware điều khiển 4 nút như trong bài trước). Về cơ bản thì không khác nhiều mấy so với trong bài trước, mình dùng một mảng kiểu unit8_t để lưu thông tin về layout bàn phím, đây là một mảng 3 chiều, nó gồm có 2 mảng 2 chiều, mỗi một mảng 2 chiều là một layout:

    uint8_t keyLayout[][ROWS][COLS] = { // Default layout { { KEY_TAB , KEY_Q , KEY_W , KEY_E , KEY_R , KEY_T , KEY_Y ,... { NULL_KEY , KEY_A , KEY_S , KEY_D , KEY_F , KEY_G , KEY_H ,... { NULL_KEY , KEY_Z , KEY_X , KEY_C , KEY_V , KEY_B , KEY_N ,... { KEY_TILDE, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY,... }, // Fn layout { { KEY_ESC , KEY_1 , KEY_2 , KEY_3 , KEY_4 , KEY_5 , KEY_6 ,... { NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY,... { NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY,... { NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY,... }
    };
    

    Code cho việc chuyển layout bằng phím Fn:

    if (keys[i].code == FN_KEY) { layoutId = FN_LAYOUT; break;
    }
    submitLayout(keys, keyLayout[layoutId]);
    

    Một thay đổi nữa so với bài viết trước, đó là thuật toán debounce, sau khi thử nghiệm và tham khảo từ các firmware khác, thì mình quyết định làm đơn giản hơn, giống với các firmware phổ biến như QMK/TMK, là quét từng đợt sau mỗi 15 milli giây, đơn giản đến không đỡ được:

    #define DEBOUNCE_DELAY 15 void loop()
    { unsigned long timeNow = millis(); if (timeNow - lastFrame > DEBOUNCE_DELAY) { lastFrame = timeNow; // Scan key }
    }
    

    Khi compile và upload firmware vào bàn phím, ban đầu thì mọi thứ có vẻ hoạt động rất trơn tru, nhưng khi mình thử gõ một đoạn nội dung dài vào, thì xảy ra tình trạng mất phím, ví dụ gõ:

    Hello I am Huy

    thì lại thành ra:

    Helo I m Hy

    Thế là tốn thêm 1 ngày để debug, nguyên nhân thì hết sức ngớ ngẩn vì trong lúc viết firmware, mình lười và chỉ làm cho cái bàn phím đọc mỗi một phím duy nhất ở một thời điểm, và khi gõ nhanh, ở một thời điểm có thể sẽ có rất nhiều phím được nhấn xuống. Cũng nhờ thế mà lại biết thêm được khái niệm NKRO (n-key roll over), một chức năng giúp cho bàn phím có thể ghi nhận được nhiều phím trong một thời điểm. Đối với các bàn phím sử dụng cổng USB, thì tối đa chi ghi nhận được 6 phím, trong khi đó bàn phím dùng cổng PS/2 thì xả láng.

    Việc implement chức năng này cũng không mấy khó khăn, nhờ các hàm Keyboard.set_key1, Keyboard.set_key2, Keyboard.set_key3,... của Teensyduino. Về ý tưởng thì ở mỗi lần quét, mình tạo một mảng gồm 6 phần tử để lưu lần lượt giá trị các phím nhận được:

    #define MAXIMUM_STROKES 6 struct Key* readKey() { struct Key* result = (Key*)malloc(MAXIMUM_STROKES * sizeof(struct Key)); int currentFinger = 0; for (int row = 0; row < ROWS; row++) { for (int col = 0; col < COLS; col++) { if (keyPressedAt(row, col)) { result[currentFinger].row = row; result[currentFinger].col = col; if (currentFinger < MAXIMUM_STROKES) currentFinger++; } } } return result;
    }
    

    Rồi sau đó lần lượt sử dụng các hàm Keyboard.set_key<x> để gán giá trị cho từng phím, và gửi đi một lần bằng hàm Keyboard.send_now():

    void submitLayout(struct Key* keys, uint8_t layout[ROWS][COLS]) { int currentFinger = 0; ... for (int i = 0; i < SUPPORTED_STROKES; i++) { int c = layout[pos.r][pos.c]; if (c != NULL_KEY) { setKey(currentFinger, c); currentFinger++; } } ... Keyboard.send_now();
    }
    

    Một số bàn phím còn cho phép người dùng tự cấu hình layout bằng phần mềm trên máy tính, xét ở góc độ firmware, điều này không quá khó, chỉ việc chuyển mảng keyLayout về một cấu trúc khác có thể lưu được vào bộ nhớ của Teensy, từ đó ta có thể load ra mỗi khi bàn phím được khởi động. Ví dụ lưu vào EEPROM thông qua hàm EEPROM.read()EEPROM.write(), tuy nhiên cần lưu ý, EEPROM của Teensy 3.2 chỉ có 2KB, hơi ít, nhưng chắc vừa đủ xài. Nhưng nếu đã tự build được firmware, thì chả cần làm vậy cho mất công, chỉ cần customize layout bằng cách customize luôn source code

    Mấy hôm nay ngồi xem kĩ lại firmware QMK, thấy nó có vài features khá thú vị, như Grave Escape Key, Key Lock, Tap Dance hay Mouse Key,... hôm nào có thời gian mình sẽ ngồi clone lại và viết thêm về chủ đề này.

    Chỉ cần chừng đó thứ thì bạn đã có thể tự mình viết được firmware cho chiếc bàn phím của mình rồi. Nếu quan tâm, các bạn có thể tham khảo mã nguồn đầy đủ của firmware lẫn hardware cho bàn phím này tại đây https://github.com/huytd/snackymini-keyboard/


    Xin cảm ơn các bạn đã kiên nhẫn đọc đến tận đây (tui nói vậy thôi chứ tui biết bạn scroll xuống đây từ đầu trang, chỉ tốn có 3 giây). Nếu bạn cũng là dân chơi mech, hy vọng bài viết này giúp các bạn hiểu thêm về những chiếc bàn phím tiền triệu mà mình đã mua. Nếu bạn chưa phải là dân chơi, hy vọng bài viết này làm nhụt chí và ngăn bạn lao vào con đường tốn kém này. Nếu đã đọc hết mà vẫn quyết định sẽ mua hoặc tự làm một chiếc bàn phím cơ, thì mình xin chúc mừng và chúc các bạn may mắn luôn.

    P/S: Nếu bạn nào đang ở US, thì mình còn dư vài cái PCB, nếu có hứng thú thì cứ PM mình qua Facebook, mình sẽ gửi tặng.

    Bài viết này được gõ bằng bàn phím SnackyMini Keyboard

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tìm bug với Eyewitness

. Chào các bạn, trong bài này mình sẽ viết về tool Eyewitness. Eyewiteness có tính năng chính là chụp hình lại giao diện trang web sau đó tạo một report thông qua file .

0 0 24

- vừa được xem lúc

[I passed OSWE] Nguồn gốc và sức mạnh | Tự tin và sự cố gắng

1. Giới thiệu.

0 0 17

- vừa được xem lúc

Tôi đã đánh cắp tên miền của MIT như thế nào?

. Chào cả nhà, lại là mình đây! Hôm này mình mang tới chủ đề mới đó là subdomain takeover hay nói cách đơn giản chiếm subdomain của người khác. Lỗi này rất thú vị và khá đơn giản để tìm kiếm.

0 0 33

- vừa được xem lúc

Keyboard from Scratch: Debounce

Keyboard from Scratch: Debounce. Bạn đang xem phần hai của một sê ri nhiều phần, nhiều chừng nào, nhiều đến khi nào, thì chưa biết được. . .

0 0 24

- vừa được xem lúc

Keyboard from Scratch: Prototype

Keyboard from Scratch: Prototype. 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.

0 0 21

- vừa được xem lúc

Chuyện biểu diễn ma trận trên máy tính

Chuyện biểu diễn ma trận trên máy tính. Cách đây mấy hôm mình có share cái screenshot trên Facebook, khoe linh tinh vụ mình đang viết lại cái CHIP-8 emulator bằng Rust.

0 0 31