main.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. /**
  2. * My Nixie Clock IN-12
  3. * Vladimir N. Shilov <shilow@ukr.net>
  4. * 2019.01.18
  5. */
  6. /* Compiler libs */
  7. #include <stdbool.h>
  8. #include <stdint.h>
  9. #include <stdlib.h>
  10. #include <avr/io.h>
  11. #include <avr/interrupt.h>
  12. #include <avr/sleep.h>
  13. #include <avr/eeprom.h>
  14. #include <avr/pgmspace.h>
  15. /* Project libs */
  16. #include "i2c.h"
  17. #include "ds3231.h"
  18. #include "rtos.h"
  19. #include "event-system.h"
  20. #include "common.h"
  21. #include "main.h"
  22. /* Defines */
  23. /* Timer2 settings */
  24. #define TIMER2_HZ 400
  25. #define TIMER2_PRESCALER 1024
  26. #define TIMER2_CS (1<<CS22 | 1<<CS21 | 1<<CS20)
  27. #define TIMER2_CNT (0x100 - (F_CPU / TIMER2_PRESCALER / TIMER2_HZ))
  28. /* Display timeout, sec */
  29. #define DISP_WDT_TIME 10
  30. #ifdef USE_UART
  31. /* USART */
  32. #define BAUD 19200UL
  33. #define BAUD_PRESCALE (uint8_t)((F_CPU / BAUD / 16UL) - 1)
  34. #define CHAR_NEWLINE '\n'
  35. #define CHAR_RETURN '\r'
  36. #define RETURN_NEWLINE "\r\n"
  37. #endif // USE_UART
  38. #ifdef USE_BRIGHT_CONTROL
  39. /* Lamp brightness */
  40. #define BRIGHT_IDX_MAX 4
  41. #define FULL_BRIGHT_ON 0x06
  42. #define FULL_BRIGHT_OFF 0x22
  43. static const uint8_t PROGMEM brightConv[BRIGHT_IDX_MAX+1] = {
  44. 218, 225, 230, 240, 255
  45. };
  46. #endif // USE_BRIGHT_CONTROL
  47. #ifdef USE_DHT
  48. // timeout in timer tiks, step 4 mks
  49. #define DHT_TIMEOUT 1500
  50. #define DHT_TOUT1 55
  51. static struct {
  52. uint8_t Humidity;
  53. uint16_t Temperature;
  54. } dhtData;
  55. #endif // USE_DHT
  56. /* Variables */
  57. static volatile uint8_t Digit[4] = {1, 2, 3, 4};
  58. static rtc_t RTC, setRTC;
  59. static volatile struct {
  60. uint8_t RTC_Int: 1;
  61. uint8_t saveCal: 1;
  62. uint8_t blinkC: 1;
  63. uint8_t blink0: 1;
  64. uint8_t blink1: 1;
  65. uint8_t blink2: 1;
  66. uint8_t blink3: 1;
  67. uint8_t saveEEP: 1;
  68. } Flag;
  69. static btn_t Button[BTN_NUM] = {
  70. {0, evBTN1Pressed, evBTN1Holded, BUTTON1_PIN},
  71. {0, evBTN2Pressed, evBTN2Pressed, BUTTON2_PIN},
  72. {0, evBTN3Pressed, evBTN3Pressed, BUTTON3_PIN}
  73. };
  74. static volatile uint8_t DISP_WDT = 0;
  75. static EEMEM uint8_t EEP_BrightIdx;
  76. static uint8_t brightIdx;
  77. static EEMEM uint8_t EEP_SummerTime;
  78. /* Function prototypes */
  79. static void Board_Init(void);
  80. static void dotOn(void);
  81. static void btnProcess(void);
  82. static void valIncrease(uint8_t * val, uint8_t max);
  83. static void valDecrease(uint8_t * val, uint8_t max);
  84. static void blink(void);
  85. static void setSummerWinterTime(void);
  86. #ifdef USE_DHT
  87. static void dhtStart(void);
  88. static void dhtProcess(void);
  89. static void dhtEnd(void);
  90. static void dhtTimeout(void);
  91. static void dhtNoAck(void);
  92. #endif // USE_DHT
  93. #ifdef USE_UART
  94. void usart_putc (char send);
  95. void usart_puts (const char *send);
  96. #endif // USE_UART
  97. void main(void) {
  98. /**
  99. * Локальные переменные
  100. */
  101. uint8_t event = 0;
  102. Flag.RTC_Int = 0;
  103. Flag.saveCal = 0;
  104. Flag.blink0 = 0;
  105. Flag.blink1 = 0;
  106. Flag.blink2 = 0;
  107. Flag.blink3 = 0;
  108. Flag.blinkC = 0;
  109. Flag.saveEEP = 0;
  110. #ifdef USE_BRIGHT_CONTROL
  111. brightIdx = eeprom_read_byte(&EEP_BrightIdx);
  112. if (brightIdx > BRIGHT_IDX_MAX) {
  113. brightIdx = BRIGHT_IDX_MAX;
  114. }
  115. #endif // USE_BRIGHT_CONTROL
  116. /**
  117. * Инициализация, настройка...
  118. */
  119. Board_Init();
  120. /* Initialize Scheduler */
  121. RTOS_Init();
  122. tdelay_ms(1000); // warm up
  123. /* Initialize I2C Bus and RTC */
  124. I2C_Init();
  125. RTC_Init();
  126. RTC_ReadAll(&RTC);
  127. /* Initialize Event State Machine */
  128. ES_Init(stShowTime);
  129. showTime();
  130. RTOS_SetTask(btnProcess, 3, BTN_SCAN_PERIOD);
  131. #ifdef USE_DHT
  132. RTOS_SetTask(dhtStart, 2000, 15000);
  133. #endif // USE_DHT
  134. /** main loop */
  135. do {
  136. /* new second interrupt from RTC */
  137. if (Flag.RTC_Int != 0) {
  138. Flag.RTC_Int = 0;
  139. ES_PlaceEvent(evNewSecond);
  140. RTC_ReadTime(&RTC);
  141. if (RTC.Sec == 0 && RTC.Min == 0) {
  142. // begin of new hour
  143. if (RTC.Hr == 0) {
  144. RTC_ReadCalendar(&RTC);
  145. ES_PlaceEvent(evRefreshCal);
  146. }
  147. #ifdef USE_BRIGHT_CONTROL
  148. if (RTC.Hr >= FULL_BRIGHT_ON && RTC.Hr < FULL_BRIGHT_OFF) {
  149. OCR2 = pgm_read_byte(&brightConv[BRIGHT_IDX_MAX]);
  150. } else {
  151. OCR2 = pgm_read_byte(&brightConv[brightIdx]);
  152. }
  153. #endif // USE_BRIGHT_CONTROL
  154. setSummerWinterTime();
  155. } // begin new hour
  156. if (DISP_WDT != 0) {
  157. DISP_WDT --;
  158. if (DISP_WDT == 0) {
  159. ES_PlaceEvent(evDisplayWDT);
  160. if (Flag.saveCal != 0) {
  161. Flag.saveCal = 0;
  162. RTC_WriteCalendar(&RTC);
  163. }
  164. if (Flag.saveEEP != 0) {
  165. Flag.saveEEP = 0;
  166. eeprom_update_byte(&EEP_BrightIdx, brightIdx);
  167. }
  168. }
  169. }
  170. } // End of New Second
  171. event = ES_GetEvent();
  172. if (event) {
  173. ES_Dispatch(event);
  174. }
  175. // крутим диспетчер
  176. RTOS_DispatchTask();
  177. // делать нечего -- спим, ждём прерывание
  178. set_sleep_mode(SLEEP_MODE_IDLE);
  179. sleep_mode();
  180. } while(1);
  181. }
  182. /**
  183. * П о д п р о г р а м м ы
  184. */
  185. /**
  186. * @brief Initialize peripheral
  187. */
  188. static void Board_Init(void) {
  189. /* power off Analog Comparator */
  190. ACSR = ACD;
  191. /* GPIO */
  192. PORTB = BUTTON_PINS; // enable pull-up
  193. DDRC = DIGIT_PINS; // as output
  194. DDRD = (DOT_PIN | ANOD_PINS); // as output
  195. #ifdef USE_DHT
  196. /* Timer1, IC negative edge, CTC mode, 64 prescaler, 4 mks one tick */
  197. TCCR1B = ((0<<ICES1) | (1<<CS11) | (1<<CS10));
  198. #endif // USE_DHT
  199. /* Timer2 - refresh Nixie values */
  200. TCCR2 = TIMER2_CS;
  201. TCNT2 = TIMER2_CNT;
  202. TIMSK = _BV(TOIE2);
  203. #ifdef USE_BRIGHT_CONTROL
  204. OCR2 = pgm_read_byte(&brightConv[BRIGHT_IDX_MAX]);
  205. TIMSK |= _BV(OCIE2);
  206. #endif // USE_BRIGHT_CONTROL
  207. /* Interrupt from RTC */
  208. MCUCR = _BV(ISC11); // falling edge
  209. GICR = _BV(INT1);
  210. #ifdef USE_UART
  211. /* USART */
  212. // Turn on USART hardware (no RX, TX)
  213. UCSRB |= (0 << RXEN) | (1 << TXEN);
  214. // 8 bit char sizes
  215. UCSRC |= (1 << UCSZ0) | (1 << UCSZ1);
  216. // Set baud rate
  217. UBRRH = (BAUD_PRESCALE >> 8);
  218. UBRRL = BAUD_PRESCALE;
  219. #endif // USE_UART
  220. /* Enable Interrupts */
  221. sei();
  222. }
  223. /**
  224. * @brief Correct current time for Sun or Winter
  225. */
  226. static void setSummerWinterTime(void) {
  227. uint8_t sunTime = eeprom_read_byte(&EEP_SummerTime);
  228. /* Переход на летнее время */
  229. if ((RTC.Mon == 3) && (RTC.WD == 7) && (RTC.Hr == 3) && (sunTime != 0)) {
  230. if ((RTC.Day + 7) > 31) {
  231. RTC.Hr = 4;
  232. RTC_WriteHHMM(&RTC);
  233. sunTime = 0;
  234. }
  235. }
  236. /* Переход на зимнее время */
  237. if ((RTC.Mon == 10) && (RTC.WD == 7) && (RTC.Hr == 4) && (sunTime == 0)) {
  238. if ((RTC.Day + 7) > 31) {
  239. RTC.Hr = 3;
  240. RTC_WriteHHMM(&RTC);
  241. sunTime = 1;
  242. }
  243. }
  244. eeprom_update_byte(&EEP_SummerTime, sunTime);
  245. }
  246. static void dotOn(void) {
  247. PORTD |= DOT_PIN;
  248. }
  249. void dotOff(void) {
  250. PORTD &= ~(DOT_PIN);
  251. }
  252. void dotOnPersistent(void) {
  253. RTOS_DeleteTask(dotOff);
  254. PORTD |= DOT_PIN;
  255. }
  256. #ifdef USE_DHT
  257. static void dhtStart(void) {
  258. RTOS_SetTask(dhtProcess, 2, 0);
  259. DHT_PIN_LOW;
  260. }
  261. static void dhtProcess(void) {
  262. uint8_t cnt1, cnt2, buf;
  263. uint16_t tcnt_old, hmdt, tmprtr;
  264. DHT_PIN_INPUT;
  265. TCNT1 = 0;
  266. // ждём первого "0"
  267. while(bit_is_set(PINB, PB0) && TCNT1<DHT_TOUT1);
  268. if (TCNT1 >= DHT_TOUT1) {
  269. RTOS_SetTask(dhtNoAck, 0, 0);
  270. return;
  271. }
  272. // white for end of preamble
  273. while(bit_is_clear(PINB, PB0));
  274. while(bit_is_set(PINB, PB0) && TCNT1<DHT_TIMEOUT);
  275. if (TCNT1 >= DHT_TIMEOUT) {
  276. RTOS_SetTask(dhtTimeout, 0, 0);
  277. }
  278. hmdt = 0; tmprtr = 0;
  279. for (cnt1=0; cnt1<32; cnt1+=8) { // 0 8 16 24 32
  280. buf = 0;
  281. for (cnt2=0; cnt2<8; cnt2++) {
  282. buf <<= 1;
  283. // "0", начало периода
  284. while(bit_is_clear(PINB, PB0)); // ждём начало импульса
  285. tcnt_old = TCNT1; // начало импульса
  286. while(bit_is_set(PINB, PB0) && TCNT1<DHT_TIMEOUT); // ждём конец импульса
  287. if ((TCNT1 - tcnt_old) > 10) {
  288. buf |= 1;
  289. }
  290. }
  291. switch (cnt1) {
  292. case 0:
  293. hmdt = buf << 8;
  294. break;
  295. case 8:
  296. hmdt |= buf;
  297. break;
  298. case 16:
  299. tmprtr = buf << 8;
  300. break;
  301. case 24:
  302. tmprtr |= buf;
  303. break;
  304. }
  305. }
  306. if (TCNT1 >= DHT_TIMEOUT) {
  307. RTOS_SetTask(dhtTimeout, 0, 0);
  308. return;
  309. }
  310. dhtData.Humidity = (uint8_t)((hmdt + 5) / 10);
  311. dhtData.Temperature = tmprtr;
  312. RTOS_SetTask(dhtEnd, 0, 0);
  313. }
  314. static void dhtEnd(void) {
  315. #ifdef USE_UART
  316. char buffer[6];
  317. usart_puts("Humidity: ");
  318. itoa(dhtData.Humidity, buffer, 10);
  319. usart_puts(buffer);
  320. usart_puts(" %\t\t");
  321. usart_puts("Temperature: ");
  322. itoa(dhtData.Temperature/10, buffer, 10);
  323. usart_puts(buffer);
  324. usart_putc('.');
  325. itoa(dhtData.Temperature%10, buffer, 10);
  326. usart_puts(buffer);
  327. usart_puts("oC\r\n");
  328. #endif // USE_UART
  329. }
  330. static void dhtNoAck(void) {
  331. #ifdef USE_UART
  332. usart_puts("DHT22 no ACK occurred.\r\n");
  333. #endif // USE_UART
  334. }
  335. static void dhtTimeout(void) {
  336. #ifdef USE_UART
  337. usart_puts("DHT22 Timeout occurred.\r\n");
  338. #endif // USE_UART
  339. }
  340. void showTemperature(void) {
  341. dotOn();
  342. uint8_t a = dhtData.Temperature / 10;
  343. uint8_t b = dhtData.Temperature % 10;
  344. Digit[0] = a / 10;
  345. Digit[1] = a % 10;
  346. Digit[2] = b;
  347. Digit[3] = DIGIT_BLANK;
  348. }
  349. void showHumidity(void) {
  350. dotOff();
  351. Digit[0] = DIGIT_BLANK;
  352. Digit[1] = DIGIT_BLANK;
  353. Digit[2] = dhtData.Humidity / 10;
  354. Digit[3] = dhtData.Humidity % 10;}
  355. #endif // USE_DHT
  356. /**
  357. * @brief Обработка кнопок.
  358. * @param : None
  359. * @retval : None
  360. */
  361. static void btnProcess(void) {
  362. uint8_t i;
  363. for (i=0; i<BTN_NUM; i++) {
  364. if (Button[i].pin != 0) {
  365. // button pressed
  366. if (BUTTON_STATE(Button[i].pin) == 0) {
  367. Button[i].time ++;
  368. if (Button[i].time >= BTN_TIME_HOLDED) {
  369. Button[i].time -= BTN_TIME_REPEATED;
  370. if (Button[i].holded == Button[i].pressed) {
  371. // if pressed and holded - same function, then button pressed auto repeat
  372. ES_PlaceEvent(Button[i].pressed);
  373. }
  374. }
  375. } else {
  376. // button released
  377. if (Button[i].time >= (BTN_TIME_HOLDED - BTN_TIME_REPEATED)) {
  378. ES_PlaceEvent(Button[i].holded); // process long press
  379. } else if (Button[i].time >= BTN_TIME_PRESSED) {
  380. ES_PlaceEvent(Button[i].pressed); // process short press
  381. }
  382. Button[i].time = 0;
  383. RTOS_SetTask(btnProcess, BTN_TIME_PAUSE, BTN_SCAN_PERIOD);
  384. }
  385. } /* end (pin == 0) */
  386. } /* end FOR */
  387. }
  388. void showTime(void) {
  389. switch(RTC.Sec) {
  390. #ifdef USE_DHT
  391. case 0x20:
  392. case 0x50:
  393. showTemperature();
  394. break;
  395. case 0x22:
  396. case 0x52:
  397. showHumidity();
  398. break;
  399. #endif // USE_DHT
  400. case 0x27:
  401. case 0x28:
  402. case 0x29:
  403. case 0x57:
  404. case 0x58:
  405. case 0x59:
  406. dotOn();
  407. showMMSS();
  408. break;
  409. default:
  410. dotOn();
  411. RTOS_SetTask(dotOff, 500, 0);
  412. if (RTC.Hr > 0x09) {
  413. Digit[0] = RTC.Hr >> 4;
  414. } else {
  415. Digit[0] = DIGIT_BLANK;
  416. }
  417. Digit[1] = RTC.Hr & 0x0F;
  418. Digit[2] = RTC.Min >> 4;
  419. Digit[3] = RTC.Min & 0x0F;
  420. }
  421. }
  422. void showMMSS(void) {
  423. Digit[0] = RTC.Min >> 4;
  424. Digit[1] = RTC.Min & 0x0F;
  425. Digit[2] = RTC.Sec >> 4;
  426. Digit[3] = RTC.Sec & 0x0F;
  427. }
  428. void showWDay(void) {
  429. DISP_WDT = DISP_WDT_TIME;
  430. Digit[0] = DIGIT_BLANK;
  431. Digit[1] = DIGIT_BLANK;
  432. Digit[2] = RTC.WD & 0x0F;
  433. Digit[3] = DIGIT_BLANK;
  434. }
  435. void showMDay(void) {
  436. DISP_WDT = DISP_WDT_TIME;
  437. Digit[0] = RTC.Day >> 4;
  438. Digit[1] = RTC.Day & 0x0F;
  439. Digit[2] = DIGIT_BLANK;
  440. Digit[3] = DIGIT_BLANK;
  441. }
  442. void showMonth(void) {
  443. DISP_WDT = DISP_WDT_TIME;
  444. Digit[0] = DIGIT_BLANK;
  445. Digit[1] = DIGIT_BLANK;
  446. Digit[2] = RTC.Mon >> 4;
  447. Digit[3] = RTC.Mon & 0x0F;
  448. }
  449. void showYear(void) {
  450. DISP_WDT = DISP_WDT_TIME;
  451. Digit[0] = 0x02;
  452. Digit[1] = 0x00;
  453. Digit[2] = RTC.Year >> 4;
  454. Digit[3] = RTC.Year & 0x0F;
  455. }
  456. void incWDay(void) {
  457. if (RTC.WD < 7) {
  458. RTC.WD ++;
  459. } else {
  460. RTC.WD = 1;
  461. }
  462. Flag.saveCal = 1;
  463. }
  464. void decWDay(void) {
  465. if (RTC.WD > 1) {
  466. RTC.WD --;
  467. } else {
  468. RTC.WD = 7;
  469. }
  470. Flag.saveCal = 1;
  471. }
  472. void incMDay(void) {
  473. valIncrease(&RTC.Day, 31);
  474. Flag.saveCal = 1;
  475. }
  476. void decMDay(void) {
  477. valDecrease(&RTC.Day, 31);
  478. Flag.saveCal = 1;
  479. }
  480. void incMonth(void) {
  481. valIncrease(&RTC.Mon, 12);
  482. if (RTC.Mon == 0) {
  483. RTC.Mon = 1;
  484. }
  485. Flag.saveCal = 1;
  486. }
  487. void decMonth(void) {
  488. valDecrease(&RTC.Mon, 12);
  489. if (RTC.Mon == 0) {
  490. RTC.Mon = 0x12;
  491. }
  492. Flag.saveCal = 1;
  493. }
  494. void incYear(void) {
  495. valIncrease(&RTC.Year, 99);
  496. Flag.saveCal = 1;
  497. }
  498. void decYear(void) {
  499. valDecrease(&RTC.Year, 99);
  500. Flag.saveCal = 1;
  501. }
  502. #ifdef USE_BRIGHT_CONTROL
  503. void showBright(void) {
  504. DISP_WDT = DISP_WDT_TIME;
  505. Digit[0] = DIGIT_BLANK;
  506. Digit[1] = DIGIT_BLANK;
  507. Digit[2] = brightIdx;
  508. Digit[3] = DIGIT_BLANK;
  509. }
  510. void incBright(void) {
  511. if (brightIdx < BRIGHT_IDX_MAX) {
  512. brightIdx ++;
  513. OCR2 = pgm_read_byte(&brightConv[brightIdx]);
  514. Flag.saveEEP = 1;
  515. }
  516. }
  517. void decBright(void) {
  518. if (brightIdx > 0 ) {
  519. brightIdx --;
  520. OCR2 = pgm_read_byte(&brightConv[brightIdx]);
  521. Flag.saveEEP = 1;
  522. }
  523. }
  524. #endif // USE_BRIGHT_CONTROL
  525. static void blink(void) {
  526. static uint8_t s = 0;
  527. switch (s) {
  528. case 0:
  529. Flag.blinkC = 0;
  530. RTOS_SetTask(blink, 750, 0);
  531. s = 1;
  532. break;
  533. case 1:
  534. Flag.blinkC = 1;
  535. RTOS_SetTask(blink, 250, 0);
  536. s = 0;
  537. break;
  538. default:
  539. s = 0;
  540. }
  541. }
  542. void setTimeShow(void) {
  543. dotOn();
  544. RTOS_SetTask(dotOff, 500, 0);
  545. Digit[0] = setRTC.Hr >> 4;
  546. Digit[1] = setRTC.Hr & 0x0F;
  547. Digit[2] = setRTC.Min >> 4;
  548. Digit[3] = setRTC.Min & 0x0F;
  549. }
  550. void setTimeBegin(void) {
  551. RTC_ReadTime(&setRTC);
  552. RTOS_SetTask(btnProcess, 500, BTN_SCAN_PERIOD);
  553. }
  554. void setHHBegin(void) {
  555. Flag.blink0 = 1;
  556. Flag.blink1 = 1;
  557. Flag.blink2 = 0;
  558. Flag.blink3 = 0;
  559. RTOS_SetTask(blink, 0, 0);
  560. setTimeShow();
  561. }
  562. void setHHInc(void) {
  563. valIncrease(&setRTC.Hr, 23);
  564. }
  565. void setHHDec(void) {
  566. valDecrease(&setRTC.Hr, 23);
  567. }
  568. void setMMBegin(void) {
  569. Flag.blink0 = 0;
  570. Flag.blink1 = 0;
  571. Flag.blink2 = 1;
  572. Flag.blink3 = 1;
  573. RTOS_SetTask(blink, 0, 0);
  574. setTimeShow();
  575. }
  576. void setMMInc(void) {
  577. valIncrease(&setRTC.Min, 59);
  578. }
  579. void setMMDec(void) {
  580. valDecrease(&setRTC.Min, 59);
  581. }
  582. void setTimeEnd(void) {
  583. RTOS_SetTask(btnProcess, 500, BTN_SCAN_PERIOD);
  584. setRTC.Sec = 0;
  585. RTC_WriteTime(&setRTC);
  586. RTOS_DeleteTask(blink);
  587. Flag.blink0 = 0;
  588. Flag.blink1 = 0;
  589. Flag.blink2 = 0;
  590. Flag.blink3 = 0;
  591. Flag.blinkC = 0;
  592. RTC_ReadTime(&RTC);
  593. }
  594. /**
  595. * @brief Increase BCD value.
  596. * @param : val, max
  597. * @retval : None
  598. */
  599. static void valIncrease(uint8_t * val, uint8_t max) {
  600. uint8_t bin = 10 * (*val >> 4) + (*val & 0x0f);
  601. if (bin < max) {
  602. bin ++;
  603. } else {
  604. bin = 0;
  605. }
  606. *val = ((bin / 10 ) << 4) | (bin % 10);
  607. }
  608. /**
  609. * @brief Decrease BCD value.
  610. * @param : value, max
  611. * @retval : None
  612. */
  613. static void valDecrease(uint8_t * val, uint8_t max) {
  614. uint8_t bin = 10 * (*val >> 4) + (*val & 0x0f);
  615. if (bin > 0) {
  616. bin --;
  617. } else {
  618. bin = max;
  619. }
  620. *val = ((bin / 10 ) << 4) | (bin % 10);
  621. }
  622. #ifdef USE_UART
  623. void usart_putc (char send) {
  624. // Do nothing for a bit if there is already
  625. // data waiting in the hardware to be sent
  626. while ((UCSRA & (1 << UDRE)) == 0) {};
  627. UDR = send;
  628. }
  629. void usart_puts (const char *send) {
  630. // Cycle through each character individually
  631. while (*send) {
  632. usart_putc(*send++);
  633. }
  634. }
  635. #endif // USE_UART
  636. /**
  637. * П р е р ы в а н и я
  638. */
  639. /**
  640. * @brief RTC one seconds interrupt
  641. */
  642. ISR (INT1_vect) {
  643. Flag.RTC_Int = 1;
  644. }
  645. /**
  646. * @brief Refresh Nixie output
  647. * @note Digit[] must be in range 0x00 - 0x0F
  648. */
  649. #pragma GCC optimize ("O3")
  650. ISR(TIMER2_OVF_vect) {
  651. static uint8_t idx = 0;
  652. // reload timer
  653. TCNT2 = TIMER2_CNT;
  654. // read current register value and clean bits
  655. uint8_t pd = PORTD & ~ANOD_PINS;
  656. uint8_t pc = PORTC & ~DIGIT_PINS;
  657. #ifndef USE_BRIGHT_CONTROL
  658. // power off lamps
  659. PORTD = pd;
  660. PORTC = pc;
  661. #endif
  662. switch (idx) {
  663. case 0:
  664. // output lamp value
  665. PORTC = pc | Digit[0];
  666. // power on lamp
  667. if (Digit[0] != DIGIT_BLANK) {
  668. if (Flag.blink0 == 0 || Flag.blinkC == 0) {
  669. PORTD = pd | ANOD1;
  670. }
  671. }
  672. idx = 1;
  673. break;
  674. case 1:
  675. PORTC = pc | Digit[1];
  676. if (Digit[1] != DIGIT_BLANK) {
  677. if (Flag.blink1 == 0 || Flag.blinkC == 0) {
  678. PORTD = pd | ANOD2;
  679. }
  680. }
  681. idx = 2;
  682. break;
  683. case 2:
  684. PORTC = pc | Digit[2];
  685. if (Digit[2] != DIGIT_BLANK) {
  686. if (Flag.blink2 == 0 || Flag.blinkC == 0) {
  687. PORTD = pd | ANOD3;
  688. }
  689. }
  690. idx = 3;
  691. break;
  692. case 3:
  693. PORTC = pc | Digit[3];
  694. if (Digit[3] != DIGIT_BLANK) {
  695. if (Flag.blink3 == 0 || Flag.blinkC == 0) {
  696. PORTD = pd | ANOD4;
  697. }
  698. }
  699. idx = 0;
  700. break;
  701. default:
  702. idx = 0;
  703. break;
  704. }
  705. }
  706. #ifdef USE_BRIGHT_CONTROL
  707. /**
  708. * @brief Power Off Nixie output
  709. * @note For Brightnes dimming
  710. */
  711. #pragma GCC optimize ("O3")
  712. ISR(TIMER2_COMP_vect) {
  713. // power off lamps
  714. PORTD &= ~ANOD_PINS;
  715. PORTC &= ~DIGIT_PINS;
  716. }
  717. #endif // USE_BRIGHT_CONTROL
  718. /**
  719. * @brief заглушка для неиспользуемых прерываний
  720. */
  721. ISR(__vector_default,ISR_NAKED) {
  722. reti();
  723. }