-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGamer.cpp
230 lines (196 loc) · 4.67 KB
/
Gamer.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/*
TO-DO
-Fix IR
-Buzzer play melody
-LDR as button event
-Scrolling text
-Gamer clear with no update
*/
#include "Gamer.h"
Gamer *thisGamer = NULL;
// Interrupt service routine
ISR(TIMER2_COMPB_vect) {
thisGamer->isrRoutine();
}
Gamer::Gamer() {
}
// Setup inputs, outputs, timers, etc. Call this from setup()!!
void Gamer::begin() {
::thisGamer = this;
_refreshRate = 50;
ldrThreshold = 300;
// Setup outputs
pinMode(3, OUTPUT);
for(int i=6; i<=10; i++) pinMode(i, OUTPUT);
pinMode(2, OUTPUT);
pinMode(13, OUTPUT);
// Setup inputs
DDRC = B00000;
PORTC = B11111;
// Change analogue read resolution to 8-bit.
ADCSRA &= ~(1 << ADPS2);
// Timer 2 setup
noInterrupts();
TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS22);
OCR2A = 51;
OCR2B = 26;
TCCR2B = (TCCR2B & 0b00111000) | 0x2;
TIMSK2 = _BV(OCIE2B);
interrupts();
}
// Inputs --------------------------------
// Returns true if a button has been pressed recently
bool Gamer::isPressed(uint8_t input) {
if(buttonFlags[input]) {
buttonFlags[input] = 0;
return true;
}
else return false;
}
// Returns true if the button is currently held down
bool Gamer::isHeld(uint8_t input) {
bool result = (PINC & (1<<input)) >> input;
return !result;
}
// Returns the current value of the LDR
int Gamer::ldrValue() {
return analogRead(LDR);
}
// Change the button threshold for the LDR.
void Gamer::setldrThreshold(uint16_t threshold) {
ldrThreshold = threshold;
}
// Outputs -------------------------------
// Set the display's refresh rate. 1 = 1 row per timer cycle. 10 = 1 row every 10 timer cycles
void Gamer::setRefreshRate(uint16_t refreshRate) {
_refreshRate = refreshRate;
}
// Burns the display[][] array onto the display. Only call when you're done changing pixels!
void Gamer::updateDisplay() {
byte newImage[8];
for(int j=0; j<8; j++) {
newImage[j] = 0x00;
for(int i=0; i<8; i++) {
newImage[j] <<= 1;
newImage[j] |= display[i][j];
}
}
if(newImage != image) {
for(int i=0; i<8; i++) image[i] = newImage[i];
}
}
// Turn on all pixels on display
void Gamer::allOn() {
for(int j=0; j<8; j++) {
for(int i=0; i<8; i++) display[i][j] = 1;
}
updateDisplay();
}
void Gamer::clear() {
for(int j=0; j<8; j++) {
for(int i=0; i<8; i++) display[i][j] = 0;
}
updateDisplay();
}
// Print an 8 byte array onto the display
void Gamer::printImage(byte* img) {
for(int j=0; j<8; j++) {
for(int i=0; i<8; i++) {
display[i][j] = (img[j] & (1 << (7-i))) != 0;
}
}
updateDisplay();
}
// Set the value of the Gamer LED
void Gamer::setLED(bool value) {
digitalWrite(LED, value);
}
// Toggle the Gamer LED
void Gamer::toggleLED() {
digitalWrite(LED, !digitalRead(LED));
}
void Gamer::enableIRTX() {
noInterrupts();
TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS22);
OCR2A = 51;
OCR2B = 26;
TCCR2B = (TCCR2B & 0b00111000) | 0x2;
interrupts();
}
void Gamer::disableIRTX() {
noInterrupts();
TCCR2A = 0;
TCCR2B = 0;
TCNT2 = 0;
interrupts();
}
// Internal display refreshing and writing to ICs ----------------------
// Load the next row in the display.
void Gamer::updateRow() {
if(counter==8) {
counter = 0;
currentRow = 0x80;
}
writeToRegister(0);
writeToDriver(image[counter]);
writeToRegister(currentRow);
currentRow >>= 1;
counter++;
}
// Writes to the TLC5916 LED driver (cathodes)
void Gamer::writeToDriver(byte dataOut) {
digitalWrite(OE, HIGH);
for(int x=0; x<=7; x++) {
digitalWrite(CLK1, LOW);
digitalWrite(DAT, (dataOut & (1<<x)) >> x);
digitalWrite(CLK1, HIGH);
}
digitalWrite(LAT, HIGH);
digitalWrite(LAT, LOW);
digitalWrite(OE, LOW);
}
// Write to the MIC5891 shift register (anodes)
void Gamer::writeToRegister(byte dataOut) {
digitalWrite(LAT, LOW);
for(int y=0; y<=7; y++) {
digitalWrite(DAT, (dataOut & (1<<y)) >> y);
digitalWrite(CLK2, HIGH);
digitalWrite(CLK2, LOW);
}
digitalWrite(LAT, HIGH);
digitalWrite(LAT, LOW);
}
// Periodically check if inputs are pressed (+ debouncing)
void Gamer::checkInputs() {
int currentInputState[6];
for(int i=0; i<6; i++) {
if(i != 5) {
currentInputState[i] = (PINC & (1<<i)) >> i;
if(currentInputState[i] != lastInputState[i]) {
if(currentInputState[i] == 0) {
buttonFlags[i] = 1;
}
}
lastInputState[i] = currentInputState[i];
}
else {
currentInputState[i] = analogRead(LDR);
if(currentInputState[i] - lastInputState[i] >= ldrThreshold) buttonFlags[i] = 1;
lastInputState[i] = currentInputState[i];
}
}
}
// Run Interrupt Service Routine tasks
void Gamer::isrRoutine() {
buzzerCount++;
pulseCount++;
if(pulseCount >= _refreshRate) {
updateRow();
pulseCount = 0;
}
if(pulseCount == _refreshRate/2) {
checkInputs();
}
}