Timer 실습

Download Report

Transcript Timer 실습

마이크로프로세서설계 – 11
Timer 실습
시스템및센서네트워크연구실
1
ATmega128
시스템및센서네트워크연구실
2
LED sink / 스위치 풀업 회로
470
5V
PC0
+5V
PC1
…..
10K
PC7
PD2
104 (0.1uF)
시스템및센서네트워크연구실
3
FND 회로
PB0
1
5
B
C
PA1
6
1K
FND
PA0
10
E
+5V
…..
PA7
시스템및센서네트워크연구실
4
시스템및센서네트워크연구실
5
타이머/카운터
 타이머/카운터
 입력으로 들어오는 펄스 또는 클럭을 셈하는 장치
 입력으로 들어오는 펄스가 어떤 형태인가에 따라 타이머와 카운터로 나
눔
• 타이머 : 클럭의 소스가 마이크로컨트롤러의 시스템 클럭에 의존
• 카운터 : 마이크로컨트롤러의 외부 핀(카운터 전용 핀)에 들어오는 펄
스를 셈하는 경우
system clock
timer clock
시스템및센서네트워크연구실
6
시스템 클럭
 시스템 클럭
 마이크로컨트롤러가 가진 내부 시계(clock)
 AVR의 경우 어셈블리어 1개 명령은 1 시스템 클럭에 수행됨
 시스템 클럭 설정 방법에 따라 클럭의 실제 시간이 결정됨
 AVR의 시스템 클럭 소스
 5종류의 클럭 소스
 퓨즈 비트 (CKSEL3 – 0)를 이용하여 선택
• 컴파일러 > project > configure > after make > program fuse bit
 External crystal/ceramic resonator
 16MHz : CKSEL3-1 – 1111 로 설정
• CodeVisionAVR에서는
프로젝트 생성시 자동 설정
 16MHz을 사용하는 경우
12-22pF
1 시스템 클럭은 1/16 usec
시스템및센서네트워크연구실
XTAL2
XTAL1
7
타이머 학습을 위한 고려사항
1. 시스템 클럭이 16MHz 크리스탈을 사용하는 경우 1/16usec으로 매우 작다.
좀 더 현실적인 크기의 시간 값을 가지게 하는 방법은 없을까?
2. 우리는 60초라는 시계 단위를 사용하는데, 마이크로컨트롤러는 어떤 시계
단위를 사용할까?
3. 마이크로컨트롤러가 타이머 클럭을 셈하였다면, 마이크로컨트롤러는 어디
에 이를 저장해 둘까?
4. 업/다운 타이머로 동작시 원하는 횟수만큼 셈하고 난 뒤, 프로그래머에게 알
리는 방법은 무엇일까?
system clock
timer clock
시스템및센서네트워크연구실
8
프리스케일러 (freescale)
 프리스케일러
 타이머에 공급하는 시스템 클럭의 속도를 조절하는 분주기
 분주기라는 말 자체가 의미하듯이 클럭을 쪼갠다는, 즉 속도를 느리게 한
다는 의미
 사용 이유
• 마이크로컨트롤러의 시스템 클럭은 연산 속도를 빨리 하기 위하여 높
은 Hz의 크리스탈을 사용함
• 그러나, 타이머의 경우 시스템 클럭을 셈하기 때문에, 분주하지 않으
면 시스템 클럭이 너무 빠른 경우가 많음
• 따라서, 프리스케일러를 이용하여 시스템 클럭을 분주하여 타이머 클
럭을 느리게 만듬
• 예 : 16MHz의 시스템 클럭(1/16usec)을 2분주하면 1 타이머 클럭은
8MHz (1/8 usec)가 됨
시스템및센서네트워크연구실
9
 10비트 프리스케일러
 분주비가 1024(210)이라는 의미
 단, 분주비가 1024까지라고 해서 모든 분주가 가능하지는 않음
 분주비를 위한 레지스터가 존재하며, 레지스터 값에 따라 분주비가 선택됨
시스템및센서네트워크연구실
10
8비트 타이머 / 16비트 타이머
 8비트 타이머
 0x00 – 0xFF 까지 셈을 할 수 있음
 0xFF까지 간 후, 오버플로(overflow)가 발생하여 0x00로 리셋(reset)됨
 1바이트만을 이용하여 셈을 할 수 있음
 BOTTOM : 0x00, MAX : 0xFF, TOP : 설정 값
 ATMega128 : timer/counter0
 16비트 타이머
 0x0000 – 0xFFFF 까지 셈을 할 수 있음
 0xFFFF까지 간 후, 오버플로(overflow)가 발생하여 0x0000로 리셋(reset)
