임베디드시스템/AVR

[AVR] DS1302 RTC 값을 I2C LCD에 Display

KHJ_940803 2021. 11. 4. 10:54

 

목표 : Pc의 comport master를 이용해 시간을 설정하고 설정된 시간과 날짜를 I2C LCD 에 출력한다.

 

개발 툴 : atmel studio

 

개발 보드 : ATMEGA128A

 

PC Uart 통신 툴 : Comport master

 

개발 기간 : 2021년 8월 22일

 

소스코드

 

DS1302.c

/*
 * DS1302.c
 *
 * Created: 2019-07-11 오후 2:09:16
 */ 
#include "DS1302.h"


struct _ds1302 stTime;

char *dayofweek[7] = {"SUN", "MON", "TUE", "WED",
	"THU", "FRI", "SAT"};

void DS1302_Init(void)
{
	DS1302_CLK_DDR |= (1<<DS1302_CLK);
	DS1302_DAT_DDR |= (1<<DS1302_DAT);
	DS1302_RST_DDR |= (1<<DS1302_RST);
}

void DS1302_Selected(void)
{
	DS1302_RST_PORT |= (1<<DS1302_RST); // CE High
}

void DS1302_Deselected(void)
{
	DS1302_RST_PORT &= ~(1<<DS1302_RST); // CE High
}

void DS1302_Clock(void)
{
	DS1302_CLK_PORT &= ~(1<<DS1302_CLK); // clk l->h->l
	DS1302_CLK_PORT |= (1<<DS1302_CLK);
	DS1302_CLK_PORT &= ~(1<<DS1302_CLK);

}

void DS1302_DataBitSet(void)
{
	DS1302_DAT_PORT |= (1<<DS1302_DAT); // data bit high
}

void DS1302_DataBitReset(void)
{
	DS1302_DAT_PORT &= ~(1<<DS1302_DAT); // data bit low
}


uint8_t DS1302_Read_DataPin(void)
{
	return (DS1302_DAT_PIN & (1<<DS1302_DAT));
}

void DS1302_Change_ReadMode(void)
{
	DS1302_DAT_DDR &= ~(1<<DS1302_DAT); // read mode
}

void DS1302_Change_WriteMode(void)
{
	DS1302_DAT_DDR |= (1<<DS1302_DAT); // write mode
}

uint8_t decimal_to_bcd(uint8_t decimal)
{
	return ( ((decimal/10)<<4) | (decimal%10) );
}

uint8_t bcd_to_decimal(uint8_t bcd)
{
	return ( ((bcd>>4) * 10) + (bcd & 0x0f) );
}

void DS1302_TxData(uint8_t txData)
{
	DS1302_Change_WriteMode();
	for (int i=0; i<8; i++)
	{
		if (txData & (1<<i))
		DS1302_DataBitSet();
		else
		DS1302_DataBitReset();
		
		DS1302_Clock();
	}
}

uint8_t DS1302_RxData(void)
{
	uint8_t rxData = 0;
	DS1302_Change_ReadMode();
	for (int i=0; i<8; i++)
	{
		rxData |= DS1302_Read_DataPin() ? (1<<i) : 0;
		// data = A ? b : c;  A가 참이면 b 반환, A가 거짓이면 c 반환
		DS1302_Clock();
	}
	return rxData;
}

void DS1302_WriteData(uint8_t address, uint8_t data)
{
	DS1302_Selected();
	DS1302_TxData(address);
	DS1302_TxData(decimal_to_bcd(data));
	DS1302_Deselected();
}

uint8_t DS1302_ReadData(uint8_t address)
{
	uint8_t rxData = 0;
	DS1302_Selected();
	DS1302_TxData(address+1);
	rxData = DS1302_RxData();
	DS1302_Deselected();
	
	return bcd_to_decimal(rxData);
}



void DS1302_GetTime(DS1302 *timeData)
{
	timeData->seconds = DS1302_ReadData(ADDRESS_SECONDS); // sec
	timeData->minutes = DS1302_ReadData(ADDRESS_MINUTES);
	timeData->hour = DS1302_ReadData(ADDRESS_HOUR);
}

