Кухонные часы-таймер
- Войдите на сайт для отправки комментариев
Сделал часы на кухню, с таймером. Время и день недели показывают постоянно (я вообще не понимаю зачем нужны часы в которых время показывается секунд 20 в минуту))). Шрифт часов можно выбрать из 3 вариантов. Могут пищать каждый час, длительность писка 200мс, т.ч. отключение на ночь не делал. Во второй строке или число и месяц или день недели и температура или выдержка таймера. Данные меняются каждые 10 секунд, время таймера показывается постоянно пока не отработает выдержку, температура берется с DS3231. В режиме таймера можно задать задержку до 999 минут. Все собрано из готовых блоков с али: 6 индикаторов на MAX7219, модуль для распбери DS3231 (он небольшой и стоит в окне внизу корпуса), пленочная клавиатура и пассивный бипер. Подключение расписано в самом скетче. Корпус печал сам, модели есть тут - https://3dtoday.ru/3d-models/for-home/kitchen/chasy_taymer_na_kukhnyu/.
/* * Connect: * MAX7219: * Pin 11 - DIN * Pin 13 - CLK * Pin 10 - CS * Matrix: * 0 2 4 * 1 3 5 * Add library 'LedControl' on IDE * * I2C MAX3231: * pin A5 - SCL * pin A4 - SDA * * Keypad: * Pin 2,3,4,5,A0,A1,A2,A3 * * Biper: * Pin 7 and VCC * * Управление: * 'A' - Set time/timer (Установка времени/таймера) * 'B' - Set mode 'Time/Timer' (Переключение режима "Часы/Таймер") * 'C' - Start/Stop timer, stop timer sound (Запуск/Остановка таймера, Выключение звука таймера) * 'D' - Enable/Disable ring every hour (Включение/Выключение сигнала каждый час) * '*' - Change time font (Смена шрифта часов) * '#' - Change screen light (Изменение яркости экрана) */ #include "LedControl.h" #include <Wire.h> #include <avr/wdt.h> #define DS3231 0x68 #define MAX_LIGHT 5 // Maximum==16 const unsigned char PinBiper=7; const unsigned char PinOut[] ={A0, A1, A2, A3}; // пины выхода клавиатуры const unsigned char PinIn[] ={2, 3, 4, 5}; // пины входа клавиатуры const char key_value[4][4]={ {'A', 'B', 'C', 'D'}, {'3', '6', '9', '#'}, {'2', '5', '8', '0'}, {'1', '4', '7', '*'}}; LedControl lc=LedControl(11,13,10,6); // Дни недели - П Н В Т С Р Ч Т П Т С Б В С const unsigned char days[]={16,17,18,19,20,21,04,19,16,19,20,06,18,20}; unsigned char scr_level=1; // Яркость экрана. Настройка сохраняется в DS3231 по аресу 0x09 unsigned char buffer[24][2]; // Буфер экрана unsigned char mode=0; // Режим: 0 - Дата, 1 - День недели/температура, 2 - Таймер, 3 - Установка времени unsigned char ds[0x12]; // Буфер DS3231 unsigned char sound_en=0; // Сигнал каждый час. Настройка сохраняется в DS3231 по адресу 0x0C unsigned int timer_min=0; // Время таймера unsigned char timer_sec=0; unsigned char timer_mode=0; // Режим таймера unsigned char font=0; // Шрифт часов 0-2 // Символы 7x4 const unsigned char DigBig1[] PROGMEM ={ 0x3E,0x41,0x41,0x3E,// 0 0x00,0x42,0x7F,0x40,// 1 0x62,0x51,0x49,0x66,// 2 0x22,0x49,0x49,0x36,// 3 0x18,0x14,0x12,0x7F,// 4 0x2F,0x49,0x49,0x33,// 5 0x3E,0x49,0x49,0x32,// 6 0x03,0x79,0x05,0x03,// 7 0x36,0x49,0x49,0x36,// 8 0x26,0x49,0x49,0x3E,// 9 0x0,0x24,0x12,0x0, // Точка 1 0x0,0x12,0x24,0x0, // Точка 2 0,0,0,0}; // Space const unsigned char DigBig2[] PROGMEM ={ 0x7F,0x63,0x63,0x7F,// 0 0x42,0x7F,0x7F,0x40,// 1 0x7B,0x7B,0x6F,0x6F,// 2 0x6B,0x6B,0x7F,0x7F,// 3 0x1F,0x18,0x18,0x7F,// 4 0x6F,0x6B,0x7B,0x7B,// 5 0x7F,0x6B,0x6B,0x7B,// 6 0x03,0x7B,0x7F,0x07,// 7 0x7F,0x6B,0x6B,0x7F,// 8 0x6F,0x6B,0x6B,0x7F,// 9 0x0,0x24,0x12,0x0, // Точка 1 0x0,0x12,0x24,0x0, // Точка 2 0,0,0,0}; // Space const unsigned char DigBig3[] PROGMEM ={ 0x7F,0x41,0x41,0x7F,// 0 0x00,0x42,0x7F,0x40,// 1 0x79,0x49,0x49,0x4F,// 2 0x49,0x49,0x49,0x7F,// 3 0x0F,0x08,0x08,0x7F,// 4 0x4F,0x49,0x49,0x79,// 5 0x7F,0x49,0x49,0x79,// 6 0x01,0x01,0x7D,0x03,// 7 0x7F,0x49,0x49,0x7F,// 8 0x4F,0x49,0x49,0x7F,// 9 0x0,0x24,0x12,0x0, // Точка 1 0x0,0x12,0x24,0x0, // Точка 2 0,0,0,0}; // Space // Символы 5x3 const unsigned char DigSmall[] PROGMEM ={ 0x1F,0x11,0x1F, // 0 0x12,0x1F,0x10, // 1 0x1D,0x15,0x17, // 2 0x15,0x15,0x1F, // 3 7,4,0x1F, // 4 0x17,0x15,0x1D, // 5 0x1F,0x15,0x1D, // 6 1,0x1D,3, // 7 0x1F,0x15,0x1F, // 8 0x17,0x15,0x1F, // 9 0,0x10,0, // Точка 10 0,0x0A,0, // Двоеточие 11 0x0A,0x04,0x0A, // Сигнал 12 0x0E,4,0, // Play 13 6,6,0, // Stop 14 0,0,0, // Space 15 // Дни недели 0x1F,1,0x1F, // П 16 0x1F,0x04,0x1F, // H 17 0x1F,0x15,0x1B, // B 18 0x01,0x1F,0x01, // T 19 0x1F,0x11,0x1B, // C 20 0x1F,0x05,0x07 // P 21 }; //*********************************************************************************************** void setup() { //Serial.begin(9600); // Клавиатура for(unsigned char i=0;i<4;i++) {pinMode(PinOut[i], OUTPUT);digitalWrite(PinOut[i],HIGH);} for(unsigned char i=0;i<4;i++) {pinMode(PinIn[i], INPUT);digitalWrite(PinIn[i],HIGH);} // I2C Wire.begin(); Wire.setClock(400000); Read_I2C(DS3231,0,0x12,ds); // Перезапуск DS3231 if(ds[0x0E] & 0x80) { ds[0]=ds[1]=ds[2]=0;ds[3]=2;ds[4]=ds[5]=1;ds[6]=0x19; for(unsigned int i=7;i<0x0E;i++)ds[i]=0; ds[0x0E]=0x20; Write_I2C(DS3231,0,15,ds); } sound_en=ds[0x0C]; scr_level=ds[9]; // Матричный экран for(unsigned char address=0;address<6;address++) {lc.shutdown(address,false); lc.setIntensity(address,scr_level); lc.clearDisplay(address);} for(unsigned char i=0;i<24;i++) {buffer[i][0]=buffer[i][1]=0;} // Biper pinMode(PinBiper, OUTPUT);digitalWrite(PinBiper,HIGH); tone(PinBiper,1000,200); // WDT wdt_reset();wdt_enable(WDTO_4S); } //*************************************************************************************** //* Запись символа 5x3 в буфер //* adr - позиция Х (0..23) //* line - линия Y (0...1) void WriteSmallChar(unsigned char adr, unsigned char line, unsigned char data) { unsigned char tmp=data*3; buffer[adr++][line] |=pgm_read_byte_near(DigSmall+tmp++)<<3; buffer[adr++][line] |=pgm_read_byte_near(DigSmall+tmp++)<<3; buffer[adr][line] |=pgm_read_byte_near(DigSmall+tmp)<<3; } //*************************************************************************************** //* Запись символа 7x4 в буфер void WriteBigChar (unsigned char adr, unsigned char line, unsigned char data) { unsigned char tmp=data*4; const unsigned char *ad=&DigBig1[tmp]; if(font==1) ad=&DigBig2[tmp]; if(font==2) ad=&DigBig3[tmp]; buffer[adr++][line]=pgm_read_byte_near(ad++); buffer[adr++][line]=pgm_read_byte_near(ad++); buffer[adr++][line]=pgm_read_byte_near(ad++); buffer[adr++][line]=pgm_read_byte_near(ad); } //*************************************************************************************** //* Вывод буфера на экран void WriteDisplay() { unsigned char z=0; for(char i=0;i<8;i++) lc.setRow(0,i,buffer[z++][0]); for(char i=0;i<8;i++) lc.setRow(2,i,buffer[z++][0]); for(char i=0;i<8;i++) lc.setRow(4,i,buffer[z++][0]); z=0; for(char i=0;i<8;i++) lc.setRow(1,i,buffer[z++][1]); for(char i=0;i<8;i++) lc.setRow(3,i,buffer[z++][1]); for(char i=0;i<8;i++) lc.setRow(5,i,buffer[z++][1]); } //*********************************************************************************************** // Опрос клавиатуры char Keypad() { char key=0; for (int i = 0; i < 4; i++) { digitalWrite(PinOut[i], LOW); for (int j = 0; j < 4; j++) if (digitalRead(PinIn[j]) == LOW) key=key_value[i][j]; digitalWrite(PinOut[i], HIGH); } return key; } //*************************************************************************************** //* Чтение регистров I2C void Read_I2C(unsigned char device, unsigned char adr, unsigned char count,unsigned char *data) { unsigned char i=0; // Установить адрес Wire.beginTransmission(device); Wire.write(adr); Wire.endTransmission(); // Считать данные Wire.beginTransmission(0x68); Wire.requestFrom(device, count); while(Wire.available()){data[i++] = Wire.read();} Wire.endTransmission(); } //*************************************************************************************** //* Запись регистров I2C void Write_I2C (unsigned char device, unsigned char adr, unsigned char count,unsigned char *data) { Wire.beginTransmission(device); Wire.write(adr); for(unsigned char i=0;i<count;i++) Wire.write(data[i]); Wire.endTransmission(); } //*********************************************************************************************** // Очистка нижней части экрана и вывод дня недели void ClearDate() { unsigned char tmp; buffer[0][1]=buffer[1][1]=buffer[22][1]=buffer[23][1]=0; tmp=2; for(unsigned char i=0;i<7;i++) {buffer[tmp++][1]=2;buffer[tmp++][1]=2;buffer[tmp++][1]=0;} tmp=(ds[3]-1)*3+2; buffer[tmp++][1]=3;buffer[tmp][1]=3; } //*********************************************************************************************** // Вывод таймера void WriteTimer() { unsigned char tmp; ClearDate(); if(timer_mode==0) WriteSmallChar(0,1,14); // Таймер остановлен if(timer_mode==2) WriteSmallChar(0,1,13); // Таймер работает tmp=timer_min%100; WriteSmallChar(3,1,timer_min/100); WriteSmallChar(7,1,tmp/10); WriteSmallChar(11,1,tmp%10); WriteSmallChar(14,1,11); WriteSmallChar(17,1,timer_sec/10); WriteSmallChar(21,1,timer_sec%10); } //*********************************************************************************************** // Вывод даты void WriteData() { ClearDate(); if(sound_en==1) WriteSmallChar(0,1,12); // Символ сигнала каждый час WriteSmallChar(4,1,ds[4]>>4); WriteSmallChar(8,1,ds[4] & 0xF); WriteSmallChar(11,1,10); WriteSmallChar(14,1,ds[5]>>4); WriteSmallChar(18,1,ds[5] & 0xF); } //*********************************************************************************************** // Вывод дня недели и температуры void WriteTemp() { unsigned char tmp=(ds[3]-1)*2; ClearDate(); if(sound_en==1) WriteSmallChar(0,1,12); // Символ сигнала каждый час WriteSmallChar(4,1,days[tmp++]); WriteSmallChar(8,1,days[tmp]); WriteSmallChar(15,1,ds[0x11]/10); WriteSmallChar(19,1,ds[0x11]%10); buffer[23][1]=0x10; } //*********************************************************************************************** // Ввод цифры часов или минут unsigned char EnterBigDigit( unsigned char adr, unsigned char v_min, unsigned char v_max, unsigned char value) { unsigned char tmp=0,key; unsigned char flash=0; while(1) { // Ожидание отпускания кнопки 'A' if(tmp==0 && Keypad()==0) tmp=1; // Ожидание ввода цифры и подтверждения 'A' if(tmp==1) { key=Keypad(); if(key>v_min && key<v_max) {value=key-'0';tmp=2;} } // Ожидание отпускания кнопки if(tmp==2 && Keypad()==0) tmp=3; if(tmp==3) { WriteBigChar(adr,0,value); WriteDisplay(); return value; } if(flash) WriteBigChar(adr,0,value); else WriteBigChar(adr,0,12); flash=!flash; WriteDisplay(); wdt_reset(); delay(200); } } //*********************************************************************************************** // Ввод цифры числа, месяца или года unsigned char EnterSmallDigit( unsigned char adr, unsigned char v_min, unsigned char v_max, unsigned char value) { unsigned char tmp=0,key; unsigned char t1=buffer[adr][1] & 3,t2=buffer[adr+1][1] & 3,t3=buffer[adr+2][1] & 3; unsigned char flash=0; while(1) { // Ожидание отпускания кнопки 'A' if(tmp==0 && Keypad()==0) tmp=1; // Ожидание ввода цифры и подтверждения 'A' if(tmp==1) { key=Keypad(); if(key>v_min && key<v_max) {value=key-'0';tmp=2;} } // Ожидание отпускания кнопки if(tmp==2 && Keypad()==0) tmp=3; if(tmp==3) { buffer[adr][1] =t1; buffer[adr+1][1] =t2; buffer[adr+2][1] =t3; WriteSmallChar(adr,1,value); WriteDisplay(); return value; } if(flash) WriteSmallChar(adr,1,value); else {buffer[adr][1] =t1; buffer[adr+1][1] =t2; buffer[adr+2][1] =t3;} flash=!flash; WriteDisplay(); wdt_reset(); delay(200); } } //****************************************************************************** // День недели по дате: 1 — понедельник, 2 — вторник и так далее. unsigned char Calc_Day(unsigned char day, unsigned char month, unsigned int year) { unsigned int t1, t2; unsigned char m[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5}; t1 = year - 2001; t2 = m[month-1]; if ( ((year & 0x0003) == 0) && (((month-1) >> 1) != 0) ) t2++; return (((t1 + (t1 >> 2) + t2 + (day-1)) % 7)+1); } //*********************************************************************************************** // Установка времени void SetupTime() { unsigned char tmp,tmp1; unsigned char hour=ds[2],minute=ds[1],date=ds[4],month=ds[5],year=ds[6]; unsigned char days_of_month[]={0,0x31,0x28,0x31,0x30,0x31,0x30,0x31,0x31,0x30,0x31,0x30,0x31}; // Ввод десятков часов tmp=EnterBigDigit(1,'0'-1,'3',hour>>4); // Ввод единиц часов if(tmp==2) { // Для 20++ часов - максимум 3 if((hour & 0xF)>3) hour=0x20; tmp1=EnterBigDigit(6,'0'-1,'4',hour & 0xF); } else tmp1=EnterBigDigit(6,'0'-1,'9'+1,hour & 0xF); hour=(tmp<<4) | tmp1; // Ввод минут tmp=EnterBigDigit(14,'0'-1,'6',minute>>4); tmp1=EnterBigDigit(19,'0'-1,'9'+1,minute & 0xF); minute=(tmp<<4) | tmp1; // Вывод года ClearDate(); WriteSmallChar(7,1,2); WriteSmallChar(11,1,0); WriteSmallChar(15,1,year>>4); WriteSmallChar(19,1,year & 0xF); WriteDisplay(); // Ввод года tmp=EnterSmallDigit(15,'0'-1,'9'+1,year>>4); tmp1=EnterSmallDigit(19,'0'-1,'9'+1,year & 0xF); year=(tmp<<4) | tmp1; // Вывод числа и месяца WriteData(); // Ввод месяца tmp=EnterSmallDigit(14,'0'-1,'2',month>>4); if(tmp==1) { if((month & 0xF)>2) month=0x10; tmp1=EnterSmallDigit(18,'0'-1,'3',month & 0xF); } else tmp1=EnterSmallDigit(18,'0'-1,'9'+1,month & 0xF); month=(tmp<<4) | tmp1; // Ввод даты if( (year%4)==0)days_of_month[2]=0x29; tmp1=(month>>4)*10+(month & 0xF); if((date>>4)>(days_of_month[tmp1]>>4)) tmp=EnterSmallDigit(4,'0'-1,(days_of_month[tmp1]>>4)+0x31,days_of_month[tmp1]>>4); else tmp=EnterSmallDigit(4,'0'-1,(days_of_month[tmp1]>>4)+0x31,date>>4); if(tmp==(days_of_month[tmp1]>>4)) { // Для числа 3++ (в феврале 2++) максимальное значение == 0/1 (для февраля 28/29) date=tmp<<4; tmp1=EnterSmallDigit(8,'0'-1,((days_of_month[tmp1] & 0xF)+0x31),date & 0xF); } else { // Нулевой даты не бывает if(!tmp) tmp1=EnterSmallDigit(8,'1'-1,'9'+1,date & 0xF); else tmp1=EnterSmallDigit(8,'0'-1,'9'+1,date & 0xF); } date=(tmp<<4) | tmp1; ds[0]=0;ds[1]=minute,ds[2]=hour,ds[4]=date,ds[5]=month,ds[6]=year; ds[3]=Calc_Day((date>>4)*10+(date & 0xF),(month>>4)*10+(month & 0xF),2000+(year>>4)*10+(year & 0xF)); Write_I2C(DS3231,0,7,&ds[0]); } //*********************************************************************************************** void loop() { unsigned char tmp; static unsigned char old_sec=0xFF; static unsigned char delay_10=10; // Задержка до смены режима "Дата/Температура" static unsigned int adr=0; // Позиция редактируемого символа таймера static unsigned char flash=0; // Мигание разряда static unsigned char next_digit=0; // Ожидание отпускания клавиши static unsigned char sec_upd=0; // Прошла 1 секунда static unsigned int old_timer=0; // Последнее введеное значение таймера static unsigned int timer_sound=0; // Задержка выключения звука таймера Read_I2C(DS3231,0,0x12,ds); // Вывод времени if(ds[2]>>4) WriteBigChar(1,0,ds[2]>>4); else WriteBigChar(1,0,12); WriteBigChar(6,0,ds[2] & 0xF); if(ds[0] & 1) WriteBigChar(10,0,10); else WriteBigChar(10,0,11); WriteBigChar(14,0,ds[1]>>4); WriteBigChar(19,0,ds[1] & 0xF); // Прошла секунда if(ds[0]!=old_sec) { old_sec=ds[0]; wdt_reset(); if(!timer_sound) digitalWrite(PinBiper,HIGH); // Отключение бипера else { timer_sound--; // Возврат в режим часов if(!timer_sound) mode=0; } sec_upd=1; // Сигнал каждый час if(sound_en && !ds[0] && !ds[1] && !timer_sound) tone(PinBiper,1000,200); // Смена режимов каждые десять секунд // В режиме таймера и установки времени режимы не меняются if(mode<2) {delay_10--; if(!delay_10) {delay_10=10; mode++;if(mode==2) mode =0; }} } // Режимы таймера: // 0 == Остановлен // 1 == Установка значений // 2 == Работает // Опрос клавиатуры tmp=Keypad(); if(tmp==0) next_digit=0; if(tmp=='A') { if(mode<2) { mode=3; WriteData(); SetupTime(); mode=0; } // Установка времени if(mode==2 && !timer_mode) // Установка таймера { timer_mode=1; timer_min=timer_sec=adr=0; if(timer_sound) {timer_sound=0; noTone(PinBiper);} } } // Смена шрифта часов if(tmp=='*' && !next_digit) { next_digit=1; font++;if(font==3)font=0; } // Изменение яркости экрана if(tmp=='#' && !next_digit) { scr_level++;if(scr_level==MAX_LIGHT) scr_level=0; for(unsigned char address=0;address<6;address++) lc.setIntensity(address,scr_level); ds[0]=scr_level; Write_I2C(DS3231,0x09,1,&ds[0]); next_digit=1; } // Таймер if(tmp=='B' && !next_digit) { if(mode<2){mode=2;timer_mode=0;timer_min=old_timer;timer_sec=0;WriteTimer();} // Вход в режим таймера else { mode=0;timer_mode=0; WriteData(); } // Выход из режима таймера next_digit=1; } // Установка времени таймера if(mode==2 && timer_mode==1) { // Ввод значения if(tmp>0 && tmp<('9'+1) && !next_digit) { if(!adr) {timer_min=(tmp-0x30)*100;adr++;} else if(adr==1) {timer_min+=(tmp-0x30)*10;adr++;} // После ввода последней цифры переход таймера в режим "Стоп" else if(adr==2) {timer_min+=(tmp-0x30); old_timer=timer_min;timer_mode=0;adr++;} next_digit=1; } // Мигание разряда ClearDate();WriteTimer(); if(adr==0 && flash) {buffer[3][1] &=3;buffer[4][1] &=3;buffer[5][1] &=3;} if(adr==1 && flash) {buffer[7][1] &=3;buffer[8][1] &=3;buffer[9][1] &=3;} if(adr==2 && flash) {buffer[11][1] &=3;buffer[12][1] &=3;buffer[13][1] &=3;} flash=!flash; } // Выключение звука таймера if((tmp=='B' || tmp=='C') && timer_sound) {timer_sound=0; noTone(PinBiper);} // Включение/Выключение таймера. Нельзя запустить таймер при нулевом счетчике if(tmp=='C' && (timer_mode==0 || timer_mode==2) && (timer_min!=0 || timer_sec!=0) && !next_digit) { if(timer_mode==2) timer_mode=0; else timer_mode=2; next_digit=1; WriteTimer(); } // Счет таймера if(mode==2 && timer_mode==2) { if(sec_upd) { sec_upd=0; // Уменьшение секунд таймера if(timer_sec || timer_min) timer_sec--; // Время кончилось if(!timer_min && !timer_sec) { timer_mode=0; tone(PinBiper,1500,30000); timer_sound=31; } // Уменьшение минут таймера else {if(timer_sec==0xFF) {timer_sec=59;timer_min--;}} WriteTimer(); } } // Сигнал каждый час вкл/выкл if(tmp=='D' && mode<2 && !next_digit) {ds[0]=sound_en=!sound_en; Write_I2C(DS3231,0x0C,1,&ds[0]);next_digit=1; } if(mode==0) WriteData(); // Вывод даты if(mode==1) WriteTemp(); // Вывод дня недели и температуры WriteDisplay(); delay(200); }
Давно искал такое совмещение, часы и таймер. Статья заинтересовала, но к сожалению по скетчу для меня не все понятно,как понял схему, нарисовал в протеусе, но она не работает.Будьте добры показать схемку.
Красиво!
Хотя цифровая клавиатура, ИМХО, здесь чрезмерна. 4 кнопки направления, энтер и сброс.