/*
08.06.2017
Program: 2030 bytes (24.8% Full)
(.text + .data + .bootloader)
Data: 13 bytes (1.3% Full)
(.data + .bss + .noinit)
Programm was changed and adapted for new red display
with two central dots for seconds and one central
dot at the bottom for DD.MM
ATMEGA8A
__________
(RESET) PC6 -| |- PC5 (ADC5/SCL)
(RXD) PD0 -| |- PC4 (ADC4/SDA)
(TXD) PD1 -| |- PC3 (ADC3)
(INT0) PD2 -| |- PC2 (ADC2)
(INT1) PD3 -| |- PC1 (ADC1)
(XCK/T0) PD4 -| |- PC0 (ADC0)
VCC -| |- GND
GND -| |- AREF
(OSC1) PB6 -| |- AVCC
(OSC2) PB7 -| |- PB5 (SCK)
(T1) PD5 -| |- PB4 (MISO)
(AIN0) PD6 -| |- PB3 (MOSI/OC2)
(AIN1) PD7 -| |- PB2 (SS/OC1B)
(ICP1) PB0 -|__________|- PB1 (OC1A)
*/
#define F_CPU 8000000L
#define DEVICE (__AVR_ATmega8__)
#include <avr/io.h>
#include <avr/interrupt.h>
//#include <stdint.h>
#define MICROPHONE
//#define DEBUGME
#include "definitions.h"
#include "functionz.c"
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// GLOBALVARIABLES
// ------------------------------------------------------------------
//volatile uint16_t TCNT = 0; //timer overflow
volatile uint8_t TCNT = 0; //timer overflow
//================================================================================
// INTERNAL INTERRUPTS SECTION
//================================================================================
#ifdef MICROPHONE
ISR(INT0_vect)
{
// micSignal = 1;
INT0_DISABLE; //disable INT0 interrupt
}
#endif
ISR(TIMER0_OVF_vect)
{
++TCNT;
}
//================================================================================
// FUNCTION SECTION
//================================================================================
int main(void)
{
#ifdef DEBUGME
uint8_t pleaseWaitFor = 0;
DDRD |= 1 << 1;
#endif
//====================------------------------------------------------
// INIT SECTION
//====================------------------------------------------------
ACSR |= 1<<ACD; //Disable analog comparator
//Timer0_START
TCCR0 = (TCCR0 | 0<<CS00) | (TCCR0 | 0<<CS01) | (TCCR0 | 1<<CS02); //256 Prescaler
TIMSK |= 1<<TOIE0; //Enable TIMER0 interrupts
//Timer0_END
#ifdef MICROPHONE
MCUCR = (MCUCR | 1<<ISC01) | (MCUCR | 0<<ISC00); //falling endge of INT0 generates an interrupt
INT0_DISABLE;
#endif
DDRB = 0x07; //0000.0111 DDRB
DDRC = 0x1E; //0001.1110
DDRC |= 1 << SENSOR_POWER;
SENSOR_POWER_DISABLE;
DDRD &= ~(BUTT_MASK); //set 0 in DDRD for buttons
PORTD |= BUTT_MASK; //PullUp for buttons
DDRD |= 1 << MR; //pin D7 output for MR bit
ZUMMER_DDR |= 1 << ZUMMER;
ZUMMER_DIS;
EN_DDR_LIGHT_SENSOR;
EN_PORT_LIGHT_SENSOR;
#ifdef MICROPHONE
MICRO_DDR_CLR;
MICRO_PORT_CLR;
MICRO_PORT_SET;
#endif
// MICRO_PORT_SET; //used in programm
CLK_LOW;
LOCK_LOW;
clearRegState();
//====================------------------------------------------------
// END of INIT SECTION
//====================------------------------------------------------
uint8_t segmentNumber = 4;
uint8_t dotsBlink = 1; //dots state and blinking (1 = dots're active)
uint8_t seconds = 52; //seconds counter
uint8_t minutes = 55;
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 leapYear; //1 - leap, 0 - NOT leap
uint8_t alarm = EEPROM_read(ALRM_ST_ADR); //alarm state
uint8_t alarm_minutes = EEPROM_read(ALRM_M_ADR); //minutes for alarm
uint8_t alarm_hours = EEPROM_read(ALRM_H_ADR); //hours for alarm
uint8_t alarmSignalRepeat = 0; //counter of repeats
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 cfgMode = 0; //for configuration (1..9)
uint8_t cfgChanges = 0; //bits for checking date and time changes
uint8_t segmentBlinking = 1; //1 - digit is turned on
uint8_t checkChangesTCNT0 = 0; //trigger is changed after every T0 interruption
uint8_t checkChangesTCNT = 0;
uint8_t nightMode = 0x00; //
uint8_t brightCounter = CHANGE_BRIGHT_MID_POINT;
#ifdef MICROPHONE
uint8_t micSignal = 0; //microphone trigger
#endif
if(month > 12 || month < 1) month = 1;
if(year_h > 99) year_h = 0;
if(year_l > 99) year_l = 0;
leapYear = leapYearFoo(year_h, year_l);
maxDay = findMaxDay(month, leapYear);
if(day > maxDay || day < 1) day = 1;
if(alarm_hours > 24) alarm_hours = 0;
if(alarm_minutes > 59) alarm_minutes = 0;
TCNT0 = 0;
SEI;
//############================================---------------------------------------
// ---------------------------------= LOOPED CYCLE =---------------------------------
//############================================---------------------------------------
for(;;)
{
//%%%%%%%%%%%%%%%%%%%%%::::::::::::::::::::::::::::::::::::::
//BIG BLOCK "EVERY SECOND" STARTS
//%%%%%%%%%%%%%%%%%%%%%::::::::::::::::::::::::::::::::::::::
//###########==========------------TO DO EVERY SECOND
if(TCNT == 0x7A && TCNT0 >= 0x12)
{
#ifdef DEBUGME
if(pleaseWaitFor)
--pleaseWaitFor;
else
PORTD &= ~(1 << 1);
#endif
TCNT = TCNT0 = 0;
++seconds; //main clock time
++displayTimer; //
INVERTBIT(dotsBlink, 0);
SENSOR_POWER_ENABLE;
// ZUMMER_DIS;
//###########==========------------IF CONFIGURATION IS TURNED ON
if(cfgMode)
{
if(displayTimer > TIME_FOR_CONFIG)
{
cfgMode = MOFF; //turn off cfg mode after X seconds
displayTimer = 0;
currentDisplay = 0;
}
else segmentBlinking = 0;
}
//###########==========------------IF SOMETHING WAS CHANGED AFTER CONFIGURATION
else if(cfgChanges) //if time or date was changed and there is no cfgMode
{
//if alarm hours or minutes are changed:
if( CHECKBIT(cfgChanges, CH_ALRM_H) ) EEPROM_write(ALRM_H_ADR, alarm_hours);
if( CHECKBIT(cfgChanges, CH_ALRM_M) ) EEPROM_write(ALRM_M_ADR, alarm_minutes);
//if alarm state is changed:
if( CHECKBIT(cfgChanges, CH_ALRM_ST) ) EEPROM_write(ALRM_ST_ADR, CHECKBIT(alarm, ALARM_STATE) );
//if year is changed:
if( CHECKBIT(cfgChanges, CH_YEARL) ) EEPROM_write(YEARL_ADR, year_l);
if( CHECKBIT(cfgChanges, CH_YEARH) ) EEPROM_write(YEARH_ADR, year_h);
if( CHECKBIT(cfgChanges, CH_YEARL) || CHECKBIT(cfgChanges, CH_YEARH) )
leapYear = leapYearFoo(year_h, year_l); //check for leap year
//if month is changed:
if( CHECKBIT(cfgChanges, CH_MONTH) )
{
maxDay = findMaxDay(month, leapYear); //calculate maximum days in month
EEPROM_write(MON_ADR, month);
}
//if day is changed:
if( CHECKBIT(cfgChanges, CH_DAY) )
{
if(day > maxDay) day = 1; //need to check after month changing by user
EEPROM_write(DAY_ADR, day);
}
cfgChanges = 0;
}
//###########==========------------MAIN TIME COUNTING
if(seconds == 60)
{
// +++++++++++++++-------------
// repeat alarm 3 times every 5 seconds or while it's not switched off
ZUMMER_DIS;
alarm &= ~(1 << ALARM_SIGNAL);
if(alarmSignalRepeat)
{
++alarm;
// if alarm == xxxx.0101 == 5
if( CHECKBIT(alarm, ALARM_REPEAT) && CHECKBIT(alarm, ALARM_REPEAT0) )
{
--alarmSignalRepeat;
alarm |= 1 << ALARM_SIGNAL;
alarm &= 0xF0;
}
if( CHECKBIT(alarm, ALARM_NO_REPEAT) )
{
alarm &= ~(1 << ALARM_NO_REPEAT);
}
}
uint8_t * pIncr = &minutes;
seconds = SetAndIncrement(0, pIncr);
//seconds = 0;
//++minutes;
if(minutes == 60)
{
pIncr = &hours;
minutes = SetAndIncrement(0, pIncr);
//minutes = 0;
//++hours;
if(hours == 24)
{
pIncr = &day;
hours = SetAndIncrement(0, pIncr);
// hours = 0;
// ++day;
if(day > maxDay)
{
pIncr = &month;
day = SetAndIncrement(1, pIncr);
// day = 1;
// ++month;
if(month == 13)
{
pIncr = &year_l;
month = SetAndIncrement(1, pIncr);
// month = 1;
// ++year_l;
if(year_l > 0x63) // 0x63 = 99
{
pIncr = &year_h;
year_l = SetAndIncrement(0, pIncr);
// year_l = 0;
// ++year_h;
if(year_h > 0x63)
{
year_h = 0;
}
cfgChanges |= 1 << CH_YEARH; //save year_h in EEPROM
}
cfgChanges |= 1 << CH_YEARL; //save year_l in EEPROM
}
cfgChanges |= 1 << CH_MONTH; //save month in EEPROM
}
cfgChanges |= 1 << CH_DAY; //save day in EEPROM
}
}
}
//###########==========------------CHANGE DISPLAY
//between TIME, DATE and YEAR if display time has gone
if(currentDisplay == 0 && displayTimer > SEC_FOR_TIME && !alarmSignalRepeat)
{
++currentDisplay;
displayTimer = 0;
}
else if(currentDisplay && displayTimer > SEC_FOR_DATE)
{
if(currentDisplay < 2) ++currentDisplay;
else currentDisplay = 0;
displayTimer = 0;
}
if( CHECKBIT(LIGHT_PIN, LIGHT_SENSOR) ) {
++brightCounter;
if(brightCounter == CHANGE_BRIGHT_DELAY) {
nightMode = NIGHTMODE_WAIT;
brightCounter = CHANGE_BRIGHT_MID_POINT;
}
}
else {
--brightCounter;
if(brightCounter == 0) {
nightMode = NIGHTMODE_OFF;
brightCounter = CHANGE_BRIGHT_MID_POINT;
}
}
/*
if( CHECKBIT(LIGHT_PIN, LIGHT_SENSOR) )
nightMode = NIGHTMODE_WAIT;
else nightMode = NIGHTMODE_OFF;
*/
SENSOR_POWER_DISABLE;
}
//%%%%%%%%%%%%%%%%%%%%%
//BIG BLOCK "EVERY SECOND" ENDS
if(!micSignal)
micSignal = checkMicrophone();
//%%%%%%%%%%%%%%%%%%%%%::::::::::::::::::::::::::::::::::::::
//BIG BLOCK "TCNT0 CHNGD" STARTS
//%%%%%%%%%%%%%%%%%%%%%::::::::::::::::::::::::::::::::::::::
if(checkChangesTCNT0 != TCNT0)
{
checkChangesTCNT0 = TCNT0;
//###########==========------------IF BUTTON IS PRESSED
uint8_t buttonState = BUTTONS_STATE; // check buttons
if( buttonState < BUTT_MASK && buttonPressed == 0 ) // if any button is pressed
{
displayTimer = 0; //reset timer for changing display
buttonPressed = 1; //set flag of pressed button
if(cfgMode == MOFF)
currentDisplay = 0; //back to screen with time
//###########==========------------1st BUTTON
// first button works only if there is no alarm signal
if( CHECKBIT(buttonState,BUTT1) == 0 && !CHECKBIT(alarm, ALARM_SIGNAL))
{
++cfgMode; //if BUTTON 1 - change mode
if(cfgMode == MDAY_H || cfgMode == MYEAR_4)
{
++currentDisplay; //go to the next display
}
else if(cfgMode == MBACK_OFF || cfgMode == MEND ) //set default display
{
currentDisplay = 0;
cfgMode = MOFF;
}
}
//###########==========------------2nd BUTTON
else if( CHECKBIT(buttonState,BUTT2) == 0 && cfgMode) //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 << CH_DAY; break; //incr day
case 7: factor = 10;
case 8: month = incrValue(month, 13, factor); cfgChanges |= 1 << CH_MONTH; break; //inc month
case 9: factor = 10;
case 10: year_h = incrValue(year_h, 100, factor); cfgChanges |= 1 << CH_YEARH; break; //
case 11: factor = 10;
case 12: year_l = incrValue(year_l, 100, factor); cfgChanges |= 1 << CH_YEARL; break; //
case 14: factor = 10; //incr alarm hour_h
case 15: alarm_hours = incrValue(alarm_hours, 24, factor);
cfgChanges |= 1 << CH_ALRM_H; break;
case 16: factor = 10; //incr alarm minute_h
case 17: alarm_minutes = incrValue(alarm_minutes, 60, factor);
cfgChanges |= 1 << CH_ALRM_M; break;
default: break;
}
if(day == 0) day = 1;
if(month == 0) month = 1;
}
//###########==========------------3rd BUTTON
else if( CHECKBIT(buttonState,BUTT3) == 0)
{
if(cfgMode)
{
currentDisplay = 3; //show time for alarm
cfgMode = MALARM_H_H; //turn on mode for changing alarm time
}
else if(alarmSignalRepeat)
{
if( !CHECKBIT(alarm, ALARM_SIGNAL) )
alarmSignalRepeat = 0; //switch off alarm signals
alarm &= ~(1 << ALARM_SIGNAL);
}
else
{
INVERTBIT(alarm,ALARM_STATE); //turn on or off alarm
alarm &= ~(1 << ALARM_NO_REPEAT);
cfgChanges |= 1 << CH_ALRM_ST; //save the state in EEPROM
}
}
}
else if( buttonPressed && buttonState == BUTT_MASK ) // if all buttons are NOT pressed
{
buttonPressed = 0;
}
//----------------------------
if(micSignal == MICRO_SIGNAL)
{
if( !CHECKBIT(alarm, ALARM_SIGNAL) )
alarmSignalRepeat = 0; //switch off alarm signals
alarm &= ~(1 << ALARM_SIGNAL);
micSignal = MICRO_OFF;
}
//###########==========------------ALARM
if( CHECKBIT(alarm, ALARM_STATE) &&
!CHECKBIT(alarm, ALARM_NO_REPEAT) &&
minutes == alarm_minutes &&
hours == alarm_hours )
{
alarm |= 1 << ALARM_NO_REPEAT;
alarm |= 1 << ALARM_SIGNAL; //switch on alarm signals
alarmSignalRepeat = ALARM_REPEATS;
}
//switch on blinking if
if( CHECKBIT(alarm, ALARM_SIGNAL) ) //if it's alarm
{
currentDisplay = 0; //show time display
displayTimer = 0; //don't switch to other displays
segmentBlinking = 0; //switch on blinking
cfgMode = 0; //disable configuration mode
if( TCNT < 0x3D )
{
// INT0_DISABLE;
micSignal = MICRO_OFF;
ZUMMER_EN;
}
else
{
micSignal = MICRO_HEAR;
// micSignal = 1;
// INT0_ENABLE;
}
}
//###########==========------------SHOW BLINKING
//in CONFIGURATION MODE or WHILE ALARM IS WORKING
//if( TCNT > HALF_SECOND )
if( TCNT > 0x3D )
{
segmentBlinking = 1;
ZUMMER_DIS;
}
//###########==========------------FOR NIGHT MODE
if(checkChangesTCNT != TCNT)
{
checkChangesTCNT = TCNT;
if(nightMode == NIGHTMODE_WAIT)
nightMode = NIGHTMODE_ON;
}
//%%%%%%%%%%%%%%%%%%%%%//%%%%%%%%%%%%%%%%%%%%%::::::::::::::::::::::::::::::::::::::
//BIG BLOCK "DISPLAY" STARTS
//%%%%%%%%%%%%%%%%%%%%%//%%%%%%%%%%%%%%%%%%%%%::::::::::::::::::::::::::::::::::::::
//###########==========------------SHOW TIME OR DATE
if( nightMode != NIGHTMODE_WAIT )
{
//cycle for selecting data and same digital segment:
if(segmentNumber == 4)
{
segmentNumber = 1;
if( nightMode > NIGHTMODE_WAIT ) --nightMode;
}
else ++segmentNumber;
uint8_t data = 0; //74HC595 pins state
uint8_t indic = 0;
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;
uint8_t funcArg1 = hours;
uint8_t funcArg3 = minutes;
switch(currentDisplay)
{
case 0: break;
case 1: funcArg1 = day; funcArg3 = month; break;
case 2: funcArg1 = year_h; funcArg3 = year_l; break;
case 3: funcArg1 = alarm_hours; funcArg3 = alarm_minutes; break;
default: break;
}
segment_1 = calcRemainder(funcArg1, pSegm2);
segment_3 = calcRemainder(funcArg3, pSegm4);
data = assignSegment(segmentNumber, segment_1, segment_2, segment_3, segment_4);
data = assignDigit(data);
//switch off segment in cfg mode or while alarming
if(
segmentBlinking == 0
&&
(
cfgMode == segmentNumber ||
cfgMode == segmentNumber + 4 ||
cfgMode == segmentNumber + 8 ||
cfgMode == segmentNumber + 13 ||
CHECKBIT(alarm, ALARM_SIGNAL) //if alarm is working
)
)
{
data = 0;
}
//if needed to switch on two central dots, 7th bit will be added:
if
(
// 2 central dots
(segmentNumber == 2 &&
((dotsBlink == 1 && currentDisplay == 0) ||
currentDisplay == 3 ||
CHECKBIT(alarm, ALARM_SIGNAL) ))
||
// 1 bottom dot
(segmentNumber == 1 && currentDisplay == 1)
)
{
data += SEC_DOTS;
}
//switch on alarm indication
if
(
currentDisplay == 3 || (
CHECKBIT(alarm, ALARM_SIGNAL) ||
(alarmSignalRepeat && dotsBlink) ||
(!alarmSignalRepeat && CHECKBIT(alarm, ALARM_STATE) ))
)
{
ALARM_INDICAT_ON;
}
switch(currentDisplay)
{
case 0: TIME_INDICAT_ON; break;
case 1: DATE_INDICAT_ON; break;
case 2: YEAR_INDICAT_ON; break;
default: break;
}
SEGM_OFF; //turn off all cathodes
clearRegState();
SEGM |= 1 << segmentNumber; //turn on actual cathode
sendRegData(indic); //data for switching LED indicators
sendRegData(data); //sending of all 8 bites of data for 74HC595N:
LOCK_HI;
LOCK_LOW;
}
else
clearRegState(); //skip indication in night mode
//%%%%%%%%%%%%%%%%%%%%%//%%%%%%%%%%%%%%%%%%%%%
//BIG BLOCK "DISPLAY" ENDS
}
//%%%%%%%%%%%%%%%%%%%%%
//BIG BLOCK "TCNT0 CHNGD" ENDS
}
return 0;
}