본문 바로가기
임베디드시스템/AVR

[AVR] LED(command work) + FND(Stopwatch+분.초시계) + LCD Display (DS1302 시간 command setting)

by KHJ_940803 2021. 11. 5.

목표 : 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 로 부터 받은 시간을 보여준다:

https://youtu.be/HtFNhNZryS8

FND 에 버튼을 이용해 STOPWATCH와 분.초시계를 보여준다:

https://youtu.be/M03nVoL0RwA

COMPORT MASTER command를 이용하여 led를 컨트롤 한다:

https://youtu.be/NenM12wjaNY

https://youtu.be/W0v3sqLQob4

https://youtu.be/M4uuLYLLK_w

https://youtu.be/ehpUDbknbWQ

https://youtu.be/GdYqa2_ZDpQ

 

댓글