void DS1302_GetDate(DS1302 *dateData)
{
	dateData->date = DS1302_ReadData(ADDRESS_DATE);
	dateData->month = DS1302_ReadData(ADDRESS_MONTH);
	dateData->dayofweek = DS1302_ReadData(ADDRESS_DAYOFWEEK);
	dateData->year = DS1302_ReadData(ADDRESS_YEAR);
}

void DS1302_SetTimeDates(DS1302 timeDate)
{
	DS1302_WriteData(ADDRESS_SECONDS, timeDate.seconds);
	DS1302_WriteData(ADDRESS_MINUTES, timeDate.minutes);
	DS1302_WriteData(ADDRESS_HOUR, timeDate.hour);
	DS1302_WriteData(ADDRESS_DATE, timeDate.date);
	DS1302_WriteData(ADDRESS_MONTH, timeDate.month);
	DS1302_WriteData(ADDRESS_DAYOFWEEK, timeDate.dayofweek);
	DS1302_WriteData(ADDRESS_YEAR, timeDate.year);
}

 

DS1302.h

/*
 * DS1302.h
 *
 * Created: 2019-07-11 오후 2:09:32
 */ 


#ifndef DS1302_H_
#define DS1302_H_

#include <avr/io.h>

#define DS1302_CLK_DDR		DDRG
#define DS1302_CLK_PORT		PORTG
#define DS1302_DAT_DDR		DDRG
#define DS1302_DAT_PORT		PORTG
#define DS1302_DAT_PIN		PING
#define DS1302_RST_DDR		DDRG
#define DS1302_RST_PORT		PORTG
#define DS1302_CLK			0
#define DS1302_DAT			1
#define DS1302_RST			2

#define ADDRESS_SECONDS		0x80
#define ADDRESS_MINUTES		0x82
#define ADDRESS_HOUR		0x84
#define ADDRESS_DATE		0x86
#define ADDRESS_MONTH		0x88
#define ADDRESS_DAYOFWEEK	0x8a
#define ADDRESS_YEAR		0x8c

typedef struct _ds1302
{
	uint8_t seconds;
	uint8_t minutes;
	uint8_t hour;
	uint8_t date;
	uint8_t month;
	uint8_t dayofweek; //sun=1, mon=2... sat=7
	uint8_t year;
	uint8_t ampm; // 0:pm, 1:am
	uint8_t hourMode; // 0:24, 1:12
	//char *paDayofweek[7];
}DS1302;

extern struct _ds1302 stTime;
extern char *dayofweek[7];

void DS1302_Init(void);
void DS1302_Selected(void);
void DS1302_Deselected(void);
void DS1302_Clock(void);
void DS1302_DataBitSet(void);
void DS1302_DataBitReset(void);
uint8_t DS1302_Read_DataPin(void);
void DS1302_Change_ReadMode(void);
void DS1302_Change_WriteMode(void);
uint8_t decimal_to_bcd(uint8_t decimal);
uint8_t bcd_to_decimal(uint8_t bcd);
void DS1302_TxData(uint8_t txData);
uint8_t DS1302_RxData(void);
void DS1302_WriteData(uint8_t address, uint8_t data);
uint8_t DS1302_ReadData(uint8_t address);
void DS1302_GetTime(DS1302 *timeData);
void DS1302_GetDate(DS1302 *dateData);
void DS1302_SetTimeDates(DS1302 timeDate);



#endif /* DS1302_H_ */

 

 

/*
 * uart0.h
 *
 * Created: 2021-08-17 오전 10:26:36
 */ 


#ifndef UART0_H_
#define UART0_H_

void UART0_init(void);
void UART0_transmit(char data);
unsigned char UART0_receive(void);
void UART0_print_string(char *str);
void UART0_tx_rx_test(void);
uint8_t isRxString();
uint8_t *getRxString();

#endif /* UART0_H_ */

 

uart0.c

/*
 * uart0.c
 *
 * Created: 2021-08-17 오전 10:26:57
 */ 
#define F_CPU 16000000UL

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>   // interrupt 관련 lib가 들어 있다. 
#include "uart0.h"

volatile uint8_t rxString[100]={0};   
volatile uint8_t rxReadyFlag=0;   // \n detect flag 
volatile int rxindex=0;

// UART0로 부터 1byte가 들어 오면 이것을 자동 실행
// RX interrupt 서비스 루틴
ISR(USART0_RX_vect)
{
	volatile uint8_t data;
	
	data = UDR0;    // UART 하드웨어 버퍼 UDR0를 읽어서 data에 저장 
	
	if (data == '\n' || data == '\r')   // led1on\n
	{                                   // 
		rxString[rxindex] = '\0';
		rxindex=0;
		rxReadyFlag=1;      // 완전한 msg를 받았다는 신호를 알려준다. 
	}
	else
	{
		rxString[rxindex++] = data;   //  rxString[rxindex] = data;   rxindex++;
	}
}

uint8_t isRxString()
{
	return rxReadyFlag;
}

uint8_t *getRxString()
{
	rxReadyFlag=0;
	return rxString;
}
// uart0를 초기화 하는 함수
#define BAUD 9600
#define BAUD_9600  ( (F_CPU / (BAUD * 8)) -1)   // 207
void UART0_init(void)
{
	UBRR0H = 0x00;
	UBRR0L = 207;   // 9600으로 설정
	
	UCSR0A |= ( 1 << U2X0);   // 2배속 sampling속도를 8로 
	UCSR0C |= 0x06;   // 비동기, data길이: 8bit/nonpairty/1stopbit
	// UART0를 송신.수신이 가능 하도록 enable
	// RXEN0 : 수신이 가능 하도록 enable 
	// TXEN0  : 송신이 가능 하도록 
	// RXCIE0  : UART0로 부터 1byte가 들어 오면 interrupt가 뜨도록 설정 
	UCSR0B = ( (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0));
}
// UART0로 1byte를 전송하는 함수
void UART0_transmit(char data)
{
	while ( !(UCSR0A & (1 << UDRE0)))   // UDRE0의 bit가 1이 되는순간 exit
		;
	UDR0 = data;   // UDR(Uart Data Register)에 값을 넣는다. 
}
// UART0로 부터 1byte를 읽어 오는 함수
unsigned char UART0_receive(void)
{
	// 76543210
	// 1   ===> RXC0 bit (RX complet)
	while ( !(UCSR0A & (1 << RXC0)))   // RXC0의 bit가 1이 되는순간 exit
		;      // nop : no operation
	
	return UDR0;   // 수신된 1byte를 return 	
}
/*
*  UART0로 string(문자열: 끝은 \0)을 출력 하는 함수 
*/
void UART0_print_string(char *str)
{
	for (int i=0; str[i] != '\0'; i++)
	{
		UART0_transmit(str[i]);
	}
}

 

menu.h

/*
 * menu.h
 *
 * Created: 2021-08-20 오후 3:06:34
 *  Author: KHJ
 */ 


#ifndef MENU_H_
#define MENU_H_
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include <stdio.h>
#include <avr/interrupt.h>   // interrupt 관련 lib가 들어 있다.
#include "uart0.h"
#include "ds1302.h"

void show_menu(void);
void menu_exec();
void updateDateTime();
uint8_t get_number();
void display_clock_lcd();
#endif /* MENU_H_ */

 

menu.c

/*
* menu.c
*
* Created: 2021-08-20 오후 3:06:51
*  Author: KHJ
*/

#include "menu.h"

void display_clock_lcd()
{
	static uint8_t prevSec =0; // 1초에 한번씩 출력 하기위한 변수
	//satatic으로 선언을 하면 local 변수라도 함수가 끝난 뒤에 값을 유지한다.
	char buffer[20];// lcd에 string값을 출력하기 위한 변수
	
	DS1302_GetTime(&stTime);
	DS1302_GetDate(&stTime);
	
	if(prevSec!= stTime.seconds)	// 초가 바뀌었다.
	{
		prevSec=stTime.seconds;
		
		//
		//sprintf를 이용하여 buffer에 원하는 값을 집어 넣을 수 있다.
		//
		
		sprintf(buffer,"date %04d-%02d-%02d", 2000+stTime.year, stTime.month, stTime.date);	 // '\n' 은 lcd 가 인식 못한다.
		
		I2C_LCD_write_string_XY(0,0,buffer);
		
		sprintf(buffer,"time %02d:%02d:%02d", stTime.hour, stTime.minutes, stTime.seconds);
		
		I2C_LCD_write_string_XY(1,0,buffer);
	}
}

void show_menu(void)
{
	printf("----- MENU ------\n");
	printf("1. show Time\n");   // 시 분 초
	printf("2. show Date\n");   // 년 월 일
	printf("3. update Date_time\n");
	printf("Select : ");
}

void menu_exec()
{
	char *rxData;
	char yy[4], mm[4], dd[4], hh[4], min[4], ss[4];
	struct _ds1302 updateData;
	
	//gettime
	//settimeyymmddhhmmss
	//led0on
	//led0off
	//ledallon
	//ledalloff
	if (isRxString())
	{
		rxData = getRxString();   // Message를 읽어 온다.
		
		if (strncmp(rxData, "help", sizeof("help")) == 0)
		{
			printf("\n-- help --\n");
			printf("gettime\n");
			printf("settimeyymmddhhmmss\n");
		}
		
		if (strncmp(rxData, "gettime", sizeof("gettime")) == 0)
		{
			DS1302_GetTime(&stTime);
			DS1302_GetDate(&stTime);
			
			printf("date %04d:%02d:%02d\n", 2000+stTime.year, stTime.month, stTime.date);
			printf("time %02d:%02d:%02d\n", stTime.hour, stTime.minutes, stTime.seconds);
		}
		// 0123456789012345678
		// settimeyymmddhhmmss
		if (strncmp(rxData, "settime", 7) == 0)
		{
			strncpy(yy,rxData+7,2); // strncpy(yy,&rxData[7],2); --> yy[2] = 0;
			strncpy(mm,rxData+9,2);
			strncpy(dd,rxData+11,2);
			strncpy(hh,rxData+13,2);
			strncpy(min,rxData+15,2);
			strncpy(ss,rxData+17,2);
			
			updateData.year =(yy[0]-0b0110000)*10+(yy[1]-0b0110000);
			updateData.month =(mm[0]-0b0110000)*10+(mm[1]-0b0110000);
			updateData.date =(dd[0]-0b0110000)*10+(dd[1]-0b0110000);
			updateData.hour =(hh[0]-0b0110000)*10+(hh[1]-0b0110000);
			updateData.minutes =(min[0]-0b0110000)*10+(min[1]-0b0110000);
			updateData.seconds =(ss[0]-0b0110000)*10+(ss[1]-0b0110000);
			
			DS1302_SetTimeDates(updateData);
			
			printf("\n\ntime update success!!!!\n");
			DS1302_GetTime(&stTime);
			DS1302_GetDate(&stTime);
			printf("date %04d:%02d:%02d\n", 2000+stTime.year, stTime.month, stTime.date);
			printf("time %02d:%02d:%02d\n", stTime.hour, stTime.minutes, stTime.seconds);
		}
	}
}

void updateDateTime()
{
	uint8_t rxdata=0;
	struct _ds1302 updateData;
	
	// year:
	// month:
	// date:
	// hour:
	// minute:
	// sec:
	for (int i=0; i < 6; i++)
	{
		switch (i)
		{
			case 0:  // 년
			printf("year(00~99): ");
			rxdata = get_number();
			updateData.year = rxdata;
			printf("set year: %d\n", updateData.year);
			break;
			case 1:  // 월
			printf("month: ");
			rxdata = get_number();
			updateData.month = rxdata;
			printf("set month: %d\n", updateData.month);
			break;
			case 2:   // 일
			printf("date: ");
			rxdata = get_number();
			updateData.date = rxdata;
			printf("set date: %d\n", updateData.date);
			break;
			case 3:   // 시
			printf("hour: ");
			rxdata = get_number();
			updateData.hour = rxdata;
			printf("set hour: %d\n", updateData.hour);
			break;
			case 4:   // 분
			printf("minutes: ");
			rxdata = get_number();
			updateData.minutes = rxdata;
			printf("set minutes: %d\n", updateData.minutes);
			break;
			case 5:   // 초
			printf("sec: ");
			rxdata = get_number();
			updateData.seconds = rxdata;
			printf("set sec: %d\n", updateData.seconds);
			break;
			break;
		}
	}
	DS1302_SetTimeDates(updateData);
	return 0;
}


uint8_t get_number()
{
	uint8_t rxdata=0, *rxstring;
	
	while(isRxString()==0)
	;
	rxstring = getRxString();
	rxdata = atoi(rxstring);
	
	return rxdata;
}

 

I2C_LCD.h

/*
 * I2C_LCD.h
 *
 * Created: 2020-01-07 오후 8:00:34
 */ 


#ifndef I2C_LCD_H_
#define I2C_LCD_H_
#define COMMAND_CLEAR_DISPLAY	0X01

#define COMMAND_DISPLAY_ON_OFF_BIT	2
#define COMMAND_CURSOR_ON_OFF_BIT	1
#define COMMAND_BLINK_ON_OFF_BIT	0

#define START 0x08
#define SLA_W (0x27<<1)    // I2C LCD 주소 0x27 , <<1 이유는 write모드 유지
#define SLA_R (0x27<<1 | 0x01)       // I2C LCD 주소 0x27 , Read모드 유지

void I2C_LCD_init(void);
void I2C_LCD_write_data(uint8_t data);
void I2C_LCD_write_command(uint8_t command);
void I2C_LCD_clear(void);
void I2C_LCD_write_string(char *string);
void I2C_LCD_goto_XY(uint8_t row, uint8_t col);
void I2C_LCD_write_string_XY(uint8_t row, uint8_t col, char *string);




#endif /* I2C_LCD_H_ */

 

I2C_LCD.c

/*
 * I2C_LCD.c
 *
 * Created: 2020-01-07 오후 7:59:31
 */ 
// 맵핑 시켜주는 코드이다.
#define F_CPU	16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include "I2C.h"
#include "I2C_LCD.h"

// 콜바이 벨류다.
//lcd에 1바이트를 display
void I2C_LCD_write_data(uint8_t data)
{
	char data_u, data_l;
	uint8_t data_t[4] = {0,};
		
	data_u = (data&0xf0);      // 상위 4bit 데이터
	data_l = ((data<<4)&0xf0); // 하위 4bit 데이터
	data_t[0] = data_u|0x0D;   //en=1, rs=1           |D7|D6|D5|D4|X|E|RW|RS|
	data_t[1] = data_u|0x09;   //en=0, rs=1
	data_t[2] = data_l|0x0D;   //en=1, rs=1
	data_t[3] = data_l|0x09;   //en=0, rs=1

	for(char i=0;i<4;i++){
		I2C_write_byte(SLA_W, data_t[i]);
	}
}


// LCD command 실행한다.
void I2C_LCD_write_command(uint8_t command)
{
	char data_u, data_l;
	uint8_t data_t[4];
	data_u = (command&0xf0);      // command의 상위 4bit 저장
	data_l = ((command<<4)&0xf0); // command의 하위 4bit 저장
	data_t[0] = data_u|0x0C;  //en=1, rs=0           |D7|D6|D5|D4|X|E|RW|RS|
	data_t[1] = data_u|0x08;  //en=0, rs=0
	data_t[2] = data_l|0x0C;  //en=1, rs=0
	data_t[3] = data_l|0x08;  //en=0, rs=0
	
	for(char i=0;i<4;i++){
		I2C_write_byte(SLA_W, data_t[i]);
	}
}

//lcd 화면 전체를 클리어 한다.
void I2C_LCD_clear(void)
{
	I2C_LCD_write_command(COMMAND_CLEAR_DISPLAY);
	_delay_ms(2);
}

//lcd를 초기화 하는것. 처음 프로그램 실행시 한번만 부르는 함수.
void I2C_LCD_init(void)
{
	I2C_init(10000);
	_delay_ms(50);
	//Initialization of HD44780-based LCD (4-bit HW)
	I2C_LCD_write_command(0x33);
	I2C_LCD_write_command(0x32);
	I2C_LCD_write_command(0x28);   //Function Set 4-bit mode
	I2C_LCD_write_command(0x0c);   //Display On/Off Control
	I2C_LCD_write_command(0x06);   //Entry mode set
	I2C_LCD_write_command(0x01);   //Clear Display
	//Minimum delay to wait before driving LCD module
	_delay_ms(10);
}

//현재 커서 위치에 string 값을 lcd에 출력한다.
void I2C_LCD_write_string(char *string)
{
	uint8_t i;
	for(i=0; string[i]; i++)
	I2C_LCD_write_data(string[i]);
}

