/* 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; }