[Embedded Software] 경희대 임베디드 소프트웨어 과제3 - Switch & Interrupt
on Study
개발 환경
- 개발보드 : JKIT-128-1
- MUC : ATmega128
- IDE : AVR Studio 4
Compiler : WinAVR
- JKIT-128-1 에서의 스위치 연결 회로도
실습 4
4.1 GPIO 포트 E 전체를 입력으로 만들어 여기로 입력되는 신호 값을 실시간으로(1초 단위) LED에 디스플레이 한다.(SW1, SW2을 누르면서 LED의 변화를 확인)
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
int main() {
DDRA = 0xFF;
// 스위치 두 개는 E포트 4,5번(0번부터 시작하였을 때)에 연결
// SW1 = 4번, SW2 = 5번
// DDRE |= ~(0x30); 과 같다.
DDRE |= 0xCF;
while(1) {
PORTA = PINE;
_delay_ms(100);
}
}
4.2 SW1 을 누르면 모든 LED 불이 켜지고 다시 스위치를 누르면 모든 LED 불이 꺼지며(toggle) SW2 를 누르면 현 상태에서 1이 증가한 값을 LED에 디스플레이한다.
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define OFF 0
#define ON 1
// volatile을 붙이면 컴파일러의 최적화를 하지 않겠다는 의미이다.
// 메모리 맵 입출력을 할 시, 개발자가 의도한대로 코드가 작동하기 위해
// (= 컴파일러에 의해 코드가 의도와 다르게 작동하는 것을 막기 위해)
// 사용된다.
volatile int int4_flag = OFF;
// 인터럽트4를 사용하여 LED 출력을 조정한다.
// JKIT보드에서 인터럽트4는 SW1(E포트 4번)이다.
// 인터럽트 발생 시, int4_flag 값에 따라 LED를 ON/OFF
SIGNAL(SIG_INTERRUPT4) {
// Interrupt Disable
cli();
if(int4_flag == OFF) {
int4_flag = ON;
PORTA = 0xFF;
}
else {
int4_flag = OFF;
PORTA = 0x00;
}
_delay_ms(100);
// Interrupt Enable
sei();
}
// 인터럽트5를 사용하여 LED 출력을 조정한다.
// JKIT보드에서 인터럽트5는 SW2(E포트 5번)이다.
// 인터럽트 발생 시, LED를 1증가하여 출력
SIGNAL(SIG_INTERRUPT5) {
cli();
if(int4_flag == OFF) {
PORTA += 1;
}
_delay_ms(100);
sei();
}
int main() {
DDRA = 0xFF;
PORTA = 0x00;
// 스위치 모두 사용
DDRE = 0x00;
// EICR(External Interrupt Control Register)
// EICRA : 외부 인터럽트 0~3의 트리거 설정
// EICRB : 외부 인터럽트 4~7의 트리거 설정
// EICRB = 0x02이면 하강에지(SW가 눌렸을 때)에서 인터럽트 발생
EICRA = 0x00;
EICRB = 0x02;
// EIMSK(External Interrupt MaSK register)
// 외부 인터럽트의 개별적인 허용 레지스터
// EIMSK = 0x30이면 4,5번 인터럽트를 사용한다는 의미이다.
EIMSK = 0x30;
sei();
while(1)
;
}
실습 5
5.1 SW1 을 누르면 모든 LED 불이 켜지고 다시 SW1 을 누르면 모든 LED 불이 꺼진다.
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define OFF 0
#define ON 1
volatile int int4_flag = OFF;
// 인터럽트4를 이용하여 int4_flag 변수 제어
SIGNAL(SIG_INTERRUPT4) {
cli();
if(int4_flag == OFF) {
int4_flag = ON;
}
else {
int4_flag = OFF;
}
_delay_ms(100);
sei();
}
int main() {
DDRA = 0xFF;
DDRE = 0xEF;
PORTA = 0x00;
EICRA = 0x00;
EICRB = 0x02;
// 인터럽트 4번을 사용한다는 의미
EIMSK = 0x10;
sei();
while(1) {
if(int4_flag == OFF) {
PORTA = 0x00;
}
else {
PORTA = 0xFF;
}
}
}
5.2 5.1에 더하여, FND의 숫자는 0에서 출발하여 SW2 를 누를 때마다 1씩 증가한다.
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define OFF 0
#define ON 1
// 인터럽트4를 사용하여 LED 출력 조정
SIGNAL(SIG_INTERRUPT4) {
volatile static int int4_flag = OFF;
cli();
if(int4_flag == OFF) {
int4_flag = ON;
PORTA = 0xFF;
}
else {
int4_flag = OFF;
PORTA = 0x00;
}
_delay_ms(100);
sei();
}
// 인터럽트5를 사용하여 FND 출력 조정
SIGNAL(SIG_INTERRUPT5) {
static unsigned char FND_DATA[ ]= {
0x3f, 0x06, 0x5b, 0x4f, 0x66,
0x6d, 0x7d, 0x27, 0x7f, 0x6f };
static unsigned int num = 0;
cli();
PORTC = FND_DATA[num];
PORTG = 0x01;
// 10으로 나눈 나머지를 사용하여 1씩 증가해도
// 배열에 들어있는 값(0~9)가 반복되도록 한다.
num = (num+1) % 10;
_delay_ms(100);
sei();
}
int main() {
DDRA = 0xFF;
DDRC = 0xFF;
DDRE = 0xCF;
PORTA= 0x00;
EICRA = 0x00;
// 인터럽트4, 5번 : 하강엣지
EICRB = 0x0A;
// 인터럽트 4, 5번 사용
EIMSK = 0x30;
sei();
while (1)
;
}
실습 6
6.1 스위치 와 FND를 이용하여 1/100초 단위의 스톱워치를 제작하는데, SW1를 누르면 FND 디스플레이가 잠시 멈추었다가 한 번 더 누르면 다시 이어서 동작을 하도록 한다.
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define OFF 0
#define ON 1
// volatile을 사용하여 컴파일러의 최적화가 적용이 안되게
// 변수를 모두 전역으로 선언
volatile int int_flag = OFF;
volatile int time_10sec = 0;
volatile int time_1sec = 0;
volatile int time_100ms = 0;
volatile int time_10ms = 0;
// 인터럽트4를 사용하여 int_flag 변수 조정
SIGNAL(SIG_INTERRUPT4) {
cli();
if(int_flag == OFF) {
int_flag = ON;
}
else {
int_flag = OFF;
}
_delay_ms(100);
sei();
}
// 인터럽트5를 사용하여 time변수들 초기화
SIGNAL(SIG_INTERRUPT5) {
cli();
time_10sec = 0;
time_1sec = 0;
time_100ms = 0;
time_10ms = 0;
int_flag = OFF;
_delay_ms(100);
sei();
}
int main() {
unsigned char FND_DATA[ ] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66,
0x6d, 0x7c, 0x07, 0x7f, 0x67,
0x77, 0x7c, 0x39, 0x5e, 0x79,
0x71, 0x80, 0x40, 0x08 };
DDRC = 0xFF;
DDRG = 0x0F;
DDRE = 0xCF;
PORTC = FND_DATA[0];
PORTG = 0x00;
EICRA = 0x00;
// 인터럽트 4, 5번 : 하강엣지
EICRB = 0x0A;
// 인터럽트 4, 5번 사용
EIMSK = 0x30;
sei();
while(1) {
if(int_flag == ON) {
time_10ms++;
if(time_10ms == 10) {
time_100ms++;
time_10ms = 0;
}
if(time_100ms == 10) {
time_1sec++;
time_100ms = 0;
}
if(time_1sec == 10) {
time_10sec++;
time_1sec = 0;
}
if(time_10sec == 6) {
time_10sec = 0;
}
}
PORTC = FND_DATA[time_10ms];
PORTG = 0x01;
_delay_ms(2);
PORTC = FND_DATA[time_100ms];
PORTG = 0x02;
_delay_ms(3);
PORTC = FND_DATA[time_1sec];
PORTG = 0x04;
_delay_ms(2);
PORTC = FND_DATA[time_10sec];
PORTG = 0x08;
_delay_ms(3);
}
}
실습응용 1
5.2의 코드는 ISR의 코드를 길게 수행하며 이는 바람직하지 않다. 이를 main함수로 이동하여 처리하도록 한다.
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define OFF 0
#define ON 1
volatile static unsigned int num = 0;
volatile static int int4_flag = OFF;
unsigned char FND_DATA[ ] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66,
0x6d, 0x7c, 0x07, 0x7f, 0x67};
// 인터럽트4는 int4_flag 변수 조정
SIGNAL(SIG_INTERRUPT4) {
cli();
if(int4_flag == OFF) {
int4_flag = ON;
}
else {
int4_flag = OFF;
}
_delay_ms(100);
sei();
}
// 인터럽트5는 num변수 조정
SIGNAL(SIG_INTERRUPT5) {
cli();
num = (num + 1) % 10;
_delay_ms(100);
sei();
}
int main() {
DDRA = 0xFF;
DDRC = 0xFF;
DDRE = 0xCF;
PORTA = 0x00;
PORTC = FND_DATA[0];
PORTG = 0x00;
EICRA = 0x00;
// 인터럽트 4, 5번 : 하강엣지
EICRB = 0x0A;
// 인터럽트 4, 5번 사용
EIMSK = 0x30;
sei();
// main함수 안의 while루프를 통해 LED와 FND의 출력 조정
while(1) {
if(int4_flag == OFF) {
PORTA = 0xFF;
}
else {
PORTA = 0x00;
}
PORTC = FND_DATA[num];
PORTG = 0x01;
_delay_ms(2);
}
}
실습응용 2
실습 6의 스톱워치를 기본으로, SW1이 눌려지면 그 순간 시간이 정지한 상태로 디스플레이하지만, 실제로는 스톱워치가 시간을 계속 카운트하고 있어서, SW1이 다시 눌려지면 현재 시간부터 디스플레이되도록 하는 프로그램을 작성하라.
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define OFF 0
#define ON 1
// volatile을 사용하여 컴파일러의 최적화가 적용이 안되게
// 변수를 모두 전역으로 선언
volatile static int first_flag = ON;
volatile static int int_flag = OFF;
volatile int time_10sec = 0;
volatile int time_1sec = 0;
volatile int time_100ms = 0;
volatile int time_10ms = 0;
volatile int stop_time_10sec = 0;
volatile int stop_time_1sec = 0;
volatile int stop_time_100ms = 0;
volatile int stop_time_10ms = 0;
volatile static unsigned char FND_DATA[ ] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66,
0x6d, 0x7c, 0x07, 0x7f, 0x67,
0x77, 0x7c, 0x39, 0x5e, 0x79,
0x71, 0x80, 0x40, 0x08 };
// 인터럽트4를 사용하여 stop_time 변수의 값 생성
SIGNAL(SIG_INTERRUPT4) {
cli();
if(int_flag == OFF) {
int_flag = ON;
if(first_flag == ON) {
first_flag = OFF;
}
}
else {
int_flag = OFF;
stop_time_10sec = time_10sec;
stop_time_1sec = time_1sec;
stop_time_100ms = time_100ms;
stop_time_10ms = time_10ms;
}
sei();
}
// 인터럽트5를 사용하여 변수 초기화
SIGNAL(SIG_INTERRUPT5) {
cli();
stop_time_10sec = time_10sec = 0;
stop_time_1sec = time_1sec = 0;
stop_time_100ms = time_100ms = 0;
stop_time_10ms = time_10ms = 0;
int_flag = OFF;
first_flag = ON;
sei();
}
int main() {
DDRC = 0xFF;
DDRG = 0x0F;
DDRE = 0xCF;
PORTC = FND_DATA[0];
PORTG = 0x0F;
EICRA = 0x00;
// 인터럽트 4, 5번 : 하강 엣지
EICRB = 0x0A;
// 인터럽트 4, 5번 사용
EIMSK = 0x30;
sei();
while(1) {
if(first_flag == OFF) {
time_10ms++;
if (time_10ms == 10) {
time_100ms++;
time_10ms = 0;
}
if (time_100ms == 10) {
time_1sec++;
time_100ms = 0;
}
if (time_1sec == 10) {
time_10sec++;
time_1sec= 0;
}
if (time_10sec == 6) {
time_10sec = 0;
}
}
if(int_flag == ON) {
PORTC = FND_DATA[time_10ms];
PORTG = 0x01;
_delay_ms(2);
PORTC = FND_DATA[time_100ms];
PORTG = 0x02;
_delay_ms(3);
PORTC = FND_DATA[time_1sec] | FND_DATA[16];
PORTG = 0x04;
_delay_ms(2);
PORTC = FND_DATA[time_10sec];
PORTG = 0x08;
_delay_ms(3);
}
else if(int_flag == OFF) {
PORTC = FND_DATA[stop_time_10ms];
PORTG = 0x01;
_delay_ms(2);
PORTC = FND_DATA[stop_time_100ms];
PORTG = 0x02;
_delay_ms(3);
PORTC = FND_DATA[stop_time_1sec] | FND_DATA[16];
PORTG = 0x04;
_delay_ms(2);
PORTC = FND_DATA[stop_time_10sec];
PORTG = 0x08;
_delay_ms(3);
}
}
}
실습응용 3
실습응용 1을 inturrpt 대신 polling 방식으로 구현
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#define OFF 0
#define ON 1
int main() {
static unsigned char FND_DATA[ ] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66,
0x6d, 0x7c, 0x07, 0x7f, 0x67,
0x77, 0x7c, 0x39, 0x5e, 0x79,
0x71, 0x80, 0x40, 0x08 };
static unsigned int num = 0;
static int int4_flag = OFF;
DDRA = 0xFF;
PORTA= 0x00;
DDRE = 0xCF;
while(1) {
unsigned int result = 0x30 & PINE;
if(0x10 == result) {
num = (num+1) % 10;
}
else if(0x20 == result) {
if(int4_flag == OFF) {
int4_flag = ON;
}
else {
int4_flag = OFF;
}
}
if(int4_flag == ON) {
PORTA = 0xFF;
}
else {
PORTA = 0x00;
}
PORTC = FND_DATA[num];
PORTG = 0x01;
_delay_ms(200);
}
}
실습응용 2를 interrupt 대신 polling으로 구현
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#define OFF 0
#define ON 1
volatile static int first_flag = ON;
volatile static int int_flag = OFF;
volatile int time_10sec = 0;
volatile int time_1sec = 0;
volatile int time_100ms = 0;
volatile int time_10ms = 0;
volatile int stop_time_10sec = 0;
volatile int stop_time_1sec = 0;
volatile int stop_time_100ms = 0;
volatile int stop_time_10ms = 0;
static unsigned char FND_DATA[ ] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66,
0x6d, 0x7c, 0x07, 0x7f, 0x67,
0x77, 0x7c, 0x39, 0x5e, 0x79,
0x71, 0x80, 0x40, 0x08 };
unsigned int prev_upButton = 0x10;
int main() {
DDRC = 0xFF;
DDRG = 0x0F;
DDRE = 0xCF;
PORTC = FND_DATA[0];
PORTG = 0x0F;
while(1) {
if(0x00 == (PINE & 0x20)) {
stop_time_10sec = time_10sec = 0;
stop_time_1sec = time_1sec = 0;
stop_time_100ms = time_100ms = 0;
stop_time_10ms = time_10ms = 0;
int_flag = OFF;
first_flag = ON;
}
if((0x00 == (PINE & 0x10)) && (prev_upButton == 0x10)) {
if(int_flag == OFF) {
int_flag = ON;
if(first_flag == ON) {
first_flag = OFF;
}
}
else {
int_flag = OFF;
stop_time_10sec = time_10sec;
stop_time_1sec = time_1sec;
stop_time_100ms = time_100ms;
stop_time_10ms = time_10ms;
}
prev_upButton = 0x00;
}
else if((0x10 == (PINE & 0x10)) && (prev_upButton == 0x00)) {
prev_upButton = 0x10;
}
if(first_flag == OFF) {
time_10ms++;
if(time_10ms == 10) {
time_100ms++;
time_10ms = 0;
}
if(time_100ms == 10) {
time_1sec++;
time_100ms = 0;
}
if(time_1sec == 10) {
time_10sec++;
time_1sec= 0;
}
if(time_10sec == 6) {
time_10sec = 0;
}
}
if(int_flag == ON) {
PORTC = FND_DATA[time_10ms];
PORTG = 0x01;
_delay_ms(2);
PORTC = FND_DATA[time_100ms];
PORTG = 0x02;
_delay_ms(3);
PORTC = FND_DATA[time_1sec] | FND_DATA[16];
PORTG = 0x04;
_delay_ms(2);
PORTC = FND_DATA[time_10sec];
PORTG = 0x08;
_delay_ms(3);
}
else if(int_flag == OFF) {
PORTC = FND_DATA[stop_time_10ms];
PORTG = 0x01;
_delay_ms(2);
PORTC = FND_DATA[stop_time_100ms];
PORTG = 0x02;
_delay_ms(3);
PORTC = FND_DATA[stop_time_1sec] | FND_DATA[16];
PORTG = 0x04;
_delay_ms(2);
PORTC = FND_DATA[stop_time_10sec];
PORTG = 0x08;
_delay_ms(3);
}
}
}