ЧАСЫ-БУДИЛЬНИК НА VDF1602 + DS3231 + DS18B20 (Arduino IDE)

Часы-будильник основаны на микроконтроллере 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 еще проще.

Распиновка дисплея

На дисплей выводится следующая информация

  1. Текущее время
  2. День недели (рус)
  3. Время будильника
  4. Индикатор работы будильника
  5. Температура
  6. Дата и месяц

Кнопки управления:

  • 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

 

Добавить комментарий

Войти с помощью: