int main(void) { init_other_hw(); /* Must call this first */ init_timer(); init_audio(); init_turnled(); init_inputs(); enable_task(TURNLED_TASK); enable_task(AUDIO_TASK); enable_task(INPUTS_TASK); enable_task(COUNTDOWN_TASK); /* initialize display, cursor off */ lcd_init(LCD_DISP_ON); init_clock(); /* Enable interrupts */ sei(); for (;;) { /* loop forever */ poll_inputs(); poll_clock(); sleep_until_interrupt(); } /* end loop forever */ }
int main(void) { setup(); uint16_t increment = 0; //DDRD &= ~(1<<PD4); no longer needed //PORTD |= (1<<PD4); while(1) { /* measure supply voltage and warn user if voltage drops too low */ if(ISR_flag.check_supply) //measure supply voltage every 10ms { check_supply_voltage(); ISR_flag.check_supply = 0; //clear flag } /* poll the inputs and look for any falling edges indicating button presses or other input signals */ if(ISR_flag.check_inputs) { poll_inputs(); ISR_flag.check_inputs = 0; //clear flag /* Detect a long button press by incrementing a variable every ms the button is pressed * This is necessary to avoid false triggering due to EMI from the motor lines. */ if(!(DOOR_BUTTON_PINREG & (1<<DOOR_BUTTON_PIN))) { increment++; }else{ increment = 0; // reset the count if the button is released. } } /* check for a 1000ms long button press * Again, this is necessary to avoid false triggering due to motor interference */ if(increment >= 1000) { increment = 0; command.delayed_lock = 1; //activate the delayed lock sequence delayed_lock_tick = 0; //reset the timer for the delayed lock sequence } /* check, if status is unknown or a reference command has been issued * If that is the case, ignore any other commands and find the reference point first! * * Note, that command.reference is not implemented yet. There was no need for this until now (10/Aug/15) */ if( ((!status.locked) && (!status.unlocked)) || (command.reference) ) { if((command.lock)||(command.unlock)||(command.reference)) { if(input_status_current[6]) //find out, if gear magnet is already near the reed contact { find_reference(0,500,2000); }else{ find_reference(1,500,2000); } command.lock = 0; command.unlock = 0; command.reference = 0; command.delayed_lock = 0; } }else { /* open the door */ if (command.unlock && !command.block_unlock && !command.reference) { command.block_lock = 1; //prevent any other lock commands while this is active enable_stepper(1); if(!status.open) //Door is not open yet, move to "open" position { if(move_to_position(OPEN)==1) //set status.open once at "open" position { status.open = 1; } ms_100_tick = 0; //reset the 100ms tick until at "open" position }else if(ms_100_tick<=35) { //wait 3.5s at "open" position before turning back to "neutral". This lets the user open the door by pushing it } if((ms_100_tick>35)&&(status.open)) //Door is "open" and we waited for 3.5s { if(move_to_position(NEUTRAL)==1) //move back to "neutral" position and reset all status and command bits. { command.unlock = 0; command.block_lock = 0; status.open = 0; status.locked = 0; status.unlocked = 1; status.error = 0; status.reached_endstop = 0; command.delayed_lock = 0; enable_stepper(0); } } } else /* lock the door */ if (command.lock && !command.block_lock && !command.reference) { /* locking is the same as a reference turn, so we use every lock command to re-reference our position * to account for stupid users turning the gear by hand */ enable_stepper(1); command.block_unlock = 1; //block any other actions while locking the door if(!status.reached_endstop && (position > (-2000))) //turn CCW until either endstop is reached or 2000 steps have passed { move_to_position(-2000); ms_100_tick = 0; } else if (position <= (-2000)) //2000 steps have passed without reaching the endstop -> something went wrong { command.lock = 0; command.block_unlock = 0; status.locked = 0; status.unlocked = 0; status.error = 1; command.delayed_lock = 0; enable_stepper(0); } else if(ms_100_tick<=1){ //endstop reached, reset the position to 0 while waiting a bit position = 0; } if((ms_100_tick>3)&&(status.reached_endstop)) //return to "neutral" position after 300ms { if(move_to_position(NEUTRAL)==1) //reset status and command bits after coming back to the "neutral" position { command.lock = 0; command.block_unlock = 0; status.reached_endstop = 0; status.locked = 1; status.unlocked = 0; status.error = 0; enable_stepper(0); command.delayed_lock = 0; } } } else /* someone locked the door by hand and triggered the endstop. Set status to "locked" */ if (!command.lock && !command.unlock && !command.reference) { if(status.reached_endstop) { status.open = 0; status.unlocked = 0; status.locked = 1; } } } /* delayed lock has been triggered. Start the countdown */ if (command.delayed_lock && status.unlocked && !status.open && !command.block_unlock && !command.block_lock && !command.lock && !command.unlock) { if(delayed_lock_tick < 150) //wait for 15s and set "status.delayed_lock". This triggers the flashing yellow LED { status.delayed_lock = 1; switch_LED(0,'B'); }else { status.delayed_lock = 0; command.delayed_lock = 0; command.lock = 1; //15s have passed, give the "lock" command to lock the door } } /* Switch LEDs according to the status bits. * * This needs to be streamlined, it is way to complicated */ if(status.delayed_lock) //Override any other LED configurations while "status.delayed_lock" is active { flash_LED(25,(180-delayed_lock_tick),'Y'); switch_LED(0,'B'); }else { if(status.error || ( (!status.unlocked)&&(!status.locked))) { flash_LED(10,20,'Y'); flash_LED(10,20,'B'); set_status('E'); } if(status.open) { flash_LED(25,40,'B'); switch_LED(0,'Y'); set_status('U'); } if(status.unlocked && !status.open) { switch_LED(0,'Y'); switch_LED(1,'B'); set_status('U'); } if(status.locked && !status.open) { switch_LED(0,'B'); switch_LED(1,'Y'); set_status('L'); } } } }