Pages: [1]   Go Down
Author Topic: Need help with scanning keyboard methods  (Read 284 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, I'm writing the software for a USB 8x16 keyboard with an internal PS/2 mouse. I'm using an Arduino Leonardo at the moment. I'm using a CD4017BE decade counter for 8 output and a MCP23017 for 16 inputs. Overall, the keyboard and the mouse works fine but the keyboard scanning is extremely slow. Here's an excerpt of the code:

Code:
CD4017 rows(11, 12);    //CLOCK, RESET
Adafruit_MCP23017 cols;

unsigned char matrix[8][16] = {...}; // a big fat keyboard matrix here
int row, col;

void setup() {
    Keyboard.begin();
    //Keyboard section
    rows.reset();              //reset decade counter
    cols.begin();              //start mcp23017
    for(col = 0; col < 16; col++) {
cols.pinMode(col, INPUT); //all pins have external pull-down resistors
}
}

void loop() {
//Keyboard scanning
if(row < 8) { //8 output rows
//scan keys
for(col = 0; col < 16; col++) {
     if(cols.digitalRead(col)) {
   Keyboard.press(matrix[row][col]);
      } else {
           Keyboard.release(matrix[row][col]);
      }
          }
row++;
rows.clock();
} else {
row = 0;
rows.reset();
 }
}

Is there a better way to scan the matrix?
« Last Edit: November 28, 2013, 01:32:47 am by congIA » Logged

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 444
Posts: 23859
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Probably - post a schematic and the rest of the code that shows what
cols.digitalRead(col)
and
rows.clock();
and
rows.reset();
does.

You're using this?
http://ww1.microchip.com/downloads/en/DeviceDoc/21952b.pdf

Should have gone for the SPI part, much faster:
• High-speed I2C™ interface (MCP23017)
- 100 kHz
- 400 kHz
- 1.7 MHz
• High-speed SPI interface (MCP23S17)
- 10 MHz (max.)

Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code for the CD4017BE
Code:
CD4017::CD4017(int clockPin, int resetPin)
{
CLOCK = clockPin;
RESET = resetPin;
pinMode(CLOCK, OUTPUT);
pinMode(RESET, OUTPUT);
} //CD4017

// default destructor
CD4017::~CD4017()
{
} //~CD4017

void CD4017::clock() {
digitalWrite(CLOCK, HIGH);
//delay(1);
digitalWrite(CLOCK, LOW);
}

void CD4017::reset() {
digitalWrite(RESET, HIGH);
//delay(1);
digitalWrite(RESET, LOW);
}

Code for the the cols.digitalRead() is the digitalRead() section of Adafruit's MCP23017 library:  https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library/blob/master/Adafruit_MCP23017.cpp

Thanks for the suggestion of the MCP23S17, I'm gonna get some of those and some of the CD74HC4017, which is a higher speed version of the CD4017 counter.

I've read that the Arduino's IO is slow because it has to do pin checking before writing, reading a pin. Would that have any significiant impact on reading with a MCP23S17?

* Arduino_Forum.sch (219.03 KB - downloaded 8 times.)
Logged

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 444
Posts: 23859
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
digitalWrite(CLOCK, HIGH);
//delay(1);
digitalWrite(CLOCK, LOW);
Yes, these digitalWrites are on the slow side.
You can hard-code them instead.  Let's say you are using PORTD bit 2 for this clock line, then:
PORTD = PORTD | 0b00000100; // make bit 2 high, leave the rest alone
PORTD = PORTD & 0b11111011; // make bit 2 low, leave the rest alone

assign the signal name the same way:
pinX = 2;
and use regular pinMode call
pinMode (pinX, OUTPUT);

I don't know what the port assignments are on the micro, you'll have to look that up.

With the SPI interface, combine the code above with SPI.transfers:
Code:
// assumes chip select is active low, check data sheet
PORTD = PORTD & 0b11110111; // make bit 3 low, leave the rest alone
lowerKeys = SPI.transfer(0); // dummy transfer of 0 out while reading in at the sametime
upperKeys = SPI.transfer(0);
PORTD = PORTD | 0b00001000; // make bit 3 high, leave the rest alone
That whole transfer will take just a couple of microseconds.
Combine it with your 4017 clock code, but not in a loop, each pass thru a loop adds 10-12uS as well:
Code:
PORTD = PORTD & 0b11110111; // make bit 3 low, leave the rest alone
lowerKeys[0] = SPI.transfer(0); // dummy transfer of 0 out while reading in at the sametime
upperKeys[0] = SPI.transfer(0);
PORTD = PORTD | 0b00001000; // make bit 3 high, leave the rest alone
// next 4017 bit
PORTD = PORTD | 0b00000100; // make bit 2 high, leave the rest alone
PORTD = PORTD & 0b11111011; // make bit 2 low, leave the rest alone

PORTD = PORTD & 0b11110111; // make bit 3 low, leave the rest alone
lowerKeys[1] = SPI.transfer(0); // dummy transfer of 0 out while reading in at the sametime
upperKeys[1] = SPI.transfer(0);
PORTD = PORTD | 0b00001000; // make bit 3 high, leave the rest alone
// next 4017 bit
PORTD = PORTD | 0b00000100; // make bit 2 high, leave the rest alone
PORTD = PORTD & 0b11111011; // make bit 2 low, leave the rest alone
PORTD = PORTD & 0b11110111; // make bit 3 low, leave the rest alone
lowerKeys[2] = SPI.transfer(0); // dummy transfer of 0 out while reading in at the sametime
upperKeys[2] = SPI.transfer(0);
PORTD = PORTD | 0b00001000; // make bit 3 high, leave the rest alone
// next 4017 bit
PORTD = PORTD | 0b00000100; // make bit 2 high, leave the rest alone
PORTD = PORTD & 0b11111011; // make bit 2 low, leave the rest alone
PORTD = PORTD & 0b11110111; // make bit 3 low, leave the rest alone
lowerKeys[3] = SPI.transfer(0); // dummy transfer of 0 out while reading in at the sametime
upperKeys[3] = SPI.transfer(0);
PORTD = PORTD | 0b00001000; // make bit 3 high, leave the rest alone
// next 4017 bit
PORTD = PORTD | 0b00000100; // make bit 2 high, leave the rest alone
PORTD = PORTD & 0b11111011; // make bit 2 low, leave the rest alone
PORTD = PORTD & 0b11110111; // make bit 3 low, leave the rest alone
lowerKeys[4] = SPI.transfer(0); // dummy transfer of 0 out while reading in at the sametime
upperKeys[4] = SPI.transfer(0);
PORTD = PORTD | 0b00001000; // make bit 3 high, leave the rest alone
// next 4017 bit
PORTD = PORTD | 0b00000100; // make bit 2 high, leave the rest alone
PORTD = PORTD & 0b11111011; // make bit 2 low, leave the rest alone
PORTD = PORTD & 0b11110111; // make bit 3 low, leave the rest alone
lowerKeys[5] = SPI.transfer(0); // dummy transfer of 0 out while reading in at the sametime
upperKeys[5] = SPI.transfer(0);
PORTD = PORTD | 0b00001000; // make bit 3 high, leave the rest alone
// next 4017 bit
PORTD = PORTD | 0b00000100; // make bit 2 high, leave the rest alone
PORTD = PORTD & 0b11111011; // make bit 2 low, leave the rest alone
PORTD = PORTD & 0b11110111; // make bit 3 low, leave the rest alone
lowerKeys[6] = SPI.transfer(0); // dummy transfer of 0 out while reading in at the sametime
upperKeys[6] = SPI.transfer(0);
PORTD = PORTD | 0b00001000; // make bit 3 high, leave the rest alone
// next 4017 bit
PORTD = PORTD | 0b00000100; // make bit 2 high, leave the rest alone
PORTD = PORTD & 0b11111011; // make bit 2 low, leave the rest alone
PORTD = PORTD & 0b11110111; // make bit 3 low, leave the rest alone
lowerKeys[7] = SPI.transfer(0); // dummy transfer of 0 out while reading in at the sametime
upperKeys[7] = SPI.transfer(0);
PORTD = PORTD | 0b00001000; // make bit 3 high, leave the rest alone

// end with resetting 4017 - say its bit 4
PORTD = PORTD | 0b00010000; // make bit 4 high, leave the rest alone
PORTD = PORTD & 0b11101111; // make bit 4 low, leave the rest alone
Now you've got your data in an array, go thru that quick & see if any data is non-zero to indicate a pressed key.
Some  might say this is not as portable - I say are you writing for speed? Then portability is secondary.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wow you probably spent a lot of time writing that. Thanks for the code. I shall try it out as soon as I get the SPI IC.
Logged

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 444
Posts: 23859
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Written, but not compiled. I am sure you will have to do some tweaking.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

EDIT: All's well. Used the wrong bit for the port.

I got some MCP23S17 today but I have been having problems using it.

I've tried using Cort Buffington's library but I couldn't get the inputs to work and the slightest touch on the SPI jumpers will cause the values to jump all over the place.  This problem happens the same with the shift register 74HC165 that also use SPI. How can I fix it?
« Last Edit: December 03, 2013, 10:30:54 am by congIA » Logged

Pages: [1]   Go Up
Jump to: