/** * My Nixie Clock IN-4x6 * Vladimir N. Shilov * 2020.01.06 */ /* Compiler libs */ #include #include #include #include #include #include #include #include /* Project libs */ #include "i2c.h" #include "ds3231.h" #include "rtos.h" #include "event-system.h" #include "main.h" #include "common.h" /* Defines */ /* Timer2 settings * Prescaler (CS22/CS21/CS20 - value): * 0/0/0 - stop * 0/0/0 - 1 (no prescale) * 0/1/0 - 8 * 0/1/1 - 32 * 1/0/0 - 64 * 1/0/1 - 128 * 1/1/0 - 256 * 1/1/1 - 1024 */ #define TIMER2_HZ 360 #if F_CPU == 16000000 #define TIMER2_PRESCALER 256 #define TIMER2_CS (1< BRIGHT_IDX_MAX) { brightIdx = BRIGHT_IDX_MAX; } #endif // USE_BRIGHT_CONTROL /** * Инициализация, настройка... */ Board_Init(); /* Initialize Scheduler */ RTOS_Init(); tdelay_ms(2000); #ifdef LAMP_TEST lampTest(); tdelay_ms(5000); #endif // LAMP_TEST /* Initialize I2C Bus and RTC */ I2C_Init(); RTC_Init(); RTC_ReadAll(&RTC); /* Initialize Event State Machine */ ES_Init(stShowTime); RTOS_SetTask(btnProcess, 3, BTN_SCAN_PERIOD); #ifdef USE_BRIGHT_CONTROL // RTOS_SetTask(startADC, 10, 500); #endif // USE_BRIGHT_CONTROL showTime(); /** main loop */ do { /* new second interrupt from RTC */ if (Flag.RTC_Int != 0) { Flag.RTC_Int = 0; ES_PlaceEvent(evNewSecond); RTC_ReadTime(&RTC); if (RTC.Sec == 0 && RTC.Min == 0) { // begin of new hour if (RTC.Hr == 0) { // begin of new day RTC_ReadCalendar(&RTC); ES_PlaceEvent(evRefreshCal); } #ifdef USE_BRIGHT_CONTROL if (RTC.Hr >= FULL_BRIGHT_ON && RTC.Hr < FULL_BRIGHT_OFF) { // if (resultADC < LIGHT_LEVEL) { OCR2 = pgm_read_byte(&brightConv[BRIGHT_IDX_MAX]); } else { OCR2 = pgm_read_byte(&brightConv[brightIdx]); } #endif // USE_BRIGHT_CONTROL setSummerWinterTime(); } // begin new hour if (DISP_WDT != 0) { DISP_WDT --; if (DISP_WDT == 0) { ES_PlaceEvent(evDisplayWDT); if (Flag.saveEEP != 0) { Flag.saveEEP = 0; eeprom_update_byte(&EEP_BrightIdx, brightIdx); } } } } // End of New Second event = ES_GetEvent(); if (event) { ES_Dispatch(event); } // крутим диспетчер RTOS_DispatchTask(); // делать нечего -- спим, ждём прерывание set_sleep_mode(SLEEP_MODE_IDLE); sleep_mode(); } while(1); } /** * П о д п р о г р а м м ы */ /** * @brief Initializy perephireal */ static void Board_Init(void) { /* power off Analog Comparator */ ACSR = ACD; /* GPIO */ DDRB = ANODB_PINS; // as output PORTB = BUTTON_PINS; // enable pull-up DDRC = DIGIT_PINS; // as output DDRD = (DOT_PIN | ANODD_PINS); // as output /* Timer2 - refresh Nixie values */ TCCR2 = TIMER2_CS; TCNT2 = TIMER2_CNT; TIMSK = _BV(TOIE2); #ifdef USE_BRIGHT_CONTROL /* ADC init */ // ADMUX = (1<> 8); UBRRL = BAUD_PRESCALE; #endif // USE_UART /* Enable Interrupts */ sei(); } /** * @brief Correct current time for Sun or Winter */ static void setSummerWinterTime(void) { uint8_t sunTime = eeprom_read_byte(&EEP_SummerTime); /* Переход на летнее время */ if ((RTC.Mon == 3) && (RTC.WD == 7) && (RTC.Hr == 3) && (sunTime != 0)) { if ((RTC.Day + 7) > 31) { RTC.Hr = 4; RTC_WriteHH(&RTC); sunTime = 0; eeprom_update_byte(&EEP_SummerTime, sunTime); } } /* Переход на зимнее время */ if ((RTC.Mon == 10) && (RTC.WD == 7) && (RTC.Hr == 4) && (sunTime == 0)) { if ((RTC.Day + 7) > 31) { RTC.Hr = 3; RTC_WriteHH(&RTC); sunTime = 1; eeprom_update_byte(&EEP_SummerTime, sunTime); } } } void dotOn(void) { PORTD |= DOT_PIN; } void dotOff(void) { PORTD &= ~(DOT_PIN); } void dotOnPersistent(void) { RTOS_DeleteTask(dotOff); dotOn(); } /** * @brief Обработка кнопок. * @param : None * @retval : None */ static void btnProcess(void) { uint8_t i; for (i=0; i= BTN_TIME_HOLDED) { Button[i].time -= BTN_TIME_REPEATED; if (Button[i].holded == Button[i].pressed) { // if pressed and holded - same function, then button pressed auto repeat ES_PlaceEvent(Button[i].pressed); } } } else { // button released if (Button[i].time >= (BTN_TIME_HOLDED - BTN_TIME_REPEATED)) { ES_PlaceEvent(Button[i].holded); // process long press } else if (Button[i].time >= BTN_TIME_PRESSED) { ES_PlaceEvent(Button[i].pressed); // process short press } Button[i].time = 0; RTOS_SetTask(btnProcess, BTN_TIME_PAUSE, BTN_SCAN_PERIOD); } } /* end (pin == 0) */ } /* end FOR */ } void showTime(void) { /* Digit[0] = DIGIT_BLANK; Digit[1] = DIGIT_BLANK; Digit[2] = DIGIT_BLANK; Digit[3] = resultADC / 100; Digit[4] = (resultADC % 100) / 10; Digit[5] = resultADC % 10; */ dotOn(); RTOS_SetTask(dotOff, 500, 0); if (RTC.Hr > 0x09) { Digit[0] = RTC.Hr >> 4; } else { Digit[0] = DIGIT_BLANK; } Digit[1] = RTC.Hr & 0x0F; Digit[2] = RTC.Min >> 4; Digit[3] = RTC.Min & 0x0F; Digit[4] = RTC.Sec >> 4; Digit[5] = RTC.Sec & 0x0F; } void showWDM(void) { DISP_WDT = DISP_WDT_TIME; Digit[0] = RTC.WD & 0x0F; Digit[1] = DIGIT_BLANK; Digit[2] = RTC.Day >> 4; Digit[3] = RTC.Day & 0x0F; Digit[4] = RTC.Mon >> 4; Digit[5] = RTC.Mon & 0x0F; } void showYear(void) { DISP_WDT = DISP_WDT_TIME; Digit[0] = DIGIT_BLANK; Digit[1] = DIGIT_BLANK; Digit[2] = 0x02; Digit[3] = 0x00; Digit[4] = RTC.Year >> 4; Digit[5] = RTC.Year & 0x0F; } #ifdef USE_BRIGHT_CONTROL void showBright(void) { DISP_WDT = DISP_WDT_TIME; Digit[0] = DIGIT_BLANK; Digit[1] = DIGIT_BLANK; Digit[2] = DIGIT_BLANK; Digit[3] = brightIdx; Digit[4] = DIGIT_BLANK; Digit[5] = DIGIT_BLANK; } void incBright(void) { if (brightIdx < BRIGHT_IDX_MAX) { brightIdx ++; OCR2 = pgm_read_byte(&brightConv[brightIdx]); Flag.saveEEP = 1; } } void decBright(void) { if (brightIdx > 0 ) { brightIdx --; OCR2 = pgm_read_byte(&brightConv[brightIdx]); Flag.saveEEP = 1; } } /* static void startADC(void) { // enable interrupt and start conversion ADCSRA |= ((1<> 4; Digit[1] = setRTC.Hr & 0x0F; Digit[2] = setRTC.Min >> 4; Digit[3] = setRTC.Min & 0x0F; Digit[4] = 0x0; Digit[5] = 0x0; } void setTimeBegin(void) { RTC_ReadTime(&setRTC); RTOS_SetTask(btnProcess, 500, BTN_SCAN_PERIOD); } void setHHBegin(void) { Flag.blink0 = 1; Flag.blink1 = 0; Flag.blink2 = 0; RTOS_SetTask(blink, 0, 0); setTimeShow(); } void setHHInc(void) { valIncrease(&setRTC.Hr, 23); } void setHHDec(void) { valDecrease(&setRTC.Hr, 23); } void setMMBegin(void) { Flag.blink0 = 0; Flag.blink1 = 1; Flag.blink2 = 0; RTOS_SetTask(blink, 0, 0); setTimeShow(); } void setMMInc(void) { valIncrease(&setRTC.Min, 59); } void setMMDec(void) { valDecrease(&setRTC.Min, 59); } void setTimeEnd(void) { RTOS_SetTask(btnProcess, 500, BTN_SCAN_PERIOD); setRTC.Sec = 0; RTC_WriteTime(&setRTC); RTOS_DeleteTask(blink); Flag.blink0 = 0; Flag.blink1 = 0; Flag.blink2 = 0; Flag.blinkC = 0; RTC_ReadTime(&RTC); } /** * Setup Calendar functions */ void setDateBegin(void) { RTC_ReadCalendar(&setRTC); RTOS_SetTask(btnProcess, 500, BTN_SCAN_PERIOD); } void setDateEnd(void) { RTOS_SetTask(btnProcess, 500, BTN_SCAN_PERIOD); RTC_WriteCalendar(&setRTC); Flag.blink0 = 0; Flag.blink1 = 0; Flag.blink2 = 0; Flag.blinkC = 0; RTC_ReadCalendar(&RTC); dotOff(); } void setWDMShow(void) { DISP_WDT = DISP_WDT_TIME; dotOnPersistent(); Digit[0] = setRTC.WD & 0x0F; Digit[1] = DIGIT_BLANK; Digit[2] = setRTC.Day >> 4; Digit[3] = setRTC.Day & 0x0F; Digit[4] = setRTC.Mon >> 4; Digit[5] = setRTC.Mon & 0x0F; } void setYearShow(void) { DISP_WDT = DISP_WDT_TIME; dotOff(); Digit[0] = DIGIT_BLANK; Digit[1] = DIGIT_BLANK; Digit[2] = 0x02; Digit[3] = 0x00; Digit[4] = setRTC.Year >> 4; Digit[5] = setRTC.Year & 0x0F; } void setWDayBegin(void) { Flag.blink0 = 1; Flag.blink1 = 0; Flag.blink2 = 0; RTOS_SetTask(blink, 0, 0); setWDMShow(); } void setMDayBegin(void) { Flag.blink0 = 0; Flag.blink1 = 1; Flag.blink2 = 0; RTOS_SetTask(blink, 0, 0); setWDMShow(); } void setMonthBegin(void) { Flag.blink0 = 0; Flag.blink1 = 0; Flag.blink2 = 1; RTOS_SetTask(blink, 0, 0); setWDMShow(); } void setYearBegin(void) { Flag.blink0 = 0; Flag.blink1 = 0; Flag.blink2 = 1; RTOS_SetTask(blink, 0, 0); setYearShow(); } void setIncWDay(void) { if (setRTC.WD < 7) { setRTC.WD ++; } else { setRTC.WD = 1; } } void setDecWDay(void) { if (setRTC.WD > 1) { setRTC.WD --; } else { setRTC.WD = 7; } } void setIncMDay(void) { valIncrease(&setRTC.Day, 31); if (setRTC.Day == 0) { setRTC.Day = 1; } } void setDecMDay(void) { valDecrease(&setRTC.Day, 31); if (setRTC.Day == 0) { setRTC.Day = 0x31; } } void setIncMonth(void) { valIncrease(&setRTC.Mon, 12); if (setRTC.Mon == 0) { setRTC.Mon = 1; } } void setDecMonth(void) { valDecrease(&setRTC.Mon, 12); if (setRTC.Mon == 0) { setRTC.Mon = 0x12; } } void setIncYear(void) { valIncrease(&setRTC.Year, 99); } void setDecYear(void) { valDecrease(&setRTC.Year, 99); } /** * @brief Increase BCD value. * @param : val, max * @retval : None */ static void valIncrease(uint8_t * val, uint8_t max) { uint8_t bin = 10 * (*val >> 4) + (*val & 0x0f); if (bin < max) { bin ++; } else { bin = 0; } *val = ((bin / 10 ) << 4) | (bin % 10); } /** * @brief Decrease BCD value. * @param : value, max * @retval : None */ static void valDecrease(uint8_t * val, uint8_t max) { uint8_t bin = 10 * (*val >> 4) + (*val & 0x0f); if (bin > 0) { bin --; } else { bin = max; } *val = ((bin / 10 ) << 4) | (bin % 10); } #ifdef USE_UART void usart_putc (char send) { // Do nothing for a bit if there is already // data waiting in the hardware to be sent while ((UCSRA & (1 << UDRE)) == 0) {}; UDR = send; } void usart_puts (const char *send) { // Cycle through each character individually while (*send) { usart_putc(*send++); } } #endif // USE_UART #ifdef LAMP_TEST /** * Lamp Test */ static void lampValInc(uint8_t n) { if (Digit[n] != DIGIT_BLANK) { Digit[n] ++; } else { Digit[n] = 1; } if (Digit[n] > 9) { Digit[n] = 0; if (n > 0) { lampValInc(n-1); } } } static void lampTest(void) { uint8_t i=0; uint8_t k, x; dotOn(); for (k = 0; k 9) { dotOn(); i = 0; lampValInc(LAMP_NUM-2); } tdelay_ms(10); if (i == 5) { dotOff(); } x = 1; for (k = 0; k