Часы-будильник основаны на микроконтроллере Atmega8, содержит часы реального времени DS3231, цифровой датчик температуры DS18B20, датчик освещенности в виде фоторезистора, зуммер для сигнала будильника, четыре кнопки управления и дисплей VDF1602.
Дисплей VDF1602 (16T202DA1E) выполнен на базе вакуумно-люминесцентного индикатора, который может отображать ASCII символы в 2 строки (16 знаков в 1 строке) каждый символ в виде матрицы 5х7 пикселей.
Дисплей 16T202DA1E программно полностью совместим с дисплеем LCD1602 контроллере HD44780.
Для правильной работы базе вакуумно-люминесцентного индикатора требуется два источника питания, это питание сеток и анодов напряжением 12-27 В и питание катода (нити накала) переменным напряжением от 1,2 до 5 В (в зависимости от типа ВЛИ). В дисплее 16T202DA1E все необходимые источники для правильной работы ВЛИ уже встроены в плату, поэтому для питания дисплея Вам понадобится только одно напряжение в 5 В. Так же в отличии от LCD1602 в дисплее 16T202DA1E нет вывода Vo (регулировка контрастности), что делает подключение дисплея к Arduino Nano еще проще.
На дисплей выводится следующая информация
- Текущее время
- День недели (рус)
- Время будильника
- Индикатор работы будильника
- Температура
- Дата и месяц
Кнопки управления:
- SET_ALARM — коррекция времени будильника, первое нажатие коррекция часа, второе — минут
- SET_TIME — коррекция (установка) времени часов, при нажатии на кнопку меняются параметры времени для корректировки (часы, минуты, секунды(обнуление), дата, месяц, день недели)
- SET_UP — Плюс изменение параметра часов и будильника
- SET_DW — Минус изменение параметра часов и будильника
В режиме вывода времени кнопки SET_UP и SET_DW позволяют отключать и включать режим будильника, а при сигнале будильника кнопки SET_UP и SET_DW отключают сигнал будильника но при этом не меняют режим работы будильника. Если не нажимать кнопки SET_UP и SET_DW то сигнал будильника будет звучать 1 минуту.
Так как дисплей VDF1602 имеет функцию программного изменения яркости свечения символов, то в схеме используется датчик освещенности (фоторезистор). Датчик освещенности меняет яркость свечения символов дисплея в зависимости от освещенности.
Датчик температуры DS18B20 рекомендуется выносить за корпус уст-ва, так как дисплей VDF1602 при работе имеет небольшой нагрев.
Время будильника и режим работы будильника сохраняются в энергонезависимой памяти.
- Красными точками на схеме указаны пины подключения программатора, как прошить прошивку описано в — http://rcl-radio.ru/?p=82486
- Более подробно о дисплеи VDF1602 описано в — http://rcl-radio.ru/?p=129034
#include <OneWire.h> // http://rcl-radio.ru/wp-content/uploads/2018/07/OneWire.zip #define ADDR 0b1101000 #define CPU_F 16000000 #define SCL_F 100000 OneWire ds(8); // Вход датчика 18b20 unsigned long times; int t_izm,brig_a; int set_time,set_alarm,year,day, mont, date, hour, minut, secon; int hh_a,mm_a; bool alarm; byte alarm_on; byte hh,mm; #define SET_ALARM PB2 #define SET_TIME PB1 #define SET_UP PC0 #define SET_DW PC1 #define BRIG PC3 #define BUZZER PC2 int t_kall = -20; void setup() { PORTB |=(1<<SET_ALARM)|(1<<SET_TIME); PORTC |=(1<<SET_UP)|(1<<SET_DW); DDRC |= (1<<BUZZER); ADMUX |= (1<<REFS0)|(1 << MUX1) | (1 << MUX0); ADCSRA |= (1<<ADEN) | (1<<ADSC) | (1<<ADFR) | (1<<ADIF); ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);// Division Factor 128 PORTC |= (1 << BRIG); lcdInit(); lcdWrite(0, 31, 17, 17, 17, 17, 17, 17, 0); //П lcdWrite(8, 17, 17, 17, 31, 1, 1, 1, 0); //Ч lcdWrite(16, 31, 16, 16, 30, 17, 17, 30, 0); //Б lcdWrite(24, 4, 14, 14, 14, 31, 4, 0, 0);// alarm TWBR = (((CPU_F)/(SCL_F)-16 )/2) ; TWSR = 0; hh_a=EEPROM_read(0); mm_a=EEPROM_read(1); alarm=EEPROM_read(2); // // set_tim(21,3,5,3,0,4,0);// год 00-99,ДН 1-пн 7-вс, месяц 1-12, дата 1-31, час 0-23, минуты 0-59, секунды 0-59 Brightness(100); lcdCurs(0,1);lcdString("ALEXANDER"); lcdCurs(1,1);lcdString("LIMAN"); _delay_ms(2000); lcdClear(); } void loop() { if(millis()-times>10000&&set_time==0){times=millis();while((ADCSRA & (1 << ADIF)) == 0);brig_a = (ADCL|ADCH << 8);t_izm = dsRead(0)+t_kall;} if(brig_a<=200){Brightness(100);} if(brig_a>200&&brig_a<=400){Brightness(75);} if(brig_a>400&&brig_a<=600){Brightness(50);} if(brig_a>600){Brightness(25);} if(((PINC >> SET_UP) & 1) == 0&&set_alarm==0&&set_time==0 && alarm_on==0){alarm=1;EEPROM_write(2,alarm);_delay_ms(200);} if(((PINC >> SET_DW) & 1) == 0&&set_alarm==0&&set_time==0 && alarm_on==0){alarm=0;EEPROM_write(2,alarm);_delay_ms(200);} if(hh_a*100+mm_a!=hh*100+mm){alarm_on=0;} if(hh_a*100+mm_a==hh*100+mm && alarm==1 && alarm_on==0){alarm_on=1;} if(hh_a*100+mm_a==hh*100+mm && alarm==1 && alarm_on==1){ for(int b=0;b<200;b++){ PORTC |=(1<<BUZZER);_delay_us(200); PORTC &=~(1<<BUZZER);_delay_us(200); }} if(((PINC >> SET_UP) & 1) == 0 && alarm_on==1){alarm_on=2;_delay_ms(200);} if(((PINC >> SET_DW) & 1) == 0 && alarm_on==1){alarm_on=2;_delay_ms(200);} if(((PINB >> SET_TIME) & 1) == 0&&set_alarm==0){set_time++;if(set_time>7){set_time=0;}lcdClear(); _delay_ms(200);} if(((PINB >> SET_ALARM) & 1) == 0&&set_time==0){set_alarm++;if(set_alarm>2){set_alarm=0;}lcdClear(); _delay_ms(200);} if(set_alarm==1){ lcdCurs(0,0);lcdString("ALARM HOUR ");lcdChar(hh_a/10+'0');lcdChar(hh_a%10+'0'); if(((PINC >> SET_UP) & 1) == 0){hh_a++;if(hh_a>23){hh_a=23;}EEPROM_write(0,hh_a);_delay_ms(100);} if(((PINC >> SET_DW) & 1) == 0){hh_a--;if(hh_a<0){hh_a=0;}EEPROM_write(0,hh_a);_delay_ms(100);} } if(set_alarm==2){ lcdCurs(0,0);lcdString("ALARM MIN ");lcdChar(mm_a/10+'0');lcdChar(mm_a%10+'0'); if(((PINC >> SET_UP) & 1) == 0){mm_a++;if(mm_a>59){mm_a=59;}EEPROM_write(1,mm_a);_delay_ms(100);} if(((PINC >> SET_DW) & 1) == 0){mm_a--;if(mm_a<0){mm_a=0;}EEPROM_write(1,mm_a);_delay_ms(100);} } byte ss = (i2c_read(ADDR,0) & 0x0F) + (((i2c_read(ADDR,0) & 0x70) >> 4) * 10); mm = (i2c_read(ADDR,1) & 0x0F) + (((i2c_read(ADDR,1) & 0x70) >> 4) * 10); hh = ((i2c_read(ADDR,2) & 0x0F) + ((i2c_read(ADDR,2) & 0x70) >> 4) * 10); byte wesk = (i2c_read(ADDR,3) & 0x0F); byte dd = ((i2c_read(ADDR,4) & 0x0F) + ((i2c_read(ADDR,4) & 0x70) >> 4) * 10); byte mn = ((i2c_read(ADDR,5) & 0x0F) + ((i2c_read(ADDR,5) & 0x70) >> 4) * 10); byte yy = ((i2c_read(ADDR,6) & 0x0F) + ((i2c_read(ADDR,6) & 0x70) >> 4) * 10); year=yy;mont=mn;date=dd;hour=hh;minut=mm;secon=ss,day=wesk; if(set_time==1){ lcdCurs(0,0);lcdString("SET HOUR ");lcdChar(hour/10+'0');lcdChar(hour%10+'0'); if(((PINC >> SET_UP) & 1) == 0){hour++;if(hour>23){hour=23;}set_t();} if(((PINC >> SET_DW) & 1) == 0){hour--;if(hour<0){hour=0;}set_t();} } if(set_time==2){ lcdCurs(0,0);lcdString("SET MIN ");lcdChar(minut/10+'0');lcdChar(minut%10+'0'); if(((PINC >> SET_UP) & 1) == 0){minut++;if(minut>59){minut=59;}set_t();} if(((PINC >> SET_DW) & 1) == 0){minut--;if(minut<0){minut=0;}set_t();} } if(set_time==3){ lcdCurs(0,0);lcdString("SET SEC ");lcdChar(secon/10+'0');lcdChar(secon%10+'0'); if(((PINC >> SET_UP) & 1) == 0){secon=0;set_t();} if(((PINC >> SET_DW) & 1) == 0){secon=0;set_t();} } if(set_time==4){ lcdCurs(0,0);lcdString("SET DATE ");lcdChar(date/10+'0');lcdChar(date%10+'0'); if(((PINC >> SET_UP) & 1) == 0){date++;if(date>31){date=31;}set_t();} if(((PINC >> SET_DW) & 1) == 0){date--;if(date<1){date=1;}set_t();} } if(set_time==5){ lcdCurs(0,0);lcdString("SET DAY OF WEEK"); lcdCurs(1,0); switch(wesk){ case 1: lcdChar(0);lcdChar(0x48);break; case 2: lcdChar(0x42);lcdChar(0x54);break; case 3: lcdChar(0x43);lcdChar(0x50);break; case 4: lcdChar(1);lcdChar(0x54);break; case 5: lcdChar(0);lcdChar(0x54);break; case 6: lcdChar(0x43);lcdChar(2);break; case 7: lcdChar(0x42);lcdChar(0x43);break; } if(((PINC >> SET_UP) & 1) == 0){day++;if(day>7){day=7;}set_t();} if(((PINC >> SET_DW) & 1) == 0){day--;if(day<1){day=1;}set_t();} } if(set_time==6){ lcdCurs(0,0);lcdString("SET MONTH ");lcdChar(mont/10+'0');lcdChar(mont%10+'0'); if(((PINC >> SET_UP) & 1) == 0){mont++;if(mont>12){mont=12;}set_t();} if(((PINC >> SET_DW) & 1) == 0){mont--;if(mont<1){mont=1;}set_t();} } if(set_time==7){ lcdCurs(0,0);lcdString("SET YEAR ");lcdChar(year/10+'0');lcdChar(year%10+'0'); if(((PINC >> SET_UP) & 1) == 0){year++;if(year>100){year=100;}set_t();} if(((PINC >> SET_DW) & 1) == 0){year--;if(year<22){year=22;}set_t();} } if(set_time==0&&set_alarm==0){ lcdCurs(0,0); lcdChar(hh/10+'0');lcdChar(hh%10+'0');lcdChar(0x3A); lcdChar(mm/10+'0');lcdChar(mm%10+'0');lcdChar(0x3A); lcdChar(ss/10+'0');lcdChar(ss%10+'0'); lcdCurs(1,0); lcdChar(dd/10+'0');lcdChar(dd%10+'0');lcdString("/"); lcdChar(mn/10+'0');lcdChar(mn%10+'0');lcdString(" "); switch(wesk){ case 1: lcdChar(0);lcdChar(0x48);break; case 2: lcdChar(0x42);lcdChar(0x54);break; case 3: lcdChar(0x43);lcdChar(0x50);break; case 4: lcdChar(1);lcdChar(0x54);break; case 5: lcdChar(0);lcdChar(0x54);break; case 6: lcdChar(0x43);lcdChar(2);break; case 7: lcdChar(0x42);lcdChar(0x43);break; } lcdCurs(1,10);lcdChar(t_izm/100+'0');lcdChar(t_izm/10%10+'0');lcdChar(0x2E);lcdChar(t_izm%10+'0');lcdChar(223); lcdString("C "); lcdCurs(0,10);lcdChar(hh_a/10+'0');lcdChar(hh_a%10+'0');lcdString(":");lcdChar(mm_a/10+'0');lcdChar(mm_a%10+'0'); lcdCurs(0,15);if(alarm==1){lcdChar(3);}else{lcdChar(0x20);} } _delay_ms(100); } void set_t(){set_tim(year,day,mont,date,hour,minut,secon); _delay_ms(100);} void lcdSend(bool rs, byte data) { if(rs==0){PORTD |= (1 << 2);} else{PORTD &= ~(1 << 2);}//RS del(); if(((data >> 7) & 1) ==1){PORTD |= (1 << 7);}else{PORTD &= ~(1 << 7);} if(((data >> 6) & 1) ==1){PORTD |= (1 << 6);}else{PORTD &= ~(1 << 6);} if(((data >> 5) & 1) ==1){PORTD |= (1 << 5);}else{PORTD &= ~(1 << 5);} if(((data >> 4) & 1) ==1){PORTD |= (1 << 4);}else{PORTD &= ~(1 << 4);} e_pin(); if(((data >> 3) & 1) ==1){PORTD |= (1 << 7);}else{PORTD &= ~(1 << 7);} if(((data >> 2) & 1) ==1){PORTD |= (1 << 6);}else{PORTD &= ~(1 << 6);} if(((data >> 1) & 1) ==1){PORTD |= (1 << 5);}else{PORTD &= ~(1 << 5);} if(((data >> 0) & 1) ==1){PORTD |= (1 << 4);}else{PORTD &= ~(1 << 4);} e_pin(); } void lcd(uint8_t cmd) {lcdSend(true, cmd);} void lcdChar(const char chr) {lcdSend(false, (uint8_t)chr);} void lcdString(const char* str) {while(*str != '\0') {del();lcdChar(*str);str++;}} void del(){_delay_ms(1);} void e_pin(){PORTD |= (1 << 3);del();PORTD &= ~(1 << 3);} void lcdCurs(byte str, byte mesto){ if(str==0){lcd(0b10000000+mesto);} if(str==1){lcd(0b11000000+mesto);} } void lcdWrite(byte addr_w, byte wr1,byte wr2,byte wr3,byte wr4,byte wr5,byte wr6,byte wr7,byte wr8){ lcd(0b01000000|addr_w);lcdChar(wr1);lcdChar(wr2);lcdChar(wr3);lcdChar(wr4);lcdChar(wr5);lcdChar(wr6);lcdChar(wr7);lcdChar(wr8);} void lcdInit(){ DDRD |= (1 << 2) | (1 << 3)| (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7); _delay_ms(100); lcd(0x03);_delay_us(4500); lcd(0x03);_delay_us(4500); lcd(0x03);_delay_us(200); lcd(0b00000010);del(); lcd(0b00001100);del(); lcdClear(); } void lcdClear(){lcd(0b00000001);} float dsRead(byte x) { byte data[2], addr[8][8], kol = 0; while (ds.search(addr[kol])) { // поиск датчиков, определение адреса и кол-ва датчиков kol++; } ds.reset_search(); // Сброс поиска датчика ds.reset(); // Инициализация, выполняется сброс шины ds.select(addr[x]); // Обращение к датчику по адресу ds.write(0x44, 0); // Измерение температуры с переносом данных в память ds.reset(); // Инициализация, выполняется сброс шины ds.select(addr[x]); // Обращение к датчику по адресу ds.write(0xBE); // Обращение памяти for (byte i=0; i<9; i++) data[i]=ds.read(); int raw=(data[1]<<8)|data[0]; float value = (float)raw / 1.60; return value; // Расчет температуры и вывод } void Brightness(byte brig){ switch(brig){ case 25 : lcd(0b00101011);break; case 50 : lcd(0b00101010);break; case 75 : lcd(0b00101001);break; case 100 : lcd(0b00101000);break; } } byte i2c_read(byte i2c_addr, byte i2c_reg){ TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); // START while (!(TWCR & (1<<TWINT))); TWDR = i2c_addr << 1; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWDR = i2c_reg; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); // START while (!(TWCR & (1<<TWINT))); TWDR = (i2c_addr << 1) | 1; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); byte i2c_data = TWDR; TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); // СТОП return i2c_data; } void i2c_write(byte i2c_addr, byte i2c_reg, byte i2c_dat){ TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); // START while (!(TWCR & (1<<TWINT))); TWDR = i2c_addr << 1; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWDR = i2c_reg; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWDR = i2c_dat; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); // СТОП } void set_tim(byte years, byte days, byte monts, byte datas, byte hours ,byte minute, byte second){ i2c_write(ADDR,0x00,(second/10<<4)+second%10); i2c_write(ADDR,0x01,(minute/10<<4)+minute%10); i2c_write(ADDR,0x02,(hours/10<<4)+hours%10); i2c_write(ADDR,0x04,(datas/10<<4)+datas%10); i2c_write(ADDR,0x05,(monts/10<<4)+monts%10); i2c_write(ADDR,0x06,(years/10<<4)+years%10); i2c_write(ADDR,0x03,days); } unsigned char EEPROM_read(unsigned int uiAddress){ while(EECR & (1<<EEWE)); EEAR = uiAddress; EECR |= (1<<EERE); return EEDR; } void EEPROM_write(unsigned int uiAddress, unsigned char ucData){ while(EECR & (1<<EEWE)); EEAR = uiAddress; EEDR = ucData; EECR |= (1<<EEMWE); EECR |= (1<<EEWE); }
Форум — http://forum.rcl-radio.ru/viewtopic.php?id=523