main.c 18 KB

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