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
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.
BROWN(WGM10-WGM13): These bits are for selecting mode of operation for timer.
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.
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:
GREEN (OCIE1A): This bit must be set for getting an interrupt on compare match between counter value and OCR1A value(10800) which we set.
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 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++);
}
}
Comments
LCD alarm clock using atmega32
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
Atmega32 LCD alarm clock
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.
Hello,does it work one
Hello,does it work one hundred percent?
Please answer me :-D
Yes it works 100%
Yes make sure all connection and change ocart1:10800 to 1350 in code
Clock is working slowly
I have connected all the wires and components and I copy above code and created hex file and uploaded it in atmega32 clock is working but at very slow rate
How to overcome this problem.
Clock is working slowly
I have connected all the wires and components and I copy above code and created hex file and uploaded it in atmega32 clock is working but at very slow rate
How to overcome this problem.
I found solution
If your clock is running slow then change 10800 prescale into 1350 (10800/8) this works in my case
I hope it works on your case also
rtc clock design with alarm function