changheepark-dev / Digital-System-Lab

Atmega128
0 stars 0 forks source link

11-06-2023 #4

Open changheepark-dev opened 11 months ago

changheepark-dev commented 11 months ago
/*
 * 프로그램 이름 : 11주차 과제
 * 프로그램 내용 : LCD 스위치 버저 LED 인터럽트 타이머 UART 통신
 * Created: 2023-11-13 오후 6:17:00
 * Author : 1922288 박창희
 * 마지막 수정일 : 2023-11-18 오후 10:38:00
 * 마지막 수정내용 : 키보드 3입력
 */ 

#define F_CPU 16000000UL        // 16MHz의 오실레이터를 사용
#include <avr/io.h>             //입출력 포트 사용을 위한 헤더 include
#include <avr/delay.h>          //딜레이 사용을 위한 헤더 inlcude
#include <avr/interrupt.h>      //인터럽트 사용을 위한 헤더 include
#include "lcd.h"                //LCD 사용을 위한 헤더 include -> " "외부의 파일을 include
#include "uart.h"

#include <stdlib.h>             // 랜덤 사용

/* 외부 인터럽트 */
int value1 = 0, trial_n = 16, ckd = 0;
ISR(INT0_vect)
{
    cli();
    if(!(PIND & (1<<PD0)) && value1 != 777 && trial_n !=0)
    {
        ckd = 1;
    }
}
void INTR_Init()
{
    EICRA = (0b10<<ISC00);      //하강엣지 트리거
    EIMSK = (1<<INT0);          //인터럽트 0 허용
    PORTD |= (1<<PD0);          //스위치를 PORTD 0번에 연결
    sei();                      //전역인터럽트 활성화
}
/* 외부 인터럽트 끝 */

/* 타이머 */
volatile int count = 0, count_m = 1000, dis = 0;    //오버플로우가 발생한 횟수
ISR(TIMER1_COMPA_vect)
{
    count++;
    if (count > 5)
    {
        count_m--;

        if (dis == 1) {
            LCDMove(1,11);
            LCD_nNum1(count_m);
        }

        if (count_m <= 0)
        {
            TIMER1_Initx();
        }
        count = 0;
    }
}
void TIMER1_Init()
{
    TCCR1A = (0<<WGM11) | (1<<WGM10); 
    TCCR1B = (0<<WGM13) | (0<<WGM12) | (1<<CS12) | (0<<CS11) | (1<<CS10);
    TIMSK |= (1 << OCIE1A);
    OCR1A = 128;
    sei();                              //전역인터럽트 활성화
}
void TIMER1_Initx()
{
    TCCR1A = (0<<WGM11) | (0<<WGM10);
    TCCR1B = (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);
    TIMSK |= (0 << OCIE1A);
    OCR1A = 128;
}
/* 타이머 끝 */

/*AD 변환*/
int readAnalog(unsigned char ch)        // AD 채널 값을 받아서 AD를 값을 읽어오는 함수.
{
    int res;

    ADCSRA = 1<<ADEN | 0b111<<ADPS0;    // 128 분주율로 AD를 사용 인에이블 설정
    ADMUX = 0b01<<REFS0 | ch<<MUX0;     // AREF를 기준전압으로 사용, AREF와 GND사이에 콘덴서 접속
    ADCSRA |= 1<<ADSC;                  // A/D 변환 시작

    while((ADCSRA & (1<<ADIF))) {}      // A/D 변환완료인터럽트플래그비트 ADC 완료 대기

    res = ADC;                          // 결과값을 res 변수에 넣음
    return res;
}

/*숫자 변환*/
int LCD_nNum1(unsigned int NUM)
{
    unsigned char Buff[8] = "0";
    Buff[0] = '0'+((NUM %1000)/100);
    Buff[1] = '0'+((NUM %100)/10);
    Buff[2] = '.';
    Buff[3] = '0'+(NUM %10);
    Buff[4] = 's';

    LCDPuts(Buff);
}
int LCD_nNum2(unsigned int NUM)
{
    unsigned char Buff[8] = " 0";
    Buff[0] = '0'+((NUM %10000)/1000);
    Buff[1] = '0'+((NUM %1000)/100);
    Buff[2] = '0'+((NUM %100)/10);
    Buff[3] = '0'+(NUM %10);

    for (unsigned char i=0; i<=2; i++)
    {
        if (Buff[i] != '0')
        {
            break;
        }
        Buff[i]=' ';
    }
    Buff[4]= '\0';
    LCDPuts(Buff);
}
int LCD_nNum3(unsigned int NUM)
{
    unsigned char Buff[8] = "0";
    Buff[0] = '0'+((NUM %100)/10);
    Buff[1] = '0'+(NUM %10);

    LCDPuts(Buff);
}
/*숫자 변환 끝*/

