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= {0x110x420x61};                                     // 설정 완료 멜로디
unsigned char BUZZER_Alarm_table[7= {0x420x2B0x110x2B0x420x420x42};           // 알람 멜로디
 
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를 공부하면서 해당 부분을 적용해볼까 합니다 ^^;

반응형
로봇쟁이