됨
 2바이트를 이용하여 셈을 할 수 있음
 BOTTOM : 0x0000, MAX : 0xFFFF, TOP : 설정 값
 ATMega128 : timer/counter1, 2, 3
시스템및센서네트워크연구실
11
타이머 값 저장 레지스터
 8비트 타이머
 1바이트 레지스터에 셈한 값을 저장
 타이머/카운터 0
• TCNT0
 16비트 타이머
 2바이트 레지스터에 셈한 값을 저장
 타이머/카운터 1
• TCNT1H
• TCTN1L
• 두 바이트를 합쳐서 TCNT1로 기재해도 인식되기도 함
시스템및센서네트워크연구실
12
동작 모드와 인터럽트
 동작 모드
 타이머가 동작하는 방법
 AVR의 경우 4가지 동작 모드를 제공
• Normal mode : 일반적인 타이머 동작
• CTC mode : 타이머의 output compare 동작
• Fast PWM mode : PWM 동작
• Phase correct PWM mode : PWM 동작
 인터럽트
 타이머에게 지정한 기능을 수행하게 한 후, 그 수행 결과를 프로그래머에
게 돌려주기 위하여 인터럽트 사용
 동작 모드에 따라 인터럽트 종류가 다름
• Normal mode : timer/counterX overflow interrupt
• CTC mode : timer/countX compare match interrupt
시스템및센서네트워크연구실
13
Normal mode
 일반 모드
 업 카운터로서만 동작
 MAX(0xFF)값이 되면, BOTTOM(0x00)값부터 다시 시작
 이 때, 오버플로우 인터럽트 발생 (TOVn 0->1)
 일정한 시간 간격으로 인터럽트가 발생되어 원하는 처리를 할 수 있음
 TCNTn의 초기값은 설정 가능
timer overflow
0xFF
TCNTn
0x00
시스템및센서네트워크연구실
14
CTC mode
 CTC 모드
 TCNTn의 값이 증가하여, OCRn 값과 일치하면
• 다음 클럭에서 0으로 클리어
• 출력 비교 인터럽트 발생
 TCNTn의 범위 : 0 – OCRn (카운터의 TOP)
 카운터 동작 중에 TCNTn보다 작은 값을 OCRn에 넣으면 카운터 값이
MAX(0xFF)까지 증가하였다가 0으로 된 후부터 정상적인 CTC 동작이 이
루어짐
output match
0xFF
TCNTn
OCRn
0x00
시스템및센서네트워크연구실
15
Timer/counter0 관련 IO 레지스터
 TCNT0(Timer/Counter0 Register)
 읽기 및 쓰기가 가능한 카운터로 동작, 자동으로 증가
 OCR0(Output Compare Register 0)
 TCNT0와 계속적으로 비교되는 8비트 레지스트
 두 레지스터의 값이 일치했을 때, OC0 핀을 통하여 설정된 값이 출력되거나 출력
비교 인터럽트 발생
 TIMSK(Timer/Counter Interrupt Mask Register)
 bit 1 – OCIE0 : timer/counter0 Output Compare Interrupt Enable
• 셋시 타이머/카운터0의 출력 비교 인터럽트 인에이블
 bit 0 – TOIE0 : Timer/counter0 Overflow Interrupt Enable
• 셋시 타이머/카운터0의 오버플로우 인터럽트 인에이블
시스템및센서네트워크연구실
16
 TCCR0 (Timer/Counter0 Control Register)
 bit 6, 3– WGM00, WGM01(Waveform Generation Mode)
• 동작 모드 설정
00 : normal
10 : phase correct PWM
01 : CTC
11 : fast PWM
 bit 2:0 – CS02:00 (Clock Selection)
• 타이머/카운터0의 분주비(프리스케일러)를 결정
• 클럭 선택 설정
 000 : 타이머/카운터 동작 중지
001 : 1분주 (프리스케일러 사용 안함)
 010 : 8분주
011 : 32분주
 100 : 64분주
101 : 128분주
 110 : 256분주
111 : 1024분주
시스템및센서네트워크연구실
17
 TIFR(Timer/Counter Interrupt Flag Register)
 bit 1 – OCF0 : timer/counter0 Output Compare Match Flag
• TCNT0와 OCR0의 값이 일치할 경우 셋
 bit 0 – TOV0 : Timer/counter0 Overflow Interrupt Flag
