ATmega328을 이용해서 USART로 출력을 하고 알람이 울리는 코드입니다.
한번 쭈욱 살펴보시면 좋을 듯 합니다.
기존에 사용했던 I2C(TWI), DS1307, USART 헤더파일로 생성하여 라이브러리처럼 만들었습니다.
해당 코드는 이전 자료를 보시면 알수 있을 듯 합니다. ^^
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "TWIlib.h"
#include "USARTlib.h"
#include "DS1307lib.h"
// 디스플레이 메뉴모드와 시작모드
#define _DISP_MODE 0
#define _MENU_MODE 1
// 설정모드에 진입 후 시간설정모드와 알람설정모드
#define _WAIT_MODE 0
#define _SETUP_MODE 1
#define _ALARM_MODE 2
// 부저 모드
#define _BUZZER_WAIT_MODE 0
#define _BUZZER_SET_MODE 1
#define _BUZZER_ALARM_MODE 2
#define MENU_SUB_CLOCK 0
#define MENU_SUB_ALARM 1
#define YEAR 0
#define MONTH 1
#define DATE 2
#define HOUR 3
#define MIN 4
#define SEC 5
#define WEEK 6
// 버튼 셋팅
#define MENU_BTN (PIND&0x04)
#define CHANGE_BTN (PIND&0x08)
#define CONFIRM_BTN (PIND&0x10)
struct _CLOCK_ST{
unsigned char y=0, m=1, dt=1, day=1, hour=12, minn=0, sec=0, week=1;
};
unsigned char BUZZER_Set_table[3] = {0x11, 0x42, 0x61}; // 설정 완료 멜로디
unsigned char BUZZER_Alarm_table[7] = {0x42, 0x2B, 0x11, 0x2B, 0x42, 0x42, 0x42}; // 알람 멜로디
volatile unsigned char MainDISP = 0;
volatile unsigned char ConfDISP = 0;
volatile unsigned char MENU_BTN_flag = 0, MENU_BTN_cnt = 0;
volatile unsigned char CHANGE_BTN_flag = 0, CHANGE_BTN_cnt = 0, CHANGE_BTN_mode = 0, CHANGE_SETTING = 0;
volatile unsigned char CONFIRM_BTN_flag = 0, CONFIRM_BTN_cnt = 0, CONFIRM_BTN_upCount = 0;
volatile unsigned char ALARM_SETTING = 3;
volatile unsigned int BUZZER_cnt = 0, BUZZER_mode = 0;
int state = 0;
Read_DT dt; //RTC 읽어오기 구조체
_CLOCK_ST CONFIG_TT; //시간설정 구조체
_CLOCK_ST ALARM_TT; //알람설정 구조체
/*
* 버튼에 따른 동작 타이머
*/
ISR(TIMER1_COMPA_vect) {
// 메뉴버튼 동작
if(MENU_BTN) {
if(MENU_BTN_flag == 0) {
MENU_BTN_flag = 1;
MENU_BTN_cnt = 0;
}
else {
if(MENU_BTN_cnt < 30) {
MENU_BTN_cnt++;
}
}
}
else {
MENU_BTN_flag = 0;
if(MENU_BTN_cnt) {
if(MENU_BTN_cnt < 15) { // 짧게 누른경우
if(MainDISP == _MENU_MODE) { // 메뉴모드에서 디스플레이모드로 변경
MainDISP = _DISP_MODE;
ConfDISP = _WAIT_MODE; // 디스플레이 모드가 되면 ConfDISP 초기화
CHANGE_BTN_mode = MENU_SUB_CLOCK; // CHANGE_BTN_mode 초기화
}
else { // 디스플레이모드에서 메뉴모드로 이동
MainDISP = _MENU_MODE;
}
}
MENU_BTN_cnt = 0;
}
}
// 변경버튼 동작
if(CHANGE_BTN) {
if(CHANGE_BTN_flag == 0) {
CHANGE_BTN_flag = 1;
CHANGE_BTN_cnt = 0;
}
else {
if(CHANGE_BTN_cnt < 30) {
CHANGE_BTN_cnt++;
}
}
}
else {
CHANGE_BTN_flag = 0;
if(CHANGE_BTN_cnt) {
if(CHANGE_BTN_cnt < 15) { // 짧게 누른경우
if((MainDISP == _MENU_MODE) && (ConfDISP == _WAIT_MODE)) { // 메인메뉴 상태의 변경버튼 역할
if(CHANGE_BTN_mode == MENU_SUB_CLOCK) {
CHANGE_BTN_mode = MENU_SUB_ALARM;
}
else {
CHANGE_BTN_mode = MENU_SUB_CLOCK;
}
}
else if(ConfDISP == _SETUP_MODE) { // 시간설정모드 상태의 변경버튼 역할
CHANGE_SETTING++; // 년->월->일->시->분->초->요일 순으로 변경
if(CHANGE_SETTING > WEEK) { // 요일에서 다시 년으로 변경
CHANGE_SETTING = YEAR;
}
}
else if(ConfDISP == _ALARM_MODE) { // 알람설정모드 상태의 변경버튼 역할
CHANGE_SETTING = 1; // 시->분->초 순으로 변경
ALARM_SETTING += CHANGE_SETTING;
if(ALARM_SETTING > SEC) {
ALARM_SETTING = 3;
}
}
}
CHANGE_BTN_cnt = 0;
}
}
// 확인버튼 동작
if(CONFIRM_BTN) {
if(CONFIRM_BTN_flag == 0) {
CONFIRM_BTN_flag = 1;
CONFIRM_BTN_cnt = 0;
}
else {
if(CONFIRM_BTN_cnt < 30) {
CONFIRM_BTN_cnt++;
}
}
}
else {
CONFIRM_BTN_flag = 0;
if(CONFIRM_BTN_cnt) {
if(CONFIRM_BTN_cnt < 15) { // 짧게 누른경우
if((ConfDISP == _WAIT_MODE) && (CHANGE_BTN_mode == MENU_SUB_CLOCK)) { // 시간설정모드 선택 할때 확인버튼
ConfDISP = _SETUP_MODE; // 시간설정모드 진입
}
else if((ConfDISP == _WAIT_MODE) && (CHANGE_BTN_mode == MENU_SUB_ALARM)){ // 알람설정모드 선택 할때 확인버튼
ConfDISP = _ALARM_MODE; // 알람설정모드 진입
}
else { // 각 설정모드 진입 후 upcount
CONFIRM_BTN_upCount = 1; // 설정모드에서 1씩 올려줌
}
}
else { // 길게 누른경우
if(ConfDISP == _SETUP_MODE) { // 시간설정모드에서 길게 누르면 실행
DS1307_set(CONFIG_TT.sec, CONFIG_TT.minn, CONFIG_TT.hour,
CONFIG_TT.week, CONFIG_TT.dt, CONFIG_TT.m, CONFIG_TT.y); // 설정한 시간을 RTC에 저장 - 초,분,시,요일,일,월,년
CHANGE_SETTING = YEAR; // 마지막으로 변경한 시점에서 다시 년부터 시작
MainDISP = _MENU_MODE; // 상위메뉴로 이동
ConfDISP = _WAIT_MODE; // 설정메뉴 선택 전
BUZZER_mode = _BUZZER_SET_MODE; // 설정완료 알람
}
else { // 알람설정모드에서 길게 누르면 실행
MainDISP = _MENU_MODE; // 상위메뉴로 이동
ConfDISP = _WAIT_MODE; // 설정메뉴 선택 전
BUZZER_mode = _BUZZER_SET_MODE; // 설정완료 알람
}
}
CONFIRM_BTN_cnt = 0;
}
}
}
/*
* 부저 알람 타이머
*/
ISR(TIMER0_OVF_vect) {
switch(BUZZER_mode) {
case _BUZZER_SET_MODE:
if(BUZZER_cnt) {
if(state == 0) {
PORTB |= 0x01;
state = 1;
}
else {
PORTB &= ~(0x01);
state = 0;
}
TCNT0 = BUZZER_Set_table[BUZZER_cnt-1];
}
else {
PORTB &= ~(0x01);
}
break;
case _BUZZER_ALARM_MODE:
if(BUZZER_cnt) {
if(state == 0) {
PORTB |= 0x01;
state = 1;
}
else {
PORTB &= ~(0x01);
state = 0;
}
TCNT0 = BUZZER_Alarm_table[BUZZER_cnt-1];
}
else {
PORTB &= ~(0x01);
}
break;
default:
break;
}
}
int main(void) {
// LED : PORTB 5, 부저 : PORTB 1 출력으로 설정
DDRB |= 0x21;
// USART 설정
UCSR0A = 0;
UCSR0B = (1 << RXCIE0) | (1 << RXEN0) | (1 << TXEN0); // RX INT EN, RX & TX Enable
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); // 8bit no parity
UBRR0H = 0; UBRR0L = 8; // 115200 bps
// RTC를 위한 I2C 설정
i2c_init();
// 버튼 조작용 타이머 설정
TCCR1A = 0x00; // CTC Mode
TCCR1B = 0x0B; // 64 prescaling 16000000 / 64 65535
TIMSK1 = 0x02; // Comapre A Match Interrupt Enable
OCR1A = 0x30D3; // 50ms TIMER SET
// 부저 알람용 타이머 설정
TCCR0A = 0x00; // CTC Mode
TCCR0B = 0x03; // 64 prescale
TIMSK0 = 0x01; // OVF ENABLE(TOIEA)
TCNT0 = 0x11; // (1/16000000) * 64 * (256-17) = 1046 Hz = '도'
BUZZER_cnt = 0;
sei(); // 인터럽트 활성화
MainDISP = _DISP_MODE; // 초기 진입모드 : 디스플레이모드
while(1) {
switch(MainDISP) {
case _DISP_MODE:
disp_CLOCK();
break;
case _MENU_MODE:
disp_MENU();
break;
}
func_BUZZER();
}
}
/*
* RTC에 저장된 현재 시간 디스플레이
*/
void disp_CLOCK() {
char str[50];
char *dday;
dt = DS1307_now();
switch(dt.dday) {
case 1:
dday = "SUN";
break;
case 2:
dday = "MON";
break;
case 3:
dday = "TUE";
break;
case 4:
dday = "WED";
break;
case 5:
dday = "TUR";
break;
case 6:
dday = "FRI";
break;
case 7:
dday = "SAT";
break;
}
sprintf(str, "CLOCK = %02d-%02d-%02d %02d:%02d:%02d %s\r\n", dt.yr+2000, dt.mh, dt.date, dt.hours, dt.minutes, dt.seconds, dday);
Tx_String(str);
sprintf(str, "ALARM = %02d:%02d:%02d\r\n", ALARM_TT.hour, ALARM_TT.minn, ALARM_TT.sec);
Tx_String(str);
if(dt.hours == ALARM_TT.hour) {
if(dt.minutes == ALARM_TT.minn) {
if(dt.seconds == ALARM_TT.sec) {
BUZZER_mode = _BUZZER_ALARM_MODE;
}
}
}
}
/*
* 메뉴에 따른 메뉴 디스플레이
*/
void disp_MENU() {
char str[50];
switch(ConfDISP) {
case _SETUP_MODE:
disp_SETUP();
break;
case _ALARM_MODE:
disp_ALARM();
break;
case _WAIT_MODE:
if(CHANGE_BTN_mode == MENU_SUB_CLOCK) {
sprintf(str, "1. Clock Configuration\r\n");
}
else {
sprintf(str, "2. Alarm Configuration\r\n");
}
Tx_String(str);
break;
}
}
/*
* 시간설정모드의 처리 및 디스플레이
*/
void disp_SETUP() {
char str[50];
char *weekSTR;
switch(CHANGE_SETTING) {
case YEAR:
CONFIG_TT.y += CONFIRM_BTN_upCount;
break;
case MONTH:
CONFIG_TT.m += CONFIRM_BTN_upCount;
if(CONFIG_TT.m > 12) {
CONFIG_TT.m = 1;
}
break;
case DATE:
CONFIG_TT.dt += CONFIRM_BTN_upCount;
if(CONFIG_TT.m == 1) {
if(CONFIG_TT.dt > 31) CONFIG_TT.dt = 1;
}
else if(CONFIG_TT.m == 2) {
if(CONFIG_TT.dt > 29) CONFIG_TT.dt = 1;
}
else if(CONFIG_TT.m == 3) {
if(CONFIG_TT.dt > 31) CONFIG_TT.dt = 1;
}
else if(CONFIG_TT.m == 4) {
if(CONFIG_TT.dt > 30) CONFIG_TT.dt = 1;
}
else if(CONFIG_TT.m == 5) {
if(CONFIG_TT.dt > 31) CONFIG_TT.dt = 1;
}
else if(CONFIG_TT.m == 6) {
if(CONFIG_TT.dt > 30) CONFIG_TT.dt = 1;
}
else if(CONFIG_TT.m == 7) {
if(CONFIG_TT.dt > 31) CONFIG_TT.dt = 1;
}
else if(CONFIG_TT.m == 8) {
if(CONFIG_TT.dt > 31) CONFIG_TT.dt = 1;
}
else if(CONFIG_TT.m == 9) {
if(CONFIG_TT.dt > 30) CONFIG_TT.dt = 1;
}
else if(CONFIG_TT.m == 10) {
if(CONFIG_TT.dt > 31) CONFIG_TT.dt = 1;
}
else if(CONFIG_TT.m == 11) {
if(CONFIG_TT.dt > 30) CONFIG_TT.dt = 1;
}
else if(CONFIG_TT.m == 12) {
if(CONFIG_TT.dt > 31) CONFIG_TT.dt = 1;
}
break;
case HOUR:
CONFIG_TT.hour += CONFIRM_BTN_upCount;
if(CONFIG_TT.hour > 23) {
CONFIG_TT.hour = 0;
}
break;
case MIN:
CONFIG_TT.minn += CONFIRM_BTN_upCount;
if(CONFIG_TT.minn > 59) {
CONFIG_TT.minn = 0;
}
break;
case SEC:
CONFIG_TT.sec += CONFIRM_BTN_upCount;
if(CONFIG_TT.sec > 59) {
CONFIG_TT.sec = 0;
}
break;
case WEEK:
CONFIG_TT.week += CONFIRM_BTN_upCount;
if(CONFIG_TT.week > 7) {
CONFIG_TT.week = 1;
}
break;
}
CONFIRM_BTN_upCount = 0;
switch(CONFIG_TT.week) {
case 1: weekSTR = "SUN"; break;
case 2: weekSTR = "MON"; break;
case 3: weekSTR = "TUE"; break;
case 4: weekSTR = "WED"; break;
case 5: weekSTR = "TUR"; break;
case 6: weekSTR = "FRI"; break;
case 7: weekSTR = "SAT"; break;
}
sprintf(str, "%02d-%02d-%02d %02d:%02d:%02d %s\r\n", CONFIG_TT.y+2000, CONFIG_TT.m, CONFIG_TT.dt, CONFIG_TT.hour, CONFIG_TT.minn, CONFIG_TT.sec, weekSTR);
Tx_String(str);
}
/*
* 알람설정모드의 처리 및 디스플레이
*/
void disp_ALARM() {
char str[50];
switch(ALARM_SETTING) {
case HOUR:
ALARM_TT.hour += CONFIRM_BTN_upCount;
if(ALARM_TT.hour > 23) {
ALARM_TT.hour = 0;
}
break;
case MIN:
ALARM_TT.minn += CONFIRM_BTN_upCount;
if(ALARM_TT.minn > 59) {
ALARM_TT.minn = 0;
}
break;
case SEC:
ALARM_TT.sec += CONFIRM_BTN_upCount;
if(ALARM_TT.sec > 59) {
ALARM_TT.sec = 0;
}
break;
}
CONFIRM_BTN_upCount = 0;
sprintf(str, "Hour : %02d Mminute : %02d Second : %02d\r\n", ALARM_TT.hour, ALARM_TT.minn, ALARM_TT.sec);
Tx_String(str);
}
/*
* 설정완료 멜로디 및 설정알람 멜로디
*/
void func_BUZZER() {
switch(BUZZER_mode) {
case _BUZZER_SET_MODE:
BUZZER_cnt++;
_delay_ms(150);
if(BUZZER_cnt >= 3) {
BUZZER_cnt = 0;
BUZZER_mode = _BUZZER_WAIT_MODE;
}
break;
case _BUZZER_ALARM_MODE:
BUZZER_cnt++;
_delay_ms(300);
if(BUZZER_cnt >= 7) {
BUZZER_cnt = 0;
BUZZER_mode = _BUZZER_WAIT_MODE;
}
break;
default:
break;
}
}
|
cs |
* 주 기능 : 시계
* 보조기능 : 시간설정, 알람 설정, 멜로디 (셋업시 알람, 알람설정한 시간과 동일시 알람 2가지)
앞으로 GLCD를 공부하면서 해당 부분을 적용해볼까 합니다 ^^;
반응형
'b. 임베디드 > AVR' 카테고리의 다른 글
[ATtiny2313A] BUTTON 예제 (0) | 2018.11.16 |
---|---|
[ATtiny2313A] Blink 예제 (0) | 2018.11.16 |
[ATmega328] Nokia 5110 LCD (GLCD) bmp파일 출력하기 (0) | 2018.08.18 |
[ATmega328] Nokia 5110 LCD (GLCD) 문자 출력하기 (0) | 2018.08.04 |
[ATmega328] DS1307 RTC I2C(TWI)통신 2탄 (0) | 2018.08.04 |
[ATmega328] 아두이노 Uno 핀맵 (0) | 2018.08.04 |
[ATmega328] DS1307 RTC I2C(TWI)통신 1탄 (0) | 2018.08.04 |
[ATmega328] UART통신 송수신 예제 (0) | 2018.08.04 |