PIC24 Support Libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
keypad.c
Go to the documentation of this file.
1 /*
2  * "Copyright (c) 2008 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
3  * All rights reserved.
4  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
5  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
6  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose, without fee, and without written agreement is
10  * hereby granted, provided that the above copyright notice, the following
11  * two paragraphs and the authors appear in all copies of this software.
12  *
13  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
15  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
16  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17  *
18  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
23  *
24  * Please maintain this header in its entirety when copying/modifying
25  * these files.
26  *
27  *
28  */
29 
30 #include "pic24_all.h"
31 
32 /** \file
33 Implements a 4x3 key scanned keypad interface.
34 A periodic timer interrupt is used to poll the keypad. Thanks goes
35 to David Weaver for suggestions on improvements to the scan function.
36 */
37 
38 #define C0 _RB9
39 #define C1 _RB8
40 #define C2 _RB7
41 #define C3 _RB6
42 
43 static inline void CONFIG_COLUMN() {
44  CONFIG_RB9_AS_DIG_INPUT();
45  ENABLE_RB9_PULLUP();
46  CONFIG_RB8_AS_DIG_INPUT();
47  ENABLE_RB8_PULLUP();
48  CONFIG_RB7_AS_DIG_INPUT();
49  ENABLE_RB7_PULLUP();
50  CONFIG_RB6_AS_DIG_INPUT();
51  ENABLE_RB6_PULLUP();
52 }
53 
54 #define R0 _LATB5
55 #define R1 _LATB4
56 #define R2 _LATB3
57 
58 #define CONFIG_R0_DIG_OUTPUT() CONFIG_RB5_AS_DIG_OUTPUT()
59 #define CONFIG_R1_DIG_OUTPUT() CONFIG_RB4_AS_DIG_OUTPUT()
60 #define CONFIG_R2_DIG_OUTPUT() CONFIG_RB3_AS_DIG_OUTPUT()
61 
62 void CONFIG_ROW() {
63  CONFIG_R0_DIG_OUTPUT();
64  CONFIG_R1_DIG_OUTPUT();
65  CONFIG_R2_DIG_OUTPUT();
66 }
67 
68 static inline void DRIVE_ROW_LOW() {
69  R0 = 0;
70  R1 = 0;
71  R2 = 0;
72 }
73 
74 static inline void DRIVE_ROW_HIGH() {
75  R0 = 1;
76  R1 = 1;
77  R2 = 1;
78 }
79 
80 void configKeypad(void) {
81  CONFIG_ROW();
82  DRIVE_ROW_LOW();
83  CONFIG_COLUMN();
84  DELAY_US(1); //wait for pullups to stabilize inputs
85 }
86 
87 //drive one row low
88 void setOneRowLow(uint8_t u8_x) {
89  switch (u8_x) {
90  case 0:
91  R0 = 0;
92  R1 = 1;
93  R2 = 1;
94  break;
95  case 1:
96  R0 = 1;
97  R1 = 0;
98  R2 = 1;
99  break;
100  default:
101  R0 = 1;
102  R1 = 1;
103  R2 = 0;
104  break;
105  }
106 }
107 #define NUM_ROWS 3
108 #define NUM_COLS 4
109 const uint8_t au8_keyTable[NUM_ROWS][NUM_COLS] = { {'1', '4', '7', '*'},
110  {'2', '5', '8', '0'},
111  {'3', '6', '9', '#'}
112 };
113 
114 #define KEY_PRESSED() (!C0 || !C1 || !C2 || !C3) //any low
115 #define KEY_RELEASED() (C0 && C1 && C2 && C3) //all high
116 
117 uint8_t doKeyScan(void) {
118  uint8_t u8_row, u8_col;
119  //determine column
120  if (!C0) u8_col = 0;
121  else if (!C1) u8_col = 1;
122  else if (!C2) u8_col = 2;
123  else if (!C3) u8_col = 3;
124  else return('E'); //error
125  //determine row
126  for (u8_row = 0; u8_row < NUM_ROWS; u8_row++) {
127  setOneRowLow(u8_row); //enable one row low
128  if (KEY_PRESSED()) {
129  DRIVE_ROW_LOW(); //return rows to driving low
130  return(au8_keyTable[u8_row][u8_col]);
131  }
132  }
133  DRIVE_ROW_LOW(); //return rows to driving low
134  return('E'); //error
135 }
136 
137 
138 typedef enum {
139  STATE_WAIT_FOR_PRESS = 0,
140  STATE_WAIT_FOR_PRESS2,
141  STATE_WAIT_FOR_RELEASE,
142 } ISRSTATE;
143 
144 ISRSTATE e_isrState = STATE_WAIT_FOR_PRESS;
145 volatile uint8_t u8_newKey = 0;
146 
147 //Interrupt Service Routine for Timer3
148 void _ISR _T3Interrupt (void) {
149  switch (e_isrState) {
150  case STATE_WAIT_FOR_PRESS:
151  if (KEY_PRESSED() && (u8_newKey == 0)) {
152  //ensure that key is sampled low for two consecutive interrupt periods
153  e_isrState = STATE_WAIT_FOR_PRESS2;
154  }
155  break;
156  case STATE_WAIT_FOR_PRESS2:
157  if (KEY_PRESSED()) {
158  // a key is ready
159  u8_newKey = doKeyScan();
160  e_isrState = STATE_WAIT_FOR_RELEASE;
161  } else e_isrState = STATE_WAIT_FOR_PRESS;
162  break;
163 
164  case STATE_WAIT_FOR_RELEASE:
165  //keypad released
166  if (KEY_RELEASED()) {
167  e_isrState = STATE_WAIT_FOR_PRESS;
168  }
169  break;
170  default:
171  e_isrState = STATE_WAIT_FOR_PRESS;
172  break;
173  }
174  _T3IF = 0; //clear the timer interrupt bit
175 }
176 
177 #define ISR_PERIOD 15 // in ms
178 
179 void configTimer3(void) {
180  //ensure that Timer2,3 configured as separate timers.
181  T2CONbits.T32 = 0; // 32-bit mode off
182  //T3CON set like this for documentation purposes.
183  //could be replaced by T3CON = 0x0020
184  T3CON = T3_OFF | T3_IDLE_CON | T3_GATE_OFF
185  | T3_SOURCE_INT
186  | T3_PS_1_64 ; //results in T3CON= 0x0020
187  PR3 = msToU16Ticks (ISR_PERIOD, getTimerPrescale(T3CONbits)) - 1;
188  TMR3 = 0; //clear timer3 value
189  _T3IF = 0; //clear interrupt flag
190  _T3IP = 1; //choose a priority
191  _T3IE = 1; //enable the interrupt
192  T3CONbits.TON = 1; //turn on the timer
193 }
194 
195 int main (void) {
196  configBasic(HELLO_MSG);
197  /** PIO config ******/
198  configKeypad();
199  /** Configure the Timer */
200  configTimer3();
201  while (1) {
202  if (u8_newKey) {
203  outChar(u8_newKey);
204  u8_newKey = 0;
205  }
206  doHeartbeat(); //ensure that we are alive
207  } // end while (1)
208 }