728x90
반응형
[Timer/Counter]
#define F_CPU 160000000UL
#include <avr/io.h>
#include <avr/interrupt.h> // 인터럽트 사용을 위한 헤더파일
#include <stdio.h>
int cnt; // 카운트 값을 저장할 변수 선언
ISR(TIMER0_OVF_vect){ // 타이머/카운터 0번의 오버플로우 인터럽트 서비스 루틴 함수
//
cnt++;
TCNT0 = 131; // 약 2ms를 만들기 위한 초기값
if(cnt == 500) // 500번째 인터럽트 발생 시 LED 출력을 변경함. 약 1초(1,000ms)
{
PORTD = ~PORTD; // 출력 반전
cnt = 0;
}
}
int main(void)
{
DDRD = 0xff;
//PORTD = 0x00; // 다 꺼진 것을 시작
PORTD = 0xaa; // 모양을 좀 더 이쁘게
//256 분주 //
TCCR0 = (1<<CS02) | (1<<CS01) | (0<<CS00); // 분주를 해야 하니까 CS01 02 00 에 값을 대입
// Overflow interrupt enable //
TIMSK = (1<<TOIE0);
sei(); // 인터럽트를 사용하기 위해, 글로벌 인터럽트를 활성화시켜줘야 한다.
while (1)
{
}
}
[Interrupt]
Interrupt 예제
버튼 신호에 따라 반응하는 interrupt
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
// 인터럽트 서비스 루틴 정의 //
ISR(INT4_vect) // 외부 인터럽트 INT4(PORTD-4) IST 정의
{
PORTD ^= (1<<0); // 반전시켜서 보낼 것이다.
}
ISR(INT5_vect)
{
PORTD ^= (1<<0);
}
int main(void)
{
// INT4 가 Falling edge(1 0)일 때, 인터럽트 발생
EICRB |= (1<<ISC41) | (0<<ISC40); // button4는 누를 때(1->0) 출력
// INT5 Rising edge(1 1)일 때, 인터럽트 발생
EICRB |= (1<<ISC51) | (1<<ISC50); // button5는 눌렀다가 뗄 때(1->0) 출력
// INT4, INT5 인터럽트 활성화
EIMSK |= (1<<INT5) | (1<<INT4);
// 버튼 입력 설정
DDRE &= ~(1<<DDRE5) | ~(1<<DDRE4); // PORTE의 4번과 5번 핀에 해당하는 DDR을 0으로 비트마스킹
// 0으로 설정해야 입력을 받음
DDRD = 0xff; // LED 출력 설정
sei(); // SREG I[7](I의 8번째 비트) 를 1로 set
// 반대 개념은 cli(); -> 0으로 만들어주는 것
while (1)
{
}
}
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
uint8_t ledShift = 0xfe; // 1111 1110 으로 시작
ISR(INT4_vect)
{
ledShift = ledShift << 1; // 함수 호출 시, led 한 칸 좌시프트
ledShift = ledShift | 0x01; // 한 칸 시프트하면, 0bit가 0으로 채워지므로 0x01과 OR 연산
if (ledShift == 0xff) // 끝까지 가면, 초기화
{
ledShift = 0xfe;
}
PORTD = ledShift;
}
int main(void)
{
DDRD = 0xff;
DDRE &= ~(1<<DDRE4);
EICRB |= (1<<ISC41) | (0<<ISC40); // falling edge일 때 동작
EIMSK |= (1<<INT4); // INT4에 해당하는 핀의 인터럽트 활성화
sei();
while (1)
{
}
}
<Debounce code 추가>
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
// 이제까지는 디바운스 코드를 안 썼다.
// while문은 계속 돌아가는 것이지만, 그 외부의 함수는 1번 실행하고 초기화된다.
// 따라서 버튼을 작동시켰을 때 사용되는 디바운스 코드는 while문 안으로 들어가야 한다.
volatile uint8_t ledShift = 0xfe;
uint8_t buttonPressed = 0; // 초기값은 0
ISR(INT4_vect)
{
buttonPressed = 1; // ISR 함수가 호출되면 buttonPressed 상태만 변화시킴(반전)
}
int main(void)
{
DDRD = 0xff; // PORTD all 출력으로 설정
DDRE &= ~(1<<DDRE4); // PORTE 4번 핀 입력 설정
PORTD = ledShift; // 전역변수 선언해놨으니 사용 가능
// 초기화
// 4번 핀을 인터럽트로 사용하기 위한 준비 //
EICRB |= (1<<ISC41) | (0<<ISC40); // INT4 핀을 falling edge로 사용할 것이다.
EIMSK |= (1<<INT4); // 4번 핀의 인터럽트 활성화
sei(); // 글로벌 인터럽트 활성화
while (1)
{
if (buttonPressed) // buttonPressed 눌린 상태라면 = 인터럽트가 발생하였다면?
// 초기값 0, 버튼 누르는 순간 ISR 함수 호출로 1로 바뀜
{
_delay_ms(50);
if (!(PINE & (1<<PINE4))) // 버튼이 계속 눌려져 있는지 확인
// 풀업 저항으로 인해 pin4는 1로 유지 중
// 버튼을 누르는 순간, pin4의 입력이 1->0으로 바뀜
// PINE = xxx0xxxx (x = N/A, PIN의 초기값은 N/A)
// 1<<PINE4 : 00010000
// 둘이 AND연산하면, 00000000 = 0
// ∴ 버튼이 눌려있다면? 이라는 의미가 된다.
{
ledShift = (ledShift << 1 ) | 0x01; // 한 칸 좌시프트하고, 빈 칸 1로 채워줌
if (ledShift == 0xff) // 끝까지 갔다면, 초기화
{
ledShift = 0xfe;
}
PORTD = ledShift; // 끝까지 안 갔다면, 시프트한 ledShift를 출력해라
}
buttonPressed = 0; // 버튼 안 눌려 있다면, buttonPressed = 0
}
}
}
Interrupt의 활용
1. FND 설치
2. Interrupt 발생할 때마다 FND 카운트 1씩 증가하게끔 코딩
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
int cnt; // 전역변수로 카운트 선언
uint8_t buttonState = 0; // 디바운스 코드 작성을 위해 선언
// Segment 배열 선언 //
uint8_t seg_arr[] ={
0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x27, 0x7f, 0x67
};
ISR(INT4_vect) // PORTE 4번 핀의 인터럽트 서비스 루틴 생성
{
buttonState = 1; // 인터럽트 발생 시, 실행
}
int main(void)
{
DDRA = 0xff; // PORTA all 출력 모드
DDRE &= ~(1<<PINE4); // PORTE 입력 모드
// 4번 핀 인터럽트 활성화 //
EICRB |= (1<<ISC41) | (0<<ISC40);
EIMSK |= (1<<INT4);
sei();
while (1)
{
if (buttonState)
{
_delay_ms(50);
if (!(PINE & (1<<PINE4)))
// 눌러진 상태라면 PINE3의 입력이 1->0,
// 1<<PINE4 : 00010000
// PINE = xxx0xxxx
// 둘이 AND 연산하면, 00000000
{
if(cnt<10)
{
PORTA = seg_arr[cnt]; // seg_arr의 cnt번째 element를 출력
cnt++;
if(cnt == 10) cnt=0; // 끝까지 가면, 초기화
}
}
buttonState = 0;
}
}
}
728x90
반응형