※ 주의사항 ※
본 블로그는 수업 내용을 바탕으로 제가 이해한 부분을 정리한 블로그입니다.
본 내용을 참고로만 보시고, 틀린 부분이 있다면 지적 부탁드립니다!
감사합니다😁
안녕하세요!!
오늘은 아래와 같은 내용을 확인해보겠습니다.
8비트 타이머/카운터
TCNTn 레지스터
TCCRn 레지스터
TIMSK 레지스터
TIFR 레지스터
OCR0 레지스터
오버플로 인터럽트
비교 일치 인터럽트
millis 함수
1. 8비트 타이머/카운터
1-1. 개요
- 입력 펄스를 세는 장치, 즉 카운터
- 일정한 주기의 펄스를 셈으로써 시간 측정도 가능하다. 즉, 타이머 역할 수행 가능
- 마이크로컨트롤러의 시스템 클록 사용 가능 (외부에서 클록 입력도 가능하다)
1) ATmega128A 타이머/카운터
(1) ATmega128A는 총 4개의 타이머/카운터를 제공합니다.
- 0번과 2번의 8비트 타이머/카운터
- 1번과 3번의 16비트 타이머/카운터
(2) 8비트 타이머/카운터
- 0 ~ 255까지 세기를 반복한다.
- 16Mhz 시스템 클록을 사용하는 경우 256개의 클록의 발생 시간은 0.016ms에 해당된다.
- 분주기를 통해 클록의 속도를 늦춤으로써 보다 긴 시간 측정 가능하다.
※ 분주라는 것은 나눈다는 의미로 2분주는 16Mhz / 2 = 8Mhz에 해당된다.
1-2. 구조
- 내부 클록 16Mhz의 주기는 62.5ns (나노 세컨드)
- 0.0625μs x 256(8비트 타이머/카운터의 레지스터 크기) → 16(μs)
- 즉, 8비트 타이머/카운터에서 0.016ms만큼 타이머(카운트) 가능하다.
(1분주 기준 0.016ms마다 오버플로 인터럽트가 발생한다.)
- 2분주로 주기를 산출할 경우 0.125μs x 256 → 32μs
즉, 8비트 타이머/카운트에서는 0.032ms만큼 타이머(카운트) 가능하다.
- 분주율이 높아질수록 카운트(타이머)할 수 있는 값이 늘어난다.
- 1024분주일 경우 16000000[hz] / 1024 = 약16Khz →→
256 / 16K = 1/64[s](즉 256개 펄스를 세었을때 발생하는 오버플로 인터럽트를 32번 체크하면 0.5초의 근사값을 산출할 수 있다.
2. 8비트 타이머/카운터 관련 레지스터
※ 타이머/카운터 레지스터의경우 1개의 레지스터에 8비트와 16비트 타이머/카운터 관련 비트가 섞여있는 경우가 있습니다. 아래의 레지스터 관련 설명글은 8비트 타이머/카운터 중에서도 0번 타이머에 해당하는 레지스터와 비트만 설명하겠습니다.
2-1. TCNT0 레지스터
- 현재까지 센 펄스의 개수를 기록하는 레지스터이다.
- TCNT0의 레지스터의 Default 값은 0이며, 비교일치 인터럽트를 사용할 경우 TCNT0의 값을 0이나 특정 값으로 초기화 해주는것도 중요하다.
2-2. TCCR0 레지스터
1) 7번 ~ 3번 비트 : 비교일치 인터럽트 중에서 파형 생성 모드와 출력 모드를 설정해주는 레지스터이다.
(비교일치 인터럽트 중에서도 파형을 출력할때 필요한 비트로 설명은 생략..)
2) CS00 ~ CS02 비트(0 ~ 2번 비트) : 분주비를 설정하기 위해 사용하는 비트
Default 값은 00으로 타이머/카운터가 멈춰있는 상태이다. 분주비를 선택하는 순간 타이머는 동작한다.
- 분주비에 따른 주기와 1ms당 클록수는 아래의 표와 같다.(16Mhz 기준)
분주비 | 주기(μs) | 1ms당 클록수 |
1 | 0.0625 | 16000 |
8 | 0.5 | 2000 |
32 | 2 | 500 |
64 | 4 | 250 |
128 | 8 | 125 |
256 | 16 | 62.5 |
1024 | 64 | 15.6(반올림) |
- 16Mhz 1024분주비의 경우 오버플로우 인터럽트의 발생 주기는 0.16384ms에 해당된다.
즉, 해당 인터럽트를 몇번 반복해도 정확히 0.5초를 산출하지 못한다. (근사값에 해당됨)
- 하지만 64분주비나 128분주비를 사용해서 해당 클록을 250번 또는 125번을 측정하면 정확한 0.5초를 산출할 수 있다.
(ex) 64분주로 설정하면 1clock은 4μs이고 펄스의 개수를 1 ~ 250까지 측정하면 1ms마다 인터럽트를 발생시킬 수 있다. 이러한 인터럽트를 500번 측정하면 0.5초라는 타이머의 값을 산출할 수 있다.
2-3. TIMSK 레지스터
1) OCIE2 비트 (7번 비트) : Output Comapre match Interrupt Enable
2) TOIE2 비트 (6번 비트) : Overflow Interrupt Enable
3) 2 ~ 5번 비트 : 1번 타이머/카운터의 설정관련 비트 (16비트 타이머)
4) OCIE0 비트 (1번 비트) : Output Comapre match Interrupt Enable
- 0번 타이머/카운터의 비교 일치 인터럽트 활성화 비트
5) TOIE0 비트 (0번 비트) : Overflow Interrupt Enable
- 0번 타이머/카운터의 오버플로 인터럽트 활성화 비트
※ 8비트 타이머/카운터 인터럽트 벡터이름 및 벡터 번호 (0번, 2번 타이머)
2-4. TIFR 레지스터
- TIFR 레지스터는 해당 비트가 세트되었을때 TIMSK 레지스터의 해당 비트 역시 세트된 상태라면 실제로 인터럽트가 발생한다. (2번 ~ 7번 비트는 다른 타이머/카운터 관련 비트이다.)
※ 타이머/카운터를 사용하기 위해 꼭 필요한 레지스터는 아니므로 필수설정과는 관계가 멀다.
1) TOV0 비트 (0번 비트) : 오버플로가 발생한 경우 세트되는 비트
2) OCF0 비트 (1번 비트) : 비교 일치가 발생한 경우 세트되는 비트
2-5. OCR0 레지스터
- 비교 일치 인터럽트를 사용하기 위해 비교값을 설정해주는 레지스터
3. 타이머/카운터 인터럽트
3-1. 오버플로 인터럽트 vs 비교일치 인터럽트
1) 오버플로 인터럽트
- 최대로 셀 수 있는 펄스의 수를 넘어설 때 TCNTn 레지스터가 0으로 바뀌면서 '오버플로 인터럽트' 발생
- 8비트 타이머의 경우 최대로 셀 수 있는 펄스의 수는 0 ~ 255이다.
2) 비교일치 인터럽트
- TCNTn의 값이 미리 설정된 OCRn 레지스터의 값과 일치하는 경우 '비교일치 인터럽트' 발생
- 비교 일치 인터럽트가 발생할때 OCn 핀을 통해 파형 출력 가능
3-2. 관련 예제 : 오버플로 인터럽트를 이용한 LED 점멸
1) 코드 설명
- Line 4 : 오버플로 인터럽트의 횟수를 카운팅 하기 위한 변수
- Line 5 : LED의 현재 상태를 저장하기 위한 변수
- Line 7 ~ 16 : 0번 타이머의 오버플로 ISR에 해당되는 함수부
Line 9 : 오버플로 인터럽트 발생할때마다 1씩 카운팅
Line 10 : 오버플로 인터럽트가 32회 발생하면 if문 실행
Line 11 : 오버플로 인터럽트의 횟수를 카운팅하는 변수 초기화
Line 12 : LED 현재 상태를 저장하는 변수값 반전
(즉 오버플로 인터럽트가 32회 발생하면 LED의 상태가 반전된다)
Line 13 : State 값이 1이면 A포트의 0번핀에 연결되어있는 LED가 점등된다.
Line 14 : state 값이 0이면 A포트의 0번핀에 연결되어있는 LED가 소등된다.
- Line 24 : 0번 타이머의 분주율을 1024로 설정한다.
- Line 25 : 0번 타이머 오버플로 인터럽트를 허용한다.(Enable)
- Line 26 : 전역 인터럽트를 허용한다.(Enable)
2) 문제점
- 위와 같은 프로그래밍의 문제점은 정확히 0.5초마다 점멸하지 않는다는 점이다.
(정확히는 0.524288s 마다 LED가 점등되었다 소등되었다 반복한다.)
- 이는 16Mhz를 분주할때 1ms당 클록수가 정수값으로 떨어지지 않기 때문에 발생한다.
(위의 2-2 레지스터의 표 참고)
- 따라서 8비트의 카운터/타이머를 이용할경우 64분주나 128분주를 사용하면 해결된다.
3) 문제점 해결
- Line 88 : 주석을 수정하지 못했지만 분주율은 64분주로 설정되었다.
- Line 73 : 클록을 카운팅하는 레지스터의 초기값을 6으로 설정하면서 250번 펄스를 셀때마다 오버플로 인터럽트를 1회 발생하도록 설정한다.
- Line 75 : 오버플로 인터럽트가 500회 발생하면 if문을 수행하도록 한다.(0.5초 주기)
※ 왜?? 위의 코드가 정확히 0.5초 주기인가??
- 16[Mhz] / 64[분주] = 250[Khz]
- 주파수 : 250[Khz] = 주기 : 4μs
- 4μs x 250 = 0.001s (6 ~ 255 = 250회, TCNT0(레지스터 초기값) = 6)
- 0.001s x 500 = 0.5s (count값이 500이면 if문 수행)
3-3. 관련 예제 : 비교 일치 인터럽트를 이용한 LED 점멸
1) 코드 설명
- Line 41 : 타이머 카운터 레지스터의 초기값을 0으로 설정한다.
즉, 비교 일치 인터럽트가 실행되면 타이머 카운터 레지스터의 값을 0으로 설정한다.
- Line 43 : 비교 일치 인터럽트가 64회 실행되면 if문을 수행한다.
- Line 57 : 분주율 1024로 설정
- Line 58 : 비교 일치 인터럽트에 사용되는 비교값을 128로 저장한다.
(TCNT0의 값이 128이 될때마다 비교 일치 ISR을 실행한다.)
2) 동작 설명
- 3-2의 오버플로 인터럽트를 사용한 LED 점멸 코드 동작과 동일하다.
- 주의해야할 점은 1024분주로 분주율은 동일하나 TCNT0의 값이 256번 마다 ISR을 실행하는 오버플로 인터럽트와는 달리 128번 마다 ISR을 실행하기 때문에 인터럽트를 카운팅하는 변수의 목표값을 달리 설정해야 한다.
(count 변수의 값이 달라진 점 확인 필요)
4. 8비트 타이머 관련 응용문제
4-1. millis함수 : 실행 시간 알아내기
- 분주비를 64로 설정한 경우 0번 타이머/카운터의 오버플로 인터럽트가 발생하기까지 64 x 256 = 16,384개의 클록이 필요하다.
- 16Mhz 클록에서 분주비 64로 설정한 타이머의 오버플로 인터럽트 발생 시간은 (64 x 256) / 16000000 = 0.001024s이다.
- 즉, 오버플로 인터럽트는 1ms 24μs 마다 발생한다는 점을 이용하여 실행시간을 알아내는 코드를 짰다.
1) 코드 설명
- Line 105 ~ 119 : 오버플로 ISR 함수부 / ms와 μs를 구분해서 데이터를 저장해주는것이 포인트!!
- Line 121 ~ 135 : millis 함수부 / 즉, 현재 시간의 값을 리턴해주는 함수부분에 해당된다.
(ISR 함수부에서 현재시간을 timer0_millis 값에 저장하고 그값을 millis 함수부분에서 m값에 저장해서 해당 변수값을 리턴해준다.)
- Line 137 ~ 142 : 0번 타이머 인터럽트 및 분주비 관련 설정부
- Line 144 ~ 172 : main 함수부 / millis 함수의 리턴값을 time_current 값에 저장하고 이전에 저장한 값과 비교해서 1초가 지났을때 마다 PORTA의 상태를 반전시켜준다.
4-2. 연습문제 : 오버플로 인터럽트를 활용한 LED 순차 점멸
1) 코드 설명
- ISR내에 사용되는 변수를 Volatile 명령어를 붙혀주어서 변수를 가변적으로 만들어 준다.
- 8개의 LED가 순차적으로 점멸하는 동작을 하도록 동작 패턴을 배열로 만든다.
- 64분주율로 설정하고 카운터 레지스트의 초기값(TCNT0)을 6으로 설정한 후 250번 반복하면 ISR이 실행된다.
(64[분주] x 250 / 16000000[hz] = 0.001s, 1ms)
- 1ms를 500번 반복(count == 500)하면 0.5초에 한번 value[i] 패턴 배열이 바뀌도록 프로그래밍
※ 본 과정에서 비교 일치 인터럽트 수행시 파형을 출력하거나 내부 클록(16Mhz) 대신 ASSR 레지스터를 통해 외부 클록을 사용할 수 있는 내용도 있었지만 생략하거나 간략하게 집고 넘어간 부분으로써 본 내용에는 생략하였습니다. 😥
'대한상공회의소 스마트팩토리 교육 > IoT 디바이스 개발' 카테고리의 다른 글
[IoT 디바이스 개발] AVR(ATmega128A)«수업-15» : PWM(펄스폭 변조, Pulse Width Modulation) (0) | 2022.02.18 |
---|---|
[IoT 디바이스 개발] AVR(ATmega128A)«수업-14» : 16비트 타이머 및 카운터 (오버플로 인터럽트 / 비교 일치 인터럽트 / 파형 출력) (0) | 2022.02.17 |
[IoT 디바이스 개발] AVR(ATmega128A)«수업-12» : 아날로그 비교기 / 인터럽트 (0) | 2022.02.15 |
[IoT 디바이스 개발] AVR(ATmega128A)«수업-11» : 아날로그-디지털 변환 (0) | 2022.02.14 |
[IoT 디바이스 개발] AVR(ATmega128A)«수업-10» : UART 시리얼 통신 (0) | 2022.02.13 |
댓글