#define F_CPU 8000000L
#define DEVICE (__AVR_ATmega8__)
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>
#define uint8_t uint8_t
//#include "my_init.h"
//#include "blinking.c"
//typedef uint8_t uint8_t;
#define NOP asm volatile("NOP"::) //NOP
#define SEI asm volatile("sei"::) //enable interrupts
#define CLI asm volatile("cli"::) //disable interrupts
#define SEGM_DDR DDRC
#define SEGM PORTC //PC1..PC4 - 1..4 segment cathodes
#define CATHODE_MASK 0xE1 //1110.0001 - mask for turning off pins [1..4]
#define SEC_DOTS 0x80 //'mask' for switching on central dots on indicator panel
#define SEGM1_ON SEGM |= (1<<1) //PORTC 1
#define SEGM2_ON SEGM |= (1<<2) //PORTC 2
#define SEGM3_ON SEGM |= (1<<3) //PORTC 3
#define SEGM4_ON SEGM |= (1<<4) //PORTC 4
#define SEGM_OFF SEGM &= CATHODE_MASK
#define SEGM_DDR_OFF SEGM_DDR &= CATHODE_MASK
#define HC595 PORTB
#define DS 0 //data
#define ST 2 //locking
#define SH 1 //clock
//PORTD
#define MR 7 //for 74HC595
#define BUTT1 6 //PORTD6 - button #1 //change for pin2 and do interrupt INT0
#define BUTT2 5 //PORTD5 - button #2
#define BUTT3 4 //PORTD4 - button #3 //change for pin6
#define BUTT_MASK 0x70 //0111.0000 //change it after making INT0 interrupt
#define BUTTONS_STATE ((PIND) & (BUTT_MASK))
//BUTTONS_MASK
// 0111.0000
// |||button_3
// ||button_2
// |button_1
// MR (74HC595)
#define DATA_HI HC595 |= (1<<DS)
#define DATA_LOW HC595 &= ~(1<<DS)
#define CLK_HI HC595 |= (1<<SH)
#define CLK_LOW HC595 &= ~(1<<SH)
#define LOCK_HI HC595 |= (1<<ST)
#define LOCK_LOW HC595 &= ~(1<<ST)
#define CLEAR_OFF PORTD |= (1<<MR)
#define CLEAR_ON PORTD &= ~(1<<MR)
//for indicator with common cathode
//D0..D7 == A,B,C,D,F,G,DP
#define DIG1 0x06;
#define DIG2 0x5B;
#define DIG3 0x4F;
#define DIG4 0x66;
#define DIG5 0x6D;
#define DIG6 0x7D;
#define DIG7 0x07;
#define DIG8 0x7F;
#define DIG9 0x6F;
#define DIG0 0x3F;
#define SYM_SPACE 0x08;
#define SYM_o 0x5C;
#define SYM_n 0x54;
#define SYM_f 0x71;
#define CHECKBIT(BYTE,BIT) (BYTE & (1<<BIT)) //check bit setting
//#define SWAPBIT(BYTE) (BYTE ^= 0x01) //
//#define CHECKBUTTS(BYTE) (BYTE = PIND & BUTT_MASK)
//configuration modes:
#define MOFF 0 //cfg mode turned off (default)
#define MHOUR_H 1 //changing 1st hour digit
#define MHOUR_L 2 //changing 2nd hour digit
#define MMINUTE_H 3 //changing 1st minute digit
#define MMINUTE_L 4 //changing 2nd minute digit
#define MDAY_H 5 //changing day
#define MDAY_L 6 //changing 2nd digit of the day
#define MMONTH_H 7 //changing month
#define MMONTH_L 8 //changing 2nd digit of the month
#define MYEAR_4 9 //changing year
#define MYEAR_3 10 //changing year
#define MYEAR_2 11 //changing year
#define MYEAR_1 12 //changing year
#define MZERO 13 //changing visibility of zero in hours (exmpl: 01:35 vs 1:35)
#define TIME_FOR_CONFIG 6 //cfg mode will have been working for 6 second after last button pressing
//timers
#define ONE_SECOND 0x7A12
#define HALF_SECOND 0x3D09
#define SEC_FOR_TIME 15 //how long will be displayed clock
#define SEC_FOR_DATE 6 //how long will be displayed date
//EEPROM addresses for variables
#define DAY_ADR 0x00
#define MON_ADR 0x01
#define YEARH_ADR 0x02
#define YEARL_ADR 0x03
//#define RAZR16
#ifndef RAZR16
#define RAZR 8
#else
#define RAZR 16
#endif
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// comment the next #define if you want to disable blinking in cfg mode:
// ------------------------------------------------------------------
#define CONFIGURATION_BLINKING
#ifdef CONFIGURATION_BLINKING
#endif
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// comment the next #define if you want to disable configuration
// of last zero visibility
// ------------------------------------------------------------------
// #define LAST_ZERO_DISABLING
#ifdef LAST_ZERO_DISABLING
#endif
volatile unsigned int TCNT = 0; //timer overflow
//================================================================================
// INTERNAL INT SECTION
//================================================================================
ISR(TIMER0_OVF_vect)
{
++TCNT;
}
void clearRegState(void);
void sendRegData(const uint8_t data);
uint8_t assignDigit(const uint8_t val);
uint8_t assignSegment(const uint8_t segNu, const uint8_t, const uint8_t, const uint8_t, const uint8_t);
uint8_t calcRemainder(uint8_t val, uint8_t * const rem);
uint8_t incrValue(uint8_t val, const uint8_t limit, const uint8_t amount);
void EEPROM_write(uint16_t uiAddress, uint8_t ucData);
uint8_t EEPROM_read(uint16_t uiAddress);
//================================================================================
// FUNCTION SECTION
//================================================================================
int main(void)
{
//====================------------------------------------------------
// INIT SECTION
//====================------------------------------------------------
ACSR |= 1<<ACD; //Disable analog comparator
//Timer0_START
TCCR0 = (TCCR0 | 1<<CS00) | (TCCR0 | 0<<CS01) | (TCCR0 | 0<<CS02); //NO Prescaler
TIMSK |= 1<<TOIE0; //Enable TIMER0 interrupts
//Timer0_END
DDRB = 0x07; //0000.0111 DDRB
DDRC = 0x1E; //0001.1110
DDRD &= ~(BUTT_MASK); //set 0 in DDRD for buttons
PORTD |= BUTT_MASK; //PullUp for buttons
DDRD |= 1 << MR; //pin D7 output for MR bit
SEGM = 0x00; //PORTC off
CLK_LOW;
LOCK_LOW;
clearRegState();
//====================------------------------------------------------
// END of INIT SECTION
//====================------------------------------------------------
uint8_t dotsBlink = 1; //dots state and blinking (1 = dots're active)
uint8_t seconds = 0; //seconds counter
uint8_t minutes = 54;
uint8_t hours = 18;
uint8_t day = EEPROM_read(DAY_ADR);
uint8_t month = EEPROM_read(MON_ADR);
uint8_t year_h = EEPROM_read(YEARH_ADR); //first two digits of year
uint8_t year_l = EEPROM_read(YEARL_ADR); //last two digits of year
uint8_t maxDay = 31; //maximum of days in month (limited by 31 or 32 !)
uint8_t displayTimer = 0; //timer for switching between clock and date displaying
uint8_t currentDisplay = 0; //0 = HH:MM, 1 = DD.MM, 2 = YYYY
uint8_t buttonPressed = 0; //set if any button pressed
uint8_t buttonState = 0; //0 = no one button is pressed, 1 - pressed
uint8_t cfgMode = 0; //for configuration (1..9)
uint8_t cfgModeTime = 0; //Auto exit from cfg mode after .. seconds
uint8_t cfgChanges = 0; //bits for checking date and time changes
#ifdef CONFIGURATION_BLINKING
uint8_t cfgBlinkState = 1; //1 - digit is turned on
#endif
if(day > maxDay) day = 1;
if(month > 12) month = 1;
if(year_h > 99) year_h = 0;
if(year_l > 99) year_l = 0;
SEI;
//############================================---------------------------------------
// ---------------------------------= LOOPED CYCLE =---------------------------------
//############================================---------------------------------------
for(;;)
{
//_____________________TIME CALCULATING________________________
//time calculating
if(TCNT >= ONE_SECOND)
{
TCNT -= ONE_SECOND; //main counter
++seconds; //main clock time
++displayTimer; //
++cfgModeTime; //time of active configuration mode
if(cfgMode/* != MOFF*/) //if clck in configuration mode
{
if(cfgModeTime > TIME_FOR_CONFIG)
{
cfgMode = MOFF; //turn off cfg mode after X seconds
cfgModeTime = 0;
displayTimer = 0;
currentDisplay = 0;
//write date and time in EEPROM if it's changed:
if(cfgChanges)
{
clearRegState();
if( CHECKBIT(cfgChanges, 0) ) EEPROM_write(DAY_ADR, day);
if( CHECKBIT(cfgChanges, 1) ) EEPROM_write(MON_ADR, month);
if( CHECKBIT(cfgChanges, 2) ) EEPROM_write(YEARH_ADR, year_h);
if( CHECKBIT(cfgChanges, 3) ) EEPROM_write(YEARL_ADR, year_l);
cfgChanges = 0;
}
}
#ifdef CONFIGURATION_BLINKING
else cfgBlinkState = 0;
#endif
}
if(dotsBlink) dotsBlink = 0; //state of 2 central dots
else dotsBlink = 1; //turn off central dots
//_______________________________________
//--== MAIN TIME COUNTING
if(seconds == 60)
{
seconds = 0;
++ minutes;
if(minutes == 60)
{
minutes = 0;
++ hours;
if(hours == 24)
{
hours = 0;
++day;
if(day == 32)
{
day = 1;
++month;
if(month == 13)
{
month = 0;
++year_h;
if(year_l > 0x63) // 0x63 = 99
{
year_l = 0;
++year_h;
if(year_h > 0x63)
year_h = 0;
} //write EEPROM if date was changed:
EEPROM_write(YEARL_ADR, year_l);
EEPROM_write(YEARH_ADR, year_h);
}
EEPROM_write(MON_ADR, month);
}
EEPROM_write(DAY_ADR, day);
}
}
}
}
//___END_OF____________TIME CALCULATING________________________
//_____________________IF BUTTON IS PRESSED________________________
buttonState = BUTTONS_STATE; // check buttons
if( buttonState < BUTT_MASK && buttonPressed == 0 ) // if any button is pressed
{
cfgModeTime = 0; //clear time after any button pressing
displayTimer = 0; //reset timer for changing display
buttonPressed = 1;
if(cfgMode == MOFF)
currentDisplay = 0; //back to screen with time
if( CHECKBIT(buttonState,BUTT1) == 0)
{
++cfgMode; //if BUTTON 1 - change mode
if(cfgMode == MDAY_H || cfgMode == MYEAR_4/* || cfgMode == MZERO*/)
{
++currentDisplay; //go to the next display
}
else if(cfgMode == MZERO) //set default display
{
++currentDisplay; //go to the next display
currentDisplay = 0;
cfgMode = MOFF;
cfgModeTime = 0;
}
}
else if( CHECKBIT(buttonState,BUTT2) == 0 && cfgMode /*> MOFF*/) //if BUTTON 2 - depends on mode
{
uint8_t factor = 1;
switch(cfgMode)
{
case 1: factor = 10; //incr hour_h
case 2: hours = incrValue(hours, 24, factor); break; //incr hour_l (depends on hour_h)
case 3: factor = 10; //incr minute_h
case 4: minutes = incrValue(minutes, 60, factor); break; //incr minute_l
case 5: factor = 10;
case 6: day = incrValue(day, maxDay, factor); cfgChanges |= 1 << 0; break; //incr day
case 7: factor = 10;
case 8: month = incrValue(month, 13, factor); cfgChanges |= 1 << 1; break; //incr month
case 9: factor = 10;
case 10: year_h = incrValue(year_h, 100, factor); cfgChanges |= 1 << 2; break; //incr year
case 11: factor = 10;
case 12: year_l = incrValue(year_l, 100, factor); cfgChanges |= 1 << 3; break; //incr year
default: break;
}
if(day == 0) day = 1;
if(month == 0) month = 1;
}
// else if( CHECKBIT(buttonState,BUTT3) == 0 && cfgMode == 1)
// {
//
// }
}
else if( buttonPressed == 1 && buttonState == BUTT_MASK ) // if all buttons are NOT pressed
{
buttonPressed = 0;
}
//___________SHOW BLINKING in CONFIGURATION MODE______________
#ifdef CONFIGURATION_BLINKING
if(cfgMode != MOFF && cfgBlinkState == 0 && TCNT > HALF_SECOND)
{
cfgBlinkState = 1;
}
#endif
//_____________________SHOW TIME OR DATE________________________
//cycle for selecting data and same digital segment:
for(uint8_t segmentNumber = 4; segmentNumber > 0; --segmentNumber)
{
uint8_t temp = 0;
uint8_t data = 0; //74HC595 pins state
uint8_t segment_1 = 0;
uint8_t segment_2;
uint8_t * const pSegm2 = &segment_2;
uint8_t segment_3 = 0;
uint8_t segment_4;
uint8_t * const pSegm4 = &segment_4;
// CHANGE DISPLAY between TIME, DATE and YEAR
// if display time has gone
if(currentDisplay == 0 && displayTimer > SEC_FOR_TIME)
{
displayTimer = 0;
currentDisplay = 1;
}
else if(currentDisplay > 0 && displayTimer > SEC_FOR_DATE)
{
if(currentDisplay == 2) currentDisplay = 0;
else currentDisplay = 2;
displayTimer = 0;
}
//SHOW TIME
if(currentDisplay == 0)
{
segment_1 = calcRemainder(hours, pSegm2);
segment_3 = calcRemainder(minutes, pSegm4);
}
//SHOW DAY AND MONTH
else if(currentDisplay == 1)
{
segment_1 = calcRemainder(day, pSegm2);
segment_3 = calcRemainder(month, pSegm4);
}
//SHOW YEAR
else if(currentDisplay == 2)
{
segment_1 = calcRemainder(year_h, pSegm2);
segment_3 = calcRemainder(year_l, pSegm4);
}
temp = assignSegment(segmentNumber, segment_1, segment_2, segment_3, segment_4);
data = assignDigit(temp);
#ifdef CONFIGURATION_BLINKING
//_____________________________________________
// dont show configurable digit for 0.5 seconds
// while cfgBlinkState == 0:
if(
cfgBlinkState == 0
&&
(
cfgMode == segmentNumber ||
cfgMode == segmentNumber + 4 ||
cfgMode == segmentNumber + 8
/* (cfgMode == segmentNumber) ||
((cfgMode == 5 || cfgMode == 9) && segmentNumber == 1) ||
((cfgMode == 6 || cfgMode == 10) && segmentNumber == 2) ||
((cfgMode == 7 || cfgMode == 11) && segmentNumber == 3) ||
((cfgMode == 8 || cfgMode == 12) && segmentNumber == 4) */
)
)
data = 0;
#endif
clearRegState();
//_____________________________________________
//if needed to turn on two central dots, 7th bit will be added:
if
(
(dotsBlink == 1 && currentDisplay == 0) ||
(segmentNumber == 4 && currentDisplay == 1)
)
{ //two dots : for time, one dot . for date, no dots for year
data |= 1 << 7;
}
SEGM_OFF; //turn off all cathodes
SEGM |= 1 << segmentNumber; //turn on actual cathode
// clearRegState();
//_____________________________________________
sendRegData(data); //sending of all 8 bites of data for 74HC595N:
}
}
return 0;
}
void clearRegState(void)
{
CLEAR_ON;
LOCK_HI;
CLEAR_OFF;
LOCK_LOW;
}
void sendRegData(const uint8_t data)
{
uint8_t bit_counter = RAZR;
do
{
DATA_LOW;
CLK_LOW;
if( CHECKBIT(data, --bit_counter) ) //if bit in data == 1
DATA_HI;
CLK_HI;
} while(bit_counter > 0);
CLK_LOW;
LOCK_HI;
LOCK_LOW;
}
uint8_t assignDigit(const uint8_t val)
{
//_____________________________________________
//START of CODE SELECTING block for number:
switch(val)
{
case 0: return DIG0;
case 1: return DIG1;
case 2: return DIG2;
case 3: return DIG3;
case 4: return DIG4;
case 5: return DIG5;
case 6: return DIG6;
case 7: return DIG7;
case 8: return DIG8;
case 9: return DIG9;
default: return val;
}
//END of CODE SELECTING block for number
}
uint8_t assignSegment(const uint8_t segNu, const uint8_t v1, const uint8_t v2, const uint8_t v3, const uint8_t v4)
{
switch(segNu)
{
case 1: return v1;
case 2: return v2;
case 3: return v3;
case 4: return v4;
default: return 0;
}
}
uint8_t calcRemainder(uint8_t val, uint8_t * const rem)
{
uint8_t temp = 0;
while(val > 9)
{
val -= 10;
++temp;
}
*rem = val;
return temp;
}
uint8_t incrValue(uint8_t val, const uint8_t limit, const uint8_t amount)
{
uint8_t remaind = 0; //remainder
uint8_t * const pRemaind = &remaind;
uint8_t result; //integer part
val = calcRemainder(val, pRemaind);
if(amount == 10)
{
result = (((++val) * 10) + remaind);
if( result >= limit )
return (0 + remaind);
else return result;
}
else// if(amount == 1)
{
result = ((val * 10) + (++remaind));
if( result >= limit || remaind == 10 )
return (val * 10);
else return result;
}
// else return 0;
}
void EEPROM_write(uint16_t uiAddress, uint8_t ucData)
{
while(EECR & (1<<EEWE)) // Wait for completion of previous write
{}
EEAR = uiAddress; //Set up address register
EEDR = ucData; //Set up data register
EECR |= (1<<EEMWE); //Write logical one to EEMWE
CLI;
EECR |= (1<<EEWE); //Start eeprom write by setting EEWE
SEI;
}
uint8_t EEPROM_read(uint16_t uiAddress)
{
while(EECR & (1<<EEWE)) // Wait for completion of previous write
{}
EEAR = uiAddress; //Set up address register
CLI;
EECR |= (1<<EERE); //Start eeprom read by writing EERE
SEI;
return EEDR; //Return data from data register
}