목표 : I2C LCD에 DS1302 로 부터 받은 시간을 보여주며, FND 에 버튼을 이용해 STOPWATCH와 분.초시계를 보여주며, COMPORT MASTER command를 이용하여 led를 컨트롤 한다.
개발 툴 : atmel studio
개발 보드 : ATMEGA128A
PC Uart 통신 툴 : Comport master
개발 기간 : 2021년 8월 23일 ~ 2021년 8월 24일
소스코드
/*
* UART0.c
*
* Created: 2021-08-17 오전 10:20:19
* Author : kcci
*/
#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"
#include "I2C.h"
#include "I2C_LCD.h"
// 버튼을 위한 include
#include "global.h" // 현재 내 디렉토리 밑에 있는 화일을 include할때는 ""
#include "fnd.h"
#include "button.h"
#include "time_clock.h"
// printf를 동작 시키위한 mapping작업
FILE OUTPUT = FDEV_SETUP_STREAM(UART0_transmit, NULL, _FDEV_SETUP_WRITE);
//for define watch or stopwatch
#define WATCH 0
#define STOPWATCH 1
unsigned char mode_state = WATCH;// 시작하자마자 시계는 돌아가게 한다.
//for stopwatch
#define STOP 0
#define RUN 1
#define RESET 2
unsigned char stop_watch_state = STOP;// 시작하면 스톱워치는 멈춰있어야 한다.
//알람 시간 설정하는 define
#define ALRMHOUR 06
#define ALRMMIN 15
#define ALRMSEC 00
unsigned char alrm_lock = 0;
//mian.c 설정한 함수
void inc_stop_watch_clock();
void stop_watch_stop_state();
void stop_watch_run_state();
void stop_watch_reset_state();
void alrm_ring();
ISR(TIMER0_OVF_vect)
{
static uint16_t sec_count=0;
static uint16_t odd_even=0;
static uint16_t blink_count =0;
if (++sec_count >= 1000) // 1000ms 는 1초이다.
{
odd_even++;
sec_count=0;
inc_time_sec();
}
//led를 지속적으로 깜빡이기 위해서는 while 문을 사용해야 한다
//하지만 while 문과 _delay_ms 를 이용하여 깜빡이면 깜빡이는 동안 시간이 흐르지 않는다.
//그래서 while문 역활을 할 무엇인가 가 필요했고 fnd display 에서 1초를 새팅 하듯이 깜빡이는 시간을 세팅하여
// 조건을 주면서 깜빡이는 led를 바꾸고 인터럽트를 이용하여 while문 처럼 사용했다.
if (++blink_count >= 400) // led가 깜빡 거리는 시간은 0.4초이다.
{
blink_count=0;
led_control_comportmaster(); // 이것을 통해 led가 깜빡인다.
}
if (stop_watch_state == RUN)
{
inc_stop_watch_clock();
}
if((alrm_lock==1)&&(mode_state == WATCH)) // 알람 시간이 되면 alrm_lock 이 1이 되면서 계속 여기서 머문다.
{
if(odd_even%2)
{
fnd_display_alrm();
}
else
{
fnd_display();
}
}
else if((odd_even%2)&&(mode_state == WATCH)) // 홀수 일때 , WATCH 모드일떄
{
fnd_display_clock(); // 점하나를 찍기 위해 4자리수를 부르는 함수를 재탕했다.
}
else if( ( (odd_even+1) %2 ) && (mode_state == WATCH) ) //짝수 일때, WATCH 모드 일때
{
fnd_display();
}
else if( mode_state == STOPWATCH ) // STOPWATCH MODE 일때.
{
fnd_display();
}
timeTick++;
}
uint16_t stop_watch_clock=0; // 전역변수
void inc_stop_watch_clock()
{
static uint8_t count =0;
if (++count >= 100)
{
count =0;
stop_watch_clock++;
}
}
int main(void)
{
// printf 초기화
stdout = &OUTPUT; // FILE : 1(stdout) 0: stdin 2:stderr
I2C_LCD_init(); // i2c 통신을 이용한 lcd display 시작
DS1302_Init(); // 시간을 흐르게 하기위한 ds1302 시작
UART0_init(); //uart 통신 시작
TIME myTime; // fnd 에 시간을 설정하기 위한 구조체
fnd_init(); // fnd 시작
button_Init(); // 스탑워치와 분촉시계를 전환하기 위한 button 시작
// 분주비를 64로 설정 16MHZ / 64 ==> 250,000HZ 이렇게 설정시 TIM0 OV 256/250,000
// 0.001sec ==> 1ms마다 timer INT 가 발생 된다.
TCCR0 |= (1 << CS02) | (0 << CS01) | (0 << CS00);
TIMSK |= (1 << TOIE0); // timer overflow INT설정: TCNT0의 register값이 256이 되는 순간 INT가 발생
sei();
DS1302_GetTime(&stTime); // ds1302 를 이용하여 시간을 받아 온다.
DS1302_GetDate(&stTime); // ds1302 를 이용하여 날짜를 받아 온다.
// ds1302 를 이용한 시간과 fnd 에 보이는 시간과 비슷하게 보이기 위한 코드 3줄
myTime.hour=stTime.hour;
myTime.min=stTime.minutes;
myTime.sec=stTime.seconds;
// fnd 에 보여지는 시간 값을 넘겨준다.
set_time_clock(myTime);
uint8_t prevSec; // 1초 1번씩 시간을 출력 하기 위한 변수
printf("\n-- help --\n");
printf("gettime\n");
printf("settimeyymmddhhmmss\n");
DDRA =0xff;// led 를 사용하는 핀을 출력으로 설정한다.
PORTA =0x00; // 처음 led는 다 꺼지게 한다.
while (1)
{
menu_exec();
display_clock_lcd();
//switch case를 이용하여 fnd 에 보여지는 값을 바꾼다.
switch (mode_state){ // 8digit display를 위한 switch case 문이다.
case WATCH:// 버튼 1을 눌러서 모드를 전환한다.
PORTE =0b00010000; //적색등 점등
get_time_clock(&myTime);
if(alrm_lock==1) {set_fnd_data(ALRMMIN*100+ALRMSEC); } // lock 걸면 세팅한 시간에서 fnd display 하게끔 한다.
else {set_fnd_data(myTime.min*100+myTime.sec);} // 시간을 받아서 fnd data에 넣고 넘겨준다.
alrm_ring(&myTime);
if(getButton1State())
{
mode_state=STOPWATCH;
}
if(getButton3State())
{
alrm_lock=0;
}
break;
case STOPWATCH:// 버튼 1을 눌러서 모드를 전환한다.
PORTE =0b00001000;// 녹색등 점등
switch (stop_watch_state)
{
case STOP:
stop_watch_stop_state();
break;
case RUN:
stop_watch_run_state();
break;
case RESET:
stop_watch_reset_state();
break;
}
if(getButton1State())
{
mode_state=WATCH;
}
}
}
}
void stop_watch_stop_state()
{
set_fnd_data(stop_watch_clock);
if (getButton2State()) // button2을 누르면
{
stop_watch_state=RUN; // RUN상태로 상태 천이
}
if (getButton3State()) // button3를 누르면 RESET버튼
{
stop_watch_state=RESET; // stopwatch를 RESET상태로 상태 천이
}
}
// 현재 stopwatch가 돌고 있는 상태에서 button1을 누르면 stop상태로 천이
void stop_watch_run_state()
{
set_fnd_data(stop_watch_clock);
if (getButton2State()) // button2을 누르면
{
stop_watch_state=STOP; // STOP상태로 상태 천이
}
}
// 현재 stopwatch가 reset상태에서 stop모드로 복귀한다.
void stop_watch_reset_state()
{
stop_watch_clock=0;
set_fnd_data(stop_watch_clock);
stop_watch_state=STOP; // STOP상태로 상태 천이
}
//설정된 시간에 알람이 lock 이 되게끔 하는 함수이다.
void alrm_ring(TIME *Time)
{ if(Time->hour ==ALRMHOUR){
if(Time->min == ALRMMIN)
{
if(Time->sec ==ALRMSEC)
{
alrm_lock =1;
}
}
}
}
button.h, button.c, fnd.h, fnd.c, global.h, extern.h time_clock.h time_clock.c는 https://khj-940803.tistory.com/2 참고
DS1302.h, DS1302.c, uart0.h, uart0.c, menu.h, menu.c, uart0.h, uart0.c, I2C_LCD.h, I2C_LCD.c, I2C.h, I2C.c 는https://khj-940803.tistory.com/4 참고
보드사진
동작 동영상
I2C LCD에 DS1302 로 부터 받은 시간을 보여준다:
FND 에 버튼을 이용해 STOPWATCH와 분.초시계를 보여준다:
COMPORT MASTER command를 이용하여 led를 컨트롤 한다:
'임베디드시스템 > AVR' 카테고리의 다른 글
[AVR] 단순 계산기 (0) | 2021.11.09 |
---|---|
[AVR] 모터 속도제어 (선풍기) (0) | 2021.11.09 |
[AVR] DS1302 RTC 값을 I2C LCD에 Display (0) | 2021.11.04 |
[AVR] DS1302 clock settime 예외처리 (0) | 2021.11.03 |
[AVR] DP Blink/Stopwatch,Clock 구분 LED표시/Alarm 시간 표시 기능 (0) | 2021.11.03 |
댓글