[2024.03.27.수] 인천인력개발원 하만 세미콘 아카데미
임베디드 시스템을 위한 SW 구조설계
복습
1. 풀업 저항
- 플로팅 상태를 없애기 위해 설치하는 저항
- 다음과 같은 구조로 설치

2. 프로그램의 실행순서: Start - Function(함수 실행) - End [선형 구조]
인터럽트(Interrupt)
- 함수 실행 시 정해진 시점에 진행이 아닌, 임의의 시점에 진행하는 것
1. 폴링 vs 인터럽트
- 폴링
- 코드 나열 순서에 의해 실행 결정
- 모든 코드는 동일한 실행 우선순위
- 코드 A에 의해 코드 B 실행에 지연 발생 가능
- 정해진 순서에 따라 실행되므로 하드웨어의 지원이 불필요
- 코드 작성 & 이해 용이
- 인터럽트
- 우선 순위에 따라 실행 순서 결정
- 인터럽트에 따라 서로 다른 우선순위
- 우선 순위가 낮은 코드 A에 의해 우선순위가 높은 코드 B의 실행 지연 발생 없음
- 하드웨어에 의해 우선순위에 따른 처리
- 코드 작성 & 이해 난이도와 복잡성이 높음
2. 인터럽트
- 마이크로컨트롤러에 특정 작업의 즉시 처리를 요구하는 비정상적 사건
- 인터럽트 발생 -> 현재 진행 작업 중단 후 인터럽트 처리 루틴(Interrupt Service Routine, ISR)로 이동
- ISR 종료 후 실행중이던 곳으로 되돌아가 작업 재개
3. ATmega128 인터럽트
- 35개의 인터럽트 사용 가능
- 인터럽트 벡터: 인터럽트 발생 시 처리가 이동할 ISR의 메모리 주소
- ATmega128의 인터럽트 벡터 테이블: 35개의 인터럽트에 대한 인터럽트 벡터 테이블(플래시 메모리의 0x0000~0x0045에 기록)
ATmega128의 인터럽트 벡터 테이블 - 인터럽트 처리 순서
- 인터럽트 발생
- 인터럽트 벡터 테이블의 해당하는 인터럽트 벡터가 저장된 테이블 위치로 이동
- 인터럽트 벡터 값에 해당하는 ISR로 이동
- ISR 처리
- 인터럽트 처리 이전에 수행하던 코드로 복귀
4. 인터럽트 처리 조건
- 전역적 인터럽트
- 상태 레지스터 SREG의 7번 'I'비트 세트
- set하려면 sei(), clear하려면 cli()함수 사용 - setinterrupt, clearinterrupt
- 개별 인터럽트 활성화 비트 세트
- 인터럽트는 비활성화 상태가 기본값
- 개별 인터럽트별로 활성화 비트 존재
6. ISR(Interrupt Service Routine)
- 인터럽트 발생 시 처리 루틴
- 하드웨어에 의해 호출(코드 상에는 ISR호출 파트 없음)
#include <avr/interrupt.h> ISR (ADC_vect) { //인터럽트 처리 }
- 반환값과 매개변수의 데이터 형 없는 함수
- 모든 ISR은 동일한 이름, 처리할 인터럽트 종류는 인터럽트 벡터 이름인 매개변수로 구분
7. 인터럽트 주의사항
- 중첩 인터럽트
- 인터럽트를 인터럽트 불가
- ISR 실행 중 발생 인터럽트 처리 불가
- ISR은 가능한 짧게 작성
- 인터럽트 우선순위
- 번호가 낮은 인터럽트의 우선순위가 우선
- 우선순위가 높은 인터럽트 먼저 처리
- Reset 인터럽트의 우선순위가 최상위
- 최적화 방지의 필요성
- ISR은 메인 코드와 무관한 코드로 간주될 수 있음(코드 내에서 호출되는 부분이 없으므로)
- ISR에서 값을 변경하는 변수는 'volatile' 키워드를 사용 (volatile키워드: 변수 최적화 방지)
volatile int value= 0; ISR(INTERRUPT_vect) { value = (value + 1) %2; }
8. 외부 인터럽트
- Reset 제외 우선순위 최상의 인터럽트
- 범용 입출력 핀의 값, 상태 변화 시 인터럽트 발생(정해진 8개 핀으로만 가능)
- 외부 인터럽트 포트