int receivedData = 0;
int main(void)
{
    restart:
    DDRB |= 0xf0;               //7~4 LED 3~0 스위치가 연결되어 있다. 상위 니블 7~4까지는 출력을로 설정 하위 니블 3~0 입력으로 설정
    DDRG |= (1<<PG3);           //PG3번에 buzzer 연결되어있음
    UDR0 |= 0x00;
    dis = 0;

    INTR_Init();                // 인터럽트 사용을 위한 초기화
    MCU_Init();                 //LCD 사용을 위한 MCU 설정
    UART_INIT();                // UART 통신 초기화 ( 9600 )
    TIMER1_Init();

    LCDInit();                  //LCD 사용을 위한 초기화 설정
    static char string1[]="- 2 team : DEA -";
    static char string2[]="Start with 3";
    static char string3[]="ready 0     ";

    while (1) {
        LCDMove(0,0);           //표시할 문자의 위치를 선택->HOME 위치
        LCDPuts(string1);
        LCDMove(1,0);           //LCD의 두번쨰 줄
        LCDPuts(string2);

        if(0 == (PINB & (1<<PB0)) || (UDR0 != 0x00)) {
            UDR0 |= 0x00;
            srand(TCNT1);
            value1 = rand() % 103;
            for (unsigned int i=3; i>0; i--) {  
                LCDMove(1,0);   //LCD의 두번쨰 줄
                string3[6] = '0' + i;
                LCDPuts(string3);

                _delay_ms(1000);
            }
            LCDInit();

            count_m = 1000;
            TIMER1_Init();

            break;
        }
    }

    static char passwd[]="passwd:";
    static char trial[]="trial:";
    static char down[]="down";
    static char up[]="up  ";
    static char hit[]="hit ";
    int analog = 0;
    dis = 1;
    trial_n = 15;
    while (1) 
    {       
        //receivedData = UART_receive();

        analog = readAnalog(6); //가변저항 ADC 6,7번에 연결
        LCDMove(0,0);
        LCDPuts(passwd);
        LCDMove(0,7);   //home 위치
        LCD_nNum2(analog);

        LCDMove(1,0);
        LCDPuts(trial);
        LCD_nNum3(trial_n);

        PORTB = trial_n << 4;
        if (trial_n == 0) {
            TIMER1_Initx();
            PORTG |= (1<<PG3);  //buzzer ON
            if(0 == (PINB & (1<<PB0)) || (UDR0 != 0x00)) {
                UDR0 |= 0x00;
                PORTG &= ~(1<<PG3); //buzzer OFF
                goto restart;
            }
        }

        // 인터럽트 처리
        if (ckd == 1) {
            trial_n --;
            int ck = analog / 10;
            if (value1 == ck) {
                LCDMove(0,12);
                LCDPuts(hit);
                LCDMove(0,0);

                value1 = 777;
                PORTB = 0x00;
            }
            else if (value1 > ck) {
                LCDMove(0,12);
                LCDPuts(up);
                LCDMove(0,0);
            }
            else {
                LCDMove(0,12);
                LCDPuts(down);
                LCDMove(0,0);
            }
            _delay_ms(500);
            ckd = 0;
        }
        //재시작
        if(0 == (PINB & (1<<PB0)) || (UDR0 != 0x00)) {
            UDR0 |= 0x00;
            goto restart;
        }

        // 저항 체크 성공
        if(value1 == 777)
        {
            TIMER1_Initx();
            for (int b = 3; b < 7; b++){
                PORTG = (b % 2 << PG3); //buzzer ON
                _delay_ms(100);
            }

            while(1){
                if(0 == (PINB & (1<<PB0)) || (UDR0 != 0x00)) {
                    UDR0 |= 0x00;
                    PORTG &= ~(1<<PG3); //buzzer OFF
                    goto restart;
                }
            }
        }

        // 부저
        int bz(void){
            PORTG |= (1<<PG3);  //buzzer ON
            _delay_ms(10);
            PORTG &= ~(1<<PG3); //buzzer OFF
            _delay_ms(10);
        }
        switch (count_m) {
            case 900:
            case 800:
            case 700:
            case 600:
            bz();break;

            case 500:
            bz();bz();bz();break;
            case 450:
            case 400:
            case 350:
            case 300:
            bz();break;

            case 250:
            bz();bz();bz();break;
            case 225:
            case 200:
            case 175:
            case 150:
            bz();break;

            case 125:
            bz();bz();bz();break;
            case 112:
            case 100:
            case 88:
            case 75:
            bz();break;

            case 62:
            bz();bz();bz();break;
            case 55:
            case 49:
            case 43:
            case 37:
            bz();break;

            case 31:
            bz();bz();bz();break;
            case 28:
            case 25:
            case 22:
            case 19:
            case 16:
            case 13:
            case 10:
            case 7:
            case 4:
            case 1:
            bz();break;

            case 0:
            while(1) {
                TIMER1_Initx();
                PORTG |= (1<<PG3);  //buzzer ON
                if(0 == (PINB & (1<<PB0)) || (UDR0 != 0x00)) {
                    UDR0 |= 0x00;
                    PORTG &= ~(1<<PG3); //buzzer OFF
                    goto restart;
                }
            }
        }
    }
}