-
Notifications
You must be signed in to change notification settings - Fork 0
/
keypad.cpp
149 lines (126 loc) · 3.79 KB
/
keypad.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
* keypad.ino
* The Keypad class implementation file
Copyright (c) 2018 Lee Dowthwaite
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "Keypad.h"
//#define ENABLE_TEST
/*
* Constructor - initialise the I/O ports
*/
Keypad::Keypad(char *keymap, int ncols, int nrows)
: _keymap(keymap), _ncols(ncols), _nrows(nrows) {
ROW_DDR &= ~ROW_MASK; // inputs
ROW_PORT |= ROW_MASK; // pullups
COL_DDR |= COL_MASK; // outputs
COL_PORT |= COL_MASK; // initialise high (inactive)
}
// scan()
// Don't call this too often - something in the order of every 50ms works well for debounced readings.
//
char Keypad::scan() {
int res = 0;
for (int col=0; col<_ncols && !res; col++) {
// turn off all columns
COL_PORT |= COL_MASK;
// drive the colum to test
COL_PORT &= ~(1<<(COL0_BIT+col));
// Need two NOPs otherwise we can miss the column signal coming back through matrix
// This makes entire scan really fast (estimated at approx 60us), so ensure we don't call this scan too often!
asm(
"nop\n"
"nop\n"
);
// read the row
byte rows = ROW_PIN & ROW_MASK;
if (rows != ROW_MASK) {
// there was a keypress on this column: work out which row it was
for (int row=0; row<_nrows; row++) {
byte rowmask = 1<<(ROW0_BIT+row);
// check valid row
if ((rows & rowmask) == 0) {
// we have a row: map to key
res = _keymap[row*_ncols + col];
break;
}
}
}
}
// turn off all columns
COL_PORT |= COL_MASK;
return res;
}
// getkey() returns only new keypresses
// Return value: The ASCII code for a keypress, or 0 if no new keypress.
//
char Keypad::getkey() {
static char prevkey = 0;
char key = scan();
if (key != prevkey) {
prevkey = key;
return key;
} else {
return 0;
}
}
#ifdef ENABLE_TEST
/*
* Standalone test code - remove when using library in another project
*/
// test keymap
static const char _test_keymap[3][4] = {
{ '7', '4', '1', '0' },
{ '8', '5', '2', 'A' },
{ '9', '6', '3', 'B' },
};
// test Keypad instance
static Keypad _keypad((FlatKeymap)_test_keymap, 3, 4);
static volatile int ticks = 0;
static volatile bool process_tick = false;
#define TIMER_PERIOD_MS (50)
void init_timer() {
OCR0A = 0xaf;
TIMSK0 |= _BV(OCIE0A);
}
// test code
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println("Keypad test");
init_timer();
}
void loop() {
if (process_tick) {
process_tick = false;
unsigned long ms = millis();
Serial.print(".");
//Serial.println(ms);
char key = _keypad.getkey();
if (key != 0) {
Serial.print("key ");
Serial.println(key);
}
}
}
ISR(TIMER0_COMPA_vect) {
if (++ticks >= TIMER_PERIOD_MS) {
ticks = 0;
process_tick = true;
}
}
#endif