/***************************************************** Термостат с програмированием на неделю Chip type : ATmega8 Program type : Application Clock frequency : 4,000000 MHz Memory model : Small External RAM size : 0 Data Stack size : 256 *****************************************************/ //============================================================== // Предустановки //============================================================== #include // I2C ----------------------- #asm .equ __i2c_port=0x15 ;PORTC .equ __sda_bit=2 .equ __scl_bit=1 #endasm #include // DS1307 -------------------- #include // 1 Wire -------------------- #asm .equ __w1_port=0x15 ;PORTC .equ __w1_bit=0 #endasm #include <1wire.h> // DS18B20 ------------------- #include // LCD ----------------------- #asm .equ __lcd_port=0x12 ;PORTD #endasm #include // Задержки #include // Стандартные фун-и #include #include //============================================================== // GLOBAL DEFINES //============================================================== /* #define BISTABLE_RELAY */ // Реле моностабильное по умолчанию. Раскоментировать для использования моностабильного реле. #define scan_delay 15 // Задержка до следующего сканирования клавиатуры = n*16,3ms #define temp_max 300 // Максимальная температура уставки = n/10°С * должно быть кратно 5 #define temp_min 80 // Минимальная температура уставки = n/10°С * должно быть кратно 5 #define hyst 5 // Гистерезис переключения = n/10°С // Коды кнопок: #define btn_plus btn_tsk & 0x01 // "+" #define btn_minus btn_tsk & 0x02 // "-" #define btn_right btn_tsk & 0x08 // ">" #define btn_left btn_tsk & 0x04 // "<" #define btn_ok btn_tsk & 0x10 // "ok" //============================================================== // Прототипы функций //============================================================== void clk_adj (char cur_pos); // Меню установки часов void compare (void); // Сравнение температуры и выдача команды на включение void define_char(unsigned char flash *pc,unsigned char char_code); // Запись спецсимвола в ЖКИ void e_get_temp (char direction); // Получение или запись температур повышеного и пониженого режимов void e_temp_adj (char cur_pos); // Запись/чтение значений повыш. и пониж. температур void get_day_map (char day, char direction); // Получение или запись дневной карты char get_interval (void); // Получение номера интервала для текущнго времени с дневной карты char get_mas_pos (char n); // Получение позиции в масиве карты дня для даного интервала void get_temp (void); // Считывание и вычисление температуры DS18B20 char get_temp_status (char interval); // Получение статуса температуры для заданого интервала с дневной карты void init (void); // Начальные установки void int1_dis (void); // Запрет внешненго прерывания void int1_en (void); // Разрешение внешненго прерывания void interval_adj (char cur_pos); // Меню настройки интервалов void m_check (void); // Проверка месяца на 30,29,28 дней void m_menu (void); // Главное меню (дисплей) char not_leap (void); // Проверка на высокостный год void relay (char s); // Управление реле (0-откл., 1...255-вкл.) void start_conv (void); // Старт преобразования и проверка на исправность датчика тем-ры void t1_start (void); // Старт таймера 1 void t1_stop (void); // Останов таймера 1 void temp_adj (char cur_pos); // Вывод температуры ручной уставки void tsk_clr (void); // Очистка заданий char wd_calc (void); // Вычисление дня недели (возвр. номера дня) void y_check (void); // Проверка года на высокостность для 2-го месяца //============================================================== // Глобальные переменные //============================================================== flash char d_map [7][4]= // Карта названий для дней { {'S','U','N'}, // 0.ВСК {'M','O','N'}, // 1.ПОН {'T','U','E'}, // 2.ВТО {'W','E','N'}, // 3.СРЕ {'T','H','U'}, // 4.ЧЕТ {'F','R','I'}, // 5.ПЯТ {'S','A','T'} // 6.СУБ }; flash unsigned char m_map [12][4]= // Карта названий для месяцев { {'J','A','N'}, // 0.ЯНВ {'F','E','B'}, // 1.ФЕВ {'M','A','R'}, // 2.МАР {'A','P','R'}, // 3.АПР {'M','A','Y'}, // 4.МАЙ {'J','U','N'}, // 5.ИЮН {'J','U','L'}, // 6.ИЮЛ {'A','U','G'}, // 7.АВГ {'S','E','P'}, // 8.СЕН {'O','C','T'}, // 9.ОКТ {'N','O','V'}, // 10.НОЯ {'D','E','C'} // 11.ДЕК }; flash char str_11[11]={'D','a','t','e','/','T','i','m','e'}; // "Дата/время" flash char str_12[7]={'G','r','a','p','h'}; // "График" flash char str_13[12]={'T','e','m','p','e','r','a','t','u','r','e'}; // "Температуры" flash char str_14[6]={'E','x','i','t'}; // "Выход" flash unsigned char c_degree[8]= // Знак градуса { 0b01110, //| ooo | 0b01010, //| o o | 0b01110, //| ooo | 0b00000, //| | 0b00000, //| | 0b00000, //| | 0b00000, //| | 0b00000 //| | }; flash unsigned char c_term[8]= // Знак градусник { 0b01110, //| ooo | 0b01010, //| o o | 0b01010, //| o o | 0b01110, //| ooo | 0b01110, //| ooo | 0b11101, //|ooo o| 0b01110, //| ooo | 0b00000 //| | }; flash unsigned char c_fire[8]= // Знак огонек { 0b00100, //| o | 0b01100, //| oo | 0b01110, //| ooo | 0b11010, //|oo o | 0b11011, //|oo oo| 0b11101, //|ooo o| 0b01110, //| ooo | 0b00000 //| | }; flash unsigned char c_moon[8]= // Знак луна { 0b01100, //| oo | 0b00110, //| oo | 0b00011, //| oo| 0b00011, //| oo| 0b00011, //| oo| 0b00110, //| oo | 0b01100, //| oo | 0b00000 //| | }; // Время (часы, минуты, секунды) struct time_str { char hour; char min; char sec; } t; // Дата (день, месяц, год) struct date_str { char day; char month; char year; } d; // Температура датчика signed int temp; // Желаемая температура signed int temp2=150; // Темп. повышеного режима signed int temp_hi; // Темп. пониженого режима signed int temp_low; // Кнопки char btn_tsk; /* PB0-"+" PB1-"-" PB2-">" PB3-"<" PB4-"ok" */ // Текущее положение реле "1"-вкл. "0"-выкл. //char relay_pos=0; // Текущий интервал char cur_int; // Флаг режима антизамерзания char a_frz; // Глубина вложености меню struct menu_str { char deep; // Глубина меню (0-главн. окно) char smenu; // Субменю char q_temp; // Быстрый доступ к температуре char state; // Номер редактируемого параметра char day_sel; // Выбор дня и интервала char int_sel; // } menu; char lcd_buf[33]; // Буфер для строчного ЖКИ 16х2 (32 симв. + NULL) char day_int_map[19]; // Буфер для интервальной раскладки дня // Раскладка интервалов на неделю по умолчанию // S-статус, H-часы, M-минуты eeprom char intervals[7][19]= { // 00:00 24:00 // | | // | -> 1 -> | 2 -> | 3 -> | 4 -> | 5 -> | 6 -> | // | S H M | S H M | S H M | S H M | S H M | S H M | {1,07,00, 1,11,00, 1,14,00, 1,15,00, 1,16,00, 0,23,00}, // ВОС. {1,07,00, 0,11,00, 0,14,00, 0,15,00, 1,16,00, 0,23,00}, // ПОН. {1,07,00, 0,11,00, 0,14,00, 0,15,00, 1,16,00, 0,23,00}, // ВТО. {1,07,00, 0,11,00, 0,14,00, 0,15,00, 1,16,00, 0,23,00}, // СРЕ. {1,07,00, 0,11,00, 0,14,00, 0,15,00, 1,16,00, 0,23,00}, // ЧЕТ. {1,07,00, 0,11,00, 0,14,00, 0,15,00, 1,16,00, 0,23,00}, // ПЯТ. {1,07,00, 1,11,00, 1,14,00, 1,15,00, 1,16,00, 0,23,00} // СУБ. }; eeprom int e_temp[2]={190,230}; // Повышеные и пониженые температуры eeprom int af_temp=80; // Температура режима антизамерзания (ручной режим) eeprom char e_a_frz=0; // Флаг установки режима антизамерзания //============================================================== // External Interrupt 1 //============================================================== // Прерывание от DS1307 ежесекундно interrupt [EXT_INT1] void ext_int1_isr(void) { static char temp_status, temp_char; char temp_sign; get_temp(); // Вычисление температуры start_conv(); // Старт следующего преобразования rtc_get_date(&d.day,&d.month,&d.year); // Считываем время и дату rtc_get_time(&t.hour,&t.min,&t.sec); // if (t.hour==0 && t.min==0 && t.sec==0) // Определяем переход на следующий день { get_day_map(wd_calc(),0); // Загружаем дневную карту для нового дня menu.q_temp=0; // Сбрасываем быструю установку температуры } else if (cur_inttemp_hi) temp_char=0xD9; // Выбор стрелки вверх или вниз else if(temp2temp_low) temp_char=0xD9; // Выбор стрелки вверх или вниз else if(temp2 4MHz/256 -> 15'625Hz/256=61.035Hz Интервал прерывания: t=0.0163s=16.3ms interrupt [TIM0_OVF] void timer0_ovf_isr(void) { static char comb1,comb2,stat,delay=1; // stat=0-первичная проверка; stat=1-вторичная проверка if (--delay==0) //проверка задержки { delay=1; if (stat==0) //запись в первую комбинацию через маску { comb1=((~PINB) & 0x1F); }; if (stat==1) //проверка записи первой комбинации { comb2=((~PINB) & 0x1F); //запись во вторую комбинацию через маску, если была запись в первую if (comb1==comb2) //проверка комбинаций на соответствие { btn_tsk=comb2; //записать в переменную комбинации, если соответствует delay=scan_delay; //и установить задержку нечуствительности к след. нажатию }; stat=0; //обнулить флаг статуса comb1=0; comb2=0; //и регистры комбинаций }; if (comb1!=0) //если была нажата кнопка, то уст. повторную проверку { stat=1; }; }; } //============================================================== // Timer 1 overflow interrupt //============================================================== interrupt [TIM1_OVF] void timer1_ovf_isr(void) { t1_stop(); // Останов таймера tsk_clr(); // Очистка // В меню установки быстрой температуры... if(menu.q_temp==1 || a_frz==1) { btn_tsk=0x10; }; // В главном меню... if(menu.deep==1) { menu.smenu=4; btn_tsk=0x10; }; // В меню ДАТА/ВРЕМЯ, ГРАФИК, ТЕМПЕРАТУРЫ if(menu.deep==3) { btn_tsk=0x10; }; } //============================================================== // Начальная инициализация !!! //============================================================== void init (void) { // Input/Output Ports initialization // Port B initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=P State6=P State5=P State4=P State3=P State2=P State1=P State0=P PORTB=0xFF; DDRB=0x00; // Port C initialization // Func6=In Func5=Out Func4=Out Func3=Out Func2=In Func1=In Func0=In // State6=T State5=0 State4=0 State3=0 State2=T State1=T State0=T PORTC=0x00; DDRC=0x38; // Port D initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTD=0x00; DDRD=0x00; // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 15,625 kHz TCCR0=0x04; TCNT0=0x00; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: Timer 1 Stopped // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: Off // Input Capture Interrupt: Off // Compare A Match Interrupt: Off // Compare B Match Interrupt: Off TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Timer/Counter 2 initialization // Clock source: System Clock // Clock value: Timer 2 Stopped // Mode: Normal top=FFh // OC2 output: Disconnected ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x05; // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off ACSR=0x80; SFIOR=0x00; //relay(0); // Отключаем реле // LCD module initialization lcd_init(16); // Определение нестандартных символов define_char(&c_degree[0],0x01); // Знак градуса 0х01 define_char(&c_term[0],0x02); // Градусник 0х02 define_char(&c_fire[0],0x03); // Огонек 0х03 define_char(&c_moon[0],0x04);// Луна 0х04 // I2C Bus initialization i2c_init(); // DS1307 Real Time Clock initialization // Square wave output on pin SQW/OUT: On // Square wave frequency: 1Hz rtc_init(0,1,0); // 1 Wire Bus initialization w1_init(); ds18b20_init(0,-20,35,DS18B20_12BIT_RES); // Точность 0.0625 12-разр. tпр.=800ms start_conv(); // Первое преобразование температуры lcd_clear(); // Стартовый показ версии 1,5 сек. lcd_putsf(" Ver.:TEST"); delay_ms(1500); rtc_get_time(&t.hour,&t.min,&t.sec); // Получаем текущее время и дату с RTC rtc_get_date(&d.day,&d.month,&d.year); get_day_map(wd_calc(),0); // Получаем раскладку для даного дня с EEPROM cur_int=get_interval(); // Получаем интервал для текущего времени e_get_temp(0); // Получаем значения температуры для двух режимов a_frz=e_a_frz; // Считываем с EEPROM статус режима антизамерзания if(a_frz) temp2=af_temp; // Если вкл. режим антизамерзания, считать температуру антизамерзания // Старт внешнего прерывания GICR|=0x80; MCUCR=0x08; GIFR=0x80; #asm ("sei") } //============================================================== // Вичисление дня недели через день, месяц и год //============================================================== char wd_calc (void) { unsigned int a,y,m; a=((14-d.month)/12); y=(d.year-a); m=(d.month+(12*a)-2); return (char)((7000+(d.day+y+(y/4)-(y/100)+(y/400)+((31*m)/12)))%7); // Возврат: 0-ВСКР. 1-ПОН. 2-ВТО. 3-СРЕ. 4-ЧЕТ. 5-ПЯТ. 6-СУБ. } //============================================================== // Вычисление температуры DS18B20 //============================================================== void get_temp (void) { char integer; int frac; ds18b20_read_spd(0); // Читаем scratcpad if (__ds18b20_scratch_pad.temp_msb & 0xF8) // Проверка знака температуры, если "-" то выполнить { integer=((((~__ds18b20_scratch_pad.temp_msb) & 0x07)<<4)|((~__ds18b20_scratch_pad.temp_lsb)>>4)); frac=(10000-((__ds18b20_scratch_pad.temp_lsb & 0x0F)*625)); if (frac==10000) { integer++; frac=0; }; if (integer>=50) { integer=50; frac=0; }; temp=0-(((int)integer)*10+frac/1000); } else { integer=(((__ds18b20_scratch_pad.temp_msb & 0x07)<<4)|(__ds18b20_scratch_pad.temp_lsb>>4)); frac=((__ds18b20_scratch_pad.temp_lsb & 0x0F)*625); if (integer>=99) { integer=99; frac=0; }; temp=(((int)integer)*10+frac/1000); }; } //============================================================== // Запись символа в CGRAM //============================================================== void define_char(unsigned char flash *pc,unsigned char char_code) { unsigned char j,a; a=(char_code<<3)|0x40; for (j=0; j<8; j++) { lcd_write_byte(a++,*pc++); }; } //============================================================== // Старт преобразования DS18B20 //============================================================== void start_conv (void) { while(w1_init()==0) { lcd_clear(); lcd_putsf("1W ERROR!"); relay(0); delay_ms(1000); } w1_init(); // 1W инициализация, старт записи w1_write(0xCC); // пропустить ROM w1_write(0x44); // старт преобразования } //============================================================== // Очистка заданий //============================================================== void tsk_clr (void) { btn_tsk=0x00; } //============================================================== // Управление реле //============================================================== #ifdef BISTABLE_RELAY /* Бистабильное реле */ void relay (char s) { #asm ("cli") /* ATOMIC */ if (s) { /* SET */ PORTC |= 0x10; delay_ms(50); PORTC &= ~0x10; } else { /* RESET */ PORTC |= 0x20; delay_ms(50); PORTC &= ~0x20; }; #asm ("sei") /* END ATOMIC */ } #else /* Моностабильное реле */ void relay (char s) { #asm ("cli") /* ATOMIC */ if (s) { PORTC |= 0x10; } else { PORTC &= ~0x10; }; #asm ("cli") /* END ATOMIC */ } #endif //============================================================== // Сравнение температур и выдача команды //============================================================== void compare (void) { if ((temp2-hyst)>=temp) // Желаемая тем-ра больше измеренной - вкл. реле { relay(1); } else if (temp>=(temp2+hyst)) // Желаемая тем-ра меньше измеренной - откл. реле { relay(0); }; } //============================================================== // Старт таймера 1 //============================================================== void t1_start (void) { TCNT1H=0x00; // Регистры таймера TCNT1L=0x00; TCCR1A=0x00; // Регистры контроля TCCR1B=0x05; // F_osc./1024 PORTC |=1<<3; } //============================================================== // Останов таймера 1 //============================================================== void t1_stop (void) { TCCR1A=0x00; // Регистры контроля TCCR1B=0x00; PORTC &= ~(1<<3); } //============================================================== // Проверка на высокосный год //============================================================== char not_leap (void) { int year; year=2000+(int)d.year; if (!(year%100)) return (char)(year%400); else return (char)(year%4); } //============================================================== // Проверки на 30-й, 29-й, 28-й день //============================================================== void m_check (void) { if (d.day>30 && (d.month==4 || d.month==6 || d.month==9 || d.month==11)) d.day=30; else if(d.day>28 && d.month==2 && not_leap() ) d.day=28; else if (d.day>29 && d.month==2) d.day=29; } void y_check (void) { if (d.month==2 && d.day>28 && not_leap() ) d.day=28; else if (d.month==2 && d.day>29) d.day=29; } //============================================================== // Разрешение и запрет INT1 //============================================================== void int1_en (void) { GICR |=0x80; //Разрешение прерывания по INT1 } void int1_dis (void) { GICR &=0x7F; //Запрет прерывания по INT1 } //============================================================== // Получение позиции интервала в масиве //============================================================== char get_mas_pos (char n) { return ((n-1)*3); } //============================================================== // Получение и запись дневной раскладки в дневн. буфер с EEPROM // day - номер дня; direction - направление (1-запись, 0-чтение) //============================================================== void get_day_map (char day, char direction) { char i; eeprom char *eep; char *ram; eep=&intervals[day][0]; // Инициализируем поинтеры на ram=&day_int_map[0]; // EEPROM и RAM #asm ("cli") for(i=0;i<18;i++) { if (direction) // Direction == 1 { *eep++=*ram++; // Запысываем 18 чисел в EEPROM } else // Direction == 0 { *ram++=*eep++; // Считываем 18 чисел во временной буфер (day_int_map) }; }; #asm ("sei") } //============================================================== // Получение и запись значений температур в буферы тем-ры с EEPROM // direction - направление (1-запись, 0-чтение) //============================================================== void e_get_temp (char direction) { #asm ("cli") if(direction) { e_temp[0]=temp_low; e_temp[1]=temp_hi; } else { temp_low=e_temp[0]; temp_hi=e_temp[1]; }; #asm ("sei") }; //============================================================== // Получение текущего интервала, возврат № интервала 0...6 //============================================================== char get_interval (void) { char n=1; char status=1; char hour,min; while(status) { hour=day_int_map[get_mas_pos(n)+1]; min=day_int_map[get_mas_pos(n)+2]; if(hour>t.hour) status=0; else if(hour==t.hour && min>t.min) status=0; else if(++n==7) { status=0; }; }; return n-1; } //============================================================== // Получение статуса температуры текущего интервала, возврат // статуса (1-повыш., 0-пониж.), передача № интервала //============================================================== char get_temp_status (char interval) { char day; eeprom char *eep; if(interval==0) // Если значение интервала "0" то возвращает значение { // температуры "6"-го интервала для предыдущего дня day=wd_calc(); if((--day)==255) day=6; eep=&intervals[day][15]; return *eep; } else { return day_int_map[get_mas_pos(interval)]; }; } // Процедуры вывода меню на дисплей // ---------------------------------------- //============================================================== // Быстрый выбор температуры //============================================================== void temp_adj (char cur_pos) { char status; if(a_frz==0) status='A'; else status='P'; sprintf (&lcd_buf[0],"t%+03i.%i%cC <%c>",temp2/10,abs(temp2%10),0x01,status); lcd_clear(); lcd_gotoxy(2,0); lcd_puts(&lcd_buf[0]); if(cur_pos==1) lcd_gotoxy(2,0); else if(cur_pos==2) lcd_gotoxy(12,0); _lcd_ready(); // Вкл. мигающеее знакоместо _lcd_write_data(0x0D); } //============================================================== // Основное меню //============================================================== void m_menu (void) { sprintf(&lcd_buf[0],"MEH%c: %u/4",0xB0,menu.smenu); lcd_clear(); lcd_puts(&lcd_buf[0]); lcd_gotoxy(0,1); if (menu.smenu==1) lcd_putsf(str_11); else if(menu.smenu==2) lcd_putsf(str_12); else if(menu.smenu==3) lcd_putsf(str_13); else if(menu.smenu==4) lcd_putsf(str_14); } //============================================================== // Установка часов реального времени DS1307 //============================================================== void clk_adj (char cur_pos) { rtc_get_time(&t.hour,&t.min,&t.sec); rtc_get_date(&d.day,&d.month,&d.year); sprintf(&lcd_buf[0],"%02u:%02u:%02u",t.hour,t.min,t.sec); // Верхняя строка lcd_clear(); lcd_gotoxy(4,0); lcd_puts(&lcd_buf[0]); sprintf(&lcd_buf[0],"%02u-%p.-%02u",d.day,&m_map[d.month-1][0],d.year); // Нижняя строка lcd_gotoxy(3,1); lcd_puts(&lcd_buf[0]); if(cur_pos==1) lcd_gotoxy(4,0); else if(cur_pos==2) lcd_gotoxy(7,0); else if(cur_pos==3) lcd_gotoxy(3,1); else if(cur_pos==4) lcd_gotoxy(6,1); else if(cur_pos==5) lcd_gotoxy(11,1); _lcd_ready(); // Вкл. мигающеее знакоместо _lcd_write_data(0x0D); } //============================================================== // Установка временных интервалов //============================================================== void interval_adj (char cur_pos) { char symbol,hour,min; if(get_temp_status(menu.int_sel)) symbol=0x03; else symbol=0x04; hour=day_int_map[get_mas_pos(menu.int_sel)+1]; min=day_int_map[get_mas_pos(menu.int_sel)+2]; sprintf(&lcd_buf[0]," %p.\n %u: <%c> %02u:%02u",&d_map[menu.day_sel][0],menu.int_sel,symbol,hour,min); lcd_clear(); lcd_puts(&lcd_buf[0]); if(cur_pos==1) lcd_gotoxy(1,0); else if(cur_pos==2) lcd_gotoxy(1,1); else if(cur_pos==3) lcd_gotoxy(5,1); else if(cur_pos==4) lcd_gotoxy(8,1); else if(cur_pos==5) lcd_gotoxy(11,1); _lcd_ready(); // Вкл. мигающеее знакоместо _lcd_write_data(0x0D); } //============================================================== // Установка температур //============================================================== void e_temp_adj (char cur_pos) { sprintf(&lcd_buf[0],"%c:%+03i.%i%cC\n%c:%+03i.%i%cC",0x03,temp_hi/10,abs(temp_hi%10),0x01,0x04,temp_low/10,abs(temp_low%10),0x01); lcd_clear(); lcd_puts(&lcd_buf[0]); if(cur_pos==1) lcd_gotoxy(9,0); else if(cur_pos==2) lcd_gotoxy(9,1); _lcd_ready(); // Вкл. мигающеее знакоместо _lcd_write_data(0x0D); } //============================================================== // MAIN !!! //============================================================== void main(void) { init(); // Начальная инициализация while (1) { while(!btn_tsk); //========================================================== // Вызов ручной уставки желаемой температуры // Переход по нажатию кн. "+" или "-" //========================================================== if ((btn_plus || btn_minus) && menu.deep==0) { int1_dis(); // Запрет внешнего прерывания menu.q_temp=1; // Флаг входа в меню быстр. доступа к температуре menu.state=1; t1_start(); // Старт отсчета на выход while (!(btn_ok)) // Выполнять если "ОК" не нажата { #asm ("cli") if(btn_right) // Нажато "вправо" { if(++menu.state==3) menu.state=1; tsk_clr(); t1_start(); temp_adj(menu.state); }; if(btn_left) // Нажато "влево" { if(--menu.state==0) menu.state=2; tsk_clr(); t1_start(); temp_adj(menu.state); }; if (btn_plus) // Нажато "минус" { if(menu.state==1) { if (temp2>=temp_max) {} // Если тем-ра >= t_max то ничего не делать else // Если меньше то добавить 0.5С { temp2+=5; }; if(a_frz) menu.q_temp=0; } else if(menu.state==2) { a_frz=1; e_a_frz=a_frz; menu.q_temp=0; }; tsk_clr(); t1_start(); temp_adj(menu.state); }; if (btn_minus) // Нажато "плюс" { if(menu.state==1) { if (temp2<=temp_min) {} // Если тем-ра <= t_min то ничего не делать else // Если больше то отнять 0.5С { temp2-=5; }; if(a_frz) menu.q_temp=0; } else if(menu.state==2) { a_frz=0; e_a_frz=a_frz; menu.q_temp=1; }; tsk_clr(); t1_start(); temp_adj(menu.state); }; #asm ("sei") }; // После нажатия кнопки "ОК" #asm ("cli") if(a_frz) af_temp=temp2; rtc_get_date(&d.day,&d.month,&d.year); // Считываем дату и загружаем карту дня get_day_map(wd_calc(),0); #asm ("sei") tsk_clr(); t1_stop(); int1_en(); // Разрешение внешнего прерывания }; //========================================================== // Вход в главное меню // Переход по нажатию кн. "OK" //========================================================== if (btn_ok && menu.deep==0) { if(a_frz) { #asm ("cli") a_frz=0; e_a_frz=a_frz; tsk_clr(); #asm ("sei") } else { int1_dis(); // Запрет внешнего прерывания tsk_clr(); t1_start(); menu.deep=1; menu.smenu=1; m_menu(); while (!(btn_ok)) // Выполнять если "ОК" не нажата { #asm ("cli") if(btn_right) // Нажато "вправо" { if(++menu.smenu==5) menu.smenu=1; tsk_clr(); t1_start(); m_menu(); }; if(btn_left) // Нажато "влево" { if(--menu.smenu==0) menu.smenu=4; tsk_clr(); t1_start(); m_menu(); }; #asm ("sei") }; // После нажатия кнопки "ОК" tsk_clr(); t1_stop(); menu.deep=2; } }; //---------------------------------------------------------- // "Дата/время" //---------------------------------------------------------- if (menu.deep==2 && menu.smenu==1) { tsk_clr(); t1_start(); menu.deep=3; menu.state=1; clk_adj(menu.state); // Вывод меню времени while (!(btn_ok)) { clk_adj(menu.state); delay_ms(200); #asm ("cli") if(btn_right) // Нажато "вправо" { if(++menu.state==6) menu.state=1; tsk_clr(); t1_start(); clk_adj(menu.state); }; if(btn_left) // Нажато "влево" { if(--menu.state==0) menu.state=5; tsk_clr(); t1_start(); clk_adj(menu.state); }; if(btn_plus) // Нажато "плюс" { if(menu.state==1) // *Часы { if(++t.hour>23) t.hour=0; t.sec=0; } else if(menu.state==2) // *Минуты { if(++t.min>59) t.min=0; t.sec=0; } else if(menu.state==3) // *День { if(++d.day>31) d.day=1; else if(d.day>30 && (d.month==4 || d.month==6 || d.month==9 ||d.month==11)) d.day=1; else if(d.day>29 && d.month==2) d.day=1; else if (d.day>28 && d.month==2 && not_leap() ) d.day=1; } else if(menu.state==4) // *Месяц { if(++d.month==13) d.month=1; else m_check(); } else if(menu.state==5) // *Год { if(++d.year==99) d.year=0; y_check(); }; tsk_clr(); t1_start(); rtc_set_time(t.hour,t.min,t.sec); //Установить время и дату rtc_set_date(d.day,d.month,d.year); clk_adj(menu.state); // Вывод меню времени }; if(btn_minus) // Нажато "минус" { if(menu.state==1) // *Часы { if(--t.hour==255) t.hour=23; t.sec=0; } else if(menu.state==2) // *Минуты { if(--t.min==255) t.min=59; t.sec=0; } else if(menu.state==3) // *День { if(--d.day==0) { d.day=31; if(d.month==4 || d.month==6 || d.month==9 || d.month==11) d.day=30; else if(d.month==2 && not_leap() ) d.day=28; else if(d.month==2) d.day=29; }; } else if(menu.state==4) // *Месяц { if(--d.month==0) d.month=12; else m_check(); } else if(menu.state==5) // *Год { if(--d.year==255) d.year=99; y_check(); }; tsk_clr(); t1_start(); rtc_set_time(t.hour,t.min,t.sec); //Установить время и дату rtc_set_date(d.day,d.month,d.year); clk_adj(menu.state); // Вывод меню времени }; #asm ("sei") }; t1_stop(); menu.deep=0; }; //---------------------------------------------------------- // "График" //---------------------------------------------------------- if (menu.deep==2 && menu.smenu==2) { tsk_clr(); t1_start(); menu.deep=3; menu.state=1; menu.day_sel=1; menu.int_sel=1; get_day_map(menu.day_sel,0); interval_adj(menu.state); while(!(btn_ok)) { #asm ("cli") if(btn_right) //Кнопка "вправо" { if(++menu.state==6) menu.state=1; tsk_clr(); t1_start(); interval_adj(menu.state); }; if(btn_left) //Кнопка "влево" { if(--menu.state==0) menu.state=5; tsk_clr(); t1_start(); interval_adj(menu.state); }; if(btn_plus) //Кнопка "плюс" { if(menu.state==1) // *День недели { get_day_map(menu.day_sel,1); if(++menu.day_sel==7) menu.day_sel=0; get_day_map(menu.day_sel,0); } else if(menu.state==2) // *Интервал { if(++menu.int_sel==7) menu.int_sel=1; } else if(menu.state==3) // *Статус { day_int_map[get_mas_pos(menu.int_sel)]=1; } else if(menu.state==4) // *Часы { if(menu.int_sel==6) { if(++day_int_map[get_mas_pos(menu.int_sel)+1]==24) day_int_map[get_mas_pos(menu.int_sel)+1] =23; } else if(++day_int_map[get_mas_pos(menu.int_sel)+1] < day_int_map[get_mas_pos(menu.int_sel+1)+1]) {} else { --day_int_map[get_mas_pos(menu.int_sel)+1]; }; } else if(menu.state==5) // *Минуты { if(++day_int_map[get_mas_pos(menu.int_sel)+2]==60) day_int_map[get_mas_pos(menu.int_sel)+2]=0; }; tsk_clr(); t1_start(); interval_adj(menu.state); }; if(btn_minus) //Кнопка "минус" { if(menu.state==1) // *День недели { get_day_map(menu.day_sel,1); if(--menu.day_sel==255) menu.day_sel=6; get_day_map(menu.day_sel,0); } else if(menu.state==2) // *Интервал { if(--menu.int_sel==0) menu.int_sel=6; } else if(menu.state==3) // *Статус { day_int_map[get_mas_pos(menu.int_sel)]=0; } else if(menu.state==4) // *Часы { if(menu.int_sel==1) { if(--day_int_map[get_mas_pos(menu.int_sel)+1]==255) day_int_map[get_mas_pos(menu.int_sel)+1]=0; } else if( --day_int_map[get_mas_pos(menu.int_sel)+1] > day_int_map[get_mas_pos(menu.int_sel-1)+1] ) {} else { ++day_int_map[get_mas_pos(menu.int_sel)+1]; }; } else if(menu.state==5) // *Минуты { if(--day_int_map[get_mas_pos(menu.int_sel)+2]==255) day_int_map[get_mas_pos(menu.int_sel)+2]=59; }; tsk_clr(); t1_start(); interval_adj(menu.state); }; #asm ("sei") }; t1_stop(); get_day_map(menu.day_sel,1); // Сохраняем карту для дня menu.deep=0; }; //---------------------------------------------------------- // "Температуры" //---------------------------------------------------------- if (menu.deep==2 && menu.smenu==3) { tsk_clr(); t1_start(); menu.deep=3; menu.state=1; e_get_temp(0); // Считать тем-ры с EEPROM e_temp_adj(menu.state); while(!(btn_ok)) // Кнопка "ОК" { #asm ("cli") if(btn_left) // Кнопка "влево" { if(--menu.state==0) menu.state=2; tsk_clr(); t1_start(); e_temp_adj(menu.state); }; if(btn_right) // Кнопка "вправо" { if(++menu.state==3) menu.state=1; tsk_clr(); t1_start(); e_temp_adj(menu.state); }; if(btn_plus) // Кнопка "плюс" { if(menu.state==1) // Температура повышеная { if(temp_hi>=temp_max) {} else temp_hi+=5; } else if(menu.state==2) // Температура пониженая { if(temp_low>=temp_max) {} else temp_low+=5; }; tsk_clr(); t1_start(); e_temp_adj(menu.state); }; if(btn_minus) // Кнопка "минус" { if(menu.state==1) // Температура повышеная { if(temp_hi<=temp_min) {} else temp_hi-=5; } else if(menu.state==2) // Температура пониженая { if(temp_low<=temp_min) {} else temp_low-=5; }; tsk_clr(); t1_start(); e_temp_adj(menu.state); }; #asm ("sei") }; t1_stop(); e_get_temp(1); // Записать тем-ры в EEPROM menu.deep=0; }; //---------------------------------------------------------- // "Выход" //---------------------------------------------------------- if (menu.deep==2 && menu.smenu==4) { menu.deep=0; // Сброс положения меню menu.smenu=0; menu.q_temp=0; // Сброс флага уст. быстрой температуры rtc_get_date(&d.day,&d.month,&d.year); get_day_map(wd_calc(),0); int1_en(); // Разрешение внешнего прерывания }; }; }