• 오버플로우 발생시 셋
시스템및센서네트워크연구실
18
실습 1
// 타이머/카운터0을 이용한 LED 제어 실험 (normal mode)
// 오버플로우 인터럽트 발생시 LED를 1비트씩 쉬프트하면서 ON시키는 프로그램 작성
// TCNT0는 0으로 초기화, 프리스케일러는 1024분주
unsigned char led = 0xFE;
void main(void)
{
DDRC = 0xFF;
PORTC = led;
// 포트 C 출력으로 설정
// 포트 C에 초기값 출력
TIMSK = 0b00000001;
TCCR0 = 0b00000111;
TCNT0 = 0b00000000;
SREG = 0b10000000;
// TOIE0 = 1;
// 일반모드, 프리스케일 = CK/1024
// 타이머/카운터0 레지스터 초기값
// 전역 인터럽트 인에이블 비트 I 셋
while(1);
// 무한 루프
}
// 타이머/카운터0 오버플로우 서비스 루틴 : 인터럽트 발생 주기 1/16us * 1024분주 * 256 = 16,384us
interrupt [TIM0_OVF] void timer_int0(void)
{
led <<= 1;
led |= 0x01;
if(led == 0xFF) led = 0xFE;
PORTC = led;
}
시스템및센서네트워크연구실
19
실습 2
// 타이머/카운터0을 이용한 LED 제어 실험 (CTC mode)
// CTC모드를 이용하여 출력 비교 인터럽트가 발생할 때마다 LED를 1비트씩 쉬프트
// OCR0값은 0xFF(255)로 설정
unsigned char led = 0xFE;
void main(void)
{
DDRC = 0xFF;
PORTC = led;
// 포트 C 출력으로 설정
// 포트 C에 초기값 출력
TIMSK = 0b00000010;
TCCR0 = 0b00001111;
OCR0 = 0xFF;
TCNT0 = 0b00000000;
SREG = 0b10000000;
// OCIE0 = 1 출력 비교 인터럽트 인에이블
// 프리스케일 = CK/1024, CTC 모드
// 출력 비교 레지스터값
// 타이머/카운터0 레지스터 초기값
// 전역 인터럽트 인에이블 비트 I 셋
while(1);
// 무한 루프
}
// 타이머/카운터0 출력비교(TCNT0 = OCRO 일때) 인터럽트 서비스 루틴 : 인터럽트 발생 주기 1/16us * 1024분주 * 256 = 16,384us
interrupt [TIM0_COMP] void timer_comp0(void)
{
led <<= 1;
led |= 0x01;
if(led == 0xFF) led = 0xFE;
PORTC = led;
} 시스템및센서네트워크연구실
20
실습 3
// 타이머/카운터0을 이용한 LED 제어 실험 (normal mode 0.5초 간격)
// 오버플로우 인터럽트를 이용하여 0.5초마다 모든 LED를 ON/OFF (토클 출력)시키는 프로그램
// 1024 분주한 클럭 사용
// 0.5초 계산
// - 가장 긴 오버플로우 인터럽트 주기 : 1/16us * 256카운터 * 1024분주 = 16.384ms
// - 이 인터럽트가 31회 걸리면 508ms가 되어 약 0.5s가 됨
unsigned char led = 0xFF;
Unsigned char cnt = 0;
// 인터럽트 발생 횟수
void main(void)
{
DDRC = 0xFF;
PORTC = led;
// 포트 C 출력으로 설정
// 포트 C에 초기값 출력
TIMSK = 0b00000001; // TOIE0 = 1;
TCCR0 = 0b00000111; // 일반모드, 프리스케일 = CK/1024
TCNT0 = 0b00000000; // 타이머/카운터0 레지스터 초기값
SREG = 0b10000000; // 전역 인터럽트 인에이블 비트 I 셋
while(1);// 무한 루프
}
시스템및센서네트워크연구실
// 타이머/카운터0 오버플로우 서비스 루틴
// 1/16us x 1024 x 256 = 16.384ms
interrupt [TIM0_OVF] void timer_int0(void)
{
cnt++;
if(cnt == 31) {
// 16.384ms x 31 = 0.5sec
led = led ^ 0xFF;
PORTC = led;
cnt = 0;
}
}
21
실습 4
// 타이머를 이용하여 초를 7-segment에 출력하는 프로그램 작성
void seg_out_set(void);
char seg_pat[16]= {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};
int sec=0, cnt=0, loc=0;
void main(void)
{
DDRA = 0b11111111; // PA 출력 설정
DDRB = 0b00000011; // PB0, PB1 출력 설정 (FND1, FND2)
DDRD = 0b00000000; // PD2, PD3 입력 설정 (SW1, SW2)
EIMSK = 0b00001100; // 외부 인터럽트2, 3 인에이블
EICRA = 0b10100000; // 외부 인터럽트2, 3 하강 에지
TIMSK = 0b00000001; // TOIE0 = 1;
while(1){
TCCR0 = 0b00000111; // 일반모드, 프리스케일 = CK/1024
seg_out_set();
TCNT0 = 0b00000000; // 타이머/카운터0 레지스터 초기값
SREG = 0b10000000; // 전역 인터럽트 인에이블 비트 셋
시스템및센서네트워크연구실
// while(1) : 무한 루프
}
}
22
// 외부 인터럽트2 서비스 루틴
interrupt [EXT_INT2] void external_int2(void)
void seg_out_set(void)
// 두 자리 정수 출력
{
{
if(loc == 0) sec++;
int N10, N1;
if(loc == 1) sec += 10;
if(sec > 59) sec -= 60;
N10 = sec / 10;
// 10자리 추출
N1 = sec % 10;
// 1자리 추출
}
// 외부 인터럽트3 서비스 루틴
PORTB = 0b00000010; // FND1 활성화 (PB0=0, PB1=1)
interrupt [EXT_INT3] void external_int3(void)
PORTA = seg_pat[N1];
{
delay_ms(10);
loc = (loc + 1) % 2;
}
PORTB = 0b000000001; // FND2 활성화 (PB1=0, PB0=0)
PORTA = seg_pat[N10];
// 타이머/카운터0 오버플로우 서비스 루틴
delay_ms(10);
// 1/16us x 1024 x 256 = 16.384ms
}
interrupt [TIM0_OVF] void timer_int0(void)
{
cnt++;
if(cnt == 61) { // 16.384ms x 61 = 0.999sec
sec++;
if (sec > 59) sec = 0;
cnt = 0;
}
}
시스템및센서네트워크연구실
23
실습 5
// SW1을 이용한 타이머 시작 및 종료 기능
void seg_out_set(void);
char seg_pat[16]= {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};
int sec=0, cnt=0, sw_cnt=0;
void main(void)
{
DDRA = 0b11111111; // PA 출력 설정
DDRB = 0b00000011; // PB0, PB1 출력 설정 (FND1, FND2)
DDRD = 0b00000000; // PD2, PD3 입력 설정 (SW1, SW2)
void seg_out_set(void)
{
int N10, N1;
EIMSK = 0b00001100; // 외부 인터럽트2, 3 인에이블
EICRA = 0b10100000; // 외부 인터럽트2, 3 하강 에지
N10 = sec / 10;
N1 = sec % 10;
SREG = 0b10000000; // 전역 인터럽트 인에이블 비트 셋
while(1){
seg_out_set();
}
// 두 자리 정수 출력
// 10자리 추출
// 1자리 추출
PORTB = 0b00000010; // FND1 활성화 (PB0=0, PB1=1)
PORTA = seg_pat[N1];
delay_ms(10);
// while(1) : 무한 루프
PORTB = 0b000000001; // FND2 활성화 (PB1=0, PB0=0)
PORTA = seg_pat[N10];
delay_ms(10);
}
}
시스템및센서네트워크연구실
24
// 타이머/카운터0 오버플로우 서비스 루틴
// 1/16us x 1024 x 256 = 16.384ms
interrupt [TIM0_OVF] void timer_int0(void)
{
cnt++;
if(cnt == 61) { // 16.384ms x 61 = 0.999sec
sec++;
cnt = 0;
}
}
// 외부 인터럽트0 서비스 루틴
interrupt [EXT_INT0] void external_int0(void)
{
sw_cnt++;
if(sw_cnt%2 == 1) {
TIMSK = 0b00000001;
// TOIE0 = 1;
TCCR0 = 0b00000111;
// 일반모드, 프리스케일 = CK/1024
TCNT0 = 0b00000000;
// 타이머/카운터0 레지스터 초기값
cnt = 0;
}
else {
TIMSK = 0b00000000;
// TOIE0 = 1;
TCCR0 = 0b00000000;
// 일반모드, 프리스케일 = CK/1024
TCNT0 = 0b00000000;
// 타이머/카운터0 레지스터 초기값
cnt = 0;
}
} 시스템및센서네트워크연구실
25