From 4976af6a8458b8263abceb19368e95688031fb9a Mon Sep 17 00:00:00 2001 From: brett Date: Thu, 25 Apr 2024 00:09:09 -0500 Subject: doooone --- final_project/main.c | 106 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 36 deletions(-) (limited to 'final_project/main.c') 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); -- cgit v1.2.3