Timer 실습 1

Download Report

Transcript Timer 실습 1

마이크로콘트롤러 설계 – 3
Timer 실습 1 – T0
시스템및센서네트워크연구실
1
Timer 실습
- Timer
- Timer 관련 레지스터
- Timer를 이용한 입출력
시스템및센서네트워크연구실
2
ATmega128
시스템및센서네트워크연구실
3
LED sink / switch pullup 회로
470
5V
PC0
+5V
PC1
…..
10K
PC7
PD2
104 (0.1uF)
시스템및센서네트워크연구실
4
LCD 회로
#1
+5V
VDD
#2
LCD 밝기 조절
V0
RS
R/W
E
PC0
PC1
PC2
DB4
DB5
DB6
DB7
PC4
PC5
PC6
PC7
VSS
#3
시스템및센서네트워크연구실
+5V
LEDA
LEDK
5
시스템및센서네트워크연구실
6
LCD 함수
#include <delay.h>
#define LINE2
#define HOME
#define RSHIFT
#define LSHIFT
#define DISPON
#define DISPOFF
0xC0
0x02
0x1C
0x18
0x0c
0x08
// 2nd Line Move
// Cursor Home
// Display Right Shift
// Display Left Shift
// Display On
// Display Off
// LCD 초기화 함수
void LCD_init(void)
{
DDRC = 0xFF;
PORTC &= 0xFB;
// 포트 C 출력 설정
//E = 0;
// 충분한 지연시간을 통한 안정화 과정
delay_ms(15);
Command(0x20);
// D5=1
delay_ms(5);
Command(0x20);
// D5=1
delay_us(100);
Command(0x20);
// D5=1
void LCD_init(void);
void LCD_String(char flash str[]);
void Busy(void);
void Command(unsigned char);
void Data(unsigned char);
// 초기화 과정
Command(0x28);
Command(0x06);
Command(0x01);
Command(0x0c);
// function set
// entry mode set
// all clear
// display on
}
시스템및센서네트워크연구실
7
//데이터 쓰기 함수
void Data(unsigned char byte)
{
Busy();
// 인스트럭션 쓰기 함수
void Command(unsigned char byte)
{
Busy();
// 인스트럭션 상위 바이트
PORTC = (byte & 0xF0);
PORTC &= 0xFE;
PORTC &= 0xFD;
delay_us(1);
PORTC |= 0x04;
delay_us(1);
PORTC &= 0xFB;
// 인스트럭션 하위 바이트
PORTC = ((byte<<4) & 0xF0);
PORTC &= 0xFE;
PORTC &= 0xFD;
delay_us(1);
PORTC |= 0x04;
delay_us(1);
PORTC &= 0xFB;
// 데이터 상위 바이트
PORTC = (byte & 0xF0);
PORTC |= 0x01;
PORTC &= 0xFD;
delay_us(1);
PORTC |= 0x04;
delay_us(1);
PORTC &= 0xFB;
// 데이터
// RS = 0;
// RW = 0;
// E = 1;
// E = 0;
// 데이터 하위 바이트
PORTC = ((byte<<4) & 0xF0);
PORTC |= 0x01;
PORTC &= 0xFD;
delay_us(1);
PORTC |= 0x04;
delay_us(1);
PORTC &= 0xFB;
// 데이터
// RS = 0;
// RW = 0;
// E = 1;
// E = 0;
// 데이터
//RS = 1;
//RW = 0;
//E = 1;
//E = 0;
// 데이터
//RS = 1;
//RW = 0;
//E = 1;
//E = 0;
}
}
// 문자열 출력 함수
void LCD_String(char flash str[])
{
char flash *pStr=0;
// Busy Flag Check -> 일반적인 BF를 체크하는 것이 아니라
// 일정한 시간 지연을 이용한다.
void Busy(void)
{
delay_ms(2);
}
pStr = str;
while(*pStr) Data(*pStr++);
}
시스템및센서네트워크연구실
8
타이머/카운터
 타이머/카운터
 입력으로 들어오는 펄스 또는 클럭을 셈하는 장치
 입력으로 들어오는 펄스가 어떤 형태인가에 따라 타이머와 카운터로 나
