/*
Copyright 2021, tslil clingman
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see .
*/
#include
#include
#include
#include "TinyI2CMaster.h"
#include "font.h"
#define DISP1_ADDR 0x3C
#define DISP2_ADDR 0x3D
#define RTC_ADDR 0x68
// -----------------------------------------------------------------------------
// SSD1306 driver
#define INIT_LEN 7
PROGMEM const uint8_t init[INIT_LEN] = {0xAE, // display off
0x8D, // charge pump
0x14,
0xAF, // display on
0x20,
0xA6, // Normal display
0x02 // page address mode
};
void disp_init(const uint8_t addr, const uint8_t upside_down) {
i2c_start(addr,0);
i2c_write(0x00);
for (uint8_t k = 0; k>=2)
for (uint8_t l=0; l<4; l++)
i2c_write(((b&1)?0xF0:0x00)|
((b&2)?0x0F:0x00));
}
}
}
// -----------------------------------------------------------------------------
// Interface
uint8_t bcd_to_dec(uint8_t k) { return (((k)/16)*10) + ((k)%16); }
uint8_t dec_to_bcd(uint8_t k) { return (((k)/10)*16) + ((k)%10); }
int main(void) {
// Init screens
i2c_init();
disp_init(DISP1_ADDR,1);
disp_init(DISP2_ADDR,0);
// Setup input pullups
DDRA = ~(_BV(DDA0) | _BV(DDA1));
PORTA = _BV(DDA0) | _BV(DDA1);
// Tracking state
uint8_t input = 0, hours = 99, minutes = 99;
while(1) {
// Increase hours?
if (!(PINA&_BV(DDA0))) {
if ((hours+=1)>23) hours=0;
input = 1;
}
// Increase minutes?
if (!(PINA&_BV(DDA1))) {
if ((minutes+=1)>59) minutes=0;
input = 1;
}
// Store changes
if (input) {
input = 0;
i2c_start(RTC_ADDR,0);
i2c_write(0);
i2c_write(0); // Seconds
i2c_write(dec_to_bcd(minutes));
i2c_write(dec_to_bcd(hours));
i2c_stop();
}
// Draw minutes
disp_draw_digit(DISP1_ADDR, (minutes/10)%10, 0);
disp_draw_digit(DISP1_ADDR, (minutes%10), 4);
// Draw hours
disp_draw_digit(DISP2_ADDR, (hours/10)%10, 0);
disp_draw_digit(DISP2_ADDR, (hours%10), 4);
// Poll for update
i2c_start(RTC_ADDR,0);
i2c_write(1);
i2c_start(RTC_ADDR,2);
minutes = bcd_to_dec(i2c_read());
hours = bcd_to_dec(i2c_read());
i2c_stop();
// Delay
_delay_ms(100);
}
return 0;
}