Go Down

Topic: Atari to USB Project. Keyboard.releaseAll() issue. (Read 662 times) previous topic - next topic

Borgle

I'm using a pro micro board to adapt an old Atari 1200xl computer keyboard to a HID USB keyboard for my PC.  The keyboard is an 8x8 matrix actively scanned through two 4051 multiplexers.  A pair of signal lines, one for the modifier keys (SHIFT, CONTROL, and BREAK) and the other for all of the other keys indicate a key press by being pulled low at a given point in the scan.  The connections between the Atari keyboard and the pro micro are set out in my sketch, posted below.

This is my first arduino project and I've managed to pound out some crude but effective code that works for everything except the modifiers.  More specifically, the problem is that I can't figure out how to stop the modifiers from staying once a modifier key is pressed.  For example, holding SHIFT switches all subsequent keys to upper case, but releasing it doesn't revert things back to lower case.  Same is true for CONTROL (so everything typed after pressing Control causes much mischeif).  I've tried inserting Keyboard.releaseAll() in various places in my functions and main loop, but it doesn't seem to have any effect. 

I'm not looking for someone to code the solution for me, but I would appreciate any hints or suggestions as to what I'm missing. Here's my sketch. (Ignore the keyboard.writes for SHIFT, etc.  I just stuck those in there to test if the keys were working).

Code: [Select]
// 1200xl to USB

//  Hardware Connections to Pro Micro:
const int KR1=3;  // 1200xl connector pin 3
const int KR2=2;  // 1200xl connector pin 1
const int resetKey=15;  //1200xl connector pin 10
const int startKey=14;  // " pin 11
const int selectKey=16;  // " pin 12
const int optionKey=10;  // " pin 13

int resetKeyState;
int startKeyState;
int selectKeyState;
int optionKeyState;

int count = 0;  // binary count to 4051 pins

int keyList[]= {  // no modifiers yet
  97,49,113,61,62,122,88,42,88,54,    //  i= 0-9  ascii:  a,1,q,=,>,z,INV,not used,6
  121,117,55,216,110,218,103,53,116,105,  // 10-19  ascii:  y,u,7,F3,n,F1,g,5,t,i
  56,98,109,107,104,88,88,88,88,88, //  20-29  ascii:  8,b,m,k,h,25-28 not used, HELP
  32,106,115,50,119,45,60,120,47,43, //30-39  ascii:  30 not used,j,s,2,w,-,<,x,/,+
  100,51,101,112,48,99,46,59,193,177,  //40-49  ascii:  d,3,e,p,0,c, . , ; ,CAPS,ESC, (ascii lists 27 for ESC, but actually 177 per arduino reference)
  9,10,8,215,88,217,102,52,114,111,     //50-59  ascii:  TAB,RETURN,BACKSPACE,F4, 54 not used, F2,f,4,r (ascii lists show 13 for carriage return/enter, but it's actually 10)
  57,118,44,108};                    //60-63  ascii:  9,v, , ,l

int KR1State = HIGH; //default high= nothing pressed
int KR2State = HIGH; // same for the modifier line
int modKey= 0; // which modifier key
int keyCode = 0; // variable for the physical key, not character -- only included for debugging
char keyChar; // variable for actual character to send
const char ctrlKey = KEY_LEFT_SHIFT;
const char shiftKey = KEY_LEFT_SHIFT;
const char brkKey = KEY_END;

// variables for debounce
unsigned long timeRead = 0;
unsigned long debounceTime = 106; // best rate without hardware debouncing

//____________________________________________________SETUP___________________________________________
void setup() 

  pinMode(4,OUTPUT);   // Rows (U2)
  pinMode(5,OUTPUT); 
  pinMode(6,OUTPUT); 
  pinMode(7,OUTPUT);  // Columns (U1)
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);

  pinMode(KR1,INPUT_PULLUP);  // KR1 line (connector 3-- goes low when keypress grounds any 4051 line)
  pinMode(KR2,INPUT_PULLUP);  // separate column for SHIFT, CONTROL and BREAK
  pinMode(resetKey,INPUT_PULLUP);  //our four GTIA keys
  pinMode(startKey,INPUT_PULLUP);
  pinMode(selectKey,INPUT_PULLUP);
  pinMode(optionKey,INPUT_PULLUP);

  //Serial.begin(9600);  // use serial port for testing
  Keyboard.begin();  // don't use this until everything WORKS!


// _____________________________________  VOID LOOP___________________________________________________
void loop() 
{
 
  //  Keyboard scan
  for(count=0;count<64;count++)  // count to 64
  { 
    int a=count%2;      // and convert each count to a 6-bit binary
    int b=count/2%2;     
    int c=count/4%2;       
    int d=count/8%2; 
    int e=count/16%2;
    int f=count/32%2; 

    digitalWrite(9,a);  // c.;usend the high bits to A,B,C on U1
    digitalWrite(8,b);
    digitalWrite(7,c);
    digitalWrite(6,d);   // .;n7send the low bits to A,B,C on U2
    digitalWrite(5,e);   
    digitalWrite(4,f); 

    keyCode=count;  // each count identifies a key, e.g., 0="A", 32="S", etc.
   
    keyPress(); // has a key been pressed?
    modKeys(); // what modifier, if any, to apply?
    if (KR1State==LOW) { //seems redundant with this in the function but needs to be here anyway
      keyChar = (char) keyList[count];  //  convert the Keycode into the corresponding ascii from the array
      keySend();  // key has been debounced so go ahead and send it to USB
      Keyboard.releaseAll();
    }
   
    GTIAkeys();  // check and send RESET,START,SELECT,OPTION
     
  }  // for-loop close
}  //  void loop close

