Components and supplies
6 mm push-button switch
.1 inch header socket (17 way)
5 volt LED
USB cable (Micro B)
Arduino Micro
Apps and platforms
Arduino IDE
Project description
Code
The software
c_cpp
1#include <Keyboard.h> 2// 3//left buttons 4#define button_1 5 5#define button_2 6 6#define button_3 7 7#define button_4 8 8#define button_9 SCK 9#define button_10 MISO 10#define button_11 A5 11#define button_12 A4 12 13//right buttons 14#define button_5 9 15#define button_6 10 16#define button_7 11 17#define button_8 12//A1 18#define button_13 A3 19#define button_14 A2 20#define button_15 A1//12 21#define button_16 A0 22 23#define caps_lock_led MOSI 24#define ctrl_led 1 25//alt has not been coded into table 26#define alt_led 0 27//On my original pcb I wired fn_led to pin TX, which I couldn't get to work 28#define fn_led 4 29 30 31//from patent 4,775,225 (modified)- 32//Notes: 33//Patent table 3, which I used to create the table below, lists g twice and ommits 6 34//Patent tables 1 & 2 list 6 as occuring at 0001 0010 (sw4_t and sw7_t), the other g is in its correct place 35//Placement of ! and ? is transposed in table 3 compared to tables 1 and 2 - I chose to follow table 3 36//Tables 1 and 2 list both numbers 3 and 5 as code 2000 0001 - where 2 means switch pressed away from you and 1 is switch toward you 37//From table 3 38//3 is code 2000 0001 39//5 is code 2000 0002 40//I have redesignated uppercase(UC) and lowercase(LC) 41//code 0010 2000 used for shift 42//code 0020 1000 used for caps lock 43// 44//Warning on char codes 45//Characters are sent as if from a US keyboard 46//Characters change if receiving computer is not set up for US keyboard 47//Example: 48//In my case: 49//@ becomes " 50//" becomes @ 51//# becomes 52//See: 53//https://forum.arduino.cc/index.php?topic=428331.0 54//Retrieved 28/Dec/2017 55 56const unsigned char key_table[8][8]{'j','m','y','0','(','+','2','4', 57 'k','p','z','1',')','"','3','5', 58 ',',';','$','@','\ ',194,'\\'','%',//F1 escape(\\) required to allow character ' in table 59 '.',':','#','*',128,195,'=','\\b',//CT F2 60 'u',129,'o','n','-','?','q','w',//LC as shift 61 193,'\ 62','i','s','!','/','v','x',//UC as caps lock 63 ' ','t','h','d','6','8','b','f', 64 'e','a','r','l','7','9','c','g'}; 65//end - from patent 4,775,225 (modified) 66 67//required to debounce switch 68#define MAX_CHECKS 10 69//for right hand 70volatile uint8_t Debounced_State=0;//accessed by isr and main loop code 71uint8_t State[MAX_CHECKS]={0}; 72uint8_t Index=0; 73 74//for left hand 75volatile uint8_t left_Debounced_State=0;//accessed by isr and main loop code 76uint8_t left_State[MAX_CHECKS]={0}; 77uint8_t left_Index=0; 78 79// the setup function runs once when you press reset or power the board 80void setup() { 81 82 pinMode(button_1,INPUT_PULLUP); 83 pinMode(button_2,INPUT_PULLUP); 84 pinMode(button_3,INPUT_PULLUP); 85 pinMode(button_4,INPUT_PULLUP); 86 pinMode(button_5,INPUT_PULLUP); 87 pinMode(button_6,INPUT_PULLUP); 88 pinMode(button_7,INPUT_PULLUP); 89 pinMode(button_8,INPUT_PULLUP); 90 91 pinMode(button_9,INPUT_PULLUP); 92 pinMode(button_10,INPUT_PULLUP); 93 pinMode(button_11,INPUT_PULLUP); 94 pinMode(button_12,INPUT_PULLUP); 95 pinMode(button_13,INPUT_PULLUP); 96 pinMode(button_14,INPUT_PULLUP); 97 pinMode(button_15,INPUT_PULLUP); 98 pinMode(button_16,INPUT_PULLUP); 99 100//led setup 101 pinMode(caps_lock_led,OUTPUT); 102 pinMode(ctrl_led,OUTPUT); 103 pinMode(alt_led,OUTPUT); 104 pinMode(fn_led,OUTPUT); 105 106//test led's 107 digitalWrite(caps_lock_led,HIGH); 108 digitalWrite(ctrl_led,HIGH); 109 digitalWrite(alt_led,HIGH); 110 digitalWrite(fn_led,HIGH); 111 delay(1000); 112 digitalWrite(caps_lock_led,LOW); 113 digitalWrite(ctrl_led,LOW); 114 digitalWrite(alt_led,LOW); 115 digitalWrite(fn_led,LOW); 116 117 // initialize timer1 118 noInterrupts(); // disable all interrupts 119 TCCR1A = 0; 120 TCCR1B = 0; 121 TCNT1 = 0; 122 123 OCR1A = 625; // compare match register 16MHX/256/100HZ 124 TCCR1B |= (1 << WGM12); // CTC mode 125 TCCR1B |= (1 << CS12); // 256 prescaler 126 TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt 127 interrupts(); // enable all interrupts 128 129 130// initialize control over the keyboard: 131Keyboard.begin(); 132 133} 134 135// the loop function runs over and over again forever 136void loop() { 137 138static bool do_character=false; 139static bool button_up=false; 140static bool chord_ready=false; 141static bool ctrl_key=false; 142static bool caps_lock_key=false; 143static bool shift_key=false; 144static bool alt_key=false; 145int DOWN=0; 146int ACROSS=0; 147 148static int RHAND=0; 149static int LHAND=0; 150 151 noInterrupts(); // disable all interrupts 152if (Debounced_State && left_Debounced_State){RHAND=Debounced_State;LHAND=left_Debounced_State;chord_ready=true;}//store chord and flag as ready 153if (!Debounced_State || !left_Debounced_State){if(chord_ready){button_up=true;}} 154 interrupts(); // enable all interrupts 155 156 157 158if(button_up && chord_ready) 159{ 160chord_ready=false; 161button_up=false; 162do_character=true; 163 164//from patent 4,775,225 (modified) 165//'BYTES FROM "DEVICE" 166//The original binary values have been inverted 167 if (RHAND==128){DOWN=0;} 168 if (RHAND==64){DOWN=1;} 169 if (RHAND==32){DOWN=2;} //CONVERT BYTE VALUE TO INDEX 170 if (RHAND==16){DOWN=3;} //VALUE FOR LEFT HAND 171 if (RHAND==8){DOWN=4;} 172 if (RHAND==4){DOWN=5;} 173 if (RHAND==2){DOWN=6;} 174 if (RHAND==1){DOWN=7;} 175 if (LHAND==128){ACROSS=0;} 176 if (LHAND==64){ACROSS=1;} 177 if (LHAND==32){ACROSS=2;} 178 if (LHAND==16){ACROSS=3;} //CONVERT BYTE VALUE TO INDEX 179 if (LHAND==8){ACROSS=4;} //VALUE FOR RIGHT HAND 180 if (LHAND==4){ACROSS=5;} 181 if (LHAND==2){ACROSS=6;} 182 if (LHAND==1){ACROSS=7;} 183//READ CHARACTER FROM TABLE 184//end - from patent 4,775,225 (modified) 185//NOTE DOWN & ACROSS have default values of zero if no match 186//Example press 2 right hand keys(DOWN) and s4_a(ACROSS) gives letter m(DOWN=0;ACROSS=1) 187} 188 189if (do_character) 190{ 191 do_character=false; 192 193 switch (key_table[ACROSS][DOWN]){ 194 195 //control key 196 case 128: ctrl_key=true;digitalWrite(ctrl_led,HIGH);break; 197 198 //caps lock key 199 case 193:caps_lock_key=!caps_lock_key; 200 if(caps_lock_key){digitalWrite(caps_lock_led,HIGH);} 201 else{digitalWrite(caps_lock_led,LOW);}break;//toggle caps lock key 202 203 //shift key 204 case 129:shift_key=true;digitalWrite(caps_lock_led,HIGH);break; 205 206 default : if(!ctrl_key && !caps_lock_key && !shift_key){Keyboard.write((unsigned char)key_table[ACROSS][DOWN]);} 207 208 if(ctrl_key)//control key only 209 {Keyboard.press(128);//control on 210 Keyboard.press((unsigned char)key_table[ACROSS][DOWN]); 211 Keyboard.releaseAll();//control off 212 ctrl_key=false; 213 digitalWrite(ctrl_led,LOW);} 214 215 if(shift_key && !caps_lock_key)//shift only 216 {Keyboard.press(129);//shift on 217 Keyboard.press((unsigned char)key_table[ACROSS][DOWN]); 218 Keyboard.releaseAll();//shift off 219 shift_key=false; 220 digitalWrite(caps_lock_led,LOW);} 221 222 if(caps_lock_key && !shift_key)//caps lock only 223 { 224 if (isAlpha((unsigned char)key_table[ACROSS][DOWN])) 225 { 226 Keyboard.press(129); 227 Keyboard.press((unsigned char)key_table[ACROSS][DOWN]); 228 Keyboard.releaseAll(); 229 } 230 else 231 { 232 Keyboard.press((unsigned char)key_table[ACROSS][DOWN]); 233 Keyboard.releaseAll(); 234 } 235 } 236 237 if(shift_key && caps_lock_key)//shift and caps lock 238 { if (isAlpha((unsigned char)key_table[ACROSS][DOWN])) 239 { 240 Keyboard.press((unsigned char)key_table[ACROSS][DOWN]); 241 Keyboard.releaseAll(); 242 shift_key=false; 243 } 244 else 245 { 246 Keyboard.press(129);//shift on 247 Keyboard.press((unsigned char)key_table[ACROSS][DOWN]); 248 Keyboard.releaseAll();//shift off 249 shift_key=false; 250 } 251 }break; 252 253 } 254 255} 256 257 258} 259 260 261//my_functions 262ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine 263{ 264// 265//read buttons 266 uint8_t temp=0x00; 267 uint8_t left_temp=0x00; 268 269 left_temp|=!digitalRead(button_1)<<6;left_temp|=!digitalRead(button_9)<<7; 270 left_temp|=!digitalRead(button_2)<<4;left_temp|=!digitalRead(button_10)<<5; 271 left_temp|=!digitalRead(button_3)<<2;left_temp|=!digitalRead(button_11)<<3; 272 left_temp|=!digitalRead(button_4)<<0;left_temp|=!digitalRead(button_12)<<1; 273 274 temp|=!digitalRead(button_5)<<6;temp|=!digitalRead(button_13)<<7; 275 temp|=!digitalRead(button_6)<<4;temp|=!digitalRead(button_14)<<5; 276 temp|=!digitalRead(button_7)<<2;temp|=!digitalRead(button_15)<<3; 277 temp|=!digitalRead(button_8)<<0;temp|=!digitalRead(button_16)<<1; 278 279//debounce 280 uint8_t i,j; 281 282//for right hand 283 State[Index]= temp; 284 ++Index; 285 j=0xFF; 286 for (i=0;i<MAX_CHECKS;i++){j=j&State[i];} 287 Debounced_State=j; 288 if(Index>=MAX_CHECKS){Index=0;} 289 290//for left hand left_ 291 left_State[left_Index]= left_temp; 292 ++left_Index; 293 j=0xFF; 294 for (i=0;i<MAX_CHECKS;i++){j=j&left_State[i];} 295 left_Debounced_State=j; 296 if(left_Index>=MAX_CHECKS){left_Index=0;} 297} 298//-----------end------------ 299
The software
c_cpp
1#include <Keyboard.h> 2// 3//left buttons 4#define button_1 5 5#define button_2 6 6#define button_3 7 7#define button_4 8 8#define button_9 SCK 9#define button_10 MISO 10#define button_11 A5 11#define button_12 A4 12 13//right buttons 14#define button_5 9 15#define button_6 10 16#define button_7 11 17#define button_8 12//A1 18#define button_13 A3 19#define button_14 A2 20#define button_15 A1//12 21#define button_16 A0 22 23#define caps_lock_led MOSI 24#define ctrl_led 1 25//alt has not been coded into table 26#define alt_led 0 27//On my original pcb I wired fn_led to pin TX, which I couldn't get to work 28#define fn_led 4 29 30 31//from patent 4,775,225 (modified)- 32//Notes: 33//Patent table 3, which I used to create the table below, lists g twice and ommits 6 34//Patent tables 1 & 2 list 6 as occuring at 0001 0010 (sw4_t and sw7_t), the other g is in its correct place 35//Placement of ! and ? is transposed in table 3 compared to tables 1 and 2 - I chose to follow table 3 36//Tables 1 and 2 list both numbers 3 and 5 as code 2000 0001 - where 2 means switch pressed away from you and 1 is switch toward you 37//From table 3 38//3 is code 2000 0001 39//5 is code 2000 0002 40//I have redesignated uppercase(UC) and lowercase(LC) 41//code 0010 2000 used for shift 42//code 0020 1000 used for caps lock 43// 44//Warning on char codes 45//Characters are sent as if from a US keyboard 46//Characters change if receiving computer is not set up for US keyboard 47//Example: 48//In my case: 49//@ becomes " 50//" becomes @ 51//# becomes 52//See: 53//https://forum.arduino.cc/index.php?topic=428331.0 54//Retrieved 28/Dec/2017 55 56const unsigned char key_table[8][8]{'j','m','y','0','(','+','2','4', 57 'k','p','z','1',')','"','3','5', 58 ',',';','$','@','\ ',194,'\\'','%',//F1 escape(\\) required to allow character ' in table 59 '.',':','#','*',128,195,'=','\\b',//CT F2 60 'u',129,'o','n','-','?','q','w',//LC as shift 61 193,'\n','i','s','!','/','v','x',//UC as caps lock 62 ' ','t','h','d','6','8','b','f', 63 'e','a','r','l','7','9','c','g'}; 64//end - from patent 4,775,225 (modified) 65 66//required to debounce switch 67#define MAX_CHECKS 10 68//for right hand 69volatile uint8_t Debounced_State=0;//accessed by isr and main loop code 70uint8_t State[MAX_CHECKS]={0}; 71uint8_t Index=0; 72 73//for left hand 74volatile uint8_t left_Debounced_State=0;//accessed by isr and main loop code 75uint8_t left_State[MAX_CHECKS]={0}; 76uint8_t left_Index=0; 77 78// the setup function runs once when you press reset or power the board 79void setup() { 80 81 pinMode(button_1,INPUT_PULLUP); 82 pinMode(button_2,INPUT_PULLUP); 83 pinMode(button_3,INPUT_PULLUP); 84 pinMode(button_4,INPUT_PULLUP); 85 pinMode(button_5,INPUT_PULLUP); 86 pinMode(button_6,INPUT_PULLUP); 87 pinMode(button_7,INPUT_PULLUP); 88 pinMode(button_8,INPUT_PULLUP); 89 90 pinMode(button_9,INPUT_PULLUP); 91 pinMode(button_10,INPUT_PULLUP); 92 pinMode(button_11,INPUT_PULLUP); 93 pinMode(button_12,INPUT_PULLUP); 94 pinMode(button_13,INPUT_PULLUP); 95 pinMode(button_14,INPUT_PULLUP); 96 pinMode(button_15,INPUT_PULLUP); 97 pinMode(button_16,INPUT_PULLUP); 98 99//led setup 100 pinMode(caps_lock_led,OUTPUT); 101 pinMode(ctrl_led,OUTPUT); 102 pinMode(alt_led,OUTPUT); 103 pinMode(fn_led,OUTPUT); 104 105//test led's 106 digitalWrite(caps_lock_led,HIGH); 107 digitalWrite(ctrl_led,HIGH); 108 digitalWrite(alt_led,HIGH); 109 digitalWrite(fn_led,HIGH); 110 delay(1000); 111 digitalWrite(caps_lock_led,LOW); 112 digitalWrite(ctrl_led,LOW); 113 digitalWrite(alt_led,LOW); 114 digitalWrite(fn_led,LOW); 115 116 // initialize timer1 117 noInterrupts(); // disable all interrupts 118 TCCR1A = 0; 119 TCCR1B = 0; 120 TCNT1 = 0; 121 122 OCR1A = 625; // compare match register 16MHX/256/100HZ 123 TCCR1B |= (1 << WGM12); // CTC mode 124 TCCR1B |= (1 << CS12); // 256 prescaler 125 TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt 126 interrupts(); // enable all interrupts 127 128 129// initialize control over the keyboard: 130Keyboard.begin(); 131 132} 133 134// the loop function runs over and over again forever 135void loop() { 136 137static bool do_character=false; 138static bool button_up=false; 139static bool chord_ready=false; 140static bool ctrl_key=false; 141static bool caps_lock_key=false; 142static bool shift_key=false; 143static bool alt_key=false; 144int DOWN=0; 145int ACROSS=0; 146 147static int RHAND=0; 148static int LHAND=0; 149 150 noInterrupts(); // disable all interrupts 151if (Debounced_State && left_Debounced_State){RHAND=Debounced_State;LHAND=left_Debounced_State;chord_ready=true;}//store chord and flag as ready 152if (!Debounced_State || !left_Debounced_State){if(chord_ready){button_up=true;}} 153 interrupts(); // enable all interrupts 154 155 156 157if(button_up && chord_ready) 158{ 159chord_ready=false; 160button_up=false; 161do_character=true; 162 163//from patent 4,775,225 (modified) 164//'BYTES FROM "DEVICE" 165//The original binary values have been inverted 166 if (RHAND==128){DOWN=0;} 167 if (RHAND==64){DOWN=1;} 168 if (RHAND==32){DOWN=2;} //CONVERT BYTE VALUE TO INDEX 169 if (RHAND==16){DOWN=3;} //VALUE FOR LEFT HAND 170 if (RHAND==8){DOWN=4;} 171 if (RHAND==4){DOWN=5;} 172 if (RHAND==2){DOWN=6;} 173 if (RHAND==1){DOWN=7;} 174 if (LHAND==128){ACROSS=0;} 175 if (LHAND==64){ACROSS=1;} 176 if (LHAND==32){ACROSS=2;} 177 if (LHAND==16){ACROSS=3;} //CONVERT BYTE VALUE TO INDEX 178 if (LHAND==8){ACROSS=4;} //VALUE FOR RIGHT HAND 179 if (LHAND==4){ACROSS=5;} 180 if (LHAND==2){ACROSS=6;} 181 if (LHAND==1){ACROSS=7;} 182//READ CHARACTER FROM TABLE 183//end - from patent 4,775,225 (modified) 184//NOTE DOWN & ACROSS have default values of zero if no match 185//Example press 2 right hand keys(DOWN) and s4_a(ACROSS) gives letter m(DOWN=0;ACROSS=1) 186} 187 188if (do_character) 189{ 190 do_character=false; 191 192 switch (key_table[ACROSS][DOWN]){ 193 194 //control key 195 case 128: ctrl_key=true;digitalWrite(ctrl_led,HIGH);break; 196 197 //caps lock key 198 case 193:caps_lock_key=!caps_lock_key; 199 if(caps_lock_key){digitalWrite(caps_lock_led,HIGH);} 200 else{digitalWrite(caps_lock_led,LOW);}break;//toggle caps lock key 201 202 //shift key 203 case 129:shift_key=true;digitalWrite(caps_lock_led,HIGH);break; 204 205 default : if(!ctrl_key && !caps_lock_key && !shift_key){Keyboard.write((unsigned char)key_table[ACROSS][DOWN]);} 206 207 if(ctrl_key)//control key only 208 {Keyboard.press(128);//control on 209 Keyboard.press((unsigned char)key_table[ACROSS][DOWN]); 210 Keyboard.releaseAll();//control off 211 ctrl_key=false; 212 digitalWrite(ctrl_led,LOW);} 213 214 if(shift_key && !caps_lock_key)//shift only 215 {Keyboard.press(129);//shift on 216 Keyboard.press((unsigned char)key_table[ACROSS][DOWN]); 217 Keyboard.releaseAll();//shift off 218 shift_key=false; 219 digitalWrite(caps_lock_led,LOW);} 220 221 if(caps_lock_key && !shift_key)//caps lock only 222 { 223 if (isAlpha((unsigned char)key_table[ACROSS][DOWN])) 224 { 225 Keyboard.press(129); 226 Keyboard.press((unsigned char)key_table[ACROSS][DOWN]); 227 Keyboard.releaseAll(); 228 } 229 else 230 { 231 Keyboard.press((unsigned char)key_table[ACROSS][DOWN]); 232 Keyboard.releaseAll(); 233 } 234 } 235 236 if(shift_key && caps_lock_key)//shift and caps lock 237 { if (isAlpha((unsigned char)key_table[ACROSS][DOWN])) 238 { 239 Keyboard.press((unsigned char)key_table[ACROSS][DOWN]); 240 Keyboard.releaseAll(); 241 shift_key=false; 242 } 243 else 244 { 245 Keyboard.press(129);//shift on 246 Keyboard.press((unsigned char)key_table[ACROSS][DOWN]); 247 Keyboard.releaseAll();//shift off 248 shift_key=false; 249 } 250 }break; 251 252 } 253 254} 255 256 257} 258 259 260//my_functions 261ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine 262{ 263// 264//read buttons 265 uint8_t temp=0x00; 266 uint8_t left_temp=0x00; 267 268 left_temp|=!digitalRead(button_1)<<6;left_temp|=!digitalRead(button_9)<<7; 269 left_temp|=!digitalRead(button_2)<<4;left_temp|=!digitalRead(button_10)<<5; 270 left_temp|=!digitalRead(button_3)<<2;left_temp|=!digitalRead(button_11)<<3; 271 left_temp|=!digitalRead(button_4)<<0;left_temp|=!digitalRead(button_12)<<1; 272 273 temp|=!digitalRead(button_5)<<6;temp|=!digitalRead(button_13)<<7; 274 temp|=!digitalRead(button_6)<<4;temp|=!digitalRead(button_14)<<5; 275 temp|=!digitalRead(button_7)<<2;temp|=!digitalRead(button_15)<<3; 276 temp|=!digitalRead(button_8)<<0;temp|=!digitalRead(button_16)<<1; 277 278//debounce 279 uint8_t i,j; 280 281//for right hand 282 State[Index]= temp; 283 ++Index; 284 j=0xFF; 285 for (i=0;i<MAX_CHECKS;i++){j=j&State[i];} 286 Debounced_State=j; 287 if(Index>=MAX_CHECKS){Index=0;} 288 289//for left hand left_ 290 left_State[left_Index]= left_temp; 291 ++left_Index; 292 j=0xFF; 293 for (i=0;i<MAX_CHECKS;i++){j=j&left_State[i];} 294 left_Debounced_State=j; 295 if(left_Index>=MAX_CHECKS){left_Index=0;} 296} 297//-----------end------------ 298
Downloadable files
Eagle board and schematic (zip)
Eagle board and schematic (zip)
Eagle board and schematic (zip)
Eagle board and schematic (zip)
Circuit diagram
Circuit diagram
Comments
Only logged in users can leave comments
glennedi
0 Followers
•0 Projects
Table of contents
Intro
5
0