// Atmega328, Atmega8 16MHz
#include <avr/io.h>
#include <util/delay.h>
#define ADDR_DS3231 0b1101000
#define CPU_F 16000000 // Clock Speed
#define SCL_F 100000 // // I2C Speed
#define L_BIT PORTB &= ~(1<<PB0)
#define H_BIT PORTB |= (1<<PB0)
#define LED_MAX 88
byte rr[LED_MAX],gg[LED_MAX],bb[LED_MAX],r,g,b;
int i,up,down,brig=1,hh,mm;
byte sec,min,hour,datat,mont,year,day;
byte r_led=0,g_led=1,b_led=0;
byte mode;
bool sett,w,w1;
unsigned long times,times0;
int main(void){
cli();
TWBR = (((CPU_F)/(SCL_F)-16 )/2) ;
TWSR = 0;
DDRD &= ~(1<<PD2);// INPUT SQW DS3231
DDRB |= (1<<PB0); // INPUT WS2812B (D8 - ARDUINO)
DDRD &= ~(1<<PD3);// INPUT BUTTON MODE
DDRD &= ~(1<<PD4);// INPUT BUTTON UP
DDRD &= ~(1<<PD5);// INPUT BUTTON DOWN
DDRD &= ~(1<<PD6);// INPUT BUTTON SET
PORTD |= (1<<PD3);PORTD |= (1<<PD4);PORTD |= (1<<PD5);PORTD |= (1<<PD6);
DDRB |= (1<<PB0); // INPUT WS2812B (D8 - ARDUINO)
DDRD &= ~(1<<PD2);// BUTTON (D2 - ARDUINO)
PORTD |=(1<<PD2); // INPUT_PULLUP
/// TIMER 0 = 1ms
ADCSRA = 0b10000100;
TCCR0A = 0;TCCR0B = 0;TCNT0 = 0;
OCR0A = 249;
TCCR0A |= (1 << WGM01);
TCCR0B |= (1 << CS01) | (1 << CS00);
TIMSK0 |= (1 << OCIE0A);
sei();
_delay_ms(100);
i2c_write(ADDR_DS3231,0x0E,0b00000000);
//set_time(23,3,3,22,9,14,0);// год 00-99, ДН 1-7 (1=ВС), месяц 1-12, дата 1-31, час 0-23, минуты 0-59, секунды 0-59
if(EEPROM_read(100)!=0){for(int i1=0;i1<101;i1++){EEPROM_write(i1,1);}}// очистка памяти при первом включении
mode = EEPROM_read(0);brig = EEPROM_read(1);
while(1){
/////// BUTTON ///////////////////////////////////////////////
if(((PIND >> PD3) & 1) == 0){mode++;if(mode>7){mode=0;}_delay_ms(300);w=1;times0=times;}
switch(mode){
case 0: r_led=1,g_led=1,b_led=1; break;
case 1: r_led=1,g_led=0,b_led=0; break;
case 2: r_led=0,g_led=1,b_led=0; break;
case 3: r_led=0,g_led=0,b_led=1; break;
case 4: r_led=1,g_led=1,b_led=0; break;
case 5: r_led=1,g_led=0,b_led=1; break;
case 6: r_led=0,g_led=1,b_led=1; break;
case 7: r_led=0,g_led=0,b_led=0; break;
}
if(((PIND >> PD4) & 1) == 0 && sett==0){brig++;if(brig>255){brig=255;}_delay_ms(1);w=1;times0=times;}
if(((PIND >> PD5) & 1) == 0 && sett==0){brig--;if(brig<1){brig=1;}_delay_ms(1);w=1;times0=times;}
if(((PIND >> PD6) & 1) == 0 && sett==0){sett=1;_delay_ms(300);}
if(((PIND >> PD6) & 1) == 0 && sett==1){sett=0;_delay_ms(300);}
/////// READ TIME ////////////////////////////////////////////
sec = (i2c_read_1bit(ADDR_DS3231,0) & 0x0F) + (((i2c_read_1bit(ADDR_DS3231,0) & 0x70) >> 4) * 10);
min = (i2c_read_1bit(ADDR_DS3231,1) & 0x0F) + (((i2c_read_1bit(ADDR_DS3231,1) & 0x70) >> 4) * 10);
hour = ((i2c_read_1bit(ADDR_DS3231,2) & 0x0F) + ((i2c_read_1bit(ADDR_DS3231,2) & 0x70) >> 4) * 10);
i = hour*100+min;
//////////// SET TIME //////////////////////////////////////////////////////////////////////
if(sett==1){
hh=hour;
mm=min;
if(((PIND >> PD4) & 1) == 0){hh++;if(hh>23){hh=0;}_delay_ms(100);w1=1;}
if(((PIND >> PD5) & 1) == 0){mm++;if(mm>59){mm=1;}_delay_ms(100);w1=1;}
if(w1==1){w1=0;set_time(21,1,12,26,hh,mm,0);}
i = hh*100+mm;
}
////////// RGB ////////////////////////////////////////////////
switch(i/1000){
case 0: ws(0,0);ws(3,0);ws(6,0);ws(9,0);ws(12,0);ws(15,0);ws(18,0);break;
case 1: ws(0,0);ws(3,0);ws(6,1);ws(9,0);ws(12,0);ws(15,0);ws(18,1);break;
case 2: ws(0,0);ws(3,1);ws(6,1);ws(9,1);ws(12,1);ws(15,1);ws(18,0);break;
case 3: ws(0,0);ws(3,1);ws(6,1);ws(9,1);ws(12,0);ws(15,1);ws(18,1);break;
case 4: ws(0,1);ws(3,0);ws(6,1);ws(9,1);ws(12,0);ws(15,0);ws(18,1);break;
case 5: ws(0,1);ws(3,1);ws(6,0);ws(9,1);ws(12,0);ws(15,1);ws(18,1);break;
case 6: ws(0,1);ws(3,1);ws(6,0);ws(9,1);ws(12,1);ws(15,1);ws(18,1);break;
case 7: ws(0,0);ws(3,1);ws(6,1);ws(9,0);ws(12,0);ws(15,0);ws(18,1);break;
case 8: ws(0,1);ws(3,1);ws(6,1);ws(9,1);ws(12,1);ws(15,1);ws(18,1);break;
case 9: ws(0,1);ws(3,1);ws(6,1);ws(9,1);ws(12,0);ws(15,1);ws(18,1);break;
}
switch(i/100%10){
case 0: ws(21,1);ws(24,1);ws(27,1);ws(30,0);ws(33,1);ws(36,1);ws(39,1);break;
case 1: ws(21,0);ws(24,0);ws(27,1);ws(30,0);ws(33,0);ws(36,0);ws(39,1);break;
case 2: ws(21,0);ws(24,1);ws(27,1);ws(30,1);ws(33,1);ws(36,1);ws(39,0);break;
case 3: ws(21,0);ws(24,1);ws(27,1);ws(30,1);ws(33,0);ws(36,1);ws(39,1);break;
case 4: ws(21,1);ws(24,0);ws(27,1);ws(30,1);ws(33,0);ws(36,0);ws(39,1);break;
case 5: ws(21,1);ws(24,1);ws(27,0);ws(30,1);ws(33,0);ws(36,1);ws(39,1);break;
case 6: ws(21,1);ws(24,1);ws(27,0);ws(30,1);ws(33,1);ws(36,1);ws(39,1);break;
case 7: ws(21,0);ws(24,1);ws(27,1);ws(30,0);ws(33,0);ws(36,0);ws(39,1);break;
case 8: ws(21,1);ws(24,1);ws(27,1);ws(30,1);ws(33,1);ws(36,1);ws(39,1);break;
case 9: ws(21,1);ws(24,1);ws(27,1);ws(30,1);ws(33,0);ws(36,1);ws(39,1);break;
}
if(((PIND >> PD2) & 1) == 0 && sett==0){data_led(42, r_led*brig, g_led*brig, b_led*brig);data_led(43, r_led*brig, g_led*brig, b_led*brig);
data_led(44, r_led*brig, g_led*brig, b_led*brig);data_led(45, r_led*brig, g_led*brig, b_led*brig);}
else{data_led(42, 0, 0, 0);data_led(43, 0, 0, 0);data_led(44, 0, 0, 0);data_led(45, 0, 0, 0);}
if(sett==1){data_led(42, 0, brig, 0);data_led(43, brig, 0, 0);data_led(44, 0, brig, 0);data_led(45, brig, 0, 0);}
switch(i/10%10){
case 0: ws(46,1);ws(49,1);ws(52,1);ws(55,0);ws(58,1);ws(61,1);ws(64,1);break;
case 1: ws(46,0);ws(49,0);ws(52,1);ws(55,0);ws(58,0);ws(61,0);ws(64,1);break;
case 2: ws(46,0);ws(49,1);ws(52,1);ws(55,1);ws(58,1);ws(61,1);ws(64,0);break;
case 3: ws(46,0);ws(49,1);ws(52,1);ws(55,1);ws(58,0);ws(61,1);ws(64,1);break;
case 4: ws(46,1);ws(49,0);ws(52,1);ws(55,1);ws(58,0);ws(61,0);ws(64,1);break;
case 5: ws(46,1);ws(49,1);ws(52,0);ws(55,1);ws(58,0);ws(61,1);ws(64,1);break;
case 6: ws(46,1);ws(49,1);ws(52,0);ws(55,1);ws(58,1);ws(61,1);ws(64,1);break;
case 7: ws(46,0);ws(49,1);ws(52,1);ws(55,0);ws(58,0);ws(61,0);ws(64,1);break;
case 8: ws(46,1);ws(49,1);ws(52,1);ws(55,1);ws(58,1);ws(61,1);ws(64,1);break;
case 9: ws(46,1);ws(49,1);ws(52,1);ws(55,1);ws(58,0);ws(61,1);ws(64,1);break;
}
switch(i%10){
case 0: ws(67,1);ws(70,1);ws(73,1);ws(76,0);ws(79,1);ws(82,1);ws(85,1);break;
case 1: ws(67,0);ws(70,0);ws(73,1);ws(76,0);ws(79,0);ws(82,0);ws(85,1);break;
case 2: ws(67,0);ws(70,1);ws(73,1);ws(76,1);ws(79,1);ws(82,1);ws(85,0);break;
case 3: ws(67,0);ws(70,1);ws(73,1);ws(76,1);ws(79,0);ws(82,1);ws(85,1);break;
case 4: ws(67,1);ws(70,0);ws(73,1);ws(76,1);ws(79,0);ws(82,0);ws(85,1);break;
case 5: ws(67,1);ws(70,1);ws(73,0);ws(76,1);ws(79,0);ws(82,1);ws(85,1);break;
case 6: ws(67,1);ws(70,1);ws(73,0);ws(76,1);ws(79,1);ws(82,1);ws(85,1);break;
case 7: ws(67,0);ws(70,1);ws(73,1);ws(76,0);ws(79,0);ws(82,0);ws(85,1);break;
case 8: ws(67,1);ws(70,1);ws(73,1);ws(76,1);ws(79,1);ws(82,1);ws(85,1);break;
case 9: ws(67,1);ws(70,1);ws(73,1);ws(76,1);ws(79,0);ws(82,1);ws(85,1);break;
}
led_rgb();res();
_delay_ms(100);
////// EEPROM ///////////////////
if(times-times0>10000&&w==1){EEPROM_write(0,mode);EEPROM_write(1,brig);w=0;}
}} // end loop
void ws(int ind, bool datt){
if(datt==1){data_led(ind, r_led*brig, g_led*brig, b_led*brig);data_led(ind+1, r_led*brig, g_led*brig, b_led*brig);data_led(ind+2, r_led*brig, g_led*brig, b_led*brig);}
if(datt==0){data_led(ind, 0, 0, 0);data_led(ind+1, 0, 0, 0);data_led(ind+2, 0, 0, 0);}}
void bit_0(){H_BIT;asm("nop");asm("nop"); L_BIT;asm("nop");asm("nop");asm("nop"); asm("nop");}
void bit_1(){H_BIT;asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop"); L_BIT;}
void bit_w(bool x){if(x) bit_1(); else bit_0();}
void res(){_delay_us(100);}
void data_led(int num, byte rrr, byte ggg, byte bbb){bb[num]=bbb;rr[num]=rrr;gg[num]=ggg;}
void led_rgb(){
for(int num_i=0;num_i<LED_MAX;num_i++){
cli();
bit_w((bb[num_i] & 0x80)>>7);
bit_w((bb[num_i] & 0x40)>>6);
bit_w((bb[num_i] & 0x20)>>5);
bit_w((bb[num_i] & 0x10)>>4);
bit_w((bb[num_i] & 0x08)>>3);
bit_w((bb[num_i] & 0x04)>>2);
bit_w((bb[num_i] & 0x02)>>1);
bit_w((bb[num_i] & 0x01)>>0);
bit_w((rr[num_i] & 0x80)>>7);
bit_w((rr[num_i] & 0x40)>>6);
bit_w((rr[num_i] & 0x20)>>5);
bit_w((rr[num_i] & 0x10)>>4);
bit_w((rr[num_i] & 0x08)>>3);
bit_w((rr[num_i] & 0x04)>>2);
bit_w((rr[num_i] & 0x02)>>1);
bit_w((rr[num_i] & 0x01)>>0);
bit_w((gg[num_i] & 0x80)>>7);
bit_w((gg[num_i] & 0x40)>>6);
bit_w((gg[num_i] & 0x20)>>5);
bit_w((gg[num_i] & 0x10)>>4);
bit_w((gg[num_i] & 0x08)>>3);
bit_w((gg[num_i] & 0x04)>>2);
bit_w((gg[num_i] & 0x02)>>1);
bit_w((gg[num_i] & 0x01)>>0);
sei();
}}
void set_time(byte years, byte days, byte monts, byte datas, byte hours ,byte minute, byte second){
if(second < 255){i2c_write(ADDR_DS3231,0x00,(second/10<<4)+second%10);}
if(minute < 255){i2c_write(ADDR_DS3231,0x01,(minute/10<<4)+minute%10);}
if(hours < 255){i2c_write(ADDR_DS3231,0x02,(hours/10<<4)+hours%10);}
if(days < 255){i2c_write(ADDR_DS3231,0x03,days);}
if(datas < 255){i2c_write(ADDR_DS3231,0x04,(datas/10<<4)+datas%10);}
if(monts < 255){i2c_write(ADDR_DS3231,0x05,(monts/10<<4)+monts%10);}
if(years < 255){i2c_write(ADDR_DS3231,0x06,(years/10<<4)+years%10);}
}
int i2c_read_1bit(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)|(1<<TWEA);
while(~TWCR&(1<<TWINT));
byte i2c_data = TWDR;
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
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); // СТОП
}
ISR(TIMER0_COMPA_vect) {times++;}// millis = 1 ms
unsigned char EEPROM_read(unsigned int uiAddress){
while(EECR & (1<<EEPE)); // проверка готовности EEPROM
EEARH = ((uiAddress & 0xF0) << 2); // регистр адреса H
EEARL = uiAddress & 0x0F; // регистр адреса L
EECR |= (1<<EERE);// чтение EEPROM
return EEDR; // вывод значения
}
void EEPROM_write(unsigned int uiAddress, unsigned char ucData){
while(EECR & (1<<EEPE)); // проверка готовности EEPROM
EEARH = ((uiAddress & 0xF0) << 2); // регистр адреса H
EEARL = uiAddress & 0x0F; // регистр адреса L
EEDR = ucData; // регистр данных
EECR |= (1<<EEMPE);// Разрешение записи в EEPROM
EECR |= (1<<EEPE); // Запись в EEPROM
}