-
Notifications
You must be signed in to change notification settings - Fork 0
/
keypad.c
92 lines (77 loc) · 2.32 KB
/
keypad.c
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
#include <avr/io.h>
#include "keypad.h"
#define PBIT(n) (1 << (n)) // Set a single bit
#define NBIT(n) (0x0f ^ PBIT(n)) // Clear a single bit, but keep the rest set (low nibble)
#define SCAN(n) {PORTA |= NBIT(n); PORTA &= ~PBIT(n); DDRA &= ~NBIT(n); DDRA |= PBIT(n); }
#define NOSCAN { PORTA |= 0x0f; DDRA &= ~0x0f; } // Set all bits in lower nibble; clear all bit in lower nibble of DDR
#define NKEYS (16)
#define NSAMPLES (3)
/*
PA0 - SCAN0
PA1 - SCAN1
PA2 - SCAN2
PA3 - SCAN3
PA4 - KEY0
PA5 - KEY1
PA6 - KEY2
PA7 - KEY3
*/
void keypad_reset(void);
unsigned short _state; // The debounced state of all keys, as a bit-map.
unsigned short _changes; // A bit mask denoting transitions since the last read
unsigned short _samples[NSAMPLES];
void keypad_init(void) {
keypad_reset();
}
void keypad_reset(void) {
PORTA = 0xf0; // Makse sure all key pins are set for input
DDRA = 0x0f; // key0 - key3 are inputs with pullup
}
unsigned short keypad_scan(void) {
unsigned char i;
unsigned short keys = 0;
keypad_reset(); // This fixes a bug where keys aren't read after the display is cleared.
for (i=0; i<4; i++) {
SCAN(i);
// Read a nybble and store it
keys += ((PINA & 0xf0) >> 4) << (4 * i);
}
NOSCAN;
return ~keys; // Invert keys before returning.
}
void keypad_update(void) {
int j;
unsigned short keys_on;
unsigned short keys_off;
unsigned short new_state;
// Shift samples down by 1
if (NSAMPLES > 1) {
for (j=(NSAMPLES - 1); j > 0; j--) {
_samples[j] = _samples[j-1];
}
}
// Store the latest sample at the head
_samples[0] = keypad_scan();
// Iterate through the sample array ANDing each sample
// Only bits with a steady state will be 1
keys_on = ~0;
keys_off = ~0;
for (j=0; j < NSAMPLES; j++) {
keys_on &= _samples[j];
keys_off &= ~_samples[j];
}
// We now have two variables:
// * key_on where every bit that is 1 in all samples is 1
// * keys_off where every bit that is 0 in all samples is 1
// We can then use these two as bitmasks to set and clear bits in the key state map
new_state = (_state | keys_on) & ~keys_off;
// XOR the new state with the previous to get any transitions.
// OR with the change mask so previous changes aren't lost.
_changes |= _state ^ new_state;
_state = new_state;
}
unsigned short get_keys(void) {
unsigned short k = _state & _changes;
_changes = 0;
return k;
}