/* * BinaryClock.c * * Created: 01.05.2018 * Author : Tobias N. * Description: * Current time is displayed by default after each startup and can be set by using the set hour, minute and second buttons respectively. * Pressing the select button once, displays the current date (day/month/year) which can be set by using the set hour button * to set the day, minute button to set the month and the second button to set the year. * Pressing the select button a second time will display the room temperature in °C with a resolution of .25°C. * By continuing to press the select button, you can cycle between the 3 different modes. */ #include #include #include #include #define ACK 0 #define NACK 1 #define DS3231_ADDR (0x68 << 1) //write address: 7-bit address is shifted to the left by 1 and LSB is 0 #define DS3231_ADDR_READ (0x68 << 1 | 0x1) //read address: 7-bit address is shifted to the left by 1 and LSB is 1 /* Variables */ uint8_t digit_1, digit_2, digit_3, digit_4, digit_5, digit_6; uint8_t hour_set, minute_set, second_set, day_set, month_set, year_set; uint8_t modeCounter; const uint16_t multiplexTime = 1000; uint16_t timer1_counter; /* functions */ void i2c_init(uint32_t scl_f); void i2c_start(void); void i2c_stop(void); void i2c_write(uint8_t byte); uint8_t i2c_read(uint8_t n_ack); void DisplayMatrix(void); void DS3231setTime(void); void DS3231getTime(void); void DS3231setDate(void); void DS3231getDate(void); void DS3231getTemp(void); ISR(TIMER1_OVF_vect) { TCNT1 = timer1_counter; DisplayMatrix(); } int main(void) { /* setting up ports */ DDRB |= _BV(PORTB0) | _BV(PORTB1) | _BV(PORTB2) | _BV(PORTB3); DDRD |= _BV(PORTD2) | _BV(PORTD3) | _BV(PORTD4) | _BV(PORTD5) | _BV(PORTD6) | _BV(PORTD7); DDRC &= ~_BV(PORTC0) & ~_BV(PORTC1) & ~_BV(PORTC2) & ~_BV(PORTC3); PORTC |= _BV(PORTC0) | _BV(PORTC1) | _BV(PORTC2) | _BV(PORTC3); i2c_init(400000); //init i2c interface with a clock frequency of 400kHz cli(); TCCR1A = 0; TCCR1B = 0; /* 16MHz -> t= 62,5ns * 256 (prescaler) = 16µs 500Hz -> t = 0,002s (0,002 / 2) / 16µs = 62.5 65536(16bit) - 62 = 65474 */ timer1_counter = 65474; TCNT1 = timer1_counter; // preload timer1 TCCR1B |= _BV(CS12); // prescaler 256 TIMSK1 |= _BV(TOIE1); // overflow interrupt sei(); while (1) { switch (modeCounter) { case 0 : { DS3231setTime(); DS3231getTime(); } break; case 1 : { DS3231setDate(); DS3231getDate(); } break; case 2 : { DS3231getTemp(); } break; } if ((PINC & _BV(PINC3)) == 0) { modeCounter++; _delay_ms(200); if (modeCounter > 2) { modeCounter = 0; } } } } void i2c_init(uint32_t scl_f) { DDRC &= ~_BV(PORTC4) & ~_BV(PORTC5); //set SDA & SCL as inputs PORTC &= ~_BV(PORTC4) & ~_BV(PORTC5); //disable internal pullups TWSR = 0; //set prescaler value to 0 TWBR = ((F_CPU / scl_f) - 16) / 2; // set up bitrate register TWCR |= _BV(TWEN); //enable TWI } void i2c_start(void) { TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); //clear TWINT flag and send start condition while((TWCR & _BV(TWINT)) == 0) { //wait for TWI to execute task } } void i2c_stop(void) { TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); //clear TWINT flag and send stop condition while(TWCR & _BV(TWSTO)) { //wait for TWI to execute task } } void i2c_write(uint8_t byte) { TWDR = byte; TWCR = _BV(TWINT) | _BV(TWEN); while((TWCR & _BV(TWINT)) == 0) { //wait for TWI to execute task } } uint8_t i2c_read(uint8_t n_ack ) { if(n_ack == ACK) { TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN); } if(n_ack == NACK) { TWCR = _BV(TWINT) | _BV(TWEN); } while ((TWCR & _BV(TWINT)) == 0) { //wait for TWI to execute task } return TWDR; } void DisplayMatrix(void) { PORTB &= ~_BV(PORTB0) & ~_BV(PORTB1) & ~_BV(PORTB2) & ~_BV(PORTB3); PORTB |= (0b00001111 & digit_1); PORTD |= _BV(PORTD2); _delay_us(multiplexTime); PORTD &= ~_BV(PORTD2); PORTB &= ~_BV(PORTB0) & ~_BV(PORTB1) & ~_BV(PORTB2) & ~_BV(PORTB3); PORTB |= (0b00001111 & digit_2); PORTD |= _BV(PORTD3); _delay_us(multiplexTime); PORTD &= ~_BV(PORTD3); PORTB &= ~_BV(PORTB0) & ~_BV(PORTB1) & ~_BV(PORTB2) & ~_BV(PORTB3); PORTB |= (0b00001111 & digit_3); PORTD |= _BV(PORTD4); _delay_us(multiplexTime); PORTD &= ~_BV(PORTD4); PORTB &= ~_BV(PORTB0) & ~_BV(PORTB1) & ~_BV(PORTB2) & ~_BV(PORTB3); PORTB |= (0b00001111 & digit_4); PORTD |= _BV(PORTD5); _delay_us(multiplexTime); PORTD &= ~_BV(PORTD5); PORTB &= ~_BV(PORTB0) & ~_BV(PORTB1) & ~_BV(PORTB2) & ~_BV(PORTB3); PORTB |= (0b00001111 & digit_5); PORTD |= _BV(PORTD6); _delay_us(multiplexTime); PORTD &= ~_BV(PORTD6); PORTB &= ~_BV(PORTB0) & ~_BV(PORTB1) & ~_BV(PORTB2) & ~_BV(PORTB3); PORTB |= (0b00001111 & digit_6); PORTD |= _BV(PORTD7); _delay_us(multiplexTime); PORTD &= ~_BV(PORTD7); } void DS3231setTime(void) { if ((PINC & _BV(PINC0)) == 0) { uint8_t high, low, bcd; high = hour_set / 10; low = hour_set - (high * 10); bcd = (0b00001111 & low) | (0b00110000 & (high << 4)); i2c_start(); i2c_write(DS3231_ADDR); i2c_write(0x02); i2c_write(bcd); i2c_stop(); hour_set++; if (hour_set == 24) { hour_set = 0; } _delay_ms(100); } if ((PINC & _BV(PINC1)) == 0) { uint8_t high, low, bcd; high = minute_set / 10; low = minute_set - (high * 10); bcd = (0b00001111 & low) | (0b01110000 & (high << 4)); i2c_start(); i2c_write(DS3231_ADDR); i2c_write(0x01); i2c_write(bcd); i2c_stop(); minute_set++; if (minute_set == 60) { minute_set = 0; } _delay_ms(100); } if ((PINC & _BV(PINC2)) == 0) { uint8_t high, low, bcd; high = second_set / 10; low = second_set - (high * 10); bcd = (0b00001111 & low) | (0b01110000 & (high << 4)); i2c_start(); i2c_write(DS3231_ADDR); i2c_write(0x00); i2c_write(bcd); i2c_stop(); second_set++; if (second_set == 60) { second_set = 0; } _delay_ms(100); } } void DS3231getTime(void) { uint8_t hours, minutes, seconds; uint8_t hours_h, hours_l, minutes_h, minutes_l, seconds_h, seconds_l; i2c_start(); i2c_write(DS3231_ADDR); i2c_write(0); i2c_start(); i2c_write(DS3231_ADDR_READ); seconds = i2c_read(ACK); minutes = i2c_read(ACK); hours = i2c_read(NACK); i2c_stop(); hours_l = 0b00001111 & hours; hours_h = 0b00000011 & (hours >> 4); minutes_l = 0b00001111 & minutes; minutes_h = 0b00000111 & (minutes >> 4); seconds_l = 0b00001111 & seconds; seconds_h = 0b00000111 & (seconds >> 4); digit_1 = hours_h; digit_2 = hours_l; digit_3 = minutes_h; digit_4 = minutes_l; digit_5 = seconds_h; digit_6 = seconds_l; } void DS3231setDate(void) { if ((PINC & _BV(PINC0)) == 0) { uint8_t high, low, bcd; high = day_set / 10; low = day_set - (high * 10); bcd = (0b00001111 & low) | (0b00110000 & (high << 4)); i2c_start(); i2c_write(DS3231_ADDR); i2c_write(0x04); i2c_write(bcd); i2c_stop(); day_set++; if (day_set == 32) { day_set = 1; } _delay_ms(100); } if ((PINC & _BV(PINC1)) == 0) { uint8_t high, low, bcd; high = month_set / 10; low = month_set - (high * 10); bcd = (0b00001111 & low) | (0b00110000 & (high << 4)); i2c_start(); i2c_write(DS3231_ADDR); i2c_write(0x05); i2c_write(bcd); i2c_stop(); month_set++; if (month_set == 13) { month_set = 1; } _delay_ms(100); } if ((PINC & _BV(PINC2)) == 0) { uint8_t high, low, bcd; high = year_set / 10; low = year_set - (high * 10); bcd = (0b00001111 & low) | (0b11110000 & (high << 4)); i2c_start(); i2c_write(DS3231_ADDR); i2c_write(0x06); i2c_write(bcd); i2c_stop(); year_set++; if (year_set == 80) { year_set = 0; } _delay_ms(100); } } void DS3231getDate(void) { uint8_t days, months, years; uint8_t days_h, days_l, months_h, months_l, years_h, years_l; i2c_start(); i2c_write(DS3231_ADDR); i2c_write(0x04); i2c_start(); i2c_write(DS3231_ADDR_READ); days = i2c_read(ACK); months = i2c_read(ACK); years = i2c_read(NACK); i2c_stop(); days_l = 0b00001111 & days; days_h = 0b00000011 & (days >> 4); months_l = 0b00001111 & months; months_h = 0b00000111 & (months >> 4); years_l = 0b00001111 & years; years_h = 0b00000111 & (years >> 4); digit_1 = days_h; digit_2 = days_l; digit_3 = months_h; digit_4 = months_l; digit_5 = years_h; digit_6 = years_l; } void DS3231getTemp(void) { uint8_t temp_l, temp_h, temp_bcd_1, temp_bcd_2, temp_bcd_3, temp_bcd_4; i2c_start(); i2c_write(DS3231_ADDR); i2c_write(0x11); i2c_start(); i2c_write(DS3231_ADDR_READ); temp_h = i2c_read(ACK); temp_l = i2c_read(NACK); i2c_stop(); temp_l = (temp_l >> 6) * 25; temp_bcd_1 = temp_h / 10; temp_bcd_2 = temp_h - (temp_bcd_1 * 10); temp_bcd_3 = temp_l / 10; temp_bcd_4 = temp_l - (temp_bcd_3 * 10); digit_1 = 0; digit_2 = 0; digit_3 = temp_bcd_1; digit_4 = temp_bcd_2; digit_5 = temp_bcd_3; digit_6 = temp_bcd_4; }