AVR Microcontroller Based Digital Alarm Clock

In this project we are going to design a simple Alarm clock using ATMEGA32 timers. ATmega32A microcontroller has a 16 bit timer, and we will be using that timer to count the seconds and develop a digital clock.

 

All the digital clocks have a crystal inside of them which is the heart of clock. This crystal not only present in clock but present in all computing real time systems. This crystal generates clock pulses, which is needed for timing calculations. Although there are some other ways to get clock pulses but for accuracy and higher frequency most prefer crystal based clock. We are going to connect a crystal to ATMEGA32 for getting accurate clock.

 

Components Required

Hardware: ATmega32 microcontroller, 11.0592MHz crystal, 22pF Capacitor (2 pieces), Power supply (5v), AVR-ISP PROGRAMMER, JHD_162ALCD(16x2 LCD), 100uF capacitor (connected across power supply), buttons (four pieces),  10KΩ resistor (six pieces), 100nF capacito r(four pieces), Three pin switches (2 pieces), 2N2222 transistor, Buzzer, 200Ω resistor.

 

Software: Atmel studio 6.1, progisp or flash magic.

 

Circuit Diagram and Working Explanation 

AVR Alarm Clock Circuit Diagram

For accurate timing, we have connected a 11.0592MHz crystal for clock. Now for disabling the internal clock of ATMEGA we have to change its LOW FUSE BITS. Remember we are not touching the high fuse bits so the JTAG communication would be still enabled.

 

For telling ATMEGA to disable internal clock and to work on external we need to set:                             

LOW USE BYTE = 0xFF or 0b11111111.

 

In circuit PORTB of ATMEGA32 is connected to data port LCD. Here one should remember to disable the JTAG communication in PORTC of ATMEGA by changing the high fuse bytes, if one wants to use the PORTC as a normal communication port. In 16x2 LCD there are 16 pins over all if there is a black light, if there is no back light there will be 14 pins. One can power or leave the back light pins. Now in the 14 pins there are 8 data pins (7-14 or D0-D7), 2 power supply pins (1&2 or VSS&VDD or gnd&+5v), 3rd pin for contrast control (VEE-controls how thick the characters should be shown), and 3 control pins (RS&RW&E)

 

In the circuit, you can observe that I have only took two control pins. This gives the flexibility of better understanding, the contrast bit and READ/WRITE are not often used so they can be shorted to ground. This puts LCD in highest contrast and read mode. We just need to control ENABLE and RS pins to send characters and data accordingly.

 

The connections which are done for LCD are given below:

PIN1 or VSS to ground

PIN2 or VDD or VCC to +5v power

PIN3 or VEE to ground (gives maximum contrast best for a beginner)

PIN4 or RS (Register Selection) to PD6 of uC

PIN5 or RW (Read/Write) to ground (puts LCD in read mode eases the communication for user)

PIN6 or E (Enable) to PD5 of uC

PIN7 or D0 to PB0 of uC

PIN8 or D1 to PB1 of uC

PIN9 or D2 to PB2 of uC

PIN10 or D3 to PB3 of uC

PIN11 or D4 to PB4 of uC

PIN12 or D5 to PB5 of uC

PIN13 or D6 to PB6 of uC

PIN14 or D7 to PB7 of uC

 

In the circuit you can see we have used 8bit communication (D0-D7) however this is not a compulsory, we can use 4bit communication (D4-D7) but with 4 bit communication program becomes a bit complex. So as shown in the above table we are connecting 10 pins of LCD to controller in which 8 pins are data pins and 2 pins for control.

 

Switch one is for enabling adjust feature between alarm and time. If the pin is low, we can adjust alarm time by pressing buttons. If its high buttons are for adjusting just TIME. There are FOUR buttons present here, first is for increment MINUTES in alarm or time. Second is for decrement MINUTES in alarm or time. Third is for increment HOUR in alarm or time. FOURTH is for decrement HOURS in alarm or time.

 

The capacitors present here is for nullifying the bouncing effect of buttons. If they are removed the controller might count more than one each time the button is pressed. The resistors connected for pins are for limiting the current, when the button is pressed to pull down the pin to the ground.

 

Whenever a button is pressed, The corresponding pin of controller gets pulled down to ground and thus the controller recognizes that certain button is pressed and corresponding action is taken.

 

