Redfern_89

led_clock.c

Sep 22nd, 2019
373
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 21.60 KB | None | 0 0
  1. #define F_CPU 16000000UL
  2.  
  3. #include <avr/io.h>
  4. #include <util/delay.h>
  5. #include <avr/interrupt.h>
  6. #include "I2C.h"
  7. #include "I2C.c"
  8. #include "DS1307.h"
  9. #include "DS1307.c"
  10.  
  11. // Макросы для USART'а (использовал только при отладке и щас они нах ненужны)
  12. #define FOSC 16000000L
  13. #define BAUD 9600L
  14. #define MYUBRR FOSC / 16 / BAUD - 1
  15.  
  16. // Настройки портов ввода-вывода
  17. #define RCLK_DDR  DDRC
  18. #define SCLK_DDR  DDRD
  19. #define DATA_DDR  DDRC
  20. #define RCLK_PORT PORTC
  21. #define SCLK_PORT PORTD
  22. #define DATA_PORT PORTC
  23. #define RCLK    PC1
  24. #define SCLK    PD5
  25. #define DATA    PC0
  26.  
  27. // Упарвление защелкой и сдвигом регистров
  28. #define _74hc595_RegisterLatch(code)  { RCLK_PORT &= ~(1 << RCLK); code; RCLK_PORT |= (1 << RCLK);  }
  29. #define _74hc595_RegisterShift()    { SCLK_PORT &= ~(1 << SCLK); SCLK_PORT |= (1 << SCLK);    }
  30.    
  31. #define T2_START { TCCR2 = (1 << CS20) | (1 << CS21) | (0 << CS22); }
  32. #define T2_STOP { TCCR2 = 0x00; }
  33.  
  34. unsigned char NC = 0xFF;
  35. volatile unsigned char digits[11] = { 0xfc, 0x60, 0xda, 0xf2, 0x66, 0xb6, 0xbe, 0xe0, 0xfe, 0xf6 };
  36. volatile uint16_t groups[12] = { 0x8000, 0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100, 0x80, 0x40, 0x20, 0x10 };
  37. volatile unsigned char display_data[12]  = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  38. const int max_groups  = 12;
  39. volatile unsigned int display_pos = 0;
  40. volatile unsigned int tmp = 0;
  41. volatile unsigned long long int millis = 0;
  42. volatile int sqw_flag = 0;
  43.  
  44. // Таймер без delay
  45. #define setInterval(n, tmr, code) { if ((millis - tmr) >= n) { tmr = millis; code; }}
  46.  
  47. //  ( это ааааадовый костыль, который, я надеюсь потом уберу )
  48. // Переменные-таймеры/счетчики...так думаю, что нахуй они не нужны,
  49. // ибо более одной задержки одновременно не планирую в программе ...
  50. unsigned long long int tmr0 = 0;
  51. unsigned long long int tmr1 = 0;
  52. unsigned long long int tmr2 = 0;
  53. unsigned long long int tmr3 = 0;
  54.  
  55. /* Протокол NEC */
  56. const int NEC_MIN_CLK                   = 5;        // Минимальное значение, при котором следует начинать захват
  57. volatile int NEC_REPEAT_FLAG            = 0;
  58. volatile int NEC_START_FLAG             = 0;
  59. volatile int NEC_IR_DONE                = 0;
  60. volatile unsigned long int NEC_SCLK     = 0;        // Тактовые синхроимпульсы (64 мкс)
  61. volatile unsigned long int NEC_RECV_CNT = 0;        // Кол-во принятых битов
  62. const static int NEC_MIN_HEADER_MESSAGE_CLK       = 190;      // Преамбула+пауза (минимальное время)
  63. const static int NEC_MAX_HEADER_MESSAGE_CLK       = 245;      // Преамбула+пауза (максимальное время)
  64. const static int NEC_MIN_REPEAT         = 80;
  65. const static int NEC_MAX_REPEAT         = 170;
  66. const int NEC_MIN_ONE_BIT_CLK = 30;
  67. const int NEC_MAX_ONE_BIT_CLK = 40;
  68. const int NEC_MIN_NUL_BIT_CLK = 15;
  69. const int NEC_MAX_NUL_BIT_CLK = 25;
  70. const static int NEC_MAX_RESET_OVF      = 1200;
  71. const static int NEC_PACKET_LENGTH      = 32;
  72. volatile unsigned char addr1 = 0x00;    // Адрес
  73. volatile unsigned char addr2 = 0x00;    // Инверсия адреса
  74. volatile unsigned char cmd1 = 0x00;     // Команда
  75. volatile unsigned char cmd2 = 0x00;     // Инверсия команды
  76. volatile uint16_t command = 0x0000;     // Команда пульта
  77. int mode = 0;
  78.  
  79. // Смещения для создания битовой маски сообщенй (адрес1, адрес2, команда1, команда2)
  80. const int offset1_addr1 = 0;
  81. const int offset2_addr1 = 9;
  82. const int offset1_addr2 = 9;
  83. const int offset2_addr2 = 17;
  84. const int offset1_cmd1 = 17;
  85. const int offset2_cmd1 = 25;
  86. const int offset1_cmd2 = 25;
  87. const int offset2_cmd2 = 33;
  88.  
  89. // Коды с пульта
  90. const uint16_t POWER_OFF = 0xFF45;
  91. const uint16_t MENU = 0xFF47;
  92. const uint16_t TEST = 0xFF44;
  93. const uint16_t PLUS = 0xFF40;
  94. const uint16_t RETURN = 0xFF43;
  95. const uint16_t RWND = 0xFF07;
  96. const uint16_t PLAY = 0xFF15;
  97. const uint16_t FWND = 0xFF09;
  98. const uint16_t MINUS = 0xFF19;
  99. const uint16_t CLEAR = 0xFF0D;
  100. const uint16_t D0 = 0xFF16;
  101. const uint16_t D1 = 0xFF0C;
  102. const uint16_t D2 = 0xFF18;
  103. const uint16_t D3 = 0xFF5E;
  104. const uint16_t D4 = 0xFF08;
  105. const uint16_t D5 = 0xFF1C;
  106. const uint16_t D6 = 0xFF5A;
  107. const uint16_t D7 = 0xFF42;
  108. const uint16_t D8 = 0xFF52;
  109. const uint16_t D9 = 0xFF4A;
  110.  
  111. // Структура DateTime (для удобства работы)
  112. typedef struct {
  113.     int Sec;
  114.     int Min;
  115.     int Hour;
  116.     int Month;
  117.     int Day;
  118.     int Year;
  119.     int WeekDay;
  120.     int AMPM;
  121.     int H12_24;
  122. } TDateTime;
  123. TDateTime DateTime;
  124.  
  125. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  126.                                 USART functions
  127.  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  128. void USORT_Init(unsigned char ubrr) {
  129.     UBRRH = (unsigned char)(ubrr >> 8);
  130.     UBRRL = (unsigned char)ubrr;
  131.     UCSRB = (1 << RXEN) | (1 << TXEN);
  132.     UCSRC = (1 << USBS) | (3 << UCSZ0) | (1 << URSEL);
  133. }
  134.  
  135. void USORT_Transmit( unsigned char data ) {
  136.     while ( !( UCSRA & (1 << UDRE)) );
  137.     UDR = data;
  138. }
  139.  
  140.  
  141. // Инициализация портов ввода-вывода SPI
  142. void _74hc595_SPI_Init() {
  143.     RCLK_DDR |= (1 << RCLK);
  144.     SCLK_DDR |= (1 << SCLK);
  145.     DATA_DDR |= (1 << DATA);
  146. }
  147.  
  148. // Отправка данных в регистр
  149. void _74hc595_SPI_send(char data) {
  150.     int i;
  151.     unsigned char val;
  152.    
  153.     for (i = 0; i < 8; i++) {
  154.         val = !!(data & (1 << (7 - i)));
  155.         if (val) DATA_PORT |= 1 << DATA;
  156.         else DATA_PORT &= ~(1 << DATA);
  157.         _74hc595_RegisterShift();
  158.     }
  159. }
  160.  
  161. // Отправка данных в регистры с защелкиванием (2.0)
  162. void _74hc595_RegisterWrite(uint16_t group, uint8_t segments) {
  163.     _74hc595_RegisterLatch({
  164.         _74hc595_SPI_send(group >> 8);
  165.         _74hc595_SPI_send(group & 0xFF);
  166.         _74hc595_SPI_send(segments);
  167.     });
  168. }
  169.  
  170. // Динамическая индикация
  171. ISR (TIMER0_OVF_vect) {
  172.     TCNT0 = 0xf8;
  173.  
  174.     /* Отсылаем текущие данные в сдвиговые регистры */
  175.     display_pos = (display_pos + 1) % max_groups;
  176.     _74hc595_RegisterWrite(groups[display_pos], display_data[display_pos]);
  177. }
  178.  
  179. // Таймер подсчета миллисекунд
  180. ISR (TIMER1_OVF_vect) {
  181.     TCNT1 = 0xFF06;
  182.  
  183.     millis++;
  184. }
  185.  
  186. // Таймер подсчета промежутков между спадами на внешнем прерывании
  187. ISR ( TIMER2_OVF_vect ) {
  188.     TCNT2 = 0xF0;
  189.    
  190.     if (++NEC_SCLK >= NEC_MAX_RESET_OVF) {
  191.         T2_STOP;
  192.         NEC_SCLK = 0;
  193.         NEC_START_FLAG = 0;
  194.         NEC_REPEAT_FLAG = 0;
  195.         command = 0x0000;
  196.     }
  197.    
  198.     // Это не обязательно, но для перестраховки оставлю тут
  199.     // Если в течении 1200 тиков пришло менее 32 бит, обнуляем счетчики и переходим в режим ожидания
  200.     if (NEC_SCLK >= NEC_MAX_RESET_OVF && NEC_RECV_CNT < NEC_PACKET_LENGTH) {
  201.         T2_STOP;
  202.         NEC_SCLK = 0;
  203.         NEC_RECV_CNT = 0;
  204.         command = 0x0000;
  205.     }
  206. }
  207.  
  208. // Внешнее прерывание от IRDA-приемника
  209. ISR (INT0_vect) {
  210.     T2_START;
  211.     if (NEC_SCLK > NEC_MIN_CLK) {
  212.         // Тут определяем стартовое сообщение (преамбулу)
  213.         if (NEC_SCLK >= NEC_MIN_HEADER_MESSAGE_CLK && NEC_SCLK < NEC_MAX_HEADER_MESSAGE_CLK) {
  214.             NEC_START_FLAG = 1;
  215.             NEC_REPEAT_FLAG = 0;
  216.             NEC_RECV_CNT = 0;
  217.         }
  218.        
  219.         if (NEC_SCLK >= NEC_MIN_REPEAT && NEC_SCLK < NEC_MAX_REPEAT && NEC_START_FLAG) {
  220.             NEC_REPEAT_FLAG = 1;
  221.         }
  222.        
  223.         /* Знаю, по идиотски, Но умнее лень было придумывать */
  224.        
  225.         // Тут определяем биты нулевого значения
  226.         if ((NEC_SCLK >= NEC_MIN_NUL_BIT_CLK && NEC_SCLK < NEC_MAX_NUL_BIT_CLK) && NEC_START_FLAG) {
  227.             NEC_RECV_CNT++; // Инкрементируем колличество принятых нулей
  228.             // ну а тут мутнаые процедуры записи значений в переменные
  229.             if (NEC_RECV_CNT >= offset1_addr1 && NEC_RECV_CNT < offset2_addr1) { // Если мы в диапозоне 1-8, ...
  230.                 addr1 &= ~(1 << (NEC_RECV_CNT - offset1_addr1)); // добавляем в addr1 нули в нужные места
  231.             }
  232.             // Остальные диапозоны тоже самое
  233.             if (NEC_RECV_CNT >= offset1_addr2 && NEC_RECV_CNT < offset2_addr2) {
  234.                 addr2 &= ~(1 << (NEC_RECV_CNT - offset1_addr2));
  235.             }
  236.             if (NEC_RECV_CNT >= offset1_cmd1 && NEC_RECV_CNT < offset2_cmd1) {
  237.                 cmd1 &= ~(1 << (NEC_RECV_CNT - offset1_cmd1));
  238.             }
  239.             if (NEC_RECV_CNT >= offset1_cmd2 && NEC_RECV_CNT < offset2_cmd2) {
  240.                 cmd2 &= ~(1 << (NEC_RECV_CNT - offset1_cmd2));
  241.             }
  242.         //  IRActiveLed(0);
  243.            
  244.         }
  245.        
  246.         // Тут определяем биты положительного значения (такая-же хуйня как и с нулями, только интервалы у NEC_SCLK больше)
  247.         if ((NEC_SCLK >= NEC_MIN_ONE_BIT_CLK && NEC_SCLK < NEC_MAX_ONE_BIT_CLK) && NEC_START_FLAG) {
  248.             NEC_RECV_CNT++; // Инкрементируем колличество принятых едениц
  249.            
  250.             if (NEC_RECV_CNT >= offset1_addr1 && NEC_RECV_CNT < offset2_addr1) {
  251.                 addr1 |= (1 << (NEC_RECV_CNT - offset1_addr1));
  252.             }
  253.             if (NEC_RECV_CNT >= offset1_addr2 && NEC_RECV_CNT < offset2_addr2) {
  254.                 addr2 |= (1 << (NEC_RECV_CNT - offset1_addr2));
  255.             }
  256.             if (NEC_RECV_CNT >= offset1_cmd1 && NEC_RECV_CNT < offset2_cmd1) {
  257.                 cmd1 |= (1 << (NEC_RECV_CNT - offset1_cmd1));
  258.             }
  259.             if (NEC_RECV_CNT >= offset1_cmd2 && NEC_RECV_CNT < offset2_cmd2) {
  260.                 cmd2 |= (1 << (NEC_RECV_CNT - offset1_cmd2));
  261.             }
  262.         //  IRActiveLed(1);
  263.         }
  264.        
  265.         NEC_SCLK = 0;
  266.        
  267.         // Колличество нулей и едениц в конечном счете должно быть 32, на этом и остановимся
  268.         if (NEC_RECV_CNT == NEC_PACKET_LENGTH) {
  269.             // Выставляем в стартовое положение все счетчики и останавлиеваем подсчет
  270.             NEC_RECV_CNT = 0;
  271.             NEC_START_FLAG = 0;
  272.             T2_STOP;
  273.  
  274.             // Проверка сообщения на целостность
  275.             // В версии протокола 2.0 адрес имеет расширеное пространство и не имеет инверсии
  276.             // Значит проверяем либо сложив обе инверсии (адреса и команды), либо только инверсии команды
  277.             if ((((addr1 + addr2 == 0xFF) && (cmd1 + cmd2) == 0xFF)) || (cmd1 + cmd2 == 0xFF)) {
  278.                 NEC_IR_DONE = 1; // Сообщаем системе, что чтение завершено
  279.                 // Команду склеиваем с адресом (16 бит)
  280.                 command = ((addr1 + addr2) << 8) | cmd1;
  281.             }
  282.         }
  283.        
  284.     }
  285. }
  286.  
  287. // Отображение цифр на дисплее
  288. int print_display(int hours, int mins, int bl, int hsbl, int mbl) {
  289.     if (!hsbl) {
  290.         if (hours == 0) {
  291.                 display_data[6] = ~digits[0];
  292.                 display_data[8] = ~digits[0];
  293.             } else if (hours >= 0 && hours <= 9) {
  294.                 display_data[6] = ~digits[0];
  295.                 display_data[8] = ~digits[hours];
  296.             } else if (hours >= 10 && hours <= 99) {
  297.                 display_data[6] = ~digits[(unsigned int)round(hours % 100) / 10];
  298.                 display_data[8] = ~digits[(unsigned int)round(hours % 10)];
  299.             }
  300.             if (bl) {
  301.                 display_data[8] &= ~(1 << 0);
  302.             }
  303.     } else {
  304.         display_data[6] = 0xff;
  305.         display_data[8] = 0xff;
  306.     }
  307.    
  308.     if (!mbl) {
  309.         if (mins == 0) {
  310.             display_data[9] = ~digits[0];
  311.             display_data[11] = ~digits[0];
  312.         } else if (mins >= 0 && mins <= 9) {
  313.             display_data[9] = ~digits[0];
  314.             display_data[11] = ~digits[mins];
  315.         } else if (mins >= 10 && mins <= 99) {
  316.             display_data[9] = ~digits[(unsigned int)round(mins % 100) / 10];
  317.             display_data[11] = ~digits[(unsigned int)round(mins % 10)];
  318.         }
  319.     } else {
  320.         display_data[9] = 0xff;
  321.         display_data[11] = 0xff;
  322.     }
  323.    
  324.     return 1;
  325. }
  326.  
  327. void DS1307_ReadDateTime( void ) {
  328.     unsigned char temp;
  329.  
  330.     // Читаем данные и преобразуем из BCD в двоичную систему
  331.     DS1307Read(0x00,&temp); // Чтение регистра секунд
  332.     DateTime.Sec = (((temp & 0xF0) >> 4)*10)+(temp & 0x0F);
  333.  
  334.     DS1307Read(0x01,&temp); // Чтение регистра минут
  335.     DateTime.Min = (((temp & 0xF0) >> 4)*10)+(temp & 0x0F);
  336.  
  337.     DS1307Read(0x02,&temp); // Чтение регистра часов
  338.     DateTime.Hour = (((temp & 0xF0) >> 4)*10)+(temp & 0x0F);
  339. }
  340.  
  341. // Функция пропорционально переносит значение (value) из текущего диапазона
  342. // значений (fromLow .. fromHigh) в новый диапазон (toLow .. toHigh), заданный параметрами
  343. long map(long x, long in_min, long in_max, long out_min, long out_max) {
  344.     return (x - in_min) * (out_max - out_min + 1) / (in_max - in_min + 1) + out_min;
  345. }
  346.  
  347. // Процедура записи в микросхему из структуры TDateTime
  348. void DS1307_WriteDateTime() {
  349.     unsigned char tmp;
  350.     tmp = ((DateTime.Sec / 10) << 4) | (DateTime.Sec % 10);
  351.     DS1307Write(0x00, tmp);
  352.     tmp = ((DateTime.Min / 10) << 4) | (DateTime.Min % 10);
  353.     DS1307Write(0x01, tmp);
  354.     tmp = ((DateTime.Hour / 10) << 4) | (DateTime.Hour % 10);
  355.     DS1307Write(0x02, tmp);
  356.     tmp = ((DateTime.WeekDay / 10) << 4) | (DateTime.WeekDay % 10);
  357.     DS1307Write(0x03, tmp);
  358. }
  359.  
  360. // Внешнее прерывание с DS1307 (SQW)
  361. ISR ( INT1_vect ) {
  362.     sqw_flag = 1;
  363. }
  364.  
  365.  
  366. // Код основной программы
  367. int main(void) {
  368.     asm("CLI");
  369.     _delay_ms(100);
  370.    
  371.     // Инициализация таймера/счестчика 2 для динамической индикации
  372.     TCCR0 |= (1 << CS02);
  373.     TIMSK |= (1 << TOIE0);
  374.     TCNT1 = 0;
  375.    
  376.     TCCR1B |= (0 << CS12) | (1 << CS11) | (1 << CS10);
  377.     TIMSK |= (1 << TOIE1);
  378.     TCNT1 = 0xFF06;
  379.    
  380.     TCCR2 = (1 << CS20) | (1 << CS21) | (0 << CS22);
  381.     TIMSK |= (1 << TOIE2);
  382.     TCNT2 = 0xF0;
  383.    
  384.     MCUCR |= (1 << ISC01) | (0 << ISC00);
  385.     MCUCR |= (1 << ISC11) | (0 << ISC10);
  386.     GICR |= (1 << INT0) | (1 << INT1);
  387.  
  388.     // Инициализация портов ввода-вывода SPI
  389.     _74hc595_SPI_Init();
  390.     asm("SEI");
  391.  
  392.     DS1307Init(); // Инициализация DS1307
  393.     DS1307Write(0x07, 0b10010000); // Настраиваем выход SQW на частоту 1Hz
  394.  
  395.     // Переменные для работы интерфейса
  396.     int menu_level = 0; // позиция в главном меню
  397.     int menu_flag = 0; // Говорит о том, что открыто меню в данный момент или нет
  398.     int submenu_level = 0; // Позиция в подменю, клавиши на пульте: "<<" и ">>"
  399.     int s_hour = 0, s_min = 0; // Настраиваемые значения
  400.     int enter_menu_flag = 0; // Флаг входа в меню. выполняется каждый раз при входе в меню для приравнивания значений
  401.     int blink_flag = 0; // Флаг мигания значний в настройках
  402.     int pass_cnt = 4; // Счетчик колличества проходов по шкале
  403.     int interval = 7; // Интервал перемещения по проходу
  404.     int pass_end_flag = 0; // Флаг сброса прохода
  405.     unsigned long long int scale = 0b1111111111111111111111111111111111111111111111111111111111111111; // Светодня шкала
  406.    
  407.     while (1) {
  408.         // Рапределение значения по массиву
  409.         display_data[5] = ((((scale >> 4) & 0b00011111) << 3) | (scale >> 61));
  410.         display_data[10] = (unsigned char)(scale >> 53);
  411.         display_data[2] = (unsigned char)(scale >> 45);
  412.         display_data[1] = (unsigned char)(scale >> 37);
  413.         display_data[7] = (unsigned char)(scale >> 29);
  414.         display_data[0] = (unsigned char)(scale >> 21);
  415.         display_data[3] = (unsigned char)(scale >> 13);
  416.         display_data[4] = (unsigned char)((scale >> 9) << 4) | 0b00001111;
  417.        
  418.         // Читаем время из микросхемы
  419.         DS1307_ReadDateTime();
  420.        
  421.         // Вся суть анимации
  422.         if (sqw_flag && !menu_flag) { // Если прошла секунда
  423.             interval = map(DateTime.Sec, 0, 59, 7, 30);
  424.             setInterval(interval, tmr0, { // Устанавливаем интервал прохода
  425.                 pass_cnt++; // Приабавляем счетчик прохода
  426.                 // Если мы прошли больше, чем оставшееся время
  427.                 // PS не текущее, птому-что сдвиг идет от младшего к старшему биту и
  428.                 // потому-что бегущий светодидод идет с канца шкалы к началу
  429.                 if (pass_cnt > (63 - (DateTime.Sec))) {
  430.                     pass_cnt = 0; // Обнуляем счетчик прохода
  431.                     sqw_flag = 0; // Обнуляем флаг SQW (т.е. секунда прошла)
  432.                     pass_end_flag = 1; // Выставляем флаг конца прохода шкалы
  433.                 }
  434.                 // Бежим по шкале одним светодиодом
  435.                 scale &= ~(1ULL << pass_cnt);
  436.                 // Что-бы не оставлять засобой шлейф из светодиодов, после,
  437.                 // Гасим остальные диоды за ним... т.е. биты выставляем в 1
  438.                 for (int h = 4; h <= (pass_cnt -1); h++) {
  439.                     scale |= (1ULL << h);
  440.                 }
  441.             });
  442.         }
  443.        
  444.         // Если-же мы прошли шкалу
  445.         if (pass_end_flag) {
  446.             // Рисуем уже пройденную шкалу от начала
  447.             for (int j = 59; j >= (59 - DateTime.Sec); j--) {
  448.                 scale &= ~(1ULL << (j + 3));
  449.             }
  450.             // Выставляем флаг конца прохода шкалы в ноль
  451.             pass_end_flag = 0;
  452.         }
  453.        
  454.         // Если пришла команда с пульа
  455.         if (NEC_IR_DONE) {
  456.             // Уже нет
  457.             NEC_IR_DONE = 0;
  458.            
  459.             // Заходим в меню
  460.             if (command == MENU) {
  461.                 menu_level++; // Прибавляем уровень меню
  462.                 menu_flag = 1; // Говорим системе, что мы в меню
  463.                 submenu_level = 0; // Обнуляем позицию подменю
  464.                 if (menu_level > 2) menu_level = 1; // Пунктов меню всего два
  465.                 enter_menu_flag = 1; // Говорим системе, что вошли в меню
  466.             }
  467.             // Если мы в меню и нажали на RETURN
  468.             if (command == RETURN && menu_flag) {
  469.                 // Выходим из меню и обнуляем счетчики позиций
  470.                 menu_flag = 0;
  471.                 menu_level = 0;
  472.                 submenu_level = 0;
  473.             }
  474.             // При нажатии на ">>" перемещаемся по подменю
  475.             if (command == FWND && menu_flag) {
  476.                 submenu_level++;
  477.                 if (submenu_level > 1) submenu_level = 0;
  478.             }
  479.             // Тоже самое для "<<"
  480.             if (command == RWND && menu_flag) {
  481.                 submenu_level--;
  482.                 if (submenu_level < 0) submenu_level = 1;
  483.             }
  484.             // Если мы в меню и нажали на "+"
  485.             if (command == PLUS && menu_flag) {
  486.                 if (submenu_level == 0) { // Если настраиваем часы
  487.                     s_hour++; // прибавляем часы
  488.                     if (s_hour > 23) s_hour = 0; // но не больше 23
  489.                     print_display(s_hour, s_min, 0, 0, 0); // так как настраиваемые цифры мигают, задержим их во время настройки
  490.                 }
  491.                 // тоже самое и с настройками минут
  492.                 if (submenu_level == 1) {
  493.                     s_min++;
  494.                     if (s_min > 59) s_min = 0;
  495.                     print_display(s_hour, s_min, 0, 0, 0);
  496.                 }
  497.             }
  498.             // Тоже самое, что и в "+", только значения убавляем и соблюдаем пороги
  499.             if (command == MINUS && menu_flag) {
  500.                 if (submenu_level == 0) {
  501.                     s_hour--;
  502.                     if (s_hour < 0) s_hour = 23;
  503.                     print_display(s_hour, s_min, 0, 0, 0);
  504.                 }
  505.                 if (submenu_level == 1) {
  506.                     s_min--;
  507.                     if (s_min < 0) s_min = 59;
  508.                     print_display(s_hour, s_min, 0, 0, 0);
  509.                 }
  510.             }
  511.             // Кнопка PLAY - это кнопка OK, при ее нажатии сохраняем текущие настройки
  512.             if (command == PLAY && menu_flag) {
  513.                 if (menu_level == 1) { // Если настраиваем время
  514.                     DateTime.Sec = 0; // Устанавливаем такой формат XX:XX:00
  515.                     DateTime.Min = s_min;
  516.                     DateTime.Hour = s_hour;
  517.                     DS1307_WriteDateTime(); // Пишем новое время в микросхему DS1307
  518.                 }
  519.                 if (menu_level == 2) { // Если настраиваем будильник
  520.                 //  AlarmData.Hour = s_hour;
  521.                 //  AlarmData.Min = s_min;
  522.                 //  AlarmWriteTime(); // Записываем настройки в EEPROM
  523.                 }
  524.                 // И выходим из меню после сохранения всех настроек
  525.                 menu_flag = 0;
  526.                 menu_level = 0;
  527.                 submenu_level = 0;
  528.             }
  529.  
  530.         }
  531.  
  532.         if (menu_flag) {
  533.             if (enter_menu_flag) {
  534.                 enter_menu_flag = 0;
  535.                 if (menu_level == 1) { // Если настраиваем время
  536.                     DS1307_ReadDateTime();
  537.                     s_hour = DateTime.Hour;
  538.                     s_min = DateTime.Min;
  539.                 }
  540.             }
  541.             setInterval(450, tmr0, {
  542.                 blink_flag ^= 1;
  543.                 if (submenu_level == 0) {
  544.                     print_display(s_hour, s_min, 0, blink_flag, 0);
  545.                 }
  546.                 if (submenu_level == 1) {
  547.                     print_display(s_hour, s_min, 0, 0, blink_flag);
  548.                 }
  549.             });
  550.  
  551.         } else {
  552.             print_display(DateTime.Hour, DateTime.Min, sqw_flag, 0, 0);
  553.         }
  554.        
  555.  
  556.     }
  557.    
  558.     return 1;
  559. }
Advertisement
Add Comment
Please, Sign In to add comment