Shop OBEX P1 Docs P2 Docs Learn Events
4x4 Keypad With Four I/O Pins (using shift registers) — Parallax Forums

4x4 Keypad With Four I/O Pins (using shift registers)

Duane DegnDuane Degn Posts: 10,588
edited 2013-10-12 21:53 in Propeller 1
I'm working on a terminal for a CNC controller.

After adding TV, VGA, keyboard and a mouse, I was starting to get low on pins. I wanted to include a 4x4 keypad as an input device but I didn't want to use eight I/O pins to interface with it.

I'm sure there are lots of better solutions, but I have lots of 74xx595 serial to parallel shift registers and several 74xx165 parallel to serial shift registers. I used one of each to interface with the keypad.

Four of the eight pins of the chips are used. It would be possible to use the extra pins to control additional inputs and outputs.

I wired up the shift registers before having a clear idea of who I'd program them. I figured I should be able to share clock and latch lines and I also shared the data line. I figured I'd need to control the chips' enable pins and I thought I could use the enable pins as chip select pins of SPI devices. Once I got around to writing the code, I realized I needed to be able to turn the '165 on and off but that the '595 chip needed to be continuously active. In hindsight, I see I could have tied the '595 enable pin low.

Another "hindsight" realization was the '165 chip clock the "A" input in last. While I only need to clock four output clocks, I have to clock a full eight cycles to retrieve the input bits.

All attach the code in case anyone is interested in it. I'm also including some of it inline to make it easier for people to see how I took care of shifting bits out and in. I'm curious if any of you have ideas on how it could have possible been done better?
CON

  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000


  DATA_PIN = 0
  CLOCK_PIN = 1
  LATCH_PIN = 2
  CS_165_PIN = 3
  CS_595_PIN = 4


  KEYPAD_STACK = 32


  KEYPAD_BUFFER_POWER_OF_2 = 4  ' Use this constant to change buffer size.
  KEYPAD_BUFFER_SIZE = 1 << KEYPAD_BUFFER_POWER_OF_2 '16
  KEYPAD_BUFFER_MAX_INDEX = KEYPAD_BUFFER_SIZE - 1 ' Used to wrap head and tail pointers 
  
  KEYPAD_COLUMNS = 4
  KEYPAD_ROWS = 4
  KEYPAD_SIZE = KEYPAD_COLUMNS * KEYPAD_ROWS
  MAX_COLUMN_INDEX = KEYPAD_COLUMNS - 1
  MAX_ROW_INDEX = KEYPAD_ROWS - 1


  BITS_TO_DISPLAY = KEYPAD_SIZE


  UNUSED_INPUTS = 4 ' '165 inputs to clock in without reading
                    ' These inputs may be used for other purposes.
                     
  QUOTE = 34
  KEYPAD_LOC_X = 0
  KEYPAD_LOC_Y = 4


  BITS_IN = KEYPAD_COLUMNS
  
  DEBUG_BAUD = 115_200


  NO_KEY_PRESS = 0


VAR


  long stack[KEYPAD_STACK]
  long keypadBits, previousKeypadBits


  byte keypadBuffer[KEYPAD_BUFFER_SIZE]
  byte head, tail
  
OBJ
                             
  Com : "Parallax Serial Terminal"        
  
PUB Setup


  Com.Start(DEBUG_BAUD)                                        
 
  result := cognew(Keypad, @stack)
  
  Com.Str(string("Keypad started in cog #"))
  Com.Dec(result)
  Com.Char(13)
  waitcnt(clkfreq * 3 + cnt)
  Com.Clear
  repeat
    if head <> tail
      Com.Position(KEYPAD_LOC_X, KEYPAD_LOC_Y - 3)
      Com.Str(string("Keypad Bits = %"))
      Com.Bin(previousKeypadBits, BITS_TO_DISPLAY) ' Display previousKeypadBits since
                                                   ' keypadBits spends much of the time
                                                   ' cleared.
      Com.Position(KEYPAD_LOC_X, KEYPAD_LOC_Y - 1)
      if keypadBuffer[tail] == NO_KEY_PRESS
        Com.Str(string("No Key   ")) 
      else
        Com.Str(string("Key = ", QUOTE))
        Com.Char(keypadBuffer[tail])
        Com.Char(QUOTE)
      tail++
      tail &= KEYPAD_BUFFER_MAX_INDEX ' zero tail if it passes end of buffer    


PUB Keypad | rowData, outputBit
   
  outa[CS_165_PIN] := 1
  dira[CS_165_PIN] := 1
  outa[CS_595_PIN] := 0 ' The enable pin could be tied low.
  dira[CS_595_PIN] := 1
  dira[CLOCK_PIN] := 1
  dira[LATCH_PIN] := 1
  dira[DATA_PIN] := 1
                                      
  repeat
    rowData := 1
    previousKeypadBits := keypadBits
    keypadBits := 0                                    
    repeat KEYPAD_COLUMNS
      dira[DATA_PIN] := 1
      outputBit := rowData
      repeat KEYPAD_COLUMNS ' shift out active column
                            ' The four unused output pins may be used
                            ' for other purposes.
        outa[DATA_PIN] := outputBit
        outa[CLOCK_PIN] := 1
        outputBit >>= 1
        outa[CLOCK_PIN] := 0
      outa[CS_165_PIN] := 0
      outa[LATCH_PIN] := 0
      outa[LATCH_PIN] := 1  ' latch both output and input
      dira[DATA_PIN] := 0
      repeat UNUSED_INPUTS ' since I used the wrong four pins on the '165 chip
        outa[CLOCK_PIN] := 1
        outa[CLOCK_PIN] := 0
         
      repeat KEYPAD_ROWS
        keypadBits <<= 1
        keypadBits += ina[DATA_PIN] 
        outa[CLOCK_PIN] := 1
        outa[CLOCK_PIN] := 0
      rowData <<= 1  ' Move bit to next column.
      outa[CS_165_PIN] := 1 ' don't gather input from next latch                     
      outa[LATCH_PIN] := 1  ' latch output so it's ready for real output
      outa[LATCH_PIN] := 0  ' The output from this latch isn't used.
   
    if keypadBits <> previousKeypadBits
      previousKeypadBits := keypadBits
      keypadBuffer[head++] := keypadCharacters[>|keypadBits]
      head &= KEYPAD_BUFFER_MAX_INDEX  


DAT


' The character order was determined by running the program
' and observing the bit position each button produced.
' These characters will likely need to be rearranged
' when using a keypad from a different vendor or
' if the wire order connection the shift registers to
' the keypad is changed.


keypadCharacters        byte NO_KEY_PRESS, "2580"
                        byte "369F"
                        byte "ABCD"
                        byte "137E"

I have some simple '165 code here in case anyone is interested (I'm pretty sure there are lots of '165 objects around).

Comments

  • Cluso99Cluso99 Posts: 18,069
    edited 2013-10-08 15:52
    Duane: Perhaps you could post a block diag or circuit. We might be able to comment better with this.
    Thanks for describing your project and posting code.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-08 16:42
    Cluso99 wrote: »
    Duane: Perhaps you could post a block diag or circuit. We might be able to comment better with this.
    Thanks for describing your project and posting code.

    That's a good idea.

    I'll try to make a better schematic. I do have connections listed in the comments of the code. These comments aren't included in the code I posted in the code block but they are included in the Spin file.

    Here are the comments with partial schematic.
    CON{{
      ****** Public Notes ******
    
    
      by Duane Degn
      October 2013
    
    
      This object reads a 4x4 keypad using
      both a 74xx595 serial to parallel shift
      register and a 74xx165 parallel to serial
      shift register.
      The two shift registers share data, clock
      and latch pins. The enable pin of the '595
      chip could be tied low.
      This arrangement of shift register allows
      the 4x4 keypad to be read with four I/O pins
      of the Propeller (though five are used in
      this example).
      
      
    }}
    
    
    CON
    {{
      Note:
      I don't think my columns and rows match what is shown in
      the schematic. The bits in the output didn't match what
      I was expecting. This isn't really a problem since I
      can adjust the list of characters stored in the
      "keypadCharacters" array.
      It's important that columns and rows aren't mixed
      together when connecting to the shift registers.
      All the column pins need to connected to either
      the '595 outputs or the '165 inputs. It doesn't
      really matter which chip is connected to the
      columns as long as all the column pins are
      connected with the same chip.
      
    }}
    {{
    
    
      Keypad Front
      
      1  2  3  A
      4  5  6  B
      7  8  9  C
      *  0  #  D
    
    
      Schematic:
    
    
    Looking at the front of the 4x4 keypad...
       1    2    3    4
    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
    &#9474;                    &#9474;
    &#9474;  1    2    3    A  &#9474; 5 
    &#9474;                    &#9474;
    &#9474;  4    5    6    B  &#9474; 6
    &#9474;                    &#9474;
    &#9474;  7    8    9    C  &#9474; 7 
    &#9474;                    &#9474;
    &#9474;  *    O    #    D  &#9474; 8
    &#9474;                    &#9474;
    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472; &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474; &#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
           &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9507;&#9472;&#9472;&#61629;&#61630;&#9472;&#9488; 10K&#937; Pull-Down on each input.       
           &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9507;&#9532;&#9472;&#9472;&#61629;&#61630;&#9472;&#9515; 
           &#9474;&#9474;&#9474;&#9474;&#9474;&#9507;&#9532;&#9532;&#9472;&#9472;&#61629;&#61630;&#9472;&#9515;        
           &#9474;&#9474;&#9474;&#9474;&#9507;&#9532;&#9532;&#9532;&#9472;&#9472;&#61629;&#61630;&#9472;&#9515;
           &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;     &#9474; 
           12345678     &#61464;
    
    
    *************************************************
        74HC595 Shift Register Schematic
    *************************************************    
     
            Motorola's pin names in the following diagram:
                    
                             &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
    to pin #2 of keypad  QB  &#9515;1•  16&#9507;  Vcc                 
    to pin #3 of keypad  QC  &#9515;2   15&#9507;  QA to pin #1 of keypad                               
    to pin #4 of keypad  QD  &#9515;3   14&#9507;  A (Data in from Propeller) DATA_PIN             
                         QE  &#9515;4   13&#9507;  Output Enable              CS_595_PIN (could be tied low)
                         QF  &#9515;5   12&#9507;  Latch Clock                LATCH_PIN
                         QG  &#9515;6   11&#9507;  Shift Clock                CLOCK_PIN
                         QH  &#9515;7   10&#9507;  RESET 
                        gnd  &#9515;8    9&#9507;  QH' (not connected) 
                             &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;       
                                        
    
    
    *************************************************
        74HC165 Shift Register Schematic
    ************************************************* 
                    
                      __  &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
        LATCH_PIN  SH/LD  &#9515;1•  16&#9507;  Vcc                 
        CLOCK_PIN    CLK  &#9515;2   15&#9507;  CLK INH                    CS_165_PIN 
                       E  &#9515;3   14&#9507;  D to pin #8 of keypad   ' It would be better to have used       
                       F  &#9515;4   13&#9507;  C to pin #7 of keypad   ' E through H as inputs.    
                       G  &#9515;5   12&#9507;  B to pin #6 of keypad   ' A is the last input to be clocked in.   
                     _ H  &#9515;6   11&#9507;  A to pin #5 of keypad
     (not connected) Qh   &#9515;7   10&#9507;  SER (not connected)
                     GND  &#9515;8    9&#9507;  Qh (Data out to Propeller) DATA_PIN
                          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;      
    
    
     The four input pins connected to the keypad should each have 10K&#937; pull-down resistor.
                                             
    }}
    

    I don't think the code could be written to use fewer pins (fewer than four that is). Since the data lines are shared, the '165 needs to be disabled while bits are clocked out to the '595 or the data from the '165 chip would interfere with the data going out to the '595.

    The code posted works fine but I'm often surprised to see how others use shift registers in clever ways which require few than expected I/O pins or less code than I had supposed.

    The obvious improvement to the way I did it would be to use the other set of four input pins on the '165. I had assumed the "A" input would be the first to be clocked in since the "0" output on the '595 is the first to be clocked out.

    As I said, I'll try to get a better schematic to post, but since this already works, it's not a high priority. If someone would really like to see an improved schematic let me know and I'll make an extra effort to get it posted soon.

    I was pleased not to need eight I/O pins to read the keypad. I may find a use for the unused output and input pins.
  • jmgjmg Posts: 15,173
    edited 2013-10-09 12:33
    If you want to use just one chip, another popular shifter scanner is the (HEF)4021. This has CK,DI,PL and 7 IN and 3 OP pins.
    The 4000 series have light drive so do not need drive protection resistors.

    You wire the 3 OP to 3 rows, and tie the 4th row to GND.
    To check any key, you shift out L to all 3, and check for any IP LO -> Have Key.
    Then you release the L from OP one at a time, and check IP.
    If the IP is still low with all 3 released, it is on the 4th (gnd) row, and you can decode 4x8 using this.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-09 14:58
    jmg wrote: »
    If you want to use just one chip, another popular shifter scanner is the (HEF)4021. This has CK,DI,PL and 7 IN and 3 OP pins.
    The 4000 series have light drive so do not need drive protection resistors.

    You wire the 3 OP to 3 rows, and tie the 4th row to GND.
    To check any key, you shift out L to all 3, and check for any IP LO -> Have Key.
    Then you release the L from OP one at a time, and check IP.
    If the IP is still low with all 3 released, it is on the 4th (gnd) row, and you can decode 4x8 using this.

    I'll admit to not understanding a lot of what you just wrote, but I won't ask any questions until I have a look at the 4021 datasheet. Thanks for the suggestion. I'll probably include some in my next electronics order to experiment with.

    Here's the way I have the '595 and '165 wired up.
    {{
    
      Schematic:
    
    
                                      Looking at the front of the 4x4 keypad...
                                         1    2    3    4
                                      &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
                                      &#9474;                    &#9474;
                                      &#9474;  1    2    3    A  &#9474; 5 
                                      &#9474;                    &#9474;
                                      &#9474;  4    5    6    B  &#9474; 6
                                      &#9474;                    &#9474;
                                      &#9474;  7    8    9    C  &#9474; 7 
                                      &#9474;                    &#9474;
                                      &#9474;  *    O    #    D  &#9474; 8
                                      &#9474;                    &#9474;
                                      &#9474;      12345678      &#9474;
                                      &#9492;&#9472;&#9472;&#9472;&#9472;&#9472; &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474; &#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                                             &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9507;&#9472;&#9472;&#9472;&#9472;&#61629;&#61630;&#9472;&#9488; 10K&#937; Pull-Down on each input.       
                                             &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9507;&#9532;&#9472;&#9472;&#9472;&#9472;&#61629;&#61630;&#9472;&#9515; 
                                             &#9474;&#9474;&#9474;&#9474;&#9474;&#9507;&#9532;&#9532;&#9472;&#9472;&#9472;&#9472;&#61629;&#61630;&#9472;&#9515;        
                                             &#9474;&#9474;&#9474;&#9474;&#9507;&#9532;&#9532;&#9532;&#9472;&#9472;&#9472;&#9472;&#61629;&#61630;&#9472;&#9515;
                                             &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;       &#9474; 
                                             &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;       &#61464;
                                             &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;
                                             &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
                           &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9496;&#9474;&#9474;&#9474;&#9474;&#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;&#9474; 
                          &#9484;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9496;&#9474;&#9474;&#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;&#9474;&#9474;
                         &#9484;&#9532;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9496;&#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;&#9474;&#9474;&#9474;
                         &#9474;&#9474;&#9474;                 &#9474;   3.3V  &#9474;&#9474;&#9474;&#9474;
                         &#9474;&#9474;&#9474;       74HC595   &#9492;&#9472;&#9472;&#9488; &#61463;    &#9474;&#9474;&#9474;&#9474;
                         &#9474;&#9474;&#9474;&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;&#9474; &#9507;&#9472;&#9488;  &#9474;&#9474;&#9474;&#9474; 0.1µF Capacitor
    to pin #2 of keypad  &#9474;&#9474;&#9492;&#9515;1 Q1        Vcc 16&#9507;&#9532;&#9472;&#9515;&#61612;&#61613;&#61614; &#9474;&#9474;&#9474;&#9474;                  
    to pin #3 of keypad  &#9474;&#9492;&#9472;&#9515;2 Q2         Q0 15&#9507;&#9496; &#9474; &#61464;  &#9474;&#9474;&#9474;&#9474; to pin #1 of keypad                               
    to pin #4 of keypad  &#9492;&#9472;&#9472;&#9515;3 Q3    Data In 14&#9507;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9488;&#9474;&#9474;&#9474;&#9474;                               
                           X&#9515;4 Q4    /Enable 13&#9507;&#9472;&#9472;&#9532;&#9472;&#9472;&#9488;&#9474;&#9474;&#9474;&#9474;&#9474; (/Enable could be tied low)
                           X&#9515;5 Q5      Latch 12&#9507;&#9472;&#9472;&#9532;&#9472;&#9488;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;                     
                           X&#9515;6 Q6      Clock 11&#9507;&#9472;&#9472;&#9532;&#9488;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;                       
                           X&#9515;7 Q7      Reset 10&#9507;&#9472;&#9472;&#9515;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;                   
                         &#9484;&#9472;&#9472;&#9515;8 GND   Data Out 9&#9507;X &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;        
                         &#9474;  &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;  &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;      
                         &#9474;                        &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;
     Propeller I/O Pins  &#9474;                        &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;
      DATA_PIN   &#61615;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9532;&#9532;&#9532;&#9515;&#9474;&#9474;&#9474;&#9474;
      CLOCK_PIN  &#61609;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9523;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9496;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;
      LATCH_PIN  &#61609;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9532;&#9523;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9496;&#9474;&#9474;&#9474;&#9474;&#9474;&#9474;
      CS_165_PIN &#61609;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9532;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;&#9474;  &#9474;&#9474;&#9474;&#9474;&#9474;&#9474;
      CS_595_PIN &#61609;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9532;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9532;&#9472;&#9472;&#9496;&#9474;&#9474;&#9474;&#9474;&#9474;
     (CS_595_PIN is      &#9474;&#9474;&#9474;                     &#9474;&#9474;   &#9474;&#9474;&#9474;&#9474;&#9474;
      optional. The      &#9474;&#9474;&#9474;     74HC165         &#9474;&#9507;&#9472;&#9488; &#9474;&#9474;&#9474;&#9474;&#9474;
      /Enable pin on     &#9474;&#9474;&#9474;&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488; &#9474;&#9474;&#61612;&#61613;&#61614;&#9474;&#9474;&#9474;&#9474;&#9474; 0.1µF Capacitor
      the '595 may be    &#9474;&#9474;&#9492;&#9515;1 Latch     Vcc 16&#9507;&#9472;&#9532;&#9496; &#61464; &#9474;&#9474;&#9474;&#9474;&#9474;             
      tied to ground.)   &#9474;&#9492;&#9472;&#9515;2 Clock /Enable 15&#9507;&#9472;&#9496;    &#9474;&#9474;&#9474;&#9474;&#9474; 
                         &#9474; X&#9515;3 E           D 14&#9507;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9532;&#9532;&#9532;&#9496;to pin #8 of keypad          
                         &#9474; X&#9515;4 F           C 13&#9507;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9532;&#9532;&#9496; to pin #7 of keypad       
                         &#9474; X&#9515;5 G           B 12&#9507;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9532;&#9496;  to pin #6 of keypad      
                         &#9474; X&#9515;6 H           A 11&#9507;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9496;   to pin #5 of keypad
                         &#9474; X&#9515;7 /Qh       SER 10&#9507;X     &#9474;
                         &#9507;&#9472;&#9472;&#9515;8 GND   Data Out 9&#9507;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;   
                         &#9474;  &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;      
                         &#61464;             The four input pins connected to the keypad
                                       should each have 10K&#937; pull-down resistor.
                                             
                                    ' It would have been better to have used
                                    ' the E through H as inputs.
                                    ' Input A is the last input to be clocked in.
    }}
    

    As I've mentioned a couple of times, I used the wrong four pins of the '165.

    Do I need to worry about letting the four unused inputs of the '165 float?

    One thing I'd like to figure out is a way to use these shift registers with other SPI chips. I think if I do use other SPI chips in a project, I should separate the two data lines so there's a MOSI and MISO line.

    I suppose even with other SPI devices, I could leave the enable pin of the '595 tied low (though it's not presently) since I doubt it would hurt the '595 to be shifting bits while the MOSI line is used on another device. The keypad garbage data won't be read in with the '165 disabled.

    I actually had 8 pins I could have used for the keypad but it wouldn't have left many to spare and I'm not sure I won't need a few more I/O pins for something else.
  • jmgjmg Posts: 15,173
    edited 2013-10-09 17:11
    Duane Degn wrote: »
    I'll admit to not understanding a lot of what you just wrote, but I won't ask any questions until I have a look at the 4021 datasheet.

    The HEF4021 is essentially a '165 + 3/8 of a '595, in one package. (on an IP/OP basis)
    The last 3 bits of the 8 bit shifter, come out to pins.

    So you give it 8 clocks, and the first 3 bits loaded, appear on the pins, then you pulse PL, and 8 more clocks shift out the loaded IPs
    Duane Degn wrote: »

    Do I need to worry about letting the four unused inputs of the '165 float?

    It is a good idea to tie unused input pins to something, as a floating pin can draw more power from Vcc.
    - usually whatever is nearest will do.
  • ChrisGaddChrisGadd Posts: 310
    edited 2013-10-10 11:40
    If you want to save even more pins, you can try this single I/O-pin 4x4 keypad reader. Just requires 8 resistors and a capacitor to use.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-10 12:05
    ChrisGadd wrote: »
    If you want to save even more pins, you can try this single I/O-pin 4x4 keypad reader. Just requires 8 resistors and a capacitor to use.

    Now I think I should have looked around a bit more before starting wiring up my shift registers. The next 4x4 keypad I use, I'll try your object. If I end up needing more pins in my current project, I'll also try your object.

    I think I ought to post my plans to the forum before I start them so I can be told the better options available.

    Thanks for pointing out your object. It sure seems like a great idea.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-10 13:03
    I was using an identical keypad to the one I've mounted in my enclosure to test the software. As I mentioned, the test keypad worked fine. I did have a problem when switching to the keypad mounted in the enclosure though.

    As I mentioned in this thread, I'm using a TV with the keypad as a controller for my CNC machine.

    attachment.php?attachmentid=103490&d=1377232308

    When I use the keypad with the TV I get a lot of false keypresses. Most of these false keypresses appear to be from the top row of keys. If I move the TV control board away from the keypad and wires, the noise goes away.

    My first of two ideas to reduce the noise would be to use some metal shielding between the TV control board and the keypad/wires. My second idea is to use stronger pull-down resistors on the '165 input pins.

    Do one of these ideas sound better than the other? If I use a stronger pull-down resistor any suggested values? I'm currently using 10K ohm resistors on the pull-downs.

    Any other ideas?
  • KMyersKMyers Posts: 433
    edited 2013-10-10 13:47
    Hi Duane,

    The wires from the keypad, are they twisted or open type wires? Shieding would probably help. In the old days I would use aluminmum foil at hi rf fields. Possibly cardboard with foil on it seperated from bottom/top of boards??

    Still like that case!!!
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-10 15:10
    KMyers wrote: »
    Hi Duane,

    The wires from the keypad, are they twisted or open type wires? Shieding would probably help. In the old days I would use aluminmum foil at hi rf fields. Possibly cardboard with foil on it seperated from bottom/top of boards??

    Still like that case!!!

    The wire is open. 8 individual wire (like the wire used in indoor phone wiring).

    I realize I have a lot of wire running through the enclosure. There an 18-pin header above the VGA port in the picture I posted. The 18 pins control the step and direction pulses to the stepper controller. It will also need to be protected from the TV driver noise.

    I'm debating between making metal sleeves for the various wires with some 2" copper tape I have or to wrap the TV driver board in the copper tape. I'm afraid wrapping the driver board with copper tape would cause heat issues with the TV board.

    I was leaning towards encasing either the wires or drive board with metal, do you really think just a metal sheet between the two boards would stop the noise? I was thinking I'd need a faraday cage?

    I'll wait a bit before I try anything to see if anyone else has ideas of how to block the noise.

    I'll probably try the metal and cardboard barrier you suggest since it's the easiest to implement.

    I'm hoping once I have my CNC router going, cutting holes in enclosures will be easier. The cutouts I made look pretty good as long as you don't look carefully (or with your eyes open).
  • KMyersKMyers Posts: 433
    edited 2013-10-10 15:33
    I think it looks great, with only one good arm its beyond what could achieve! I once had a generator to create a pilot control for agc on a string of amplifiers. They put a pager system next to my tower that would kill my control signal. The tin foil worked until I get a modern sig gererator.

    LOL about the faraday cage, times I could have used one also!
  • kwinnkwinn Posts: 8,697
    edited 2013-10-10 17:30
    Duane Degn wrote: »
    I was using an identical keypad to the one I've mounted in my enclosure to test the software. As I mentioned, the test keypad worked fine. I did have a problem when switching to the keypad mounted in the enclosure though.

    As I mentioned in this thread, I'm using a TV with the keypad as a controller for my CNC machine.


    When I use the keypad with the TV I get a lot of false keypresses. Most of these false keypresses appear to be from the top row of keys. If I move the TV control board away from the keypad and wires, the noise goes away.

    My first of two ideas to reduce the noise would be to use some metal shielding between the TV control board and the keypad/wires. My second idea is to use stronger pull-down resistors on the '165 input pins.

    Do one of these ideas sound better than the other? If I use a stronger pull-down resistor any suggested values? I'm currently using 10K ohm resistors on the pull-downs.

    Any other ideas?

    Either one should work, so whatever is easiest. Try 1K pulldowns as a starting point.

    I have used some aluminum foil with mactac on both sides as insulator for a shield on occasions. Works well as long as you leave an area of foil bare to connect to ground. A copper clad pcb also works.
  • Cluso99Cluso99 Posts: 18,069
    edited 2013-10-10 19:45
    maybe you are reading the input 4 pins too quickly after driving the other 4 pins. Try a couple of nops after setting the output pins, or read them a couple of times and compare them.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-10 22:09
    kwinn wrote: »
    Either one should work, so whatever is easiest. Try 1K pulldowns as a starting point.

    I have used some aluminum foil with mactac on both sides as insulator for a shield on occasions. Works well as long as you leave an area of foil bare to connect to ground. A copper clad pcb also works.

    I don't think I have room for copper clad PCB material. I think whatever I use will have to somewhat flexible in order to fit between all the parts I'm jamming in the enclosure.

    I'm glad you said something about grounding the shield; I hadn't thought of it.

    Thanks.
    Cluso99 wrote: »
    maybe you are reading the input 4 pins too quickly after driving the other 4 pins. Try a couple of nops after setting the output pins, or read them a couple of times and compare them.

    The code (at least for now) is in Spin (see post #1 of thread). I'd think Spin is slow enough to let the pins be driven high? I'll try reading the inputs a few times to see if that would help. If the noise is short in duration, it shouldn't be the same with multiple reads. I could read the inputs four times and only accept inputs which remained constant over all four reads (or something like that).

    Even if a software solution could be found, I'll probably need to address the hardware side of the problem since I don't think there will be a software trick that will clean up signals to the stepper driver.

    Thanks for the suggestions.
  • LoopyonionLoopyonion Posts: 24
    edited 2013-10-11 00:38
    Hi, Im not sure if I can be any assistance, but I did a little experimentation into a method of eliminating noise on inputs for a project im doing. In a nutshell, an MCP3208 with 5v power, the MCP3208 object, tying each of the MCP3208 inputs through a 10k resistor to 5v. Then, when the input is connected to 0v at one side, and the other to the MCP3208 input pin. On button press, the read value drops to 0 from whatever it was reading inactive. By increasing the sample time eliminates contact bounce, and the logic of - If ADC sample is less than 2000, then button pressed. This I found absorbs a fair bit of noise. 8 inputs of adjustable level/logic, and 3 IO pins used. And I know its not the devices intended use... but seems to work ok. Maybe the experts out there can say if its ok to do this?
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2013-10-11 03:33
    Oh boy, this shouldn't be complicated at all. For the record I would have just used the equivalent of a PCF8574 I2C I/O expander however the problem here is the software which is not taking contact bounce or EMI into account.

    There are quite a few different ways you can do a reliable keypad scan. The thing though to do with keypad scanning is to take it easy, don't rush it. If for instance you have all columns active so that you can sense any key press then once some key has been sensed you need to find out which column it's on so you start scanning through the column outputs one at a time (normally). To give each input a chance to settle you test the row inputs not after you select a new column but before you select it as it has had time from the last column select. If it's active then you can hang ten (hundred's of microseconds or even milliseconds) before you sample it again. If it is still active then you could accept as “good enough for me”. Once you encode a keypress or even no press you also want to compare this with the last key code so that you only pass a single code for each press. I like to encode these as standard ASCII representing the keys themselves and the null character is the code for no keys pressed.
    Although shielding could stop the noise it's not really necessary as it's not a high-speed databus that you are trying to shield, the keypad is running on simple I/O and just needs to be validated for a whole number of reasons.

    BTW, keypad contacts are necessarily "switches" as they could have hundreds of ohms contact resistance which combined with pin capacitance requires a delay for settling.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-11 10:03
    Oh boy, this shouldn't be complicated at all. For the record I would have just used the equivalent of a PCF8574 I2C I/O expander however the problem here is the software which is not taking contact bounce or EMI into account.

    Now you tell me. I needed to know to use a PCF8574 I2C I/O expander before my last electronic order. :smile:
    As I mentioned, I have a bunch of '595 and '165 chips and they also happen to be among the handful of ICs I've previously worked with.
    There are quite a few different ways you can do a reliable keypad scan. The thing though to do with keypad scanning is to take it easy, don't rush it. If for instance you have all columns active so that you can sense any key press then once some key has been sensed you need to find out which column it's on so you start scanning through the column outputs one at a time (normally). To give each input a chance to settle you test the row inputs not after you select a new column but before you select it as it has had time from the last column select. If it's active then you can hang ten (hundred's of microseconds or even milliseconds) before you sample it again. If it is still active then you could accept as “good enough for me”.

    The scanning is done in Spin so it's pretty slow already. I will add some code to check the input multiple times before deciding it's a valid press.
    Once you encode a keypress or even no press you also want to compare this with the last key code so that you only pass a single code for each press. I like to encode these as standard ASCII representing the keys themselves and the null character is the code for no keys pressed.

    Done and done. I'm glad I did this part right.
    if keypadBits <> previousKeypadBits
          previousKeypadBits := keypadBits
          keypadBuffer[head++] := keypadCharacters[>|keypadBits]
          head &= KEYPAD_BUFFER_MAX_INDEX  
    
    
    DAT
    
    
    ' The character order was determined by running the program
    ' and observing the bit position each button produced.
    ' These characters will likely need to be rearranged
    ' when using a keypad from a different vendor or
    ' if the wire order connection the shift registers to
    ' the keypad is changed.
    
    
    keypadCharacters        byte NO_KEY_PRESS, "2580"
                            byte "369F"
                            byte "ABCD"
                            byte "137E"
    

    The constant "NO_KEY_PRESS" equals zero.
    The keypresses (or NO_KEY_PRESS) is stored in a small circular buffer.

    I just noticed I have the columns and rows switched. I could switch them back by adding a half twist to the wires but the keypad works the same either way so I'll probably leave it as is.

    The code, as it is now, only reads the highest bit. Only one button will be noticed if more than one button is pressed.
    Although shielding could stop the noise it's not really necessary as it's not a high-speed databus that you are trying to shield, the keypad is running on simple I/O and just needs to be validated for a whole number of reasons.

    BTW, keypad contacts are necessarily "switches" as they could have hundreds of ohms contact resistance which combined with pin capacitance requires a delay for settling.

    The keypad code as posted in post #1 worked fine with my test pad. Even the keypad withing the enclosure works fine with the original code if I move the TV control board away from the wires.

    I'll try a software solution as suggested by Peter and Cluso99. I'm concerned even if I can get the keypad to work without shielding, I may still need shielding on the step and direction wires which pass by the same TV control board.

    BTW, I'm using the USB on the Protoboard to program both Propeller chips. I cut the traces to P30 and P31 and route them through a DPDT switch. The reset and ground lines are shared. When I want to program one of the Propellers, I just position the switch appropriately and load the program. Since the reset lines are shared both Propellers are reset so I need to make sure the other Propeller's program is stored in EEPROM.

    I've thought about using a 3PDT switch to also switch the reset line but all the three pole switches I've seen are really big. I can live with the double reset.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2013-10-12 20:55
    Duane Degn wrote: »

    I'll try a software solution as suggested by Peter and Cluso99. I'm concerned even if I can get the keypad to work without shielding, I may still need shielding on the step and direction wires which pass by the same TV control board.

    BTW, I'm using the USB on the Protoboard to program both Propeller chips. I cut the traces to P30 and P31 and route them through a DPDT switch. The reset and ground lines are shared. When I want to program one of the Propellers, I just position the switch appropriately and load the program. Since the reset lines are shared both Propellers are reset so I need to make sure the other Propeller's program is stored in EEPROM.

    I've thought about using a 3PDT switch to also switch the reset line but all the three pole switches I've seen are really big. I can live with the double reset.

    Good, but with the Prop outputs you shouldn't have to worry much at all as they are low-impedance and far less likely to be affected by the normal EMI you are seeing whereas the keypad inputs are at least 10K pull-down. Of course you could decrease the pull-down or add caps but as mentioned software is all that is needed. One thing though about the stepper lines is that it might be a good idea to add pull-up/downs to the step clock line (DIR doesn't matter) so that this isn't glitched during reset and power-up etc.

    As for the reset switch I would think that you only really need a single pole switching the receive line with the transmits diode OR'd together (with a pull-up). But a DPDT is a simple solution in your case. The other way you could do it is to hold the unwanted Prop (or Props) in reset so that only the active one responds in which case you just need a simple push-button for each Prop and a diode back to the serial reset. Push buttons are much more compact than any DPDT switch and you end up with a manual reset button for each Prop.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-12 21:53
    Good, but with the Prop outputs you shouldn't have to worry much at all as they are low-impedance and far less likely to be affected by the normal EMI you are seeing whereas the keypad inputs are at least 10K pull-down. Of course you could decrease the pull-down or add caps but as mentioned software is all that is needed.

    Reading the inputs twice was enough to eliminate the noise problem. I used bitwise "&" to make sure the inputs were high on both reads (I also tried three and four reads but two turned out to be enough).
    One thing though about the stepper lines is that it might be a good idea to add pull-up/downs to the step clock line (DIR doesn't matter) so that this isn't glitched during reset and power-up etc.

    I've heard of doing this on other motor controllers but I hadn't though to use them on the stepper controller. Thanks, I'll take your advice in this matter.
    As for the reset switch I would think that you only really need a single pole switching the receive line with the transmits diode OR'd together (with a pull-up). But a DPDT is a simple solution in your case. The other way you could do it is to hold the unwanted Prop (or Props) in reset so that only the active one responds in which case you just need a simple push-button for each Prop and a diode back to the serial reset. Push buttons are much more compact than any DPDT switch and you end up with a manual reset button for each Prop.

    I'll keep the diode ideas in mind if I do something like this again, but in this project I really like being able to switch both the RX and TX debug lines with the DPDT switch. I can switch the serial connection with the PC from one Prop to the other this way.

    I added some copper tape to the back side of the keypad and to the wires. I scrapped way the coating on the copper and soldered some wires to the copper in order to connect them to ground. The shielding reduced the amount of noise I was experiencing but it didn't eliminate it. Adding the software changes suggested in this thread took care of the rest of the noise (it probably would have taken care of all of it but then I wouldn't have been able to use my cool copper tape).

    attachment.php?attachmentid=104376&d=1381638778

    I'm marking the thread "Solved". Thanks for all your help. I have sure learned a lot on this forum.
    451 x 605 - 125K
    348 x 603 - 120K
Sign In or Register to comment.