I'm working on a RTC Digital clock project to run a 24-hour format clock using a 4-digit 7-segment LED with a DS1302 module and 3 buttons as the figure below:
Button on the right is button 1, to the left is button 2 and 3 accordingly. The LED pins are connected to Arduino as: pin A - G use PORTD0 to PORTD6, Digit1-Digit4 pins use PORTB0 to PORTB3 accordingly. Button 1, 2, 3 use PORTC0, C1, C2, and DS1302 Clock pin use PORTC4, Data pin use PORTC5 and Reset pin use PORTC6. Instead of using DS1302 library, I wrote the logic code myself.
Press button 1 turn into Set time mode or press again to run the clock. Press button 2 to choose the number I want to change, button 3 to increase the chosen number. However, it's not work as intended, the clock doesn't run at all, just flickering 0 or 1, and the buttons are messsed up.
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#define DS1302_CLK PC3
#define DS1302_CLK_DDR DDRC
#define DS1302_CLK_PORT PORTC
#define DS1302_DIO PC4
#define DS1302_DIO_DDR DDRC
#define DS1302_DIO_PORT PORTC
#define DS1302_DIO_PIN PINC
#define DS1302_CE PC5
#define DS1302_CE_DDR DDRC
#define DS1302_CE_PORT PORTC
#define DS1302_DELAY_USEC 3
void DS1302_Init(void) {
// CE - output, set low
DS1302_CE_DDR |= (1 << DS1302_CE);
DS1302_CE_PORT &= ~(1 << DS1302_CE);
// CLK - output, set low
DS1302_CLK_DDR |= (1 << DS1302_CLK);
DS1302_CLK_PORT &= ~(1 << DS1302_CLK);
// DIO - output, set low (for now)
DS1302_DIO_DDR |= (1 << DS1302_DIO);
DS1302_DIO_PORT &= ~(1 << DS1302_DIO);
}
void DS1302_TransmitByte(uint8_t byte)
{
// DIO - output, set low
DS1302_DIO_DDR |= (1 << DS1302_DIO);
DS1302_DIO_PORT &= ~(1 << DS1302_DIO);
// transmit byte, lsb-first
for (uint8_t i = 0; i < 8; i++)
{
if ((byte >> i) & 0x01)
{
// set high
DS1302_DIO_PORT |= (1 << DS1302_DIO);
}
else
{
// set low
DS1302_DIO_PORT &= ~(1 << DS1302_DIO);
}
// send CLK signal
DS1302_CLK_PORT |= (1 << DS1302_CLK);
_delay_us(DS1302_DELAY_USEC);
DS1302_CLK_PORT &= ~(1 << DS1302_CLK);
}
}
uint8_t DS1302_ReceiveByte(void) {
// DIO - input
DS1302_DIO_DDR &= ~(1 << DS1302_DIO);
// receive byte, lsb-first
uint8_t byte = 0;
for (uint8_t i = 0; i < 8; i++)
{
if (DS1302_DIO_PIN & (1 << DS1302_DIO))
{
byte |= (1 << i);
}
// send CLK signal
DS1302_CLK_PORT |= (1 << DS1302_CLK);
_delay_us(DS1302_DELAY_USEC);
DS1302_CLK_PORT &= ~(1 << DS1302_CLK);
}
return byte;
}
uint8_t dec2bcd(uint8_t dec)
{
return ((dec / 10 * 16) + (dec % 10));
}
uint8_t bcd2dec(uint8_t bcd)
{
return ((bcd / 16 * 10) + (bcd % 16));
}
volatile int timer = 0;
volatile bool one_minute = false;
volatile bool one_second = false;
int hour1 = 0;
int hour2 = 0;
int minute1 = 0;
int minute2 = 0;
int main (void)
{
DS1302_Init();
DDRD = 0xFF;
DDRB |= (1 << 0); //Digit 1
DDRB |= (1 << 1); //Digit 2
DDRB |= (1 << 2); //Digit 3
DDRB |= (1 << 3); //Digit 4
DDRC &= ~(1 << 0); // BUTTON 1
DDRC &= ~(1 << 1); // BUTTON 2
DDRC &= ~(1 << 2); // BUTTON 3
TCCR1B |= (1 << WGM12); // Turn on the CTC mode for Timer 1
TCCR1B |= (1 << CS12 ) | (1 << CS10); // Set up Timer 1 with the prescaler of 1024
OCR1A = 15624; // Set CTC compare value to 0.125Hz at 16 MHz AVR clock , with a prescaler of 1024
TIMSK1 = 1 << OCIE1A; // Enable Output Compare A Match Interrupt
sei(); // Enable the Global Interrupt Bit
while (1)
{
if (!(PINC & (1 << PINC2))) // Button 4 is used to switch from 'time mode' to 'set time mode' for the system
{
_delay_ms(250);
set_time();
}
if (one_second)
{
uint8_t bytes[8];
DS1302_CE_PORT |= (1 << DS1302_CE);
DS1302_TransmitByte(0xBF);
for (uint8_t i = 0; i < sizeof(bytes); i++)
{
bytes[i] = DS1302_ReceiveByte();
}
DS1302_CE_PORT &= ~(1 << DS1302_CE);
int minute = bcd2dec(bytes[1]);
int hour = bcd2dec(bytes[2]);
hour1 = hour / 10;
hour2 = hour % 10;
minute1 = minute / 10;
minute2 = minute % 10;
one_second = false;
}
display_time();
time_system();
}
}
ISR (TIMER1_COMPA_vect)
{
one_second = true;
timer++;
if (timer > 59)
{
timer = 0;
one_minute = true;
}
}
void time_system()
{
if (one_minute)
{
minute2++;
one_minute = false;
}
if (minute2 > 9)
{
minute2 = 0;
minute1++;
}
if (minute1 > 5)
{
minute1 = 0;
minute2 = 0;
if (hour1 == 0 && hour2 > 9)
{
hour2 = 0;
hour1++;
}
if (hour1 == 1 && hour2 > 9)
{
hour2 = 0;
hour1++;
}
if (hour1 == 2 && hour2 >= 3)
{
hour1 = 0;
hour2 = 0;
}
else
{
hour2++;
}
}
}
void set_time()
{
int set_h1 = hour1;
int set_h2 = hour2;
int set_m1 = minute1;
int set_m2 = minute2;
int change_digit = 1;
bool button_3_pressed = false;
while (button_3_pressed == false)
{
if (!(PINC & (1 << PINC2)))
{
_delay_ms(250);
uint8_t bytes[8];
uint8_t minute = dec2bcd(set_m1 * 10 + set_m2);
uint8_t hour = dec2bcd(set_h1 * 10 + set_h2);
bytes[1] = minute;
bytes[2] = hour;
DS1302_CE_PORT |= (1 << DS1302_CE);
DS1302_TransmitByte(0xBE);
for (uint8_t i = 0; i < sizeof(bytes); i++)
{
DS1302_TransmitByte(bytes[i]);
}
DS1302_CE_PORT &= ~(1 << DS1302_CE);
}
if (change_digit == 1)
{
hour1_display(set_h1);
}
if (change_digit == 2)
{
hour2_display(set_h2);
}
if (change_digit == 3)
{
minute1_display(set_m1);
}
if (change_digit == 4)
{
minute2_display(set_m2);
}
if (!(PINC & (1 << PINC1)))
{
_delay_ms(250);
if (change_digit == 1)
{
change_digit = 2;
}
else if (change_digit == 2)
{
change_digit = 3;
}
else if (change_digit == 3)
{
change_digit = 4;
}
else if (change_digit == 4)
{
change_digit = 1;
}
}
if (!(PINC & (1 << PINC2)))
{
_delay_ms(250);
timer = 0;
button_3_pressed = true;
}
if (!(PINC & (1 << PINC0)) && change_digit == 1 )
{
_delay_ms(250);
if ( set_h1 < 1 && set_h2 >= 5)
{
set_h1++;
}
else if ( set_h1 < 2 && set_h2 <= 4)
{
set_h1++;
}
else
{
set_h1 = 0;
}
}
else if (!(PINC & (1 << PINC0)) && change_digit == 2)
{
_delay_ms(250);
if ( (set_h1 == 0 || set_h1 == 1) && set_h2 < 9)
{
set_h2++;
}
else if (set_h1 == 2 && set_h2 < 3)
{
set_h2++;
}
else
{
set_h2 = 0;
}
}
else if (!(PINC & (1 << PINC0)) && change_digit == 3 )
{
_delay_ms(250);
set_m1++;
if (set_m1 > 5)
{
set_m1 = 0;
}
}
else if (!(PINC & (1 << PINC0)) && change_digit == 4)
{
_delay_ms(250);
set_m2++;
if (set_m2 > 9)
{
set_m2 = 0;
}
}
}
button_3_pressed = false;
hour1 = set_h1;
hour2 = set_h2;
minute1 = set_m1;
minute2 = set_m2;
}
void display_time()
{
hour1_display(hour1);
_delay_ms(5);
hour2_display(hour2);
_delay_ms(5);
minute1_display(minute1);
_delay_ms(5);
minute2_display(minute2);
_delay_ms(5);
}
void hour1_display(int i)
{
PORTB |= (1 << 0);
PORTB &= ~(1 << 1);
PORTB &= ~(1 << 2);
PORTB &= ~(1 << 3);
if (i == 0)
{
number_0();
}
else if (i == 1)
{
number_1();
}
else if (i == 2)
{
number_2();
}
}
void hour2_display(int i)
{
PORTB |= (1 << 1);
PORTB &= ~(1 << 0);
PORTB &= ~(1 << 2);
PORTB &= ~(1 << 3);
if (i == 0)
{
number_0();
}
else if (i == 1)
{
number_1();
}
else if (i == 2)
{
number_2();
}
else if (i == 3)
{
number_3();
}
else if (i == 4)
{
number_4();
}
else if (i == 5)
{
number_5();
}
else if (i == 6)
{
number_6();
}
else if (i == 7)
{
number_7();
}
else if (i == 8)
{
number_8();
}
else if (i == 9)
{
number_9();
}
}
void minute1_display(int i)
{
PORTB |= (1 << 2);
PORTB &= ~(1 << 0);
PORTB &= ~(1 << 1);
PORTB &= ~(1 << 3);
if (i == 0)
{
number_0();
}
else if (i == 1)
{
number_1();
}
else if (i == 2)
{
number_2();
}
else if (i == 3)
{
number_3();
}
else if (i == 4)
{
number_4();
}
else if (i == 5)
{
number_5();
}
}
void minute2_display(int i)
{
PORTB |= (1 << 3);
PORTB &= ~(1 << 0);
PORTB &= ~(1 << 1);
PORTB &= ~(1 << 2);
if (i == 0)
{
number_0();
}
else if (i == 1)
{
number_1();
}
else if (i == 2)
{
number_2();
}
else if (i == 3)
{
number_3();
}
else if (i == 4)
{
number_4();
}
else if (i == 5)
{
number_5();
}
else if (i == 6)
{
number_6();
}
else if (i == 7)
{
number_7();
}
else if (i == 8)
{
number_8();
}
else if (i == 9)
{
number_9();
}
}
void number_0()
{
PORTD = 0b11000000;
}
void number_1()
{
PORTD = 0b11111001;
}
void number_2()
{
PORTD = 0b10100100;
}
void number_3()
{
PORTD = 0b10110000;
}
void number_4()
{
PORTD = 0b10011001;
}
void number_5()
{
PORTD = 0b10010010;
}
void number_6()
{
PORTD = 0b10000010;
}
void number_7()
{
PORTD = 0b11111000;
}
void number_8()
{
PORTD = 0b10000000;
}
void number_9()
{
PORTD = 0b10010000;
}