//커서를 LCD의 특정 위치로 MOVE 할때.
//EX) LINE 0line의 10 col로  move시 	   I2C_LCD_goto_XY(0, 10);
void I2C_LCD_goto_XY(uint8_t row, uint8_t col)
{
	col %= 16;
	row %= 2;
	
	uint8_t address = (0x40 * row) + col;
	uint8_t command = 0x80 + address;
	
	I2C_LCD_write_command(command);
}

//해당 되는 위치에가서 해당 값을 쓴다.
void I2C_LCD_write_string_XY(uint8_t row, uint8_t col, char *string)
{
	I2C_LCD_goto_XY(row, col);
	I2C_LCD_write_string(string);
}

I2C_LCD.c

 

I2C.h

/*
 * I2C.h
 *
 * Created: 2020-01-07 오후 7:57:06
 */ 


#ifndef I2C_H_
#define I2C_H_
void I2C_init(unsigned int baud);
void I2C_start(void);
void I2C_transmit(uint8_t data);
void I2C_write_byte(uint8_t address, uint8_t data);
void I2C_stop(void);
uint8_t I2C_receive_ACK(void);
uint8_t I2C_receive_NACK(void);




#endif /* I2C_H_ */

 

I2C.c

/*
 * I2C.c
 *
 * Created: 2020-01-07 오후 7:58:00
 */ 
#include <avr/io.h>
#include "I2C.h"

void I2C_init(unsigned int baud){
	TWBR = baud;
}

void I2C_start(void)
{
	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
	while (!(TWCR & (1<<TWINT)));  // 시작 완료 대기
}

void I2C_transmit(uint8_t data)
{
	TWDR = data;
	TWCR = (1<<TWINT) | (1<<TWEN);
	while (!(TWCR & (1<<TWINT)));
}

void I2C_write_byte(uint8_t address, uint8_t data)
{
	I2C_start();
	I2C_transmit(address);	  //주소를 보내는 이유는 슬레이브가 여러명 일 수 있기 떄문이다.
	I2C_transmit(data);
	I2C_stop();
}

void I2C_stop(void)
{
	TWCR = (1<<TWINT)|(1<<TWEN)| (1<<TWSTO);
}

uint8_t I2C_receive_ACK(void)
{
	TWCR = (1<<TWINT) | (1<<TWEN) |(1<<TWEA);
	
	while( !(TWCR & (1<<TWINT)));             // 수신 완료 대기
	
	return TWDR;
}

uint8_t I2C_receive_NACK(void)
{
	TWCR = (1<<TWINT) | (1<<TWEN);
	
	while( !(TWCR & (1<<TWINT)));             // 수신 완료 대기
	
	return TWDR;
}

 

main.c

/*
* main.c
*
* Created: 2021-08-22 오전 10:20:19
* Author : KHJ
*/
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include <stdio.h>
#include <avr/interrupt.h>   // interrupt 관련 lib가 들어 있다.
#include "uart0.h"
#include "ds1302.h"


void UART0_rx_interrupt_setRC522(void);
// printf를 동작 시키위한 mapping작업
FILE OUTPUT = FDEV_SETUP_STREAM(UART0_transmit, NULL, _FDEV_SETUP_WRITE);

int main(void)
{
	long count=0; // lcd 카운터 변수
	char buffer[20];  // text lcd에 출력 하기 위함이다.
	
	// printf 초기화
	stdout = &OUTPUT;   // FILE : 1(stdout) 0: stdin 2:stderr
	I2C_LCD_init();
	DS1302_Init();
	UART0_init();
	sei();
	
#if 1
		   while(1)
		   {
		   menu_exec();	  
		   display_clock_lcd();
		   }
		   
#else		 // 테스트 코드
	I2C_LCD_write_string_XY(0,0,"HI THERE");
	while (1)
	{
		
		_delay_ms(100);
		sprintf(buffer, "%04d",count);
		I2C_LCD_write_string_XY(1,0,buffer);
		count++;
	}
	#endif

}
//comport master 에서 settimeyymmddhhmmss로 ds1302 rtc를 설정

void UART0_rx_interrupt_setRC522(void)
{
	stdout = &OUTPUT;
	DS1302_Init();
	UART0_init();
	sei();
}

 

 

동작 동영상

https://youtu.be/HtFNhNZryS8