////////////////////////////////////////////////////////////////////////// // File: rtc7seg.c // // RTC-7seg Digital Clock // joselito.rapisora@gmail.com // To God be the Glory! // // Rev 1.0 Aug2013 Initial release // Rev 2.0 Jan2015 Added minutes calibration routine // ////////////////////////////////////////////////////////////////////////// // MCU: ATTINY2313A // FUSE VALUE: FF.D9.64 ////////////////////////////////////////////////////////////////////////// #include #include #include #include #include "i2c.h" #define F_CPU 1000000L // PINNAME PORTPIN // PINNUM #define RESET PA2 // 1 #define segG PD0 // 2 #define segB PD1 // 3 //#define NC PA1 // 4 //#define NC PA0 // 5 #define segD PD2 // 6 #define segA PD3 // 7 #define segF PD4 // 8 #define segE PD5 // 9 //#define GND NA // 10 #define segC PD6 // 11 #define segP PB0 // 12 #define ce1 PB1 // 13 #define ce2 PB2 // 14 #define ce4 PB3 // 15 #define ce3 PB4 // 16 #define SDA PB5 // 17 //#define NC PB6 // 18 #define SCL PB7 // 19 //#define VCC NA // 20 #define SEG_PORT PORTD #define SEL_PORT PORTB #define RTC_PORT PORTB #define SEC_PORT PORTB #define SEG_IOREG DDRD #define SEL_IOREG DDRB #define RTC_IOREG DDRB #define SEC_IOREG DDRB #define MSGBUF_SIZE 16 #define RTCADDR 0xD0 // DS1307 hardware address #define REFRESHRATE 0xBF // 60Hz refresh rate (60Hz x 4 = 240Hz interval between digits) #define NOWMINADDR 0x01 // DS1307 minute location. #define DPMFACADDR 0x08 // DS1307 ram location for 'days per minute' factor. Needs to be programmed initially #define LCALDADDR 0x0A // DS1307 ram location for 'last calibration day number'. Needs to be programmed initially uint8_t msgBuff[MSGBUF_SIZE]; uint8_t digitVal[4]; uint8_t digitSelect[] = { ce1,ce2,ce3,ce4 }; uint8_t segmentOn[] = { 0b10000001,0b11110101,0b10100010,0b10100100,0b11010100,0b10001100,0b10001000,0b11100101,0b10000000,0b10000100 }; uint16_t dpmFactor; // days per -minute factor uint16_t lastCalDay; // last calibration day (since Jan 1 of the year) uint8_t nowDay; uint8_t nowMonth; uint8_t nowMin; uint8_t decToBcd(uint8_t val) { return ( (val/10*16) + (val%10) ); } uint8_t bcdToDec(uint8_t val) { return ( (val/16*10) + (val%16) ); } uint16_t dayNum(uint8_t day, uint8_t month) // Get day number since first day of year given day and month { uint16_t monthDays[] = { 0,0,31,59,90,120,151,181,212,243,273,304,334,365 }; // Cumulative days for each end of month return (monthDays[month] + (uint16_t)day); } uint8_t doCalib() { myI2C_init(); readRTC(1); uint16_t nowDayN = dayNum(nowDay, nowMonth); uint16_t difDays = (lastCalDay > nowDayN) ? (nowDayN + (365 - lastCalDay)) : (nowDayN - lastCalDay); // Calculate day difference. Account for new year... uint8_t minFactor = (uint8_t)(difDays / dpmFactor); if ((minFactor == 0) || ((nowMin / minFactor) == 0)) return 0; // Return if no calibration is required // Or if required, just forgo if roll-back in hours is needed (for code simplicity) myI2C_init(); msgBuff[0] = RTCADDR|0x00; // Slave address with write bit msgBuff[1] = NOWMINADDR; // Cal required: adjust RTC minutes msgBuff[2] = decToBcd(nowMin - minFactor); myI2C_start(); myI2C_master_write(msgBuff, 3); myI2C_stop(); _delay_us(1000); myI2C_init(); msgBuff[0] = RTCADDR|0x00; // Slave address with write bit msgBuff[1] = LCALDADDR; // Cal required: save last calibration day num to RTC ram msgBuff[2] = (uint8_t)(nowDayN / 256); // lastCalDay 16bit MSB msgBuff[3] = (uint8_t)(nowDayN % 256); // lastCalDay 16bit LSB myI2C_start(); myI2C_master_write(msgBuff, 4); myI2C_stop(); _delay_us(1000); debugOut(4); return 1; } void readRTC(uint8_t option) { uint8_t x; myI2C_init(); msgBuff[0] = RTCADDR|0x00; // slave address with write bit msgBuff[1] = 0x00; // address pointer 0x00 myI2C_start(); myI2C_master_write(msgBuff, 2); // write msgBuff to slave resetting address pointer to 0x00 msgBuff[0] = RTCADDR|0x01; // slave address with read bit myI2C_start(); // repeated start myI2C_master_write(msgBuff, 1); // write msgBuff to slave for request to read if (option == 0) myI2C_master_read(msgBuff, 3); // reading 3bytes to msgBuff starting from 0x00 if (option == 1) myI2C_master_read(msgBuff, 12); // reading 12bytes to msgBuff starting from 0x00 myI2C_stop(); _delay_us(1000); if (option == 0) // Option 0 for normal operation i.e. read hours and minutes only { x = bcdToDec(msgBuff[2]); // convert read value for each 7seg digit digitVal[0] = x / 10; digitVal[1] = x % 10; x = bcdToDec(msgBuff[1]); digitVal[2] = x / 10; digitVal[3] = x % 10; } if (option == 1) // Option 1 read calibration values { nowMonth = bcdToDec(msgBuff[5]); nowDay = bcdToDec(msgBuff[4]); nowMin = bcdToDec(msgBuff[1]); dpmFactor = (msgBuff[8] << 8) | msgBuff[9]; lastCalDay = (msgBuff[10] << 8) | msgBuff[11]; } } void updateDisplay() { static uint8_t secBit; static uint8_t select; static uint8_t subSec; select >= 3 ? select = 0 : select++; // roll digit select SEG_PORT = segmentOn[digitVal[select]]; // update 7-segment value SEL_PORT = (0<