As some of you may know, I've started a personal keyboard project back in April after I've joined geekhack and it finally came to completion last week.
It's a 60% keyboard like the HHKB but with cherry mx switches and programmable multiple layout firmware.
Here are the details about the keyboard and all the information you need if you want to build one for yourself.
First, Ive started out by drawing up the PCB in the software from
http://expresspcb.com/.
Download Here. [ Attachment Invalid Or Does Not Exist ] 19744[/ATTACH]
Then, I've redrawn the entire keyboard in Solidworks to design the case/mounting plate and to make sure everything would fit.
Download Here. [ Attachment Invalid Or Does Not Exist ] 19745[/ATTACH]
Once I was set with the design, I've ordered the PCB from
http://expresspcb.com/ directly from the software. 2 PCB cost 149$.
I've ordered 128 clear and 30 blue switches from
Mouser for 160$ and a G80-3000 from Half-Saint for 45$ to harvest some cherry blue stem and springs.
I'm using ergo clear and blue switches in my keyboards.
I got 200 1N41418 diodes from
onlinecomponents.com for about nothing.
For the controller, I'm using a teensy form
http://www.pjrc.com/ I've ordered 3 of those for 48$.
I've took the code from
PrinsValium symmetric stagger keyboard and modified it to fit my needs.
Download Here.It doesn't have NKRO but it does have 6KRO + 4 modifiers.
[ Attachment Invalid Or Does Not Exist ] 19958[/ATTACH]
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "usb_keyboard.h"
#define bool uint8_t
#define true 1
#define false 0
#define _PINB (uint8_t *const)&PINB
#define _PORTC (uint8_t *const)&PORTC
#define _PORTD (uint8_t *const)&PORTD
#define _PORTF (uint8_t *const)&PORTF
#define NULL 0
#define NA 0
#define KEY_MACRO 0
#define KEY_FN 0
#define FN_KEY1_ID 13*6+1
#define FN_KEY2_ID 0*6+1
#define MACRO_KEY_ID 0*6+0
const uint8_t is_modifier[84] = {
//ROW 0 ROW 1 ROW 2 ROW 3 ROW 4
1, 1, 1, 1, 0, 0, // COL 0
1, 0, 0, 0, 0, 0, // COL 1
1, 0, 0, 0, 0, 0, // COL 2
0, 0, 0, 0, 0, 0, // COL 3
0, 0, 0, 0, 0, 0, // COL 4
0, 0, 0, 0, 0, 0, // COL 5
0, 0, 0, 0, 0, 0, // COL 6
0, 0, 0, 0, 0, 0, // COL 7
0, 0, 0, 0, 0, 0, // COL 8
1, 0, 0, 0, 0, 0, // COL 9
1, 0, 0, 0, 0, 0, // COL 10
0, 0, 0, 0, 0, 0, // COL 11
1, 1, 0, 0, 0, 0, // COL 12
0, 1, 0, 0, 0, // COL 13
0 // COL 14
};
const uint8_t layer1[84] = {
//ROW 0 ROW 1 ROW 2 ROW 3 ROW 4
KEY_MACRO, KEY_FN, KEY_LEFT_SHIFT, KEY_LEFT_CTRL, KEY_TAB, KEY_ESC, // COL 0
KEY_LEFT_GUI, KEY_Z, KEY_A, KEY_Q, KEY_1, NULL, // COL 1
KEY_LEFT_ALT, KEY_X, KEY_S, KEY_W, KEY_2, NULL, // COL 2
NULL, KEY_C, KEY_D, KEY_E, KEY_3, NULL, // COL 3
NULL, KEY_V, KEY_F, KEY_R, KEY_4, NULL, // COL 4
KEY_SPACE, KEY_B, KEY_G, KEY_T, KEY_5, NULL, // COL 5
NULL, KEY_N, KEY_H, KEY_Y, KEY_6, NULL, // COL 6
NULL, KEY_M, KEY_J, KEY_U, KEY_7, NULL, // COL 7
NULL, KEY_COMMA, KEY_K, KEY_I, KEY_8, NULL, // COL 8
KEY_RIGHT_ALT, KEY_PERIOD, KEY_L, KEY_O, KEY_9, NULL, // COL 9
KEY_RIGHT_GUI, KEY_SLASH, KEY_SEMICOLON, KEY_P, KEY_0, NULL, // COL 10
NULL, NULL, KEY_QUOTE, KEY_LEFT_BRACE, KEY_MINUS, NULL, // COL 11
KEY_RIGHT_CTRL, KEY_RIGHT_SHIFT, NULL, KEY_RIGHT_BRACE, KEY_EQUAL, NULL, // COL 12
KEY_DELETE, KEY_FN, KEY_ENTER, KEY_BACKSPACE, KEY_BACKSLASH, // COL 13
KEY_TILDE // COL 14
};
const uint8_t layer2[84] = {
//ROW 0 ROW 1 ROW 2 ROW 3 ROW 4
NULL, KEY_FN, KEY_LEFT_SHIFT, KEY_LEFT_CTRL, KEY_CAPS_LOCK, KEY_ESC, // COL 0
KEY_LEFT_GUI, KEY_Z, KEY_LEFT, KEY_Q, KEY_F1, NULL, // COL 1
KEY_LEFT_ALT, KEY_X, KEY_DOWN, KEY_UP, KEY_F2, NULL, // COL 2
NULL, KEY_C, KEY_RIGHT, KEY_E, KEY_F3, NULL, // COL 3
NULL, KEY_V, KEY_F, KEY_R, KEY_F4, NULL, // COL 4
KEY_SPACE, KEY_B, KEY_G, KEY_T, KEY_F5, NULL, // COL 5
NULL, KEY_N, KEY_H, KEY_Y, KEY_F6, NULL, // COL 6
NULL, KEY_M, KEY_J, KEY_U, KEY_F7, NULL, // COL 7
NULL, KEY_HOME, KEY_PAGE_UP, KEY_PRINTSCREEN, KEY_F8, NULL, // COL 8
KEY_RIGHT_ALT, KEY_END, KEY_PAGE_DOWN, KEY_SCROLL_LOCK, KEY_F9, NULL, // COL 9
KEY_RIGHT_GUI, KEY_DOWN, KEY_LEFT, KEY_PAUSE, KEY_F10, NULL, // COL 10
NULL, NULL, KEY_RIGHT, KEY_UP, KEY_F11, NULL, // COL 11
KEY_RIGHT_CTRL, KEY_RIGHT_SHIFT, NULL, KEY_RIGHT_BRACE, KEY_F12, NULL, // COL 12
KEY_DELETE, KEY_FN, KEY_ENTER, KEY_BACKSPACE, KEY_INSERT, // COL 13
KEY_DELETE // COL 14
};
const uint8_t layer3[84] = {
//ROW 0 ROW 1 ROW 2 ROW 3 ROW 4
NULL, KEY_FN, KEY_LEFT_SHIFT, KEY_LEFT_CTRL, KEY_TAB, KEY_ESC, // COL 0
KEY_LEFT_GUI, KEY_Z, KEY_LEFT, KEY_Q, KEY_F1, NULL, // COL 1
KEY_LEFT_ALT, KEY_X, KEY_DOWN, KEY_UP, KEY_F2, NULL, // COL 2
NULL, KEY_C, KEY_RIGHT, KEY_E, KEY_F3, NULL, // COL 3
NULL, KEY_V, KEY_F, KEY_R, KEY_F4, NULL, // COL 4
KEY_SPACE, KEY_B, KEY_G, KEY_T, KEY_F5, NULL, // COL 5
NULL, KEY_N, KEY_H, KEY_Y, KEY_F6, NULL, // COL 6
NULL, KEYPAD_0, KEYPAD_1, KEYPAD_4, KEYPAD_7, NULL, // COL 7
NULL, KEY_COMMA, KEYPAD_2, KEYPAD_5, KEYPAD_8, NULL, // COL 8
KEY_RIGHT_ALT, KEY_PERIOD, KEYPAD_3, KEYPAD_6, KEYPAD_9, NULL, // COL 9
KEY_RIGHT_GUI, KEY_SLASH, KEY_SEMICOLON, KEY_P, KEYPAD_SLASH, NULL, // COL 10
NULL, NULL, KEY_QUOTE, KEY_LEFT_BRACE, KEYPAD_MINUS, NULL, // COL 11
KEY_RIGHT_CTRL, KEY_RIGHT_SHIFT, NULL, KEY_RIGHT_BRACE, KEYPAD_PLUS, NULL, // COL 12
KEY_DELETE, KEY_FN, KEY_ENTER, KEY_BACKSPACE, KEYPAD_ASTERIX, // COL 13
KEY_NUM_LOCK // COL 14
};
const uint8_t *layout = layer1;
uint8_t *const row_port[6] = { _PINB, _PINB, _PINB, _PINB, _PINB, _PINB};
const uint8_t row_bit[6] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20};
uint8_t *const col_port[14] = {_PORTD, _PORTD, _PORTD, _PORTD, _PORTD, _PORTC, _PORTD, _PORTD, _PORTF, _PORTF, _PORTF, _PORTF, _PORTF, _PORTF};
const uint8_t col_bit[14] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x40, 0x80, 0x40, 0x01, 0x02, 0x10, 0x20, 0x80, 0x40};
bool pressed[84];
uint8_t queue[7] = {0,0,0,0,0,0,0};
uint8_t mod_keys = 0;
void init(void);
void send(void);
void poll(void);
void key_press(uint8_t key_id);
void key_release(uint8_t key_id);
int main(void) {
init();
for(;;) poll();
}
void send(void) {
uint8_t i;
if(pressed[FN_KEY1_ID])
layout = layer2;
else if(pressed[FN_KEY2_ID])
layout = layer3;
else
layout = layer1;
for(i=0; i<6; i++)
keyboard_keys[i] = layout[queue[i]];
keyboard_modifier_keys = mod_keys;
usb_keyboard_send();
}
void poll() {
uint8_t row, col, key_id;
_delay_ms(5);
for(col=0; col<14; col++) {
*col_port[col] &= ~col_bit[col];
_delay_us(1);
for(row=0; row<6; row++) {
key_id = col*6+row;
if(!(*row_port[row] & row_bit[row])) {
if(!pressed[key_id])
key_press(key_id);
}
else if(pressed[key_id])
key_release(key_id);
}
*col_port[col] |= col_bit[col];
}
}
void key_press(uint8_t key_id) {
uint8_t i;
pressed[key_id] = true;
if(is_modifier[key_id])
mod_keys |= layer1[key_id];
else {
for(i=5; i>0; i--) queue[i] = queue[i-1];
queue[0] = key_id;
}
send();
}
void key_release(uint8_t key_id) {
uint8_t i;
pressed[key_id] = false;
if(is_modifier[key_id])
mod_keys &= ~layout[key_id];
else {
for(i=0; i<6; i++) if(queue[i]==key_id) break;
for(; i<6; i++) queue[i] = queue[i+1];
}
send();
}
void init(void) {
uint8_t i;
CLKPR = 0x80; CLKPR = 0;
usb_init();
while(!usb_configured());
_delay_ms(1000);
// PORTB is set as input with pull-up resistors
// PORTC,D,F are set to high output
DDRB = 0x00; DDRC = 0xFF; DDRD = 0xFF; DDRF = 0xFF;
PORTB = 0xFF; PORTC = 0xFF; PORTD = 0xFF; PORTF = 0xFF;
for(i=0; i<84; i++) pressed[i] = false;
}
Current layout: [ Attachment Invalid Or Does Not Exist ] 19756[/ATTACH]
For the mounting plate/case I've redrawn it in the software from
eachineshop.com. They quote the case at around 400$ for 2 cases depending of the material, finish, tolerances.
Download Here. [ Attachment Invalid Or Does Not Exist ] 19747[/ATTACH]
I didn't personally used emachineshop. I've ordered mine form I guy I know and I'm not pleased with the result. The bends in the parts are slightly too far out on the plates but the cutting for the switches at least is perfect. I will probably use emachineshop to order a part to fix my problem tho.
Strait switches but gap in assembly.
[ Attachment Invalid Or Does Not Exist ] 19755[/ATTACH]
Then, I've started to receive parts and assemble the keyboards.
1: Solder the diodes on the PCB.
[ Attachment Invalid Or Does Not Exist ] 19748[/ATTACH]
2: Solder some wires to the teensy and place the switches and stabilizers on the plate.
[ Attachment Invalid Or Does Not Exist ] 19749[/ATTACH]
[ Attachment Invalid Or Does Not Exist ] 19750[/ATTACH]
3: Solder the teensy to the PCB and then the PCB to the switches.
[ Attachment Invalid Or Does Not Exist ] 19751[/ATTACH]
4: Have fun with your new keyboards!
[ Attachment Invalid Or Does Not Exist ] 19753[/ATTACH]
[ Attachment Invalid Or Does Not Exist ] 19752[/ATTACH]
[ Attachment Invalid Or Does Not Exist ] 19754[/ATTACH]
So that is how you build a DoxKB!
Sorry about the bad pictures...