- 사용 예시
ISR(INT0_vect)
{
state= (state+ 1) % 2; //LED 상태 전환
}
void INIT_INT0(void)
{
EIMSK I= (1 << INT0); //INT0 인터럽트 활성화
EICRA I= (1 << ISC01); //하강 에지에서 인터럽트 발생,
sei (); //전역적으로 인터럽트 허용
}

9. EIMSK 레지스터
- EIMSK: External Interrupt MaSK
- 외부 인터럽트 활성화 레지스터
- 8개 외부 인터럽트의 개별 활성화 가능

10. EICRA 레지스터
- 인터럽트 발생 시점 결정(INT0~INT3)
- EICRB레지스터로 INT4~INT7 인터럽트 발생 시점 결정


실습 1: 인터럽트 응용 스탑워치 설계
1. 회로 구성



2. 프로젝트 생성 - test03-intr 프로젝트 생성 - test03-intr 우클릭 후 set startup project

3. 7seg 실습에서 사용한 상단 코드 가져오기
#define F_CPU 16000000L //Board CLK 정보(16MHz)
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
uint8_t digit[] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x27, 0x7F, 0x67, 0x77, 0x7c, 0x58, 0x5e, 0x79, 0x71 };
uint8_t character[] = { // -,
0x40 };
char arr[5]; //세그먼트 이미지 정보를 담을 안전공간
4. 인터럽트 설정(메인함수 내에서)
EIMSK = 0x70; //0111 0000 //INT 4~INT 6 활성화
EICRB = 0x2a; //4개의 B그룹(INT4~INT7)의 인터럽트 발생 시점 결정(00 10 10 10, 각 7 6 5 4에서의 INT발생 시점을 rising edge로 결정)
SREG |= 0x80; //status Register - 인터럽트 허용 상태 레지스터
sei()
- 스위치 동작 시 HIGH에서 LOW로 변하는 하강 에지에 작동하도록 설정: EICRB = 0x2a;
- sei(): 인터럽트 시작
5. 메인함수 밖에 4, 5, 6번 인터럽트 ISR 설정
ISR(INT4_vect){ //INT4 인터럽트 처리 루틴: sw1
opt++;
if (opt >= 3) opt = 0;
}
ISR(INT5_vect){ //INT5 인터럽트 처리 루틴: sw2
state++;
if (state >= 3) state = 0;
}
ISR(INT6_vect){ //INT6 인터럽트 처리 루틴: sw3
}
조건을 나타내는 상수는 #define을 통해 상수로 선언하는 것 추천
//상단에 상수 선언 후
#define OPTMAX 3
#define STATEEMAX 3
//ISR 코드 변경
ISR(INT4_vect){ //INT4 인터럽트 처리 루틴: sw1
opt++;
if (opt >= OPTMAX) opt = 0;
}
ISR(INT5_vect){ //INT5 인터럽트 처리 루틴: sw2
state++;
if (state >= STATEMAX) state = 0;
}
ISR(INT6_vect){ //INT6 인터럽트 처리 루틴: sw3
}
6. 메인함수 위에 volatile로 변수 선언 - 최적화 금지
volatile int opt = 0; state = 0;
7. 7seg 실습에서 사용한 코드를 가져와 붙여넣기
void seg(int sel, uint8_t c){
PORTC |= 0X0F;
PORTC &= ~(1 << (3-sel));
PORTD = c; //숫자 데이터 출력
_delay_ms(2);
}
void FND_4(char *inf){ //segment Image 배열
for (int i = 0; i < 4; i++){
seg(i, *(inf+i));
}
}
//16진수 segment image 배열
char* Display(unsigned long num){ //10진 정수를 입력받아 16진수 문자열로 변환 ex)65535 ==> 0xffff, 56506=>0xBCDA
int n1 = num % 10; //A(10): 문자가 아닌 숫자
int n2 = (num / 10) % 10; //B(11)
int n3 = (num / 100) % 10; //C(12)
int n4 = num / 1000; //D(13)
arr[0] = digit[n1]; arr[1] = digit[n2]; arr[2] = digit[n3] + 0x80; arr[3] = digit[n4];
if ( num<10 ){
arr[3] = 0; arr[1] = 0; arr[2] = 0x80;
}
else if ( num<100 ){
arr[2] = 0x80; arr[3] = 0;
}
else if ( num<1000 ){
arr[3] = 0;
}
FND_4();
return arr;
}
8. 전체 코드
/*
* test03.c
*
* Created: 2024-03-27 오후 12:26:02
* Author : jong9
*/
#define F_CPU 16000000L //Board CLK 정보(16MHz)
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
#define OPTMAX 3
#define STATEMAX 3
uint8_t digit[] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x27, 0x7F, 0x67, 0x77, 0x7c, 0x58, 0x5e, 0x79, 0x71 };
char arr[5]; //세그먼트 이미지 정보를 담을 안전공간
volatile int opt = 0, state = 0;
void seg(int sel, uint8_t c){
PORTC |= 0X0F;
PORTC &= ~(1 << (3-sel));
PORTD = c; //숫자 데이터 출력
_delay_ms(2);
}
void FND_4(char *inf){ //segment Image 배열
for (int i = 0; i < 4; i++){
seg(i, *(inf+i));
}
}
//16진수 segment image 배열
char* Display(unsigned long num){ //10진 정수를 입력받아 16진수 문자열로 변환 ex)65535 ==> 0xffff, 56506=>0xBCDA
int n1 = num % 10; //A(10): 문자가 아닌 숫자
int n2 = (num / 10) % 10; //B(11)
int n3 = (num / 100) % 10; //C(12)
int n4 = num / 1000; //D(13)
arr[0] = digit[n1]; arr[1] = digit[n2]; arr[2] = digit[n3] + 0x80; arr[3] = digit[n4];
if ( num<10 ){
arr[3] = 0; arr[1] = 0; arr[2] = 0x80;
}
else if ( num<100 ){
arr[2] = 0x80; arr[3] = 0;
}
else if ( num<1000 ){
arr[3] = 0;
}
FND_4(arr);
return arr;
}
int main(void)
{
//7-Segment 사용 : 4 Module - C type
// Pin assign : PDx - Segment img, PCx - module sel
//Interrupt 사용 : INT4~INT6 (External Interrupt)
// Pin assign : PE4~PE6
DDRD = 0xFF;
DDRC = 0x0F;
DDRE = 0x00;
//인터럽트 설정
EIMSK = 0x70; //0111 0000 //INT 4~INT 6 활성화
EICRB = 0x2a; //4개의 B그룹(INT4~INT7)의 인터럽트 발생 시점 결정(00 10 10 10, 각 7 6 5 4에서의 INT발생 시점을 rising edge로 결정)
SREG |= 0x80; //status Register - 인터럽트 허용 상태 레지스터
sei(); //set interrupt
int t = 0;
while (1)
{
switch(opt){
case 0: //reset단계
t = 0; break;
case 1: //stopwatch start
t++; break;
case 2: //stopwatch stop
break;
default: break;
}
Display(t); //값이 증가하며 Disp가 호출될 때 t가 증가하며 각 자릿수에 맞는 시간 표시
_delay_ms(2);
}
}
ISR(INT4_vect){ //INT4 인터럽트 처리 루틴: sw1
opt++;
if (opt >= OPTMAX) opt = 0;
}
ISR(INT5_vect){ //INT5 인터럽트 처리 루틴: sw2
state++;
if (state >= STATEMAX) state = 0;
}
ISR(INT6_vect){ //INT6 인터럽트 처리 루틴: sw3
}
9. 작동 확인 - 오작동: 값을 할당하지 않은 SW1의 버튼 누르면 작동하는 현상 발생
이유: RC공진에 의한 오작동으로 파악 -> SW2의 저항을 제거하여 공진현상 방지
실습 2: 인터럽트 응용하여 주방 타이머 설계 - 16일차 진행
'하만(Harman) 세미콘 반도체 설계 과정 > 임베디드 시스템을 위한 SW 구조설계' 카테고리의 다른 글
하만(Harman) 세미콘 아카데미 17일차 - SW 구조설계(주방 타이머 설계 이어서) (24) | 2024.03.29 |
---|---|
하만(Harman) 세미콘 아카데미 16일차 - SW 구조설계(8비트 타이머/카운터, 16비트 타이머/카운터, 주방 타이머 설계 실습) (1) | 2024.03.28 |
하만(Harman) 세미콘 아카데미 12일차 - SW 구조설계( 7세그먼트 - 16진수 출력, 스톱워치 구현) (23) | 2024.03.22 |
하만(Harman) 세미콘 아카데미 11일차 - SW 구조설계( 데이터 입출력, 버튼 LED 점멸, 7세그먼트 출력 ) (22) | 2024.03.21 |