BASIC4MCU | 질문게시판 | atmega128 문제를 보고 코딩 고쳐주세요ㅠㅠㅠ부탁드립니다
페이지 정보
작성자 호빵맨 작성일2020-09-26 23:02 조회7,369회 댓글1건본문
문제-> 다음의 조건을 만족하는 ‘엘리베이터 층 수 표시기’를 제작한다.
• 건물 층은 지하3층부터 지상 22층까지 있다.
• 엘리베이터는 2 초마다 1층씩 올라가거나 내려오며, 최상층이나 • 최하층에 도달하면 자동으로 이동 방향이 바뀐다.
• 엘리베이터 층 수 숫자 표시는 FND의 가운데 2개만 사용하여 디스플레이하며, 지하 표시는 숫자 앞에 '-'를 붙여 구분한다. (예 : 지하 1층은 “-1” 표시)
• SW1은 한 번 누르면 정지하고 한 번 더 누르면 다시 진행한다.
• SW2는 한 번 누를 때마다 엘리베이터의 이동 방향이 바뀐다.
내가 한 코딩
#include <avr/io.h> // ATmega128 register 정의
#include <avr/interrupt.h> // 인터럽트 서비스 루틴 처리 시 사용
#define F_CPU 16000000UL
#include <util/delay.h>
#define IDLE 0 // IDLE 상태 값
#define STOP 1 // STOP 상태 값
#define GO 2 // GO 상태 값
#define DOWN 3
volatile int cur_time = 0; // ‘현재 시간’ 변수 초기화
volatile int stop_time = 0; // ‘STOP 시간’ 변수 초기화
volatile int state = IDLE; // state : 현재 상태를 나타내는 전역변수(Global Variable)
// 처음 시작 시에는 STOP 상태에서 출발
unsigned char digit[]= {0x3f, 0x06, 0x5b, 0x4f, 0x66,
0x6d, 0x7c, 0x07, 0x7f, 0x67};
unsigned char fnd_sel[4] = {0x01, 0x02, 0x04, 0x08}; // FND 선택 신호 어레이
ISR(INT4_vect)
{
_delay_ms(100); // 스위치 바운스 기간 동안 기다림
if ((PINE & 0x10)==0x10) // 인터럽트 입력 핀(PE4)을 다시 검사하여
return; // 눌러진 상태가 아니면(‘1’) 리턴
EIFR |= 1 << 4; // 그 사이에 바운스에 의하여 생긴 인터럽트는 무효화
if (state == IDLE || state == STOP) // IDLE 또는 STOP 상태라면
state = GO;
else // 만약 GO 상태라면
{
state = STOP; // -> STOP (상태 변경)
stop_time = cur_time; // 그리고, “현재 시간”을 복사
}
}
ISR(INT5_vect)
{
_delay_ms(100); // 스위치 바운스 기간 동안 기다림
if ((PINE & 0x20)==0x20) // 인터럽트 입력 핀(PE5)을 다시 검사하여
return; // 눌러진 상태가 아니면(‘1’) 리턴]
EIFR |= 1 << 5; // 그 사이에 바운스에 의하여 생긴 인터럽트는 무효화
state = IDLE; // 상태(state) 초기화, RESET 시 -> IDLE
if( state == DOWN )
state = GO;
else if ( state == GO )
state = DOWN;
}
void init_stopwatch(void); // main 함수가 call하는 함수는 main
// 함수보다 먼저 나타나거나 그 타입만
// 먼저 나오고 나중에 call 경우 유효함
void display_fnd(int); // 마찬가지 이유
int main()
{
init_stopwatch( );
while(1)
{
if (state == IDLE) // IDLE 상태이면
display_fnd(stop_time); // 초기값 00.00 디스플레이, 시간은 정지
else if (state == STOP) // STOP 상태이면
display_fnd(stop_time); // SW1이 눌러진 순간의 시간 디스플레이
else if (state == GO) // GO 상태이면
{
display_fnd(cur_time); // 경과 시간 디스플레이
cur_time++;
}
else
{
display_fnd(cur_time);
cur_time--;
}
if (cur_time == 23) // 22 다음은 내려감.
{ cur_time = cur_time -1;
state = DOWN;
}
if (cur_time == -3) // 0 다음은 올라감.
{ cur_time = cur_time +1;
state = GO;
}
}
}
void init_stopwatch(void)
{
DDRC = 0xff; // C 포트는 FND 데이터 신호
DDRG = 0x0f; // G 포트는 FND 선택 신호
DDRE = 0x00; // PE4(SW1), PE5(SW2)을 포함한 PE 포트는 입력 신호
sei(); // SREG 7번 비트(I) 세트
// sei() 는 “SREG |= 0x80” 와 동일한 기능을 수행
EICRB = 0x0a; // INT4, INT5 트리거는 하강 에지(Falling Edge)
EIMSK = 0x30; // INT4, INT5 인터럽트 enable
}
void display_fnd(int count) // 이 함수의 1회 수행시간은
// 약 10ms(1/100초)로 _delay_ms()
// 외의 코드 실행시간은 us 단위로 무시
{
int i, fnd[4]; // 각 자리수의 변수를 다르게 해도 되지만
// 여기처럼 변수를 어레이로 잡는 것도 방법임
// 천 자리
fnd[3] = (count/1000)%10; // 천 자리
fnd[2] = (count/100)%10; // 백 자리
fnd[1] = (count/10)%10; // 십 자리
fnd[0] = count%10;
for (i=0; i<4; i++) // 어레이의 첨자를 이용하면 프로그램 단순화 가능
{
PORTC = digit[fnd[i]];
PORTG = fnd_sel[i];
if (i%2)
_delay_ms(2);
else
_delay_ms(3);
// 루프를 돌므로 총 10ms(1/100초) 경과
}
}
댓글 1
조회수 7,369master님의 댓글
master 작성일
엘리베이터는 조금 복잡해서 실제로 돌려가면서 디버깅해야 합니다.
회로를 꾸민 사람만 가능하겠죠?