MyTetra Share
Делитесь знаниями!
Clock with 7-segments ver.4
Время создания: 30.11.2017 14:56
Раздел: Electronics - Microcontrollers - AVR8 - AVR GCC - C_PROJ - Clock 7sgm (blue)

#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

}


 
MyTetra Share v.0.53
Яндекс индекс цитирования