-
Notifications
You must be signed in to change notification settings - Fork 0
/
Main.c
290 lines (242 loc) · 6.92 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
/*************************************************************************
* Yuqi (Mark) Zhao and Claire Chen
* ECE 3140 Final Project - Drumroll-Bot
* Cornell University - Spring 2016
*
*/
#include "Buttons.h"
#include "LED.h"
#include "Servo.h"
#include "Beats.h"
//Flags that store if the red or green LED are on
volatile int intflag = 0;
volatile int intflag2 = 0;
//volatile int counter = 0;
//Servo 1
volatile int is_servo1_high = 0; //0 if low, 1 if high
volatile int servo1_angle = 0; //Global variable to hold angle of servo1
volatile int tap_dat_1 = 0; //Flag that is set when we want to "hit" the first drum
volatile int tap_counter_1 = 0; //Counter that holds time elapsed for a "hit" of servo 1
//Servo 2
volatile int is_servo2_high = 0; //0 if low, 1 if high
volatile int servo2_angle = 0; //Global variable to hold angle of servo2
volatile int tap_dat_2 = 0; //Flag that is set when we want to "hit" the first drum
volatile int tap_counter_2 = 0; //Counter that holds time elapsed for a "hit" of servo 2
//Head of list that stores user-entered beats
beat_t* beat_list = NULL;
//Counter that keeps track of time elapsed per period
volatile int time_ms = 0;
//volatile int start_time = 0;
//State variable
volatile int state = 0;
/*
* Main Function
*/
int main(void){
beat_t* current;
/**********************Configure Timers, Buttons, Servos********************************/
//Test pullup
configure_buttons();
setup_LED();
servo_init();
servo_setup_timers();
//Set up the current_time timer
setup_beat_timer();
/****************************************************************************************/
//Now prompt for user input
prompt_for_input();
//Do nothing until we're in state 3. Then delay and repeat the sequence
while(state < 2){
//Spin and wait for users to finish inputting data
}
delay(DELAY_TIME);
LEDRed_Off();
state = 3;
//Now keep walking through the beat list and replay each beat
while(1){
time_ms = 0;
PIT->CHANNEL[2].TCTRL = 3;
//Get the first beat and hit it
current = beat_list;
servo_hit(current->servo_num);
//Walk through the beat list until we reach the end
while(current->next != NULL){
current = current->next;
//Don't hit the next beat until the time is greater than the beat's time
while(current->hit_time > time_ms){
//Spin
}
servo_hit(current->servo_num);
}
//Now at the end of the period, reset the timer and repeat
PIT->CHANNEL[2].TCTRL = 0;
};
return 0;
}
/***************************Button IRQ Handlers**********************************/
/*
* Interrupt Handler for Buttons
*/
void PORTC_IRQHandler(void){
if( (state == 0 || state == 1) && ( (PORTC->ISFR & (1<<BT1)) || (PORTC->ISFR & (1<<BT2)) )){
beat_t* beat;
// This is the first beat, so append to head
if(PORTC->ISFR & (1<<BT1)){
beat = create_beat(1, time_ms);
}
else{
beat = create_beat(2, time_ms);
}
//Append to beat list
if(beat != NULL){
add_to_tail(&beat_list, beat);
}
if(state == 0){
state = 1;
//Start the timer
PIT->CHANNEL[2].TCTRL = 3;
LEDRed_On();
}
}
//END command is hit
//In this case, we treat the END command as another servo hit, to put in the correct delay after the last hit
//Before repeating the period. Thus, we just treat "servo 3" as the END signal
if( (state == 1) && (PORTC->ISFR & (1<<BT3)) )
{
beat_t* end_beat = create_beat(3, time_ms);
if(end_beat != NULL){
add_to_tail(&beat_list, end_beat);
}
LEDGrn_Off();
state = 2;
//Stop the timer and reset the time
PIT->CHANNEL[2].TCTRL = 0;
time_ms = 0;
}
//Functions to hit servos and stuff
//NVIC_DisableIRQ(PORTC_IRQn);
//delay(500000);
if ((PORTC-> ISFR & (1<<BT1)) && (state == 0 || state == 1)){
servo_hit(1);
/*
if(intflag == 0){
intflag = 1;
LEDGrn_On();
}
else{
intflag = 0;
LEDGrn_Off();
}
*/
}
else if((PORTC->ISFR & (1<<BT2)) && (state == 0 || state == 1)){
servo_hit(2);
/*
if(intflag2 == 0){
intflag2 = 1;
LEDRed_On();
}
else{
intflag2 = 0;
LEDRed_Off();
}
*/
}
//NVIC_EnableIRQ(PORTC_IRQn);
//Reset the ISF
PORTC->PCR[BT1] |= (1 << 24);
PORTC->PCR[BT2] |= (1 << 24);
PORTC->PCR[BT3] |= (1 << 24);
}
/****************************************************************************************/
/**********************PIT IRQ Handlers ***********************************************/
/*
* Interrupt Handler for servo 1. This should trigger twice every 20ms.
*/
void PIT0_IRQHandler(void){
int val;
PIT->CHANNEL[0].TCTRL = 0; //Disable Timer
switch(is_servo1_high){
case 0:
//Load high timer value
val = servo_get_high(servo1_angle);
//Write high
PTD->PDOR |= (1 << SERVO1); //Write a high value
is_servo1_high = 1;
//Increase the tap_counter_1 every 20ms only when we're tapping
if(tap_dat_1){
tap_counter_1++;
}
break;
case 1:
val = servo_get_low(servo1_angle);
//Write low
PTD->PDOR &= ~(1 << SERVO1);
is_servo1_high = 0;
break;
}
//If we've counted 20x (400ms have elapsed), then raise servo to neutral pos
if(tap_counter_1 >= TAP_LIMIT){
tap_dat_1 = 0; //no more tapping :(
servo1_angle = SERVO1_NEUTRAL;
tap_counter_1 = 0; //Reset Counter for future tapping
}
PIT->CHANNEL[0].LDVAL = val; //Write appropriate timer val
PIT->CHANNEL[0].TFLG |= (1 << 0); //Clear flag
PIT->CHANNEL[0].TCTRL = 3; //Re-enable timer
return;
}
/*
* Interrupt Handler for servo 1. This should trigger twice every 20ms.
*/
void PIT1_IRQHandler(void){
int val;
PIT->CHANNEL[1].TCTRL = 0; //Disable Timer
switch(is_servo2_high){
case 0:
//Load high timer value
val = servo_get_high(servo2_angle);
//Write high
PTD->PDOR |= (1 << SERVO2); //Write a high value
is_servo2_high = 1;
//Increase the tap_counter_2 every 20ms only when we're tapping
if(tap_dat_2){
tap_counter_2++;
}
break;
case 1:
val = servo_get_low(servo2_angle);
//Write low
PTD->PDOR &= ~(1 << SERVO2);
is_servo2_high = 0;
break;
}
//If we've counted 20x (400ms have elapsed), then raise servo to neutral pos
if(tap_counter_2 >= TAP_LIMIT){
tap_dat_2 = 0; //no more tapping :(
servo2_angle = SERVO2_NEUTRAL;
tap_counter_2 = 0; //Reset Counter for future tapping
}
PIT->CHANNEL[1].LDVAL = val; //Write appropriate timer val
PIT->CHANNEL[1].TFLG |= (1 << 0); //Clear flag
PIT->CHANNEL[1].TCTRL = 3; //Re-enable timer
return;
}
/*
* IRQ Handler to increment the global time variable for each period.
*/
void PIT2_IRQHandler(void){
time_ms++;
//Reset the interrupt flag and refresh the timer.
PIT->CHANNEL[2].TFLG = 1;
PIT->CHANNEL[2].TCTRL = 0;
PIT->CHANNEL[2].TCTRL = 3;
//else do nothing
}
/******************************************************************************/
/*********************** Helper Functions****************************************/
void delay(int delay){
int i;
for(i = 0; i < delay; i++);
}
/******************************************************************************/