눔
• 타이머 : 클럭의 소스가 마이크로컨트롤러의 시스템 클럭에 의존
• 카운터 : 마이크로컨트롤러의 외부 핀(카운터 전용 핀)에 들어오는 펄
스를 셈하는 경우
system clock
timer clock
시스템및센서네트워크연구실
9
시스템 클럭
 시스템 클럭
 마이크로컨트롤러가 가진 내부 시계(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
10
타이머 학습을 위한 고려사항
1. 시스템 클럭이 16MHz 크리스탈을 사용하는 경우 1/16usec으로 매우 작다.
좀 더 현실적인 크기의 시간 값을 가지게 하는 방법은 없을까?
2. 우리는 60초라는 시계 단위를 사용하는데, 마이크로컨트롤러는 어떤 시계
단위를 사용할까?
3. 마이크로컨트롤러가 타이머 클럭을 셈하였다면, 마이크로컨트롤러는 어디
에 이를 저장해 둘까?
4. 업/다운 타이머로 동작시 원하는 횟수만큼 셈하고 난 뒤, 프로그래머에게 알
리는 방법은 무엇일까?
system clock
timer clock
시스템및센서네트워크연구실
11
프리스케일러 (freescale)
 프리스케일러
 타이머에 공급하는 시스템 클럭의 속도를 조절하는 분주기
 분주기라는 말 자체가 의미하듯이 클럭을 쪼갠다는, 즉 속도를 느리게 한
다는 의미
 사용 이유
• 마이크로컨트롤러의 시스템 클럭은 연산 속도를 빨리 하기 위하여 높
은 Hz의 크리스탈을 사용함
• 그러나, 타이머의 경우 시스템 클럭을 셈하기 때문에, 분주하지 않으
면 시스템 클럭이 너무 빠른 경우가 많음
• 따라서, 프리스케일러를 이용하여 시스템 클럭을 분주하여 타이머 클
럭을 느리게 만듬
• 예 : 16MHz의 시스템 클럭(1/16usec)을 2분주하면 1 타이머 클럭은
8MHz (1/8 usec)가 됨
시스템및센서네트워크연구실
12
 10비트 프리스케일러
 분주비가 1024(210)이라는 의미
 단, 분주비가 1024까지라고 해서 모든 분주가 가능하지는 않음
 분주비를 위한 레지스터가 존재하며, 레지스터 값에 따라 분주비가 선택됨
시스템및센서네트워크연구실
13
8비트 타이머 / 16비트 타이머
 8비트 타이머
 0x00 – 0xFF 까지 셈을 할 수 있음
 0xFF까지 간 후, 오버플로(overflow)가 발생하여 0x00로 리셋(reset)됨
 1바이트만을 이용하여 셈을 할 수 있음
 BOTTOM : 0x00, MAX : 0xFF, TOP : 설정 값
 ATMega128 : timer/counter0, 2
 16비트 타이머
 0x0000 – 0xFFFF 까지 셈을 할 수 있음
 0xFFFF까지 간 후, 오버플로(overflow)가 발생하여 0x0000로 리셋(reset)
됨
 2바이트를 이용하여 셈을 할 수 있음
 BOTTOM : 0x0000, MAX : 0xFFFF, TOP : 설정 값
 ATMega128 : timer/counter1, 3
시스템및센서네트워크연구실
14
타이머 값 저장 레지스터
 8비트 타이머
 1바이트 레지스터에 셈한 값을 저장
 타이머/카운터 0
• TCNT0
 16비트 타이머
 2바이트 레지스터에 셈한 값을 저장
 타이머/카운터 1
• TCNT1H
• TCTN1L
• 두 바이트를 합쳐서 TCNT1로 기재해도 인식되기도 함
시스템및센서네트워크연구실
15
동작 모드와 인터럽트
 동작 모드
 타이머가 동작하는 방법
 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
시스템및센서네트워크연구실
16
Normal mode
 일반 모드
 업 카운터로서만 동작
 MAX(0xFF)값이 되면, BOTTOM(0x00)값부터 다시 시작
 이 때, 오버플로우 인터럽트 발생 (TOVn 0->1)
 일정한 시간 간격으로 인터럽트가 발생되어 원하는 처리를 할 수 있음
 TCNTn의 초기값은 설정 가능
timer overflow
0xFF
TCNTn
0x00
시스템및센서네트워크연구실
17
CTC mode
 CTC 모드
 TCNTn의 값이 증가하여, OCRn 값과 일치하면
• 다음 클럭에서 0으로 클리어
• 출력 비교 인터럽트 발생
 TCNTn의 범위 : 0 – OCRn (카운터의 TOP)
 카운터 동작 중에 TCNTn보다 작은 값을 OCRn에 넣으면 카운터 값이
MAX(0xFF)까지 증가하였다가 0으로 된 후부터 정상적인 CTC 동작이 이
루어짐
output match
0xFF
TCNTn
OCRn
0x00
시스템및센서네트워크연구실
18
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의 오버플로우 인터럽트 인에이블
시스템및센서네트워크연구실
19
 TCCR0 (Timer/Counter0 Control Register)
 bit 6, 3– WGM00, WGM01(Waveform Generation Mode)
• non-PWM 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분주
시스템및센서네트워크연구실
20
 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
• 오버플로우 발생시 셋
시스템및센서네트워크연구실
21
실습 1
// 타이머/카운터0을 이용한 LED 제어 실험 (normal mode 1초 간격)
// 오버플로우 인터럽트를 이용하여 1초마다 모든 LED를 ON/OFF (토클 출력)시키는 프로그램
// 1024 분주한 클럭 사용
// 1초 계산
// - 가장 긴 오버플로우 인터럽트 주기 : 1/16us * 1024분주 * 256카운트 = 16.384ms
// - 이 인터럽트가 61회 걸리면 999.424ms가 되어 약 1s가 됨
unsigned char led = 0xFF;
unsigned char cnt = 0;
// 인터럽트 발생 횟수
void main(void)
{
DDRF = 0xFF;
PORTF = led;
// 포트 F 출력으로 설정
// 포트 F에 초기값 출력
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 == 61) {
// 16.384ms x 61 = 0.999424sec
led = led ^ 0xFF;
PORTF = led;
cnt = 0;
}
}
22
void main(void)
{
실습 2
DDRD = 0b00000000; // PD0, PD1 입력 설정 (SW1, SW2)
// 타이머를 이용한 디지털시계 제작
// 분과 초를 LCD에 출력
EICRA = 0b00001010; // 외부 인터럽트0, 1 하강 에지
EIMSK = 0b00000011;// 외부 인터럽트0, 1 인에이블
TIMSK = 0b00000001; // TOIE0 = 1;
#include <mega128.h>
#include <delay.h>
#define LINE2
#define HOME
#define RSHIFT
#define LSHIFT
#define DISPON
#define DISPOFF
TCCR0 = 0b00000111; // 일반모드, 프리스케일 = CK/1024
TCNT0 = 0b00000000; // 타이머/카운터0 레지스터 초기값
0xC0
0x02
0x1C
0x18
0x0c
0x08
void LCD_init(void);
void LCD_String(char flash str[]);
void Busy(void);
void Command(unsigned char);
void Data(unsigned char);
// 2nd Line Move
// Cursor Home
// Display Right Shift
// Display Left Shift
// Display On
// Display Off
SREG = 0b10000000;
LCD_init();
time_display();
while(1);
// while(1) : 무한 루프
}
// 외부 인터럽트0 서비스루틴
interrupt [EXT_INT0] void external_int0(void)
{
if(loc == 0) sec++;
void time_display(void);
if(loc == 1) min++;
int sec=0, min=0, loc=0, cnt=0;
if(sec > 59) sec == 0;
if(min > 59) min == 0;
time_display();
}
시스템및센서네트워크연구실
23
// 외부 인터럽트1 서비스 루틴
// 시간 출력 부함수
interrupt [EXT_INT1] void external_int1(void)
void time_display(void) {
int temp1, temp0;
{
loc = (loc + 1) % 2;
Command(HOME);
}
LCD_String(“Time : ”);
// 타이머/카운터0 오버플로우 서비스 루틴
// 1/16us x 1024분주 x 256 = 16.384ms
temp1 = min / 10;
// 분의 10자리 추출
interrupt [TIM0_OVF] void timer_int0(void)
temp0 = min % 10;
// 분의 1자리 추출
{
Data(0x30 + temp1);
Data(0x30 + temp0);
cnt++;
// 16.384ms x 61 = 0.999424sec
LCD_String(“: ”);
if(cnt == 61) {
sec++;
if(sec >= 60) {
sec = 0;
min++;
// 초의 10자리 추출
temp0 = sec % 10;
// 초의 1자리 추출
Data(0x30 + temp1);
Data(0x30 + temp0);
if(min >= 60)
min = 0;
temp1 = sec / 10;
}
}
time_display();
cnt = 0;
}
}
시스템및센서네트워크연구실
24
실습 3
// SW1을 이용한 타이머 시작 및 종료 기능
// 함수 선언, LCD 명령어 정의
// 타이머/카운터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.999424sec
num++;
void num_display(void);
num_display();
int num=0, cnt=0, sw_cnt=0;
cnt = 0;
}
void main(void)
{
DDRD = 0b00000000; // PD0 입력 설정 (SW1)
EIMSK = 0b00000001; // 외부 인터럽트0 인에이블
EICRA = 0b00000010; // 외부 인터럽트0 하강 에지
SREG = 0b10000000; // 전역 인터럽트 인에이블 비트 셋
LCD_init();
num_display();
while(1);
// while(1) : 무한 루프
}
시스템및센서네트워크연구실
}
// 외부 인터럽트0 서비스 루틴
interrupt [EXT_INT0] void external_int0(void)
{
sw_cnt++;
if(sw_cnt%2 == 1) {
TIMSK = 0b00000001; // TOIE0 = 1;
TCCR0 = 0b00000111; // 일반모드, 프리스케일 = CK/1024
}
else {
TIMSK = 0b00000000; // TOIE0 = 1;
TCCR0 = 0b00000000; // 일반모드, 프리스케일 = CK/1024
}
}
25
// 값 출력 부함수
void num_display(void) {
int temp0, temp1;
Command(HOME);
LCD_String(“Number : ”);
temp1 = num / 10;
// num의 10자리 추출
temp0 = num % 10;
// num의 1자리 추출
Data(0x30 + temp1);
Data(0x30 + temp0);
}
시스템및센서네트워크연구실
26