/*! ******************************************************************************* * main program ******************************************************************************/ int main(void) { bool last_state_mnt; //!< motor mounted bool state_mnt; //!< motor mounted bool err; //!< error bool ref_pos_changed; //!< ref Position changed uint8_t last_statekey; //!< state of keys on last loop uint8_t last_second; //!< RTC-second of last main cycle uint8_t ref_position; //!< desired position in percent motor_speed_t speed; //!< motor speed (fast or quiet) uint8_t display_mode; //!< desired display output uint16_t value16; //!< 16 Bit value int16_t value16s; //!< signed 16 Bit value uint8_t value8; //!< 8 Bit value //! initalization init(); //! load/set default values load_defauls(); //! Enable interrupts sei(); //! show POST Screen LCD_AllSegments(LCD_MODE_ON); // all segments on delay(1000); LCD_AllSegments(LCD_MODE_OFF); LCD_PrintDec(REVHIGH, 1, LCD_MODE_ON); // print version LCD_PrintDec(REVLOW, 0, LCD_MODE_ON); LCD_Update(); delay(1000); LCD_AllSegments(LCD_MODE_OFF); // all off //! \todo Send Wakeup MSG state_mnt=false; ref_pos_changed=true; last_second=99; speed=full; last_statekey = 0; last_state_mnt = false; m_key_action = true; ref_position = 10; display_mode=3; ISR(PCINT1_vect); // get keystate // We should do the following once here to have valid data from the start ADC_Measure_Ub(); ADC_Measure_Temp(); /*! **************************************************************************** * main loop * * 1) process keypresses * - m_state_keys and m_wheel are set from IRQ, only process them * - you can set m_wheel to a new value * - controll content of LCD * 2) \todo calc new valveposition if new temp available * - temp is measured by IRQ * 3) calibrate motor * - start calibration is valve mounted changed to on * (during calibration the main loop stops at least for 10 seconds) * - reset calibration is valve mounted changed to off * 4) start motor if * - actual valveposition != desired valveposition && motor is off * 5) if motor is on call MOTOR_CheckBlocked at least once a second * - that switches motor of if it is blocked * 6) store keystate at end of loop before going to sleep * 7) Check for serial command to process * 8) \todo goto sleep if * - motor is of * - no key is pressed (AUTO, C, PROG) * - no serial communication active ***************************************************************************/ for (;;){ // change displaystate every 10 seconds 0 to 5 // Activate Auto Mode // setautomode(true); // 1) process keypresses if (m_key_action){ m_key_action = false; state_mnt = !(m_state_keys & KEYMASK_MOUNT); // State of keys AUTO, C and PROG and valve mounted if ((m_state_keys & KEYMASK_AUTO) != 0){ display_mode--; LCD_SetHourBarVal(display_mode, LCD_MODE_ON); ref_pos_changed = true; LCD_SetSeg(LCD_SEG_AUTO, LCD_MODE_ON); } else { LCD_SetSeg(LCD_SEG_AUTO, LCD_MODE_OFF); } if ((m_state_keys & KEYMASK_C) != 0){ if (display_mode==9){ m_reftemp = input_temp(m_reftemp); } //LCD_SetHourBarVal(display_mode, LCD_MODE_ON); //ref_pos_changed = true; //LCD_SetSeg(LCD_SEG_MANU, LCD_MODE_ON); } else { LCD_SetSeg(LCD_SEG_MANU, LCD_MODE_OFF); } if ((m_state_keys & KEYMASK_PROG)!= 0){ display_mode++; LCD_SetHourBarVal(display_mode+1, LCD_MODE_ON); ref_pos_changed = true; LCD_SetSeg(LCD_SEG_PROG, LCD_MODE_ON); } else { LCD_SetSeg(LCD_SEG_PROG, LCD_MODE_OFF); } } // 2) calc new valveposition if new temp available // - temp is measured by IRQ // 3) calibrate motor // - start calibration if valve is now mounted // TODO: // (during calibration the main loop stops for a long time // maybe add global var to cancel callibration, e.g.: if // HR20 removed from ther gear) // - reset calibration is valve mounted changed to off if (last_state_mnt != state_mnt) { MOTOR_SetMountStatus(state_mnt); if (state_mnt) { LCD_ClearNumbers(); LCD_PrintChar(LCD_CHAR_C, 3, LCD_MODE_ON); LCD_PrintChar(LCD_CHAR_A, 2, LCD_MODE_ON); LCD_PrintChar(LCD_CHAR_L, 1, LCD_MODE_ON); LCD_Update(); // DEBUG: if next line is disabled, not calibration and no // motor control is done // MOTOR_Calibrate(ref_position, speed); LCD_ClearNumbers(); } } // 4) start motor if // - actual valveposition != desired valveposition // - motor is off // - motor is calibrated if ((ref_pos_changed) && (MOTOR_IsCalibrated())){ err = MOTOR_Goto(ref_position, speed); ref_pos_changed = false; } // 5) if motor is on call MOTOR_CheckBlocked at least once a second // - that switches motor of if it is blocked if (MOTOR_On()){ if (last_second != RTC_GetSecond()){ MOTOR_CheckBlocked(); last_second = RTC_GetSecond(); } } // 6) store keystate at end of loop before going to sleep last_statekey = m_state_keys; last_state_mnt = state_mnt; // 7) Check if there is a serial command to process // Loop until all is processed e_meassure(); // test call to sample values and send them to serial port while( (COM_Process() == true) ){}; // 8) goto sleep if // - motor is of // - no key is pressed (AUTO, C, PROG) // - no serial communication active if (display_mode==1) { // Ub: ADC Value Hex ADC_Measure_Ub(); value16 = ADC_Get_Bat_Val(); LCD_PrintHexW(value16, LCD_MODE_ON); }else if (display_mode==2) { // Ub: ADC Value Decimal ADC_Measure_Ub(); value16 = ADC_Get_Bat_Val(); LCD_PrintDecW(value16, LCD_MODE_ON); }else if (display_mode==3) { // Ub: Voltage [mV] ADC_Measure_Ub(); value16 = ADC_Get_Bat_Voltage(); LCD_PrintDecW(value16, LCD_MODE_ON); }else if (display_mode==4) { // Temp: ADC Value Hex ADC_Measure_Temp(); value16 = ADC_Get_Temp_Val(); LCD_PrintHexW(value16, LCD_MODE_ON); }else if (display_mode==5) { // Temp: ADC Value Decimal ADC_Measure_Temp(); value16 = ADC_Get_Temp_Val(); LCD_PrintDecW(value16, LCD_MODE_ON); }else if (display_mode==6) { // Temp: Temperature (Degree) ADC_Measure_Temp(); value16s = ADC_Get_Temp_Degree(); LCD_PrintTempInt(value16s, LCD_MODE_ON); }else if (display_mode==7) { // - 9,87 °C value16s = -987; LCD_PrintTempInt(value16s, LCD_MODE_ON); }else if (display_mode==8) { // 98,76 °C value16s = 9876; LCD_PrintTempInt(value16s, LCD_MODE_ON); }else{ value16 = display_mode; LCD_PrintDecW(value16, LCD_MODE_ON); } /* // Bar 24 on if calibrated if (MOTOR_IsCalibrated()) { LCD_SetSeg(LCD_SEG_BAR24, LCD_MODE_ON); } else { LCD_SetSeg(LCD_SEG_BAR24, LCD_MODE_OFF); } // Hour 0 on if state_mnt if (state_mnt) { LCD_SetSeg(LCD_SEG_B0, LCD_MODE_ON); } else { LCD_SetSeg(LCD_SEG_B0, LCD_MODE_OFF); } // Hour 1 on if last_state_mnt if (last_state_mnt) { LCD_SetSeg(LCD_SEG_B1, LCD_MODE_ON); } else { LCD_SetSeg(LCD_SEG_B1, LCD_MODE_OFF); } if (!MOTOR_IsCalibrated()) { LCD_PrintChar(LCD_CHAR_E, 3, LCD_MODE_ON); LCD_PrintChar(LCD_CHAR_2, 2, LCD_MODE_ON); } else { LCD_PrintDec(ref_position, 1, LCD_MODE_ON); LCD_PrintDec(MOTOR_GetPosPercent(), 0, LCD_MODE_ON); } */ // impulses = MOTOR_GetImpulses(); // update Display each main loop LCD_Update(); } //End Main loop return 0; }
/*! ******************************************************************************* * main program ******************************************************************************/ int main(void) { //! initalization init(); task=0; //! Enable interrupts sei(); /* check EEPROM layout */ if (EEPROM_read((uint16_t)&ee_layout)!=EE_LAYOUT) { LCD_PrintStringID(LCD_STRING_EEPr,LCD_MODE_ON); task_lcd_update(); for(;;) {;} //fatal error, stop startup } COM_init(); // We should do the following once here to have valid data from the start /*! **************************************************************************** * main loop ***************************************************************************/ for (;;){ // go to sleep with ADC conversion start asm volatile ("cli"); if ( ! task && ((ASSR & (_BV(OCR2UB)|_BV(TCN2UB)|_BV(TCR2UB))) == 0) // ATmega169 datasheet chapter 17.8.1 ) { // nothing to do, go to sleep if(timer0_need_clock() || RS_need_clock()) { SMCR = (0<<SM1)|(0<<SM0)|(1<<SE); // Idle mode } else { if (sleep_with_ADC) { SMCR = (0<<SM1)|(1<<SM0)|(1<<SE); // ADC noise reduction mode } else { SMCR = (1<<SM1)|(1<<SM0)|(1<<SE); // Power-save mode } } if (sleep_with_ADC) { sleep_with_ADC=0; // start conversions ADCSRA |= (1<<ADSC); } DEBUG_BEFORE_SLEEP(); asm volatile ("sei"); // sequence from ATMEL datasheet chapter 6.8. asm volatile ("sleep"); asm volatile ("nop"); DEBUG_AFTER_SLEEP(); SMCR = (1<<SM1)|(1<<SM0)|(0<<SE); // Power-save mode } else { asm volatile ("sei"); } // update LCD task if (task & TASK_LCD) { task&=~TASK_LCD; task_lcd_update(); continue; // on most case we have only 1 task, iprove time to sleep } if (task & TASK_ADC) { task&=~TASK_ADC; if (task_ADC()==0) { // ADC is done // TODO } continue; // on most case we have only 1 task, iprove time to sleep } // communication if (task & TASK_COM) { task&=~TASK_COM; COM_commad_parse(); continue; // on most case we have only 1 task, iprove time to sleep } // motor stop if (task & TASK_MOTOR_STOP) { task&=~TASK_MOTOR_STOP; MOTOR_timer_stop(); continue; // on most case we have only 1 task, iprove time to sleep } // update motor possition if (task & TASK_MOTOR_PULSE) { task&=~TASK_MOTOR_PULSE; MOTOR_updateCalibration(mont_contact_pooling()); MOTOR_timer_pulse(); continue; // on most case we have only 1 task, iprove time to sleep } //! check keyboard and set keyboards events if (task & TASK_KB) { task&=~TASK_KB; task_keyboard(); } if (task & TASK_RTC) { task&=~TASK_RTC; { bool minute = RTC_AddOneSecond(); valve_wanted = CTL_update(minute,valve_wanted); if (minute && (RTC_GetDayOfWeek()==6) && (RTC_GetHour()==10) && (RTC_GetMinute()==0)) { // every sunday 10:00AM // TODO: improve this code! // valve protection / CyCL MOTOR_updateCalibration(0); } } MOTOR_updateCalibration(mont_contact_pooling()); MOTOR_Goto(valve_wanted); task_keyboard_long_press_detect(); if ((MOTOR_Dir==stop) || (config.allow_ADC_during_motor)) start_task_ADC(); if (menu_auto_update_timeout>=0) { menu_auto_update_timeout--; } menu_view(false); // TODO: move it, it is wrong place LCD_Update(); // TODO: move it, it is wrong place // do not use continue here (menu_auto_update_timeout==0) } // menu state machine if (kb_events || (menu_auto_update_timeout==0)) { bool update = menu_controller(false); if (update) { menu_controller(true); // menu updated, call it again } menu_view(update); // TODO: move it, it is wrong place LCD_Update(); // TODO: move it, it is wrong place } } //End Main loop
/*! ******************************************************************************* * calibrate the motor and drive it to position in percent * \ returns * - true if calibration successfull * - false if not successfull possible reasons: * - motor is not stopped after \ref MOTOR_MAX_IMPULSES impulses * - motor has been dismounted * * \param percent desired position after calibration 0-100 * - 0 : closed * - 100 : open * * \param speed motorspeed in percent for PWM * * \note minimises motor time (save power) ******************************************************************************/ bool MOTOR_Calibrate(uint8_t percent, motor_speed_t speed) { uint16_t postmp; if (percent > 50) { // - close till no movement or more than MOTOR_MAX_IMPULSES MOTOR_PosAct = MOTOR_MAX_IMPULSES; MOTOR_PosStop = 0; MOTOR_Control(close, speed); do { postmp = MOTOR_PosAct; delay(200); } while ((MOTOR_Dir != stop) && (postmp != MOTOR_PosAct) && MOTOR_Mounted); // motor still on, moving and mounted // stopped by ISR?, turning too long, not mounted -> error if ((MOTOR_Dir == stop) || (MOTOR_Mounted==false)){ return false; } // motor is on, but not turning any more -> endposition reached -> stop the motor MOTOR_Control(stop, speed); // now open till no movement or more than MOTOR_MAX_IMPULSES MOTOR_PosAct = 0; MOTOR_PosStop = MOTOR_MAX_IMPULSES; MOTOR_Control(open, speed); do { postmp = MOTOR_PosAct; delay(200); } while ((MOTOR_Dir != stop) && (postmp != MOTOR_PosAct) && MOTOR_Mounted); // motor still on, moving and mounted // stopped by ISR?, turning too long, not mounted -> error if ((MOTOR_Dir == stop) || (MOTOR_Mounted==false)){ return false; } // motor is on, but not turning any more -> endposition reached -> stop the motor MOTOR_Control(stop, speed); MOTOR_PosMax = MOTOR_PosAct; } else { // - open till no movement or more than MOTOR_MAX_IMPULSES MOTOR_PosAct = 0; MOTOR_PosStop = MOTOR_MAX_IMPULSES; MOTOR_Control(open, speed); do { postmp = MOTOR_PosAct; delay(200); } while ((MOTOR_Dir != stop) && (postmp != MOTOR_PosAct) && MOTOR_Mounted); // motor still on, moving and mounted // stopped by ISR?, turning too long, not mounted -> error if ((MOTOR_Dir == stop) || (MOTOR_Mounted==false)){ return false; } // motor is on, but not turning any more -> endposition reached -> stop the motor MOTOR_Control(stop, speed); // now close till no movement or more than MOTOR_MAX_IMPULSES MOTOR_PosAct = MOTOR_MAX_IMPULSES; MOTOR_PosStop = 0; MOTOR_Control(close, speed); do { postmp = MOTOR_PosAct; delay(200); } while ((MOTOR_Dir != stop) && (postmp != MOTOR_PosAct) && MOTOR_Mounted); // motor still on, moving and mounted // stopped by ISR?, turning too long, not mounted -> error if ((MOTOR_Dir == stop) || (MOTOR_Mounted==false)){ return false; } // motor is on, but not turning any more -> endposition reached -> stop the motor MOTOR_Control(stop, speed); MOTOR_PosMax = MOTOR_MAX_IMPULSES - MOTOR_PosAct; MOTOR_PosAct = 0; } // now MOTOR_PosMax and MOTOR_PosAct calibated // goto desired position MOTOR_Goto(percent, speed); // Send out notify to com.c COM_setNotify(NOTIFY_CALIBRATE); // finished return true; }