// ____________________________________DEBOUNCE FUNCTION_____________________________________________
void debounceWait()
{
  do {  // nothing until debounceTime is reached
  }
  while (millis() - timeRead < debounceTime); //
}

// ______________________________________KEPRESS FUNCTION ___________________________________________
boolean keyPress()
{
  KR1State = digitalRead(KR1);  // check for keypress
 
  if (KR1State == LOW){  // i.e., if a key is pressed
    timeRead = millis();  // start time for the debounce function
    debounceWait();
  }
  return(KR1State);
}
//_____________________________________MODIFIER KEYS ________________________________
char modKeys()
{
  KR2State=digitalRead(KR2);
    if (KR2State==LOW){
     
      if(keyCode==13){ //SHIFT
      modKey=shiftKey; 
      Keyboard.print("SHIFT");
      }
        else
   
        if (keyCode==47) { //CONTROL
        modKey=ctrlKey;
        Keyboard.print("CONTROL");
        }
          else
       
          if (keyCode==60) {  //BREAK
          modKey==brkKey;
          Keyboard.print("BREAK");
          }
    } 
  return(modKey);
}
// _______________________________________KEYSEND FUNCTION___________________________________________
void keySend()
{
  //Serial.print(keyChar);  // change to keyboard after everything debugged
  Keyboard.press(modKey);  //apply modifier
  Keyboard.write(keyChar);
}
//________________________________________GTIA KEYS__________________________________________________
void GTIAkeys()

  //these four keys are not part of the matrix and are debounced in hardware
  resetKeyState=digitalRead(resetKey);
  startKeyState=digitalRead(startKey);
  selectKeyState=digitalRead(selectKey);
  optionKeyState=digitalRead(optionKey);

  if (resetKeyState==LOW) {
    resetSend();
  }
  if (startKeyState==LOW){
    startSend();
  }
  if (selectKeyState==LOW) {
    selectSend();
  }
  if (optionKeyState==LOW) {
    optionSend();
  }
}

//____________________________________RESET SEND___________________________________
void resetSend()
{
  Keyboard.print("A");//---just send some letters for testing
}
//____________________________________SELECT SEND__________________________________
void startSend()
{
  Keyboard.print("B");
}
//_____________________________________SELECT SEND_________________________________
void selectSend()
{
  Keyboard.print("C");
}
//_____________________________________OPTION SEND__________________________________
void optionSend()
{
  Keyboard.print("D");
}












PaulS

Code: [Select]
const char ctrlKey = KEY_LEFT_SHIFT;
const char shiftKey = KEY_LEFT_SHIFT;

What?

Code: [Select]
    int a=count%2;      // and convert each count to a 6-bit binary
    int b=count/2%2;     
    int c=count/4%2;       
    int d=count/8%2;
    int e=count/16%2;
    int f=count/32%2;

and store the single bit value in a 16 bit int. What a waste.

Code: [Select]
void debounceWait()
{
  do {  // nothing until debounceTime is reached
  }
  while (millis() - timeRead < debounceTime); //
}

Why is that better than delay(debounceTime)? NOTHING can happen during your delay function, either.

Code: [Select]
          modKey==brkKey;
The point of this comparison is?

Borgle

PaulS:  as you can see, I'm new at this, so please bear with me.  I also see that I obviously didn't proofread the last save of my sketch before posting it here, which was stupid on my part.

Regarding the ctrlKey and shiftKey variables- I see I screwed that up and have two shift keys.  You're right, there is no point to the modKey comparison.  It's supposed to be =, not ==.  I'll go through my code again and look for similar mistakes. 

I see what you mean about the debounce function, I wrote it and it worked so I left it be. Same goes for the binary count.  I never said it was efficient or artful.  It worked so I left it alone.

I do welcome your observations though since I am looking at this as a learning exercise. 

PaulS

Quote
I've tried inserting Keyboard.releaseAll() in various places in my functions and main loop, but it doesn't seem to have any effect. 
Perhaps you need to specifically release the modifier keys.

Borgle

That worked!  I added an if-else statement to the keySend function, i.e., if KR2 ==low, Keyboard.press (modKey) else Keyboard.release(modKey)-- just ahead of the main keyboard write and it works.  I'm not sure why the Keyboard.releaseAll() statement doesn't work there but I'm not complaining.  Thanks for the help.   

Now I'd like to take each function and explore better ways to code.   For starters, I'm curious what other ways there might be to produce the scan count and export the bits to the six output pins.  I initially explored using port manipulation but I don't have breakouts to a complete port on my micro controller.  Am I mistaken in thinking that's necessary for such approach?

I also wonder if the two signal lines might be read as ISR's. Any thoughts on that. 

PaulS

Quote
Am I mistaken in thinking that's necessary for such approach?
If you need 6 seats together, and the only available seats are on a bench that seats 8, does it matter what happens to the other 2 seats, as long as your party doesn't try to use those two other seats? No, it doesn't.

You can use direct port manipulation to manipulate 6 bits of the 8 bit port, as long as you ONLY manipulate the 6 bits you need.

Quote
I also wonder if the two signal lines might be read as ISR's. Any thoughts on that. 
If you have 2 free external interrupt pins, sure. Not that they are "read as ISR's". Rather, they can trigger interrupt service routines that know what to do when a pin goes HIGH, goes LOW, or changes (going either way).

Go Up