-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.c
379 lines (327 loc) · 7.24 KB
/
main.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
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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
#include <msp430g2553.h>
/*
* Definitions
*/
#define PWM_CHANNELS 3
#define PWM_RES 16 // Don't change, see set color
#define TIMER_COUNT 3
/*
* Global Variables
*/
unsigned timer[TIMER_COUNT];
unsigned long clock;
unsigned pwmChannel[PWM_CHANNELS];
int capChannel; // Holds current reading
int capBase; // Initialized to an average of reading at startup
int capTreshold = 1000; // Threshold to consider as a touch
/*
* Colors
*/
typedef struct COLOR {
int h; // Hue
int s; // Saturation
int b; // Brightness
} color_t;
color_t off = {0, 0, 0};
color_t white = {0, 0, 255};
color_t red = {0, 255, 255};
color_t yellow = {40, 255, 255};
color_t green = {80, 255, 255};
color_t blue = {160, 255, 255};
color_t orange = {20, 255, 255};
color_t lblue = {120, 255, 255};
color_t purple = {200, 255, 200};
color_t pink = {200, 255, 255};
/*
* Hot Potato States
*/
typedef enum GAME_STATE {
INACTIVE,
FLYING,
TAKEN,
PASS,
LOSE
} state_t;
/*
* Function Prototypes
*/
void ledSetColor();
void capCalibrate();
int capButton();
unsigned long getRandom(unsigned long, unsigned long);
/*
* Main Loop
*/
int main(void) {
/*
* Initialization
*/
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
// Port Configuration
P1SEL2 = BIT7; // Capacitive Sensing (P1.7)
P1DIR = 0x7F; // LEDs (All P1 - 1.7)
P2DIR = 0xFF; // LEDs (All P2)
// Oscillators
BCSCTL2 = SELM_0 | DIVM_0 | DIVS_0; // DCOCLK, DIV by 1
/*if (CALBC1_16MHZ != 0xFF) {
__delay_cycles(100000);
DCOCTL = 0x00;
BCSCTL1 = CALBC1_16MHZ; // Set DCO to 16MHz
DCOCTL = CALDCO_16MHZ;
}*/
BCSCTL1 |= XT2OFF | DIVA_0; // Disable XT2CLK
BCSCTL3 = XT2S_0 | LFXT1S_2 | XCAP_1;
// Timer 0 (Capacitive Sensing)
TA0CTL = TASSEL_3 | ID_0 | MC_2; // INCLK (Capacitive oscillator)
// Timer 1 (PWM / Clock)
TA1CCTL0 = CM_3 | CCIS_0 | OUTMOD_0 | CCIE; // Compare mode
TA1CCTL1 = CM_3 | CCIS_2 | CAP | OUTMOD_0; // Capture mode
TA1CCR0 = 1600; // (16Mhz / 1600 = 10000Hz)
TA1CTL = TASSEL_2 | ID_0 | MC_1; // SMCLK, DIV1, Up Mode
// Interrupts
IFG1 &= ~(WDTIFG); // Clear Watchdog Interrupt
IE1 |= WDTIE; // Enable Watchdog Interrupt
__bis_SR_register(GIE); // Enable interrupts
// Watchdog (Capacitive Sensing)
// Interval timer, ACLK, DIV64 (12KHz / 64 = 187.5Hz)
WDTCTL = WDTPW | WDTTMSEL | WDTSSEL | WDTIS0 | WDTIS1;
// Capacitive Sensing
capCalibrate();
/*
* Infinite Loop
*/
static state_t state = FLYING; // Game State
static color_t color; // Current Color
static unsigned long throwTime; // Random time to throw ball
while (1) {
switch (state) {
case FLYING:
// Cycle colors
//color.s = 255; color.b = 255;
color = green;
/*if (timer[0] > 50) {
color.h++;
if (color.h == 255) color.h = 0;
timer[0] = 0;
}*/
// Detect if ball is taken
if (capButton()) {
clock = 0;
timer[0] = 0;
timer[1] = 0;
throwTime = getRandom(10000, 40000);
color = yellow;
state = TAKEN;
}
// Detect Inactivity
if (clock > 200000) {
clock = 0;
state = INACTIVE;
}
break;
case TAKEN:
// Flash color
//color.s = 255;
if (timer[0] > 1500) {
color.b = 255 - color.b;
timer[0] = 0;
}
// Wait random time to pass
if (timer[1] > throwTime) {
timer[0] = 0;
timer[1] = 0;
state = PASS;
}
// If ball is thrown before time, lose
if (capButton() == 0 && timer[1] > 1000) {
timer[0] = 0;
timer[1] = 0;
state = LOSE;
}
break;
case PASS:
// Flash white
color.s = 0;
if (timer[0] > 500) {
color.b = 255 - color.b;
timer[0] = 0;
}
// 500ms to throw ball, if not player loses
if (timer[1] > 10000) {
timer[0] = 0;
timer[1] = 0;
state = LOSE;
}
// If player throws ball, reset to flying
if (capButton() == 0) {
timer[0] = 0;
timer[1] = 1;
state = FLYING;
}
break;
case LOSE:
// Flash red
color.h = red.h; color.s = 255;
if (timer[0] > 5000) {
color.b = 255 - color.b;
timer[0] = 0;
}
// Wait 5s and restart
if (timer[1] > 50000) {
timer[0] = 0;
timer[1] = 0;
state = FLYING;
}
break;
case INACTIVE:
// Turn Off LED
color = off;
// Wake Up
if (capButton()) {
clock = 0;
state = FLYING;
}
break;
}
ledSetColor(color);
}
return 0;
}
/*
* Timer 1 Interrupt
* 1000Hz
*
* PWM / Clock
*/
#pragma vector=TIMER1_A0_VECTOR
__interrupt void TIMER1_A0_ISR_HOOK(void)
{
/*
* PWM
*/
static int pwmCycle = 0;
static int i = 0;
//for (i = 0; i < PWM_CHANNELS; i++) {
// Modified to repeat signal on 4 pins
if (pwmChannel[i] > pwmCycle) {
P1OUT |= (1 << i) + (1 << (i+3));
P2OUT |= (1 << i) + (1 << (i+3));
} else {
P1OUT &= ~((1 << i) + (1 << (i+3)));
P2OUT &= ~((1 << i) + (1 << (i+3)));
}
//}
pwmCycle++;
if (pwmCycle == 16) {
pwmCycle = 0;
i++;
if (i == 3) i = 0;
}
/*
* Clock
*/
clock++;
/*
* Timers
*/
int j;
for (j = 0; j < TIMER_COUNT; j++) {
timer[j]++;
}
}
/*
* Watchdog Timer Interrupt
* 187.5Hz
*
* Capacitive Sensing
*/
#pragma vector=WDT_VECTOR
__interrupt void WDT_ISR_HOOK(void)
{
capChannel = TA0R; // Save current reading
TA0CTL |= TACLR; // Clear timer
}
/*
* LED Functions
*/
void ledSetColor(color_t color) {
// Set according to connected color
int *r = &pwmChannel[0];
int *g = &pwmChannel[1];
int *b = &pwmChannel[2];
// Convert HSB to RGB
if (color.s == 0) {
*r = *g = *b = color.b / PWM_RES; // Does not work for PWM_RES != 16
} else {
unsigned scaledHue = color.h * 6;
unsigned sector = scaledHue >> 8;
unsigned offset = scaledHue - (sector << 8);
unsigned p = (color.b * (255 - color.s)) >> 8;
unsigned q = (color.b * (255 - ((color.s * offset) >> 8) )) >> 8;
unsigned t = (color.b * (255 - ((color.s * (255 - offset)) >> 8) )) >> 8;
switch (sector) {
case 0:
*r = color.b / PWM_RES;
*g = t / PWM_RES;
*b = p / PWM_RES;
break;
case 1:
*r = q / PWM_RES;
*g = color.b / PWM_RES;
*b = p / PWM_RES;
break;
case 2:
*r = p / PWM_RES;
*g = color.b / PWM_RES;
*b = t / PWM_RES;
break;
case 3:
*r = p / PWM_RES;
*g = q / PWM_RES;
*b = color.b / PWM_RES;
break;
case 4:
*r = t / PWM_RES;
*g = p / PWM_RES;
*b = color.b / PWM_RES;
break;
default:
*r = color.b / PWM_RES;
*g = p / PWM_RES;
*b = q / PWM_RES;
break;
}
}
}
/*
* Capacitive Sensor
*/
void capCalibrate() {
int i;
capBase = 0;
for (i = 0; i < 64; i++) {
capBase += capChannel / 64;
__delay_cycles(32000);
}
}
int capButton() {
if (capChannel < capBase - capTreshold) {
return 1;
} else {
return 0;
}
}
/*
* Random Number
*/
unsigned long getRandom(unsigned long low, unsigned long high) {
static unsigned long a = 543;
static unsigned long b = 234;
static unsigned long c = 982;
static unsigned long x = 2;
x++;
a = (a^c^x);
b = (b+a);
c = (c+(b>>1)^a);
return (c%(high-low)) + low;
}