Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 10 of 10

Thread: Dymo Stylus Tact Alpha Keyboard for Teensy 3.

  1. #1
    Senior Member
    Join Date
    Nov 2012
    Posts
    412

    Dymo Stylus Tact Alpha Keyboard for Teensy 3.

    Dymo Stylus Tact Alpha Keyboard for Teensy 3.

    Ever wanted a 48 key tact keyboard for the Teensy 3?
    Sparkfun has a SX1509 breakout board which handles automatic microcontroller keyboard scanning and debounce.
    Note: This I2C I/O expander can also drive PWM LEDs and do level conversion.

    Operation is very simple. On any tact keypress, the interrupt output (input to T3) goes low. The T3 polls this digital and
    reads the I2C keypress data.

    In our application, we only used 6 rows and 8 columns.(48 tact keys) (8x8 64 keys max)
    You need I2C (2 wires + ground & 3.3V power) and interrupt input GPIO and one output reset GPIO.

    We made our custom mini tact keyboard PCB which can be easily labeled with a Walmart Dymo 3/8" tape label maker.
    An iPad stylus was used to activate the small tact swiches or "very small fingers" can be used.
    Our main design goal is to use this alpha numeric tact keyboard with an e-ink display for a low power RF terminal.

    https://www.sparkfun.com/products/11502

    T3 code below - enjoy



    Code:
    /* SX1509 Library Example 03
       Keypad interfacing
       by: Jim Lindblom
       SparkFun Electronics
       license: Beerware. Please use, reuse, share, and modify this
       code. I'd ask that you maintain attribution and open-source.
       If you find it useful, you can buy me a beer when we meet
       some day.
      
       This example shows how you can use the following SX1509 
       library methods:
         - constructor
         - init()
         - configClock()
         - keypad(numRows, numCols, sleepTime, scanTime)
         - readKeyData()
         - debounceConfig(debounceTime)
         
        Hardware: The SX1509 should be hooked up like so:
        SX1509 Pin      Arduino Pin
           3.3V ---------- 3.3V
           GND ----------- GND
           SDA ----------- A4 (or SDA on newer boards)
           SCL ----------- A5 (or SCL on newer boards)
           nRST ---------- 8 (could be any unused digital pin)
           nINT ---------- 7 (could be any unused digital pin)
           OSCIO is not used in this example.
       
       See the SX1509_ADDRESS defines to decide which address you need
       to send to the constructor. By default the SX1509 Breakout
       sets both ADDR pins to 0 (so 0x3E I2C address).
    
       In addition SX1509 is connected to a 4x4 matrix of 16 buttons.
       I used the SparkFun 4x4 button pad breakout:
                           https://www.sparkfun.com/products/8033
       You could tie 4 of those together and interface this chip
       with the 8x8 array of 64(!) buttons.
       
       The four rows of the button matrix should be connected to
       the SX1509's 0:3 pins. The columns of the button matrix should
       be connected to the SX1509's 8:11 pins.
       
       Works on the Teensy 3 <-----------------------------<<<<<<<<<<<<
       100 KHZ default bit rate
       10 k pullups ???
    */
    
    #include <Wire.h>  // Wire.h library is required to use SX1509 lib 
    #include <sx1509_library.h>  // Include the SX1509 library
    
    // Uncomment one of the four lines to match your SX1509's address
    //  pin selects. SX1509 breakout defaults to [0:0] (0x3E).
    const byte SX1509_ADDRESS = 0x3E;  // SX1509 I2C address (00) <-----<<<<< default on board
    //const byte SX1509_ADDRESS = 0x3F;  // SX1509 I2C address (01)
    //const byte SX1509_ADDRESS = 0x70;  // SX1509 I2C address (10)
    //const byte SX1509_ADDRESS = 0x71;  // SX1509 I2C address (11)
    
    // Arduino pin definitions
    //const byte resetPin = 8;
    const byte resetPin = 16;
    //const byte interruptPin = 7;
    const byte interruptPin = 17;
    
    int run_led = 13;
    
    //////////////////////////////////
    //// Global Variables  ///////////
    //////////////////////////////////
    // Here we'll define the number of rows and columns our keypad
    //  matrix has. Each of these values can be between 1 and 8.
    //  4x4 = 16 buttons
    const byte numRows = 6;
    //const byte numRows = 6;
    const byte numCols = 8;
    //const byte numCols = 8;
    // This key map will be used to define what keypress is sent to
    //  the computer when a key on the keypad is pressed.
    char keyMap[numRows][numCols] = { 
       {'1','2','3','4','5','6','7','8'},
       {'A','B','C','D','E','F','G','H'},
       {'Q','R','S','T','U','V','W','X'},
       {'9','0','+','-','u','d','l','r'},     
       {'I','J','K','L','M','N','O','P'},   
       {'Y','Z','E','B','C','H',' ','.'}};
    
    
    //char keyMap[numRows][numCols] = {
      //{'1','2','3','4'},
      //{'q','w','e','r'},
      //{'a','s','d','f'},
      //{'z','x','c','v'}};
    
      
       
     // Create a new sx1509Class object
    sx1509Class sx1509(SX1509_ADDRESS, resetPin, interruptPin);
    
    void setup()
    {
      // This example will use a Leonardo to send USB keypresses to
      //  the computer its connected to. The 'Keyboard.' statements
      //  can easily be replaced by Serial.print's, etc.
      //#ifdef HID_ENABLED
      //Keyboard.begin();
      //#else
      Serial.begin(9600);
      //#endif
      
        // initialize the digital pin as an output.
      pinMode(run_led, OUTPUT);
     digitalWrite(run_led, LOW); // run led off
      
      delay(10000); // wait for serial monitor
      
      // Must first initialize the sx1509:
      int x = 0;
      x = sx1509.init();
      if (x)
      {
      Serial.println("SX1509 Init OK");
      }
      else
      {
      Serial.println("SX1509 Init Failed");  
      }
      
      // In order to use the keypad, the clock must first be
      // configured. We can call configureClock() with the default
      // parameters (2MHz internal oscillator, no clock in/out).
      sx1509.configClock();
      // Next call the keypad function with the number of rows
      //  and columns.
      //sx1509.keypad(numRows, numCols);  // Basic keypad init
      // There are two optional parameters in the keypad method:
      //  sleepTime and scanTime. Each of these values can be between
      //  0 and 7. If not set, these values default to 0 (sleep off
      //  scan time set to 1ms).
    
      byte sleepTime = 7;
      byte scanTime = 5;  // Scan time per row <--<<<< 5 min for T3
      
      sx1509.keypad(numRows, numCols, sleepTime, scanTime);  // Advanced keypad init
      // We can also debounce the keypad inputs. The debounceConfig
      //  method takes one parameter. Similar to the scanTime it's a
      //  3-bit value (0-7). This value must be <= scanTime!
      byte debounceTime = 5;   // The debounce config value
      sx1509.debounceConfig(debounceTime);
    }
    
    //////////////////////////////////
    //// Loop Variables  /////////////
    //////////////////////////////////
    unsigned int keyData;  // The raw data from the key press register
    unsigned int previousKeyData = 0;  // previously read raw data
    byte activeRow;  // The row of the button being pressed
    byte activeColumn;  // The column of the button being pressed
    // These variables are used to emulate a key-hold. While the key
    //  is held down, there's a long delay before the second character
    //  is printed. Then a shorter delay between the remaining key presses
    unsigned int holdCount = 0;
    // This behavior is highly dependent on scanTime and debounceConfig
    //  which are set in the setup.
    const byte holdCountMax = 25;
    // These releaseCount variables 
    //  The keypad engin on the SX1509 doesn't generate an interrupt
    //  when a key is relased. So we'll use this counter to generate
    //  releases.
    unsigned int releaseCount = 0;  // Our counter
    unsigned int releaseCountMax = 100;  // Top, in about milliseconds
    
    // The loop will poll the interrupt pin. If the pin
    //  is pulled low by the SX1509, we'll read the keypad data and
    //  sort it into row and column, and send the corresponding key
    //  press out to the computer.
    void loop()
    {
      //delay(500);
      digitalWrite(run_led, HIGH);   // turn the LED on (HIGH is the voltage level)
      //delay(500);
      
      // The interrupt is active low, and pulled-up otherwise.
      //  The interrupt will be activated whenever a key press is read
      
      
      //int y = 0;
      //y = digitalRead(interruptPin);
      //Serial.println(y,DEC); 
      
      if (!digitalRead(interruptPin))
      {
            
        // readKeyData() returns a 16-bit word of data. The lower 8-bits 
        //  represent each of the up-to 8 rows. The upper 8-bits
        //  correspond to the columns. A 1 in a bit position means
        //  that a button in that row or column is being pressed.
        keyData = sx1509.readKeyData();
        
        // Next, we'll sort out which row and column are being pressed.
        //  And we'll send out a keypress over USB HID  
        activeRow = keyData & 0xFF;  // The row is the lower 8-bits
        activeColumn = keyData >> 8;  // column is the upper 8-bits
        // The getBitPosition functio will return which bit is our 1
        activeRow = getBitPosition(activeRow);
        activeColumn = getBitPosition(activeColumn);
        
        // If it's a new button press spit it out, reset hold delay
        if (keyData != previousKeyData)
        {
          holdCount = 0;
          // Keyboard.write is a Leonardo-specific Arduino function.
          //  It'll perform a key press and release just like any
          //  keyboard connected to your computer. For testing, this
          //  could easily be replaced by
          //#ifdef HID_ENABLED      
          //Keyboard.write(keyMap[activeRow][activeColumn]);
          //#else
          Serial.println(keyMap[activeRow][activeColumn]);
          //#endif
        }
        else
        {
          holdCount++;  // Increment holdCount
          // This works as something of a key-press delay. Hold
          //  down a key on your computer to see what I'm talking
          //  about. After the initial delay, all characters following
          //  will stream out quickly.
          if (holdCount > holdCountMax)
          {
           // #ifdef HID_ENABLED      
            //Keyboard.write(keyMap[activeRow][activeColumn]);
            //#else
            Serial.println(keyMap[activeRow][activeColumn]);
            //#endif
          }
        }
        // Reset release count since there's been a key-press
        releaseCount = 0;
        // Set keyData as previousKeyData
        previousKeyData = keyData;
      }
      
      // If no keys have been pressed we'll continuously increment
      //  releaseCount. Eventually creating a release, once the count
      //  hits the max.
      releaseCount++;
      if (releaseCount == releaseCountMax)
      {
        releaseCount = 0;
        previousKeyData = 0;
      }
      delay(1);  // This gives releaseCountMax a more intuitive unit
      digitalWrite(run_led, LOW);    // turn the LED off by making the voltage LOW
    } // EOL
    
    // This function scours a byte and returns the position of the 
    //  first byte it sees a 1. Great if our data bytes only have
    //  a single 1 in them! Should return 0-7 if it sees a 1, 255 otherwise
    byte getBitPosition(byte dataByte)
    {
      for (int i=0; i<8; i++)
      {
        if (dataByte & (1<<i))
        {
          return i;
        }
      }
      return 255;  // Otherwise return an error
    }
    Last edited by t3andy; 03-17-2013 at 03:09 PM.

  2. #2
    Senior Member
    Join Date
    Nov 2012
    Posts
    412
    Attached pics
    Attached Files Attached Files
    Last edited by t3andy; 03-17-2013 at 01:27 AM.

  3. #3
    Senior Member
    Join Date
    Nov 2012
    Posts
    412
    BTW ... In our testing of the tact keyboard, the SX1509 "on chip" adjustable de-bounce settings are awesome. This relieves the Teensy 3 of this slow "cycle stealing", mundane task. This also includes the auto keyboard scanning.
    Last edited by t3andy; 03-21-2013 at 03:32 PM.

  4. #4
    Junior Member
    Join Date
    Feb 2013
    Posts
    11
    can this detect more than one key at a time? (and if so is there a max?)

  5. #5
    Senior Member
    Join Date
    Nov 2012
    Posts
    412
    No - how would SX1509 detect two keypresses with only one interrupt?
    I see where you are coming from... like holding down the shift or control key with another key to expand the detected keypresses.
    The SX1509 detects if you hold down one key just like on the PC. See software above.
    Last edited by t3andy; 03-25-2013 at 09:03 AM.

  6. #6
    Member
    Join Date
    Dec 2012
    Location
    Adelaide, SA
    Posts
    70
    Yes of course you can, you'll get successive interrupts for each key held during a full matrix scan, and it will continue scanning after you read out the key row/col.

    I don't think there is a maximum, as you can handle buffering them yourself, but if you want full NKRO you'll need a diode on each key in the matrix, of course.

    - Peter

  7. #7
    Senior Member
    Join Date
    Nov 2012
    Posts
    412
    but if you want full NKRO you'll need a diode on each key in the matrix, of course.
    64 diodes added to this small breakout board? Sorta defeats its small form factor.

    Yes of course you can, you'll get successive interrupts for each key held during a full matrix scan
    Before you wire up 64 diodes, and to make 100% sure, contact the Sparkfun demo software/hardware author - Jim Lindblom.



    --------------------------
    KIS --> keep it simple
    Last edited by t3andy; 03-25-2013 at 01:53 PM.

  8. #8
    Member
    Join Date
    Dec 2012
    Location
    Adelaide, SA
    Posts
    70
    ... or read the datasheet.

  9. #9
    Junior Member
    Join Date
    Apr 2013
    Posts
    8
    This is definitely going on my "shopping list". My project, controls for a flight simulator, will eventually have a lot of tactile buttons, plus a small keyboard (a bit bigger than this one.)

  10. #10
    Junior Member
    Join Date
    Nov 2013
    Posts
    6
    Forgive me for bringing up such an old post, but I am just learning about these things.

    Could I modify this using simple mechanical switches like cherry reds and achieve the same results?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •