AN2034 PSoC® 1 – Reading Matrix and Common Bus Keypads Author: Dave Van Ess, Rajiv Badiger Associated Project: Yes Associated Part Family: CY8C27xxx, CY8C29xxx, CY8C21x23, CY8C21x34,CY8C21x45, CY8C22x45, CY8C24x23, CY8C24x94, CY8C28xxx ® Software Version: PSoC Designer™ 5.4 Related Application Notes: None ® AN2034 shows how to use PSoC 1 to read mechanical keypads. It covers matrix and common bus keypads, in both polled and interrupt modes. Contents Introduction Introduction .......................................................................1 Matrix Keypad ...................................................................2 Algorithm ......................................................................2 C Function ....................................................................2 Decoding a Key Press ..................................................3 Debounce Mechanism ..................................................3 Making the Scanning Process Polled or Interrupt Driven.............................................................4 Example Project ...........................................................4 Common Bus Keypad .......................................................5 PSoC 1 Implementation................................................5 SAR ADC Input Voltages..............................................6 Determining Resistor Values ........................................7 Interrupt Driven Keypad Reading .................................7 Debouncing ..................................................................7 Example Project ...........................................................7 Summary ...........................................................................8 Appendix A: ‘C’ Code for Matrix Keypad Scanning Using Interrupt Method ......................................................9 Appendix B: ‘C’ Code for Common Bus Keypad Using Polling Method ...................................................... 14 Document History ............................................................ 17 Depending on how individual switches are connected, mechanical keypads are commonly available in two forms – matrix and common bus. A typical matrix keypad – the telephone keypad - is shown in Figure 1. In this keypad, each switch connects a unique pair of row and column wires. The number of I/Os (pins) required equals ROWS + COLUMNS. The number of switches supported is ROWS x COLUMNS. Figure 1. Matrix Keypad In a common bus keypad, one terminal of each switch is connected to a common bus wire as shown in Figure 2. www.cypress.com Document No. 001-40409 Rev. *E 1 PSoC® 1 - Reading Matrix and Common Bus Keypads Figure 2. Common Bus Keypad significant CPU time. If only a single key press needs to be detected, you can use the following algorithm instead: The number of I/Os required for a common bus keypad appears to equal the number of switches plus 1, however, a method exists that uses only one pin to read the common bus keypads. This application note shows how to use PSoC 1 to read both the matrix and common bus keypads. The associated projects are created using the PSoC Designer software tool. If you are new to the PSoC 1 device or the PSoC Designer development tool, it is recommended that you review the online tutorials. Matrix Keypad This section focuses on a typical 4x4 matrix keypad, but you can use the same technique with a matrix keypad of any dimensions. A matrix keypad can be connected to the PSoC 1 without using any external components as shown in Figure 3. Figure 3. Matrix Keypad Interface to PSoC 1 Drive all columns high simultaneously and read all rows Combine the above data to determine which switch is closed To understand how the algorithm works, consider the following example, where switch [1, 2] (row 1, column 2) is pressed. The algorithm reads the keypad in six steps. 1. Output b00001111 to the port. This drives all the rows high, leaving the columns passively pulled down. 2. Read the port. The driven pins 0 through 3 remain high, and because the switch [1, 2] is closed pin 6 is now high. The value read is b01001111. 3. Output b11110000 to the port. This drives all the columns high, leaving the rows passively pulled down. 4. Read the port. The driven pins 4 through 7 remain high, and because the switch [1, 2] is closed pin 1 is now high. The value read is b11110010. 5. Do a logical AND of the results of steps 2 and 4 to get the answer b01000010. 6. The upper 4 bits can be decoded as column 2 and the lower 4 bits as row 1. The above algorithm can be implemented as a function keypad_scan(). It reads a 4x4 keypad connected to port 0 and returns the ANDed result, as shown in Code 1: R0 1 CPU Drive all rows high simultaneously and read all columns C Function 4 x 4 Matrix Keypad 0 [0,0] [0,1] [0,2] [0,3] [1,0] [1,1] [1,2] [1,3] [2,0] [2,1] [2,2] [2,3] 2 3 R1 Code 1. Keypad Scan Function 4 5 6 R2 /* This is the port mapping for the keypad ports. 7 PSoC 1 Port Data register R3 [3,0] [3,1] C0 [3,2] C1 [3,3] C2 C3 PSoC 1 pins are highly flexible and can be configured in many different modes, such as strong drive, resistive pull-up, resistive pull-down, open drain drive high/low, and high impedance. To avoid a floating input when no key is pressed, use the resistive pull-down mode for all row and column pins. Algorithm The standard algorithm for reading a matrix keypad is to drive each row high, one at a time, and sample the column lines. This technique enables detection of multiple key presses. However, scanning the entire keypad takes www.cypress.com p0.0 ---1----2----3----A | | | | p0.1 ---4----5----6----B | | | | p0.2 ---7----8----9----C | | | | p0.3 ---*----0----#----D | | | | p0.4 p0.5 p0.6 p0.7 */ unsigned char keypad_scan(void) { unsigned char rows; unsigned char cols; /* Drive rows, read columns */ PRT0DR = 0x0F; cols = PRT0DR; Document No. 001-40409 Rev. *E 2 PSoC® 1 - Reading Matrix and Common Bus Keypads presses. One way to handle this problem is to implement a delay from when the first edge is detected (A or C) to when the ports are read (B or D). This delay ensures that the signal at the port pins is stable during the CPU read operation. A delay of 10 ms is usually sufficient for most types of switches. /* Drive columns, read rows*/ PRT0DR = 0xF0; rows = PRT0DR; /* combine results */ return (rows & cols); No bits are set if no key is pressed A delay can be implemented using a firmware or a hardware timer. The disadvantage of a firmware delay is that it requires the CPU. In an application where the CPU must do many tasks, it is better to generate the delay using a hardware timer. PSoC 1’s configurable digital blocks make it possible to create such a timer; it is available in the form of a PSoC Designer user module named Timer. A single bit in the upper nibble and a single bit in the lower nibble are set for a single key press To add a debounce delay using a hardware timer, do the following: Any other condition is a multiple key closure and is defined as not valid 1. } Decoding a Key Press The output of the keypad_scan() function is a single byte that shows the row or column status of the keypad. It is decoded as follows: You will usually need to translate the row or column bits into a more useful form, for example an ASCII character corresponding to the key press. The most speed efficient way to do this is to use a lookup table (LUT) array. For a size efficient implementation, use switch case statements. Place a Timer user module in the design, as shown in Figure 5: Figure 5. Timer User Module In this project, the LUT method is used: the byte output of the keypad_scan() function is used as an index to a 256-byte array. In the 4x4 keypad case, 16 elements in the array contain codes corresponding to valid key presses, and the remaining elements contain codes for "no key press" or "undefined". See Appendix A: ‘C’ Code for Matrix Keypad Scanning Using Interrupt Method for details. 2. Debounce Mechanism When any key is pressed or released, due to mechanical structure, the contacts may make or break connection multiple times. Due to this, an oscillating waveform can be obtained at the row or column line as shown in Figure 4: You can also use an 8-bit timer, which consumes one less digital block, with a lower input clock frequency to generate the same delay. The input clock to a timer can be derived using internal clock dividers VC1, VC2, and VC3. Figure 4. Key Bounce Key is pressed Key is released 3. time Stable state Debounce delay A Configure the timer clock input and period to generate the required delay. As an example, a 16-bit timer is configured with a 32 kHz internal low-speed oscillator (ILO) input clock, with a period of 320 counts, to generate a delay of 10 ms. The Timer user module can generate an interrupt, and you can call the keypad scanning function from the Timer interrupt service routine (ISR). This will cause the CPU to read the ports after a debounce delay. Debounce delay B C D If the CPU reads the ports at a high rate, the bounce oscillations may be wrongly detected as multiple key www.cypress.com Document No. 001-40409 Rev. *E 3 PSoC® 1 - Reading Matrix and Common Bus Keypads Making the Scanning Process Polled or Interrupt Driven Figure 6. Interrupt and Debounce Action Key is pressed Key is released The scanning algorithm in the keypad_scan() function can be executed once the key press is detected. There are two ways to call the function and detect key activity - polling and interrupt. With the polling method, the CPU periodically scans the keypad to check if any key is pressed. The CPU can either read the keypad in a while loop or can be interrupted at regular intervals using a timer. The scan period must be greater than the debounce delay and less than the minimum key press time. The problem with this method is that most of the time the keys are not pressed, and doing a scan during those times is a waste of CPU cycles. A better way is to do a scan only when a key press event is detected. With the interrupt method, the CPU can be interrupted on a key press. The ISR then starts the timer for a debounce delay and a keypad scan is done at the timer interrupt. To configure PSoC for an interrupt-based method, do the following: Configure the four lower (row) pins (see Figure 3) as inputs, with resistive pull-down Drive the four upper (column) pins high Enable the GPIO interrupt Write a GPIO interrupt handler that enables the timer, for a debounce delay The row pins stay low when no key is pressed. On a key press, the rising edge signal is produced on one of the row lines which trigger an interrupt. The GPIO ISR enables the timer for a debounce delay. After the delay, the Timer ISR does the scan. See Figure 6 for more details. time Stable state Debounce delay A Debounce delay B C D A Key is pressed. Rising edge signal interrupts CPU. CPU starts the timer for debounce delay B Debounce delay elapsed. Timer triggers interrupt to the CPU to read the ports to identify the key pressed. C Key is released. Rising edge signal interrupts CPU once again. CPU starts the timer for debounce delay D Debounce delay elapsed. Timer triggers interrupt to the CPU to read port once again. As key is released, no key press will be detected. * Note that switch may not bounce during switch release and C and D events may not occur. The interrupt method also helps to reduce the power consumption by allowing the device to be put in sleep mode. When any key is pressed, the resulting interrupt can wake the device. Note that the PSoC 1 interrupt system combines the interrupt signals from all of the pins in the device to generate a single interrupt. Thus, any key press will trigger a common interrupt. However, any other external event will also trigger the same interrupt. To handle this you may need to have the ISR read other ports to determine the cause of the interrupt. Example Project The PSoC Designer project “MatrixKeypad”, based on PSoC 1 CY8C27443, is provided. The project uses the interrupt method and is configured for the external connections shown in Figure 7. In the project, the closed key is displayed on a Hitachi-compatible 2x16 character LCD. The number of times any key is pressed is also displayed to evaluate the debounce logic. If the debounce logic is working correctly, you will notice that the count increments only once on each key press. See Appendix A: ‘C’ Code for Matrix Keypad Scanning Using Interrupt Method for the application firmware. www.cypress.com Document No. 001-40409 Rev. *E 4 PSoC® 1 - Reading Matrix and Common Bus Keypads Figure 7. External Connections for Testing "MatrixKeypad" Project Hitachi compatible 2x16 character LCD module D0 D1 D2 D3 EN Character LCD RS R/W P2[0] P0[0] 1 2 3 A P0[1] 4 5 6 B P0[2] 7 8 9 C P0[3] * 0 # D Common Bus Keypad This section shows how to read an 8-key common bus keypad using only one PSoC pin. The logic behind the single pin solution is to generate a distinct analog voltage on a key press and to decode it using the ADC. The block diagram of the solution is given in Figure 8. P2[1] P2[2] A switch-resistor network forms a voltage divider connected between the power supply (VDD) and the ground (VSS). The PSoC 1 ADC is configured to read the input voltage from VDD to VSS. The resistor values are chosen so that when a particular switch is pressed, the input voltage to the ADC is within a certain range. A simple algorithm can be created that compares the ADC result with the predetermined codes to identify the key pressed. P2[3] P2[4] P2[5] PSoC 1 P0[4] P2[6] P0[5] P0[6] +5V Vdd GND Contrast control voltage P0[7] When multiple keys are pressed, the one which is closer to the pin takes priority; the resistor network beyond the closed key is bypassed. In Figure 8, S0 has the highest priority and S7 has the lowest priority. Figure 8. Block Diagram - Common Bus Keypad Interface to PSoC VDD R0 ADC R1 S0 R2 S1 S2 R3 R4 S3 S4 R5 S5 R6 S6 R7 S7 PSoC 1 Keypad VSS PSoC 1 Implementation PSoC Designer provides different types of ADCs that are implemented using generic analog blocks in PSoC 1. Consumes one PSoC 1 switched capacitor (SC) analog block Produces a 1 byte 2’s complement output, ranging from -32 to +31 The resolution of the ADC is an important parameter for this application as it determines the number of switches N that can be interfaced. Ideally, with an N-bit ADC 2 switches can be read. But due to the tolerances of the resistors, it is significantly lower. To read an 8-switch keypad, a 6-bit SAR ADC is sufficient. The SAR ADC is available in the form of a user module in PSoC Designer. This user module has the following features: www.cypress.com Table 1. SAR ADC Input to Output Mapping Input Voltage (VIN) Digital Output AGND (analog ground) 00h AGND < VIN < VH 00h to 1Fh VL < VIN < AGND E0 to FFh Document No. 001-40409 Rev. *E Comments RefMux setting in Global resources tab of PSoC Designer decides VH and VL and AGND. 5 PSoC® 1 - Reading Matrix and Common Bus Keypads The input impedance of the SAR ADC is in the kΩ range; it depends on the frequency of the clock to the SC block. To avoid errors due to low input impedance, place a programmable gain amplifier (PGA) module between the SAR ADC and the external network. The PGA uses a PSoC 1 continuous time (CT) analog block which has high input impedance. Figure 10. Global Resource Settings Using PSoC Designer, configure the PSoC 1 as follows: Place the PGA and SAR ADC user modules on the design Route the PGA input to a pin connected to the external switch-resistor network, as shown in Figure 9. Figure 9. User Modules Placement and Routing SAR ADC Input Voltages When mapped uniformly for a VDD of 5.0 V, each switch produces a nominal increase of 5.0 V / 8 = 0.625 V, or a 12.5 percent change in the ADC input voltage. Table 2 provides the input voltage range for the ADC for each switch. The midpoint of each range is the theoretical ADC input voltage neglecting all error sources such as resistor tolerances, ADC error, noise, and so on. Table 2. Mapping Switch Press to the Voltage Generated Switch Voltage Range at Input Byte Range Resistor Value S0 0 V – 0.3125 V [E0 – E4] - S1 0.3125 V – 0.9375 V [E4 – EC] R1 = 1.5 kΩ Route the PGA output to the SAR ADC input S2 0.9375 V – 1.5625 V [EC – F4] R2 = 1.8 kΩ Set the PGA gain to 1 in the PGA module properties S3 1.5625 V – 2.1875 V [F4 – FC] R3 = 2.7 kΩ Set the analog column clock to VC2, with the frequency between 128 kHz and 1.33 MHz in the global resource settings. This clock controls the switching frequency of the SC block. S4 2.1875 V – 2.8125 V [FC – 04] R4 = 4.3 kΩ S5 2.8125 V – 3.4375 V [04 – 0C] R5 = 6.8 kΩ S6 3.4375 V – 4.0625 V [0C – 14] R6 = 13 kΩ In the global resources tab, set the VC2 frequency to 1 MHz by setting the VC1 divider to 12 and the VC2 divider to 2, as shown in Figure 10. Note that the system clock (SysClk) of the PSoC 1 device is 24 MHz. S7 4.0625 V – 4.6875 V [14 – 1A] R7 = 33 kΩ No Switch 5.0 V 1F - Also in the global resources tab, set the RefMux option to (VDD/2) +/- (VDD/2). This sets the SAR ADC measurement range as 0 to VDD, and the AGND voltage to VDD/2. www.cypress.com If none of the switches are closed, the input to the ADC is equal to VDD. When S0 is closed, current flows from VDD to VSS through R0 and S0. A value of 10 kΩ was chosen for R0 to limit the maximum supply current to 0.5 mA. The remaining resistors are calculated based on VDD = 5 V, R0 = 10 kΩ, and a nominal step size of 0.625 V for each switch. The following section explains how to select the resistors. Document No. 001-40409 Rev. *E 6 PSoC® 1 - Reading Matrix and Common Bus Keypads Determining Resistor Values Basic resistor voltage divider analysis can be used to determine the resistor values. Consider the case when switch S1 is pressed (see Figure 8) Solving for R1 and inserting nominal values for V DD and R0 gives The closest ±5% standard value resistor is 1.5 kΩ. With R1 = 1.5 kΩ and R0 = 10 kΩ, the typical ADC input voltage with S1 closed is 0.652 V. This error is acceptable since it falls within the allowed voltage range for SW1, that is, 0.3125 V to 0.9375 V. Moreover, with the worst case resistor tolerances (R0 = 10 kΩ – 5% and R1 = 1.5 kΩ + 5%, or R0 = 10 kΩ + 5% and R1 = 1.5 kΩ – 5%), the input voltage deviates by just 0.059 V from the ideal value. The same type of analysis can be used to determine the remaining resistor values, which are provided in Table 2. The interrupt pin is pulled low using a resistor (R). When any key is pressed, the rising edge signal is developed across R causing an interrupt to the device. The value of the resistor R must be high enough so that the voltage developed across it, on any key press, is greater than the VIH specification for a GPIO (minimum 2.1 V). After an interrupt is generated, the interrupt pin is grounded by writing a ‘0’ to the port data register. This causes the resistor R to be bypassed while reading the voltage using the ADC. Note that the lower end of the switches is not exactly 0 V - it is lifted above the ground by a few millivolts depending on the sink current value. Using the higher value of resistor R0 limits the sink current and thus the voltage lift. For this application, use R0 of 10 kΩ or higher. Debouncing It is possible for a switch press or release to occur during an ADC conversion, which would result in an erroneous output. To avoid these errors, you can implement a debounce mechanism similar to that for the matrix keypad: Configure the timer user module to generate a delay of at least 10 ms If an interrupt method is used, start the timer when the GPIO interrupt is detected. For the polling method, start the timer when the ADC reads a value different from the "no keys pressed" value. At the timer interrupt, read the ADC. If the ADC reading is same as the previous reading, a key can be assumed to be pressed and stable. Interrupt Driven Keypad Reading As seen in the section Making the Scanning Process Polled or Interrupt Driven, it is better to read the ADC on an interrupt when any key is pressed rather than reading the ADC continuously. This saves CPU bandwidth as well as device power consumption if sleep mode is used. To make the process interrupt driven, one more pin must be used for generating an interrupt signal. See Figure 11 for external connections. Figure 11. Interrupt Driven Scanning Process Vdd Example Project The project "CommonBusKeypad", based on the CY8C27443 PSoC 1 device, uses the polling method. The complete code is also provided in Appendix B: ‘C’ Code for Common Bus Keypad Using Polling Method. The project can be tested with the external connections shown in Figure 12. In the project, key presses are displayed on a Hitachi-compatible 2x16 character LCD. R0 ADC R1 S0 Interrupt signal PSoC1 S1 R2 S2 Rn Sn Keypad R Vss www.cypress.com Document No. 001-40409 Rev. *E 7 PSoC® 1 - Reading Matrix and Common Bus Keypads Figure 12. External Connections for Testing “CommonBusKeypad” Project Hitachi compatible 2x16 character LCD module D0 D1 D2 D3 EN Character LCD RS R/W Vdd=+5V P2[0] P2[1] R P2[2] P2[3] P0[2] P2[4] R1 R2 R3 S0 P2[6] S1 S2 S3 PSoC1 +5V R4 R5 R6 R7 P2[5] S4 S5 S6 S7 Keypad Vdd GND Contrast control voltage Use the resistor values R and R1 to R7 as shown in Table 2. Summary About the Author This application note shows easy methods to read matrix type and a common bus type keypads using PSoC 1. It also explains the polling and the interrupt mechanisms for keypad scanning as well as debounce logic. www.cypress.com Name: Rajiv Badiger Title: Applications Engineer Background: BE Electronics and Telecommunication Contact: [email protected] Document No. 001-40409 Rev. *E 8 PSoC® 1 - Reading Matrix and Common Bus Keypads Appendix A: ‘C’ Code for Matrix Keypad Scanning Using Interrupt Method #include <m8c.h> // part specific constants and macros #include "PSoCAPI.h" // PSoC API definitions for all User Modules /*****************Variables***************************/ /* LUT for storing keys. The size of the LUT should be equal to 2 ^ (NUMBER OF ROWS + COLUMNS). Row and column information from the scanning function is used as index to this LUT for finding the key. Value 0x20 indicates invalid key. */ static const keypad_LUT[256] = {/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ /*0*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*1*/0x20, '1', '4', 0x20, '7', 0x20, 0x20, 0x20, '*', 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*2*/0x20, '2', '5', 0x20, '8', 0x20, 0x20, 0x20, '0', 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*3*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*4*/0x20, '3', '6', 0x20, '9', 0x20, 0x20, 0x20, '#', 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*5*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*6*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*7*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*8*/0x20, 'A', 'B', 0x20, 'C', 0x20, 0x20, 0x20, 'D', 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*9*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*A*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*B*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*C*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*D*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*E*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*F*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; /* These two variables are used to store the row number and the column number */ BYTE rows,cols; /* This variable holds the count for number of key press */ BYTE InterruptCounter = 0; /* This variable keeps the scanning process disabled till previously decoded key is read */ unsigned char processing = 0; www.cypress.com Document No. 001-40409 Rev. *E 9 PSoC® 1 - Reading Matrix and Common Bus Keypads /* These variable stores the key number */ unsigned char key = 0x20; /*****************************************************/ /****************Functions****************************/ /* Handles keypad function- Checks the key pressed and debounces key */ void KeyPadHandler(void); /* Keypad scanning routine */ unsigned char keypad_scan(void); /* Initializes user modules used in the design */ void InitModules(void); /* Interrupt handler for GPIO interrupt */ void GPIOInterrupt(void); /****************************************************/ void main(void) { /* Initialize variables and user modules */ InitModules(); /* Enable Global Interrupt */ M8C_EnableGInt; while(1) { /* Check the Keypad status and update LCD on valid key press */ if(key != 0x20) { /* Valid key- display the result on LCD */ /* Set LCD cursor position */ LCD_1_Position(0, 7); /* Display pressed keypad button */ LCD_1_WriteData(key); /* Set LCD cursor position */ LCD_1_Position(1, 12); /* Display nuymber of times key is pressed so far */ LCD_1_PrHexByte(InterruptCounter); /* Reset key to default value */ key = 0x20; /* Enable keypad scanning process */ processing = 0; } /* Do other tasks */ } www.cypress.com Document No. 001-40409 Rev. *E 10 PSoC® 1 - Reading Matrix and Common Bus Keypads } /* This function initializes all the user modules used in the design */ void InitModules(void) { /* Initialize LCD */ LCD_1_Start(); LCD_1_Position(0,0); LCD_1_PrCString("Switch:"); LCD_1_Position(1,0); LCD_1_PrCString("Interrupts:"); /* Initilize timer- 10ms delay */ Timer16_1_WritePeriod(320); Timer16_1_EnableInt(); /* Enable GPIO interrupt */ INT_MSK0 |= 0x20; /* Write 1's at column lines */ PRT0DR |= 0xF0; } /* This is the port mapping for the keypad ports. p0.0 p0.1 p0.2 p0.3 p0.4 p0.5 p0.6 p0.7 | | | | ---1----2----3----A | | | | ---4----5----6----B | | | | ---7----8----9----C | | | | ---*----0----#----D */ /* This function scan the keypad and identifies the key pressed */ unsigned char keypad_scan(void) { BYTE key_result; /* Drive rows */ PRT0DR = 0x0F; /* Read columns */ cols = PRT0DR; /* Drive columns */ PRT0DR = 0xF0; /* Read rows */ rows = PRT0DR; /* Combine results */ key_result = rows & cols; /* Get the key number from LUT */ return(keypad_LUT[key_result]); www.cypress.com Document No. 001-40409 Rev. *E 11 PSoC® 1 - Reading Matrix and Common Bus Keypads } /* This is the handler for GPIO interrupt. Debounce timer is started on GPIO interrupt */ #pragma interrupt_handler GPIOInterrupt void GPIOInterrupt(void) { /* Check if previous key is read. If yes, start the timer for debounce delay */ if(processing == 0) { /* Avoid enabling timer next time when previous key is not read */ processing = 1; /* Disable GPIO interrupt */ INT_MSK0 &=~ 0x20; /* Start Timer */ Timer16_1_Start(); } } /* This is the handler for the timer interrupt. This ISR calls the scanning algorithm */ void TimerInterrupt(void) { /* Stop the timer */ Timer16_1_Stop(); /* Get the key */ key = keypad_scan(); /* Check for valid key press */ if(key != 0x20) { /*********************************************************/ /* Add code here to take immediate action within the ISR */ /********************************************************/ /* Increment interrupt counter */ InterruptCounter ++; } else { /* Enable starting the timer on GPIO interrupt */ processing = 0; } /* Clear GPIO posted interrupt */ INT_CLR0 &=~ 0x20; /* Enable GPIO interrupt */ INT_MSK0 |= 0x20; } www.cypress.com Document No. 001-40409 Rev. *E 12 PSoC® 1 - Reading Matrix and Common Bus Keypads Add LJMP instruction in PSoC_GPIO_ISR function in PSoCGPIOINT.asm file as shown in the following code. PSoC_GPIO_ISR: ;@PSoC_UserCode_BODY@ (Do not change this line.) ;--------------------------------------------------; Insert your custom code below this banner ;--------------------------------------------------ljmp _GPIOInterrupt ;--------------------------------------------------; Insert your custom code above this banner ;--------------------------------------------------;@PSoC_UserCode_END@ (Do not change this line.) reti Add LCALL instruction in Timer16_1_ISR function in Timer16_1NT.asm file as shown below. _Timer16_1_ISR: ;@PSoC_UserCode_BODY@ (Do not change this line.) ;--------------------------------------------------; Insert your custom assembly code below this banner ;--------------------------------------------------; NOTE: interrupt service routines must preserve ; the values of the A and X CPU registers. ;--------------------------------------------------; Insert your custom assembly code above this banner ;--------------------------------------------------;--------------------------------------------------; Insert a lcall to a C function below this banner ; and un-comment the lines between these banners ;--------------------------------------------------PRESERVE_CPU_CONTEXT lcall _TimerInterrupt RESTORE_CPU_CONTEXT ;--------------------------------------------------; Insert a lcall to a C function above this banner ; and un-comment the lines between these banners ;--------------------------------------------------;@PSoC_UserCode_END@ (Do not change this line.) reti www.cypress.com Document No. 001-40409 Rev. *E 13 PSoC® 1 - Reading Matrix and Common Bus Keypads Appendix B: ‘C’ Code for Common Bus Keypad Using Polling Method #include <m8c.h> // part specific constants and macros #include "PSoCAPI.h" // PSoC API definitions for all User Modules /* Timer State */ #define ON 0x1 #define OFF 0x0 /* Invalid Key identifier */ #define INVALID_KEY 0x20 /* Functions */ char Get_ADC_Data(void); void GetKeyNumber(void); /* Variables */ BYTE Key = INVALID_KEY, TimerState = OFF; char ADC_Data,New_ADC_Data; void main(void) { /* Enable Timer Interrupt */ Timer16_1_EnableInt(); /* Enable Global Interrupt */ M8C_EnableGInt ; /* Start PGA operation in high power mode */ PGA_1_Start(PGA_1_HIGHPOWER); /* Start ADC operation */ SAR6_1_Start(SAR6_1_HIGHPOWER); /* Start LCD and Initialize Display */ LCD_1_Start(); LCD_1_Position(0,0); LCD_1_PrCString("Switch:"); while(1) { /* If timer is OFF (debounce is not in process), check the "key" */ if(TimerState == OFF) { /* If "Key" contains valid value, then display on LCD */ if(Key != INVALID_KEY) { LCD_1_Position(0,7); LCD_1_PrHexByte(Key); /* Invalidate Key */ Key = INVALID_KEY; } else /* No Key Pressed */ { LCD_1_Position(0,7); LCD_1_PrCString("--"); www.cypress.com Document No. 001-40409 Rev. *E 14 PSoC® 1 - Reading Matrix and Common Bus Keypads } /* Get ADC data */ ADC_Data = SAR6_1_cGetSample(); /* Check if any key is pressed */ if(ADC_Data < 0x1C || ADC_Data > 0xE0) { /* Start Timer */ Timer16_1_Start(); TimerState = ON; } } /* Do other tasks */ } } /* Interrupt Handler for Timer Interrupt */ void TimerInt(void) { BYTE Delta = 0; /* Take a second sample, compare with the first to test data validity in the presence of possible switch bounce */ New_ADC_Data = SAR6_1_cGetSample(); /* Compare the ADC values and get the difference */ if(ADC_Data > New_ADC_Data) { Delta = ADC_Data - New_ADC_Data; } else Delta = New_ADC_Data - ADC_Data; /* If difference in readings is less than 2, then decode the key */ if(Delta < 2) { /* If closely matched, decode the key */ GetKeyNumber(); } /* Stop the timer */ Timer16_1_Stop(); TimerState = OFF; } /* This function decodes the key. See Table 2 of application note for ADC result to Key mapping information */ void GetKeyNumber(void) { if((New_ADC_Data > 0xE0) && (New_ADC_Data <= 0xE4)) Key = 0; else if((New_ADC_Data > 0xE4) && (New_ADC_Data <= 0xEC)) Key = 1; else if((New_ADC_Data > 0xEC) && (New_ADC_Data <= 0xF4)) Key = 2; else if((New_ADC_Data > 0xF4) && (New_ADC_Data <= 0xFC)) Key = 3; www.cypress.com Document No. 001-40409 Rev. *E 15 PSoC® 1 - Reading Matrix and Common Bus Keypads else if((New_ADC_Data > 0xFC) Key = 4; else if((New_ADC_Data >= 0x0) Key = 4; else if((New_ADC_Data > 0x04) Key = 5; else if((New_ADC_Data > 0x0C) Key = 6; else if((New_ADC_Data > 0x14) Key = 7; else Key = INVALID_KEY; && (New_ADC_Data <= 0xFF)) && (New_ADC_Data <= 0x04)) && (New_ADC_Data <= 0x0C)) && (New_ADC_Data <= 0x14)) && (New_ADC_Data <= 0x1A)) } Add LCALL instruction in Timer16_1_ISR function in Timer16_1NT.asm file as shown in the following code. _Timer16_1_ISR: ;@PSoC_UserCode_BODY@ (Do not change this line.) ;--------------------------------------------------; Insert your custom assembly code below this banner ;--------------------------------------------------; NOTE: interrupt service routines must preserve ; the values of the A and X CPU registers. ;--------------------------------------------------; Insert your custom assembly code above this banner ;--------------------------------------------------;--------------------------------------------------; Insert a lcall to a C function below this banner ; and un-comment the lines between these banners ;--------------------------------------------------PRESERVE_CPU_CONTEXT lcall _TimerInt RESTORE_CPU_CONTEXT ;--------------------------------------------------; Insert a lcall to a C function above this banner ; and un-comment the lines between these banners ;--------------------------------------------------;@PSoC_UserCode_END@ (Do not change this line.) reti www.cypress.com Document No. 001-40409 Rev. *E 16 PSoC® 1 - Reading Matrix and Common Bus Keypads Document History ® Document Title: PSoC 1 - Reading Matrix and Common Bus Keypads – AN2034 Document Number: 001-40409 Revision ECN Orig. of Change Submission Date Description of Change ** 1532004 OGNE 10/02/2007 New publication of existing application note. *A 2640952 JVY 01/20/2009 Updated content. Added part numbers CY8C20x34, CY8C21x23, CY8C21x34, CY8C23x33, CY8C24x23A, CY8C24x94, CY8C27x43, and CY8C29x66. *B 3312765 OWEN 07/19/2011 Added section about LED display, converted code to C from assembly, updated associated project similarly. *C 3416292 RJVB 10/24/2011 Added common bus keypad interface details, introduced debounce logic and interrupt mechanism. Updated template *D 3433993 RJVB 11/09/2011 Modified title and updated project code in Appendix A and B *E 4463001 ARVI 08/01/2014 Updated example projects to PSoC Designer v5.4 www.cypress.com Document No. 001-40409 Rev. *E 17 PSoC® 1 - Reading Matrix and Common Bus Keypads Worldwide Sales and Design Support Cypress maintains a worldwide network of offices, solution centers, manufacturer’s representatives, and distributors. To find the office closest to you, visit us at Cypress Locations. PSoC® Solutions Products Automotive cypress.com/go/automotive psoc.cypress.com/solutions Clocks & Buffers cypress.com/go/clocks PSoC 1 | PSoC 3 | PSoC 4 | PSoC 5LP Interface cypress.com/go/interface Lighting & Power Control cypress.com/go/powerpsoc cypress.com/go/plc Memory cypress.com/go/memory PSoC cypress.com/go/psoc Touch Sensing cypress.com/go/touch USB Controllers cypress.com/go/usb Wireless/RF cypress.com/go/wireless Cypress Developer Community Community | Forums | Blogs | Video | Training Technical Support cypress.com/go/support PSoC is a registered trademark and PSoC Creator is a trademark of Cypress Semiconductor Corp. All other trademarks or registered trademarks referenced herein are the property of their respective owners. Cypress Semiconductor 198 Champion Court San Jose, CA 95134-1709 Phone Fax Website : 408-943-2600 : 408-943-4730 : www.cypress.com © Cypress Semiconductor Corporation, 2007-2014. The information contained herein is subject to change without notice. Cypress Semiconductor Corporation assumes no responsibility for the use of any circuitry other than circuitry embodied in a Cypress product. Nor does it convey or imply any license under patent or other rights. Cypress products are not warranted nor intended to be used for medical, life support, life saving, critical control or safety applications, unless pursuant to an express written agreement with Cypress. Furthermore, Cypress does not authorize its products for use as critical components in life-support systems where a malfunction or failure may reasonably be expected to result in significant injury to the user. The inclusion of Cypress products in life-support systems application implies that the manufacturer assumes all risk of such use and in doing so indemnifies Cypress against all charges. This Source Code (software and/or firmware) is owned by Cypress Semiconductor Corporation (Cypress) and is protected by and subject to worldwide patent protection (United States and foreign), United States copyright laws and international treaty provisions. Cypress hereby grants to licensee a personal, non-exclusive, non-transferable license to copy, use, modify, create derivative works of, and compile the Cypress Source Code and derivative works for the sole purpose of creating custom software and or firmware in support of licensee product to be used only in conjunction with a Cypress integrated circuit as specified in the applicable agreement. Any reproduction, modification, translation, compilation, or representation of this Source Code except as specified above is prohibited without the express written permission of Cypress. Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Cypress reserves the right to make changes without further notice to the materials described herein. Cypress does not assume any liability arising out of the application or use of any product or circuit described herein. Cypress does not authorize its products for use as critical components in life-support systems where a malfunction or failure may reasonably be expected to result in significant injury to the user. The inclusion of Cypress’ product in a life-support systems application implies that the manufacturer assumes all risk of such use and in doing so indemnifies Cypress against all charges. Use may be limited by and subject to the applicable Cypress software license agreement. www.cypress.com Document No. 001-40409 Rev. *E 18