First of all, the clock we choose here is 11059200 Hz, dividing it by 1024 gives 10800. So for every second we get 10800 pulses. So we are going to start a counter with 1024 prescaler to get the counter clock as 10800 Hz. Second we are going to use the CTC (Clear Timer Counter) mode of ATMEGA. There will be a 16 bit register where we can store a value (compare value), when the counter counts up to the compare value an interrupt is set to generate.

 

We are going to set the compare value to 10800, so basically we will have a ISR (Interrupt Service Routine on every comparison) for every second. So we are going to use this timely routine to get the clock we needed.

Timer Counter Control Register

BROWN(WGM10-WGM13): These bits are for selecting mode of operation for timer.

Waveform Generation Mode Bit Description

Now since we want the CTC mode with compare value in OCR1A byte, we just have to set WGM12 to one, remaining are left as they are zero by default.

RED (CS10,CS11,CS12): These three bits are for choosing the prescalar and so getting appropriate counter clock.

Clock Select Bit Description

Since we want a 1024 as prescaling, we have to set both CS12 and CS10.

 

Now there is an another register which we should consider:

Timer Counter Interrupt Mask Register

GREEN (OCIE1A): This bit must be set for getting an interrupt on compare match between counter value and OCR1A value(10800) which we set.

Output Compare Register

OCR1A value (counter compare value), is written in above register.

 

Programming Explanation

The working of Alarm clock is explained step by step in the below code:

#include <avr/io.h>

//header to enable data flow control over pins

#define F_CPU 1000000      

//telling controller crystal frequency attached

#include <util/delay.h>

//header to enable delay function in program

#define    E   5

//giving name “enable”  to 5th pin of PORTD, since it Is connected to LCD enable pin

#define RS  6

//giving name “registerselection” to 6th pin of PORTD, since is connected to LCD RS pin

void send_a_command(unsigned char command);

 void send_a_character(unsigned char character);

void send_a_string(char *string_of_characters);

ISR(TIMER1_COMPA_vect);

static volatile int SEC =0;//allocating integer memory for storing seconds

static volatile int MIN =0;// allocating integer memory for storing minutes

static volatile int HOU =0;// allocating integer memory for storing hours

int main(void)

{

DDRA = 0b11000000;//only pin7 and pin8 of port a as output

DDRD = 0xFF;

_delay_ms(50);//giving delay of 50ms

 DDRB = 00FF;//Taking portB as output.

TCCR1B |=(1<<CS12)|(1<<CS10)|(1<<WGM12);// setting prescale and CTC mode

OCR1A=10800;//setting compare value equal to counter clock frequency to get an interrupt every second

sei();// enabling global interrupts

TIMSK |=(1<<OCIE1A);//compare match interrupt enable

char SHOWSEC [2];//seconds displaying character on LCD

char SHOWMIN [2];//minutes displaying character on LCD

char SHOWHOU [2];// hours displaying character on LCD

int ALSEC = 0;//alarm seconds storing memory

int ALMIN = 0;//alarm minutes storing memory

int ALHOU = 0;//alarm hours storing memory

char SHOWALSEC [2];//alarm  seconds displaying character on LCD

char SHOWALMIN [2];// alarm minutes displaying character on LCD

char SHOWALHOU [2];//alarm hours displaying character on LCD

send_a_command(0x01); //Clear Screen 0x01 = 00000001

_delay_ms(50);

send_a_command(0x38);//telling lcd we are using 8bit command /data mode

_delay_ms(50);

send_a_command(0b00001111);//LCD SCREEN ON and courser blinking

while(1)

{

itoa(HOU/10,SHOWHOU,10); //command for putting variable number in LCD(variable number, in which character to replace, which base is variable(ten here as we are counting number in base10))

send_a_string(SHOWHOU);// telling the display to show character(replaced by variable number) of first person after positioning the courser on LCD

// displaying tens place of hours above

itoa(HOU%10,SHOWHOU,10);

 send_a_string(SHOWHOU);

// displaying ones place of hours above

send_a_string (":");//displaying character

send_a_command(0x80 + 3);// shifting cursor  to 4th shell

itoa(MIN/10,SHOWMIN,10);///as integer cannot store decimal values, when MIN=9, we have MIN/10 = 0.9(actual), = 0 for CPU(as integer cannot store decimal values)

send_a_string(SHOWMIN);

// displaying tens place of minutes above

itoa(MIN%10,SHOWMIN,10);

send_a_string(SHOWMIN);

// displaying ones place of minutes above

send_a_command(0x80 + 5);// shifting cursor  to 6th shell

send_a_string (":");

send_a_command(0x80 + 6);// shifting cursor  to 7th shell

if (bit_is_set(PINA,5))//if alarm pin is high

{

send_a_string(" ALM:ON ");//show alarm is on

if ((ALHOU==HOU)&(ALMIN==MIN)&(ALSEC==SEC))//alarm minute=min //and alarm hours= time hours and alarm seconds= time seconds

{

PORTA|=(1<<PINB7);//buzzer on

}

}

if (bit_is_clear(PINA,5))//if alarm pin is low

{

send_a_string(" ALM:OFF");//show alarm is off

PORTA&=~(1<<PINB7);//buzzer off

}

send_a_command(0x80 + 0x40 + 0);// move courser to second line zero position

send_a_string ("ALARM:");//show string of characters

send_a_command(0x80 + 0x40 + 7);//move to eight position on second line

itoa(ALHOU/10,SHOWALHOU,10);

send_a_string(SHOWALHOU);

itoa(ALHOU%10,SHOWALHOU,10);

send_a_string(SHOWALHOU);

send_a_command(0x80 + 0x40 +9);

send_a_string (":");

send_a_command(0x80 + 0x40 +10);

// Showing alarm hours above

itoa(ALMIN/10,SHOWALMIN,10);

send_a_string(SHOWALMIN);

itoa(ALMIN%10,SHOWALMIN,10);

send_a_string(SHOWALMIN);

send_a_command(0x80 + 0x40+ 12);

send_a_string (":");

send_a_command(0x80 + 0x40+ 13);

// Showing alarm minutes above                           

itoa(ALSEC/10,SHOWALSEC,10);

send_a_string(SHOWALSEC);

itoa(ALSEC%10,SHOWALSEC,10);

send_a_string(SHOWALSEC);

send_a_command(0x80 + 0);

// Showing alarm seconds above

send_a_command(0x80 + 0);// shifting cursor  to 0th position

if (bit_is_set(PINA,4)) // if switch is set to adjust TIME

{

if (bit_is_clear(PINA,0)) //button 1 is pressed

{

if (MIN<60)

{

MIN++;//if minutes of TIME are less than 60 increment it by one

_delay_ms(220);

}

if (MIN==60)

{

if (HOU<24)

{

HOU++;//if minutes of TIME =60 when button is pressed //and hours of TIME are less than 24, increment hour by one.

}

MIN=0;//if minute of TIME=60,reset it to zero

_delay_ms(220);

}

}

if (bit_is_clear(PINA,1))

{

if (MIN>0)

{

MIN--; //if second button is pressed and minute of TIME are //greater than zero, decrease minutes by one 

_delay_ms(220);

}

}

if (bit_is_clear(PINA,2))

{

if (HOU<24)

{

HOU++; //if third button is pressed and hours of TIME are less //than 24, increment the hour by one

}

_delay_ms(220);

if (HOU==24)

{

HOU=0;//if hour of TIME equal to 24, reset hour of TIME

}

}

if (bit_is_clear(PINA,3))

{

if (HOU>0)

{

HOU--;//if fourth button is pressed and hours of TIME are //greater than ZERO, decrement the hour by one

_delay_ms(220);

}

}             

}

if (bit_is_clear(PINA,4))//if alarm adjust is set

{

if (bit_is_clear(PINA,0))

{

if (ALMIN<60)

{

ALMIN++;

_delay_ms(220);

}

if (ALMIN==60)

{

if (ALHOU<24)

{

ALHOU++;

}

ALMIN=0;

_delay_ms(220);

}

}

if (bit_is_clear(PINA,1))

{

if (ALMIN>0)

{

ALMIN--;

_delay_ms(220);

}

}

if (bit_is_clear(PINA,2))

{

if (ALHOU<24)

{

ALHOU++;

}

_delay_ms(220);

 if (ALHOU==24)

{

ALHOU=0;

}

}

if (bit_is_clear(PINA,3))

{

if (ALHOU>0)

{

ALHOU--;

_delay_ms(220);

}

}

}

}

}

// Everything follows the same as described above for TIME      

ISR(TIMER1_COMPA_vect) //loop to be executed on counter compare match

{

if (SEC<60)

{

SEC++;

}

if (SEC==60)

{

if (MIN<60)

{

MIN++;

}

SEC=0;

}

if (MIN==60)

{

if (HOU<24)

{

HOU++;

}

MIN=0;

}

if (HOU==24)

{

HOU=0;

}

}

void send_a_command(unsigned char command)

{

PORTA = command;

PORTD &= ~ (1<<RS); //putting 0 in RS to tell lcd we are sending command

PORTD |= 1<<E; //telling lcd to receive command /data at the port

_delay_ms(50);

PORTD &= ~1<<E;//telling lcd we completed sending data

PORTA= 0;

}

void send_a_character(unsigned char character)

{

PORTA= character;

PORTD |= 1<<RS;//telling LCD we are sending data not commands

PORTD |= 1<<E;//telling LCD to start receiving command/data

_delay_ms(50);

PORTD &= ~1<<E;//telling lcd we completed sending data/command

PORTA = 0;

}

}

void send_a_string(char *string_of_characters)

{

while(*string_of_characters > 0)

{

send_a_character(*string_of_characters++);

}

}
Code: 

/* ---- Code for Digital Clock with Alarm using AVR Microcontroller ------ */ 

#include <avr/io.h>
#define F_CPU 11059200
#include <util/delay.h>
#include <stdlib.h>
#include <avr/interrupt.h>

#define enable            5
#define registerselection 6

void send_a_command(unsigned char command);
void send_a_character(unsigned char character);
void send_a_string(char *string_of_characters);

ISR(TIMER1_COMPA_vect);

static volatile int SEC =0;
static volatile int MIN =0;
static volatile int HOU =0;

int main(void)
{
    DDRA = 0b11000000;
    DDRB = 0xFF;
    DDRD = 0xFF;
    
    TCCR1B |=(1<<CS12)|(1<<CS10)|(1<<WGM12);
    OCR1A=10800;
    sei();
    TIMSK |=(1<<OCIE1A);
    
    char SHOWSEC [2];
    char SHOWMIN [2];
    char SHOWHOU [2];
    
    int ALSEC = 0;
    int ALMIN = 0;
    int ALHOU = 0;
    char SHOWALSEC [2];
    char SHOWALMIN [2];
    char SHOWALHOU [2];
    send_a_command(0x01); //Clear Screen 0x01 = 00000001
    _delay_ms(50);
    send_a_command(0x38);
    _delay_ms(50);
    send_a_command(0b00001111);
    _delay_ms(50);
    
    
    while(1)
    {
            
            itoa(HOU/10,SHOWHOU,10);
            send_a_string(SHOWHOU);
            itoa(HOU%10,SHOWHOU,10);
            send_a_string(SHOWHOU);
            send_a_string (":");
            send_a_command(0x80 + 3);

            itoa(MIN/10,SHOWMIN,10);
            send_a_string(SHOWMIN);
            itoa(MIN%10,SHOWMIN,10);
            send_a_string(SHOWMIN);
            send_a_command(0x80 + 5);
            send_a_string (":");
            send_a_command(0x80 + 6);
            
            itoa(SEC/10,SHOWSEC,10);
            send_a_string(SHOWSEC);
            itoa(SEC%10,SHOWSEC,10);
            send_a_string(SHOWSEC);
            
            if (bit_is_set(PINA,5))
            {
                send_a_string(" ALM:ON ");
                if ((ALHOU==HOU)&(ALMIN==MIN)&(ALSEC==SEC))
                {
                        PORTA|=(1<<PINB7);
                }
            }
            if (bit_is_clear(PINA,5))
            {
                send_a_string(" ALM:OFF");
                PORTA&=~(1<<PINB7);
            }
            send_a_command(0x80 + 0x40 + 0);
            
            send_a_string ("ALARM:");
            send_a_command(0x80 + 0x40 + 7);
            
            itoa(ALHOU/10,SHOWALHOU,10);
            send_a_string(SHOWALHOU);
            itoa(ALHOU%10,SHOWALHOU,10);
            send_a_string(SHOWALHOU);
            send_a_command(0x80 + 0x40 +9);
            send_a_string (":");
            send_a_command(0x80 + 0x40 +10);

            itoa(ALMIN/10,SHOWALMIN,10);
            send_a_string(SHOWALMIN);
            itoa(ALMIN%10,SHOWALMIN,10);
            send_a_string(SHOWALMIN);
            send_a_command(0x80 + 0x40+ 12);
            send_a_string (":");
            send_a_command(0x80 + 0x40+ 13);
            
            itoa(ALSEC/10,SHOWALSEC,10);
            send_a_string(SHOWALSEC);
            itoa(ALSEC%10,SHOWALSEC,10);
            send_a_string(SHOWALSEC);
            send_a_command(0x80 + 0);

        if (bit_is_set(PINA,4))
        {
            if (bit_is_clear(PINA,0))
            {
                if (MIN<60)
                {
                    MIN++;
                    _delay_ms(220);
                }
                if (MIN==60)
                {
                    if (HOU<24)
                    {
                        HOU++;
                    }
                    MIN=0;
                    _delay_ms(220);
                }
            }
            if (bit_is_clear(PINA,1))
            {
                if (MIN>0)
                {
                    MIN--;
                    _delay_ms(220);
                }
            }
            if (bit_is_clear(PINA,2))
            {
                if (HOU<24)
                {
                    HOU++;
                }
                _delay_ms(220);
                if (HOU==24)
                {
                    HOU=0;
                }
            }
            if (bit_is_clear(PINA,3))
            {
                if (HOU>0)
                {
                    HOU--;
                    _delay_ms(220);
                }
            }
        }
        
        
        if (bit_is_clear(PINA,4))
        {
            if (bit_is_clear(PINA,0))
            {
                    if (ALMIN<60)
                    {
                        ALMIN++;
                        _delay_ms(220);
                    }
                    if (ALMIN==60)
                    {
                        if (ALHOU<24)
                        {
                            ALHOU++;
                        }
                        ALMIN=0;
                        _delay_ms(220);
                    }
            }
            if (bit_is_clear(PINA,1))
            {
                if (ALMIN>0)
                {
                    ALMIN--;
                    _delay_ms(220);
                }
            }
            if (bit_is_clear(PINA,2))
            {
                if (ALHOU<24)
                {
                    ALHOU++;
                }
                _delay_ms(220);
                if (ALHOU==24)
                {
                    ALHOU=0;
                }
            }
            if (bit_is_clear(PINA,3))
            {
                if (ALHOU>0)
                {
                    ALHOU--;
                    _delay_ms(220);
                }
            }
        }
    }
}

ISR(TIMER1_COMPA_vect)
{
    if (SEC<60)
    {
        SEC++;
    }
    if (SEC==60)
    {
        if (MIN<60)
        {
            MIN++;
        }
        SEC=0;
    }
    if (MIN==60)
    {
        if (HOU<24)
        {
            HOU++;
        }
        MIN=0;
    }
    if (HOU==24)
    {
        HOU=0;
    }

}

void send_a_command(unsigned char command)
{
    PORTB = command;
    PORTD &= ~ (1<<registerselection);
    PORTD |= 1<<enable;
    _delay_ms(3);
    PORTD &= ~1<<enable;
    PORTB = 0xFF;
}

void send_a_character(unsigned char character)
{
    PORTB = character;
    PORTD |= 1<<registerselection;
    PORTD |= 1<<enable;
    _delay_ms(3);
    PORTD &= ~1<<enable;
    PORTB = 0xFF;
}
void send_a_string(char *string_of_characters)
{
    while(*string_of_characters > 0)
    {
        send_a_character(*string_of_characters++);
    }
}

Video: 

Comments (4)

  • hare patnaik's picture
    hare patnaik

    rtc clock design with alarm function

    Sep 08, 2015
  • Brandon's picture
    Brandon

    Hello how do I get rid of the blinking cursor ?

    Mar 11, 2016
  • Milind's picture
    Milind

    Sir I am trying to build the LCD alarm clock using atmega32, but I am not able to burn the fuse bits in the mcu for 11.059200MHz. please provide the details of the same

    Oct 03, 2016
  • Milind's picture
    Milind

    Sir,
    I have built the clock on a breadboard.but I am unable to burn the fuse bits in atmega32. Also can I make the clock using 1mhz frequency(default) using 64 prescaler? Please tell the fuse bits for 11.059200 MHz for atmega32.

    Oct 21, 2016

Leave a comment