summaryrefslogtreecommitdiff
path: root/final_project/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'final_project/main.c')
-rw-r--r--final_project/main.c106
1 files changed, 70 insertions, 36 deletions
diff --git a/final_project/main.c b/final_project/main.c
index f301ef5..926cb99 100644
--- a/final_project/main.c
+++ b/final_project/main.c
@@ -18,15 +18,45 @@
volatile int seconds_remaining; //will be used by ISR
#define SPEAKER_PORT PORTE
-#define SPEAKER_PIN 4 //rename?
+#define SPEAKER_PIN 4
#define ELEMENT_COUNT 7
-//TODO get_button and display_element unnecessarily complex
+
+
+
+/** GETTING/DISPLAYING ELEMENTS
+ * Two of the LEDs are connected to the RX1/TX1 pins, used for serial.
+ * Because of this, there's 7 possible elements.
+ * Here's how elements (guesses) are retrieved from buttons and displayed on LEDs:
+
+ * If the button is on PINA, the element is set to the reading from PINA,
+ * unmodified (aside from the two invalid buttons being masked).
+ * this allows easy LED outputting.
+
+ * If the button is the single one connected to PORTE,
+ * the 2nd bit is set. When displaying elements, we assume
+ * the second bit is the middle PORTE LED.
+
+ */
+
uint8_t get_button() {
- if(~PINE & (1 << 6)) return (1 << 2);
- return ((~PINA) & ~(0b1100)); //TODO clean up
+ //debouncing is done by waiting for the user to stop pressing the button,
+ //then waiting an amount of time for the bouncing to stop.
+ const double debounce_wait = 100.0;
+ if(~PINE & (1 << 6)) {
+ while((~PINE & (1<<6)));
+ _delay_ms(debounce_wait);
+ return (1 << 2);
+ }
+ uint8_t porta_state = (~PINA) & ~(0b1100);
+ if(porta_state) {
+ while(PINA != 0xff);
+ _delay_ms(debounce_wait);
+ }
+ return porta_state;
}
+//for documentation see above paragraph
void display_element(uint8_t element, unsigned int time) {
uint8_t portd_state = 0;
uint8_t porte_state = 0;
@@ -42,23 +72,19 @@ void display_element(uint8_t element, unsigned int time) {
}
void init_io() {
+ //initilize IO registers
+ //Buttons
DDRA = 0x00;
PORTA = 0xff;
- DDRD = 0xff;
+ //LEDs
+ DDRD = 0xff;
PORTD = 0xff;
- DDRE = (1 << 4) | (1 << 5);
+ //speaker and middle LED
+ DDRE = (1 << 4) | (1 << 5);
PORTE = 0xff;
}
-void test_timer() {
- for(;;) {
- usart_txstr("timer test\n");
- start_timer();
- while(!timer_done());
- stop_timer();
- }
-}
int main(void) {
cli();
@@ -78,6 +104,7 @@ int main(void) {
"2. Moderate\n"
"3. Give me pain.");
+ //ask until valid input
while((level > 3) || (level < 1)) level = (int)(usart_rxt_blocking() - '0');
@@ -91,7 +118,7 @@ int main(void) {
double score;
uint8_t element_list[5]; // TODO
-
+ //this is where the level properties are set depending on level
switch(level) {
case 1:
sets = 3;
@@ -117,31 +144,39 @@ int main(void) {
}
- //main level
+ //it's easier to make a variable to count the number of guesses (max_score)
+ //and increment current_score after each correct guess to calculate total score
+ //as the number of elements per set scale.
int max_score = 0;
- int current_score = 0;
+ int current_score = 0;
for(int set = 0; set < sets; set++) {
+ //scale from elements_min (first set) to elements_max (last set)
int elements = elements_min + ceil(((elements_max - elements_min) / (float)(sets - 1)) * set);
- //generate, display elements
+
+ //randomly get, display elements
for(int element = 0; element < elements; element++) {
uint8_t element_bit = (rand() % ELEMENT_COUNT);
- if(element_bit == 3) element_bit = 7;
+ // button 3 should never be pressed, so if 3 is randomly generated,
+ // we make it the last LED. We only generate 7 potential elements.
+ if(element_bit == 3) element_bit = 7;
uint8_t this_element = 1 << element_bit;
usart_txt('\n');
usart_txt(element_bit + '0');
usart_txt('\n');
- element_list[element] = this_element; // could optimize
+ element_list[element] = this_element; //will be compared to guesses later
display_element(this_element, display_time);
}
- //get elements
+ //get elements from buttono presses
+ //we'll poll the timer to see if a second has passed
+ //as timer only supports a max of 0xffff * (1024 / 16000000) seconds
seconds_remaining = response_time;
start_timer();
uint16_t guess;
for(int element = 0; element < elements; element++) {
- usart_txstr("\ngot element, waiting...\n");
+ guess = 0;
do {
- if(timer_done()) {
+ if(timer_done()) { //accounts for seconds passed
seconds_remaining--;
stop_timer(); //TODO only need one function
start_timer();
@@ -149,7 +184,6 @@ int main(void) {
}
else { guess = get_button(); }
} while((!guess) && (seconds_remaining > 0));
- _delay_ms(250); //prevent double press
max_score++;
if(guess == element_list[element]) {
current_score++;
@@ -160,25 +194,19 @@ int main(void) {
}
}
}
+ //where we check the score. Score is calculated per level.
+ //If score under 80, we break back to the menu.
score = (float)current_score / max_score;
if(score >= .8) {
level++;
usart_txstr("\nnext level\n");
- }
+ }
else {
loose();
break;
}
}
- if(level >= 3) win();
- }
-}
-
-//timer interrupt
-ISR(TIMER1_COMPA_vect) {
- if(seconds_remaining-- > 0) return;
- for(;;) {
- beep();
+ if(level >= 3) win(); //you win if you get past level 3
}
}
@@ -206,8 +234,14 @@ void loose() {
beep(294., .5);
}
-
-//TODO move somewhere else
+/** can handle specific frequencies for a durientation of time.
+ * speaker_ms is caculated by taking the period, dividing by 2
+ * (as we need to flip speaker state once per cycle)
+ * then multiplies it by 1000 to convert to ms for _delay_ms.
+ * We control how long its played by making it loop,
+ * loop count is durientation of note / period.
+ * loop_count will be off by a max of 1 period.
+ **/
void beep(double frequency, double durientation) {
double speaker_ms = ((1.0 / frequency) / 2.0) * 1000.0; //TODO clean up
int loop_count = durientation / (1.0 / frequency);