Project tutorial
Ternary Chord Keyboard

Ternary Chord Keyboard © GPL3+

Accukey lives!

  • 3,926 views
  • 4 comments
  • 9 respects

Components and supplies

A000053 iso both1
Arduino Micro & Genuino Micro
×1
5 volt LED
The type with the in built resistor.
×4
6 mm push-button switch
×16
.1 inch header socket (17 way)
×2
USB cable (Micro B)
×1

Apps and online services

About this project

In my heart I know we are stuck with the QWERTY keyboard but that doesn’t stop me wanting something different. I have thought about switching to Dvorak or Colemak key assignments but don’t want to deal with the problem of mental interference when I have to switch back to a normal keyboard.

On a search for alternate keyboards I came across the Accukey, a ternary chord keyboard [1]. The keyboard consists of 8 switches designed pushed or pulled from a center off position, one per finger. The switches are used in pairs, 1 left 1 right, to form a chord giving a total of 64 combinations.

My thinking is that this radically different keying method would give minimal interference to the typing skills that I have already.

Limited internet searching didn’t turn up the right sort of switches but I thought I could put together a test rig to sort out the code and hardware; the results of my efforts are presented here.

Hardware description:

I used 2 push-buttons to simulate each of the switches in the original design with 1 push-button representing the forward push and the other the backward pull, each switch is connected up to a port pin set as input with its internal pull up enabled.

The 5 volt LED’s are connected to 4 port pins set as output.

I mounted everything on a custom PCB.

I used 2 socket strips to plug my Arduino Micro into the PCB.

Software overview:

The switches are debounced using a software routine I found in a PDF called Debouncing by Jack G Ganssle [2] the routine is set to be called every 100th second by the Arduino timer 1 interrupt.

The main line code responds after the release of a key chord.

The key character is located and printed from a table using the technique listed in the original patent [3].

I came across 2 different key maps for this keyboard, the one in the original patent and the other [4] shown on a web page devoted to various keyboards [5].

I originally intended to implement the key mapping shown on the keyboard web-page but I did think the key mappings weird; for example the 2 pinkie fingers which I consider the weakest and least coordinated, are used to generate the character e (the most common English letter). The key mapping in the patent seemed much more sensible so I implemented most of that instead.

I did make some changes:

I corrected a number of inconsistencies and errors in the patents key mapping tables.

Instead of uppercase and lowercase I implemented shift and caps lock.

The key-map:

Errors and omissions:

As set up only 2 function keys are mapped to the keyboard. My thinking is to, at a later date, map one of them as the alt key and leave the other as function but arrange things so that the user first keys function then the number of the required function e.g. Fn then 11 for function 11.

On my original PCB I attached the Fn LED to PB0 and couldn’t get the LED to work.

I have altered the board design posted here; the Fn LED is now attached to PD4 (untested).

I had some difficulty with the key table in getting it to print the characters “ @ and #.

I eventually found out that the keyboard library implements a US keyboard and when used on a machine not set for a US keyboard some of the characters will be altered.

I left the problem characters in their original table positions as per the patent, so if you get unexpected characters this is the reason.

Oddly when you print the same characters to the serial monitor they are displayed correctly.

Notes:

I am still looking for the right type of keys to make a full size unit.

Accucorp was a US registered trademark; a trademark electronic search (TESS) lists it as dead. (1/Oct/2017)

Accukey seems not to have been listed as a trademark (TESS 1/Oct/2017), there is an accu-key listed but this is for a key cutting machine.

The original keyboard patent has expired (Date of patent: Oct 4 1988).

References:

Code

The softwareC/C++
#include <Keyboard.h>
//
//left buttons
#define button_1 5
#define button_2 6
#define button_3 7
#define button_4 8
#define button_9  SCK
#define button_10 MISO
#define button_11 A5
#define button_12 A4

//right buttons
#define button_5 9
#define button_6 10
#define button_7 11
#define button_8 12//A1
#define button_13 A3
#define button_14 A2
#define button_15 A1//12
#define button_16 A0

#define caps_lock_led MOSI
#define ctrl_led  1
//alt has not been coded into table 
#define alt_led  0
//On my original pcb I wired fn_led to pin TX, which I couldn't get to work
#define fn_led 4 


//from patent 4,775,225 (modified)-
//Notes: 
//Patent table 3, which I used to create the table below, lists g twice and ommits 6
//Patent tables 1 & 2 list 6 as occuring at 0001 0010 (sw4_t and sw7_t), the other g is in its correct place
//Placement of ! and ? is transposed in table 3 compared to tables 1 and 2 - I chose to follow table 3
//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
//From table 3
//3 is code 2000 0001
//5 is code 2000 0002
//I have redesignated uppercase(UC) and lowercase(LC)
//code 0010 2000 used for shift
//code 0020 1000 used for caps lock
//
//Warning on char codes
//Characters are sent as if from a US keyboard
//Characters change if receiving computer is not set up for US keyboard
//Example:
//In my case:
//@ becomes "
//" becomes @
//# becomes 
//See:
//https://forum.arduino.cc/index.php?topic=428331.0
//Retrieved 28/Dec/2017

const unsigned char key_table[8][8]{'j','m','y','0','(','+','2','4',
                                    'k','p','z','1',')','"','3','5',
                                    ',',';','$','@','\t',194,'\'','%',//F1  escape(\) required to allow character ' in table  
                                    '.',':','#','*',128,195,'=','\b',//CT F2 
                                    'u',129,'o','n','-','?','q','w',//LC as shift
                                    193,'\n','i','s','!','/','v','x',//UC as caps lock
                                    ' ','t','h','d','6','8','b','f',
                                    'e','a','r','l','7','9','c','g'};
//end - from patent 4,775,225 (modified)

//required to debounce switch
#define MAX_CHECKS 10
//for right hand
volatile uint8_t Debounced_State=0;//accessed by isr and main loop code
uint8_t State[MAX_CHECKS]={0};
uint8_t Index=0;

//for left hand
volatile uint8_t left_Debounced_State=0;//accessed by isr and main loop code
uint8_t left_State[MAX_CHECKS]={0};
uint8_t left_Index=0;

// the setup function runs once when you press reset or power the board
void setup() {

          pinMode(button_1,INPUT_PULLUP);
          pinMode(button_2,INPUT_PULLUP);
          pinMode(button_3,INPUT_PULLUP);
          pinMode(button_4,INPUT_PULLUP);
          pinMode(button_5,INPUT_PULLUP);
          pinMode(button_6,INPUT_PULLUP);
          pinMode(button_7,INPUT_PULLUP);
          pinMode(button_8,INPUT_PULLUP);
          
          pinMode(button_9,INPUT_PULLUP);
          pinMode(button_10,INPUT_PULLUP);
          pinMode(button_11,INPUT_PULLUP);
          pinMode(button_12,INPUT_PULLUP);
          pinMode(button_13,INPUT_PULLUP);
          pinMode(button_14,INPUT_PULLUP);
          pinMode(button_15,INPUT_PULLUP);
          pinMode(button_16,INPUT_PULLUP);

//led setup
          pinMode(caps_lock_led,OUTPUT);
          pinMode(ctrl_led,OUTPUT);
          pinMode(alt_led,OUTPUT);
          pinMode(fn_led,OUTPUT);

//test led's
          digitalWrite(caps_lock_led,HIGH);
          digitalWrite(ctrl_led,HIGH);
          digitalWrite(alt_led,HIGH);
          digitalWrite(fn_led,HIGH);
          delay(1000);
          digitalWrite(caps_lock_led,LOW);
          digitalWrite(ctrl_led,LOW);
          digitalWrite(alt_led,LOW);
          digitalWrite(fn_led,LOW);          

    // initialize timer1 
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;

  OCR1A = 625;              // compare match register  16MHX/256/100HZ 
  TCCR1B |= (1 << WGM12);   // CTC mode
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
  interrupts();             // enable all interrupts


// initialize control over the keyboard:
Keyboard.begin();
  
}

// the loop function runs over and over again forever
void loop() {

static bool do_character=false;
static bool button_up=false;
static bool chord_ready=false;
static bool ctrl_key=false;
static bool caps_lock_key=false;
static bool shift_key=false;
static bool alt_key=false;
int DOWN=0;
int ACROSS=0;

static int RHAND=0;
static int LHAND=0;

    noInterrupts();           // disable all interrupts
if (Debounced_State && left_Debounced_State){RHAND=Debounced_State;LHAND=left_Debounced_State;chord_ready=true;}//store chord and flag as ready
if (!Debounced_State || !left_Debounced_State){if(chord_ready){button_up=true;}}    
    interrupts();             // enable all interrupts



if(button_up && chord_ready)
{
chord_ready=false;
button_up=false;
do_character=true;

//from patent 4,775,225 (modified)  
//'BYTES FROM "DEVICE"
//The original binary values have been inverted
   if (RHAND==128){DOWN=0;}
   if (RHAND==64){DOWN=1;}
   if (RHAND==32){DOWN=2;}                  //CONVERT BYTE VALUE TO INDEX
   if (RHAND==16){DOWN=3;}                  //VALUE FOR LEFT HAND
   if (RHAND==8){DOWN=4;}
   if (RHAND==4){DOWN=5;}
   if (RHAND==2){DOWN=6;}
   if (RHAND==1){DOWN=7;}
   if (LHAND==128){ACROSS=0;}
   if (LHAND==64){ACROSS=1;}
   if (LHAND==32){ACROSS=2;}
   if (LHAND==16){ACROSS=3;}                  //CONVERT BYTE VALUE TO INDEX
   if (LHAND==8){ACROSS=4;}                  //VALUE FOR RIGHT HAND
   if (LHAND==4){ACROSS=5;}   
   if (LHAND==2){ACROSS=6;}
   if (LHAND==1){ACROSS=7;}
//READ CHARACTER FROM TABLE
//end - from patent 4,775,225 (modified)
//NOTE DOWN & ACROSS have default values of zero if no match
//Example press 2 right hand keys(DOWN) and s4_a(ACROSS) gives letter m(DOWN=0;ACROSS=1)
}

if (do_character) 
{
  do_character=false;

  switch (key_table[ACROSS][DOWN]){
    
    //control key
    case 128: ctrl_key=true;digitalWrite(ctrl_led,HIGH);break;

    //caps lock key
    case 193:caps_lock_key=!caps_lock_key;
              if(caps_lock_key){digitalWrite(caps_lock_led,HIGH);}
                  else{digitalWrite(caps_lock_led,LOW);}break;//toggle caps lock key

    //shift key              
    case 129:shift_key=true;digitalWrite(caps_lock_led,HIGH);break;              
                  
    default : if(!ctrl_key && !caps_lock_key && !shift_key){Keyboard.write((unsigned char)key_table[ACROSS][DOWN]);}
    
              if(ctrl_key)//control key only
              {Keyboard.press(128);//control on
               Keyboard.press((unsigned char)key_table[ACROSS][DOWN]);
               Keyboard.releaseAll();//control off
               ctrl_key=false;
               digitalWrite(ctrl_led,LOW);} 
                        
              if(shift_key && !caps_lock_key)//shift only
              {Keyboard.press(129);//shift on
               Keyboard.press((unsigned char)key_table[ACROSS][DOWN]);
               Keyboard.releaseAll();//shift off
               shift_key=false;
               digitalWrite(caps_lock_led,LOW);}
                 
              if(caps_lock_key && !shift_key)//caps lock only
              {
               if (isAlpha((unsigned char)key_table[ACROSS][DOWN]))
               {
                Keyboard.press(129);
                Keyboard.press((unsigned char)key_table[ACROSS][DOWN]);
                Keyboard.releaseAll();
                }
               else
               {
                Keyboard.press((unsigned char)key_table[ACROSS][DOWN]);
                Keyboard.releaseAll();
                }
                } 
                                                            
              if(shift_key && caps_lock_key)//shift and caps lock
              { if (isAlpha((unsigned char)key_table[ACROSS][DOWN]))
                {
                Keyboard.press((unsigned char)key_table[ACROSS][DOWN]);
                Keyboard.releaseAll();
                shift_key=false;
                }
              else
                {
                Keyboard.press(129);//shift on
                Keyboard.press((unsigned char)key_table[ACROSS][DOWN]);
                Keyboard.releaseAll();//shift off
                shift_key=false;
                }
                }break;
                                      
    }

}


}


//my_functions
ISR(TIMER1_COMPA_vect)          // timer compare interrupt service routine
{
//
//read buttons
  uint8_t temp=0x00;
  uint8_t left_temp=0x00;
  
  left_temp|=!digitalRead(button_1)<<6;left_temp|=!digitalRead(button_9)<<7;
  left_temp|=!digitalRead(button_2)<<4;left_temp|=!digitalRead(button_10)<<5;
  left_temp|=!digitalRead(button_3)<<2;left_temp|=!digitalRead(button_11)<<3;
  left_temp|=!digitalRead(button_4)<<0;left_temp|=!digitalRead(button_12)<<1;
  
  temp|=!digitalRead(button_5)<<6;temp|=!digitalRead(button_13)<<7;
  temp|=!digitalRead(button_6)<<4;temp|=!digitalRead(button_14)<<5;
  temp|=!digitalRead(button_7)<<2;temp|=!digitalRead(button_15)<<3;
  temp|=!digitalRead(button_8)<<0;temp|=!digitalRead(button_16)<<1;
            
//debounce
  uint8_t i,j;

//for right hand
  State[Index]= temp;
  ++Index;
  j=0xFF;
  for (i=0;i<MAX_CHECKS;i++){j=j&State[i];}
  Debounced_State=j;
  if(Index>=MAX_CHECKS){Index=0;} 

//for left hand left_
  left_State[left_Index]= left_temp;
  ++left_Index;
  j=0xFF;
  for (i=0;i<MAX_CHECKS;i++){j=j&left_State[i];}
  left_Debounced_State=j;
  if(left_Index>=MAX_CHECKS){left_Index=0;}
}
//-----------end------------  

Schematics

Circuit diagram
Eagle board and schematic (zip)
keyboard_eagle_files_GoENOdJpoj.zip

Comments

Similar projects you might like

A Pocket-Sized Touch Keyboard

Project tutorial by Amal Mathew

  • 3,587 views
  • 3 comments
  • 15 respects

How to Make a Customizable Punchable Keyboard Button

Project tutorial by Amal Mathew

  • 3,657 views
  • 7 comments
  • 9 respects

Keyboard Melodies

Project tutorial by Ava Baker -21 and Natalie Clark -20

  • 1,843 views
  • 2 comments
  • 8 respects

Morse Keyboard

Project showcase by Mr_Glenn

  • 731 views
  • 1 comment
  • 3 respects

Keyboard and Mouse Controller

Project showcase by pdio

  • 2,622 views
  • 0 comments
  • 3 respects

Keyboard V2.0

Project in progress by Gabriele Scordamaglia

  • 5,153 views
  • 18 comments
  • 14 respects
Add projectSign up / Login