실험 목적
ATmega1281의 타이머 동작 모드 중 Normal 모드와 CTC 모드를 이해하고 그 사용 방법을 익힌다.
타이머 인터럽트의 활용 방법을 익힌다.
실험 예비 과제
1. 다음 동작을 하는 함수 timer_init()을 작성하고 그 내용을 설명하여라.
void timer_init(void)
{
// 16-bit 타이머인 Timer3을 CTC 모드로 동작하도록 설정하고 정확하게 250 개의 타이머 입력 clock
// 마다 compare match가 발생하도록 OCR3A 레지스터의 값을 설정한다. prescaler는 /8로 설정한다.
// 16-bit 타이머인 Timer5를 Normal 모드로 동작하도록 설정하고 prescaler를 /64로 설정한다.
}
WGMn0 ~ WGMn3 pin은 Timer mode와 관련이 있고,
CSn0~CSn2 pin은 prescaler와 관련이 있다.
void timer_init(void){
TCCR3B |= _BV(WGM32) | _BV(CS31); // 16 bit timer 3, CTC, , prescaler 8
OCR3A = 249; // Compare TOP setting : 250 clk
TCCR5B |= _BV(CS51) | _BV(CS50);// 16 bit timer 5, normal, prescaler 64
}
2. 1 번에서 작성한 timer_init() 함수를 실습 보드에서 실행시킨다면 Timer3의 compare match 발생 주파수는 얼마가 되는가? 그리고 Timer5의 overflow 발생 주파수는 얼마가 되는가?
(1) Timer3 는 8kHz
(2) Timer5 은 65536개의 clock 동안 작동, 3.8kHz
3. 타이머 인터럽트를 사용하지 않고 main() 함수 안에서 Timer3의 compare match가 발생할 때 마다 PE3 핀의 출력 값을 (HW 기능을 이용하지 않고 코드를 사용해서) 계속 반전 (toggle)시키고 싶다.
Timer3는 CTC mode로 동작하도록 설정하여 OCR3A의 TOP값을 설정했으므로,
Compare match가 발생하면 Timer interrupt flag가 ISR이 실행되어야 clear 되므로 직접 clear 시켜야 한다.
int main()
{
timer_init();
DDRE = _BV(PE3);
while(1){
if(TIFR3&_BV(OCF3A)){
PORTE ^= _BV(PE3); // PE3 toggle
TIFR3 = _BV(OCF3A); // Timer3 Interrupt Flag clear
}
}
}
4. 100 Hz의 주파수로 Timer5의 overflow가 발생하도록 만들고 그 때마다 PB5 핀의 출력 값을 계속 반전 (toggle)시키고 싶다. 타이머 인터럽트를 사용하지 않고 main() 함수 안에서 이 일을 하고자 한다. 이를 위한 코드를 작성하고 그 내용을 설명하여라. (Timer3과는 무관하며 Timer5만 사용하는 것으로 가정)
계산에 따르면 TCNT5은 2,500 CLK 이후에 동작하도록 해야 한다. 그래서 -2499를 대입하거나, 63036을 넣는다.
2500Clk 이후 timer overflow가 발생하면서 TOV5 bit이 set된다. 따라서 TOV5가 set되면 toggle 되도록 하고, 추가로 해당 flag를 ISR 실행시키지 않았으므로 초기화를 시켜준다음, overflow시 초기화 될 값을 또 넣어준다.
int main()
{
timer_init();
DDRB = _BV(PB5);
TCNT5 = -2499;
while(1){
if(TIFR5&&_BV(TOV5)){
PORTB ^= _BV(TOV5);
TIFR5 = _BV(TOV5);
TCNT5 = 63036;
}
}
}
5. 4 번에서 하는 일을 Timer5의 overflow interrupt를 사용하고 하려고 한다. 인터럽트에 관련된 설정을 미리 마쳤다고 가정하고 이 일을 하도록 Timer5의 overflow interrupt의 ISR을 작성하자.
실험 과정
1. 새로운 project를 만들고 실험 6에서 사용한 board.h, fnd.h, fnd.c 파일을 project에 추가시킨다. main() 함수를 포함하고 있는 파일의 내용은 실험 6에서 사용한 파일의 내용을 복사하되 필요하지 않은 내용은 삭제하여라. interrupt_init() 함수에서 외부 인터럽트를 활성화시키는 코드는 모두 지우고 맨 마지막 sei() 명령만 남겨 두어라.
2. 예비 과제에서 작성한 timer_init() 함수를 ioport_init() 다음에 위치시키고 main() 함수에서 이 함수를 호출하여 timer 설정 초기화를 하여라. 이 함수를 호출하는 위치는 ioport_init() 함수와 interrupt_init() 사이가 적당하다.
3. board.h 파일을 열어 PE3을 SOUND_OUT이라는 새로운 이름으로 정의하는 문장을 추가하여라.
4. 3 번에서 정의한 이름을 사용하여 PE3 핀을 출력으로 설정하도록 ioport_init() 함수를 수정하여라. 그리고 PB5 핀도 출력으로 설정하여라. PB5 핀은 이번 실험에서 임시로 사용하는 출력이라 새로운 이름을 정의할 필요는 없다.
5. 예비 과제 3 번에서 작성한 코드를 실행시키고 오실로스코우프를 사용하여 PE3 핀으로 출력되는 구형파의 주파수를 측정하여라. 주파수를 측정할 때에는 오실로스코우프의 Quick Measurement 기능을 사용하거나 마이크로프로세서실험 19 Cursor 기능을 사용하면 편리하다. 이번 기회에 이 기능을 사용해 보고 사용 방법을 익히기 바란다. 측정한 값이 정확하게 예비 과제 2 번에서 계산한 주파수의 절반인지 확인하여라.
6. 예비 과제 4 번에서 작성한 코드를 실행시키고 오실로스코우프를 사용하여 PB5 핀으로 출력되는 구형파의 주파수를 측정하여라. 측정한 값이 정확하게 50 Hz인지 확인하여라.
7. 이번에는 앞 5 번과 6 번의 일을 동시에 하려고 한다. while() 루프에 들어갈 내용을 작성하고 그
내용을 설명하여라. 앞에서와 마찬가지로 오실로스코우프를 사용하여 출력 신호의 주파수를 확인하여라.
PB5와 PE3 핀으로 동시에 구형파를 출력해야 하므로 5 번과 6 번에서 했던 코드를 단순히 함께 모으는
것으로는 제대로 동작하지 않을 수도 있다.
8. 7 번의 코드는 매우 비효율적이기도 하고 출력 펄스의 주파수가 원하는 값과 조금 다를지도 모른다. 또한
main() 함수에서 해야 할 일이 더 많아지면 이와 같은 방법으로는 구형파의 주파수를 일정하게 만드는
것이 어려울 수도 있다. 이제 7 번의 코드를 좀 더 효율적으로 바꿔보자. PE3 핀은 OC3A 출력으로서의
역할도 하는데 앞의 코드에서는 이 핀을 단순히 일반적인 GPIO로 사용하고 있었다. 이제 timer_init()
함수에서 Timer3 초기화 코드를 수정하여 Timer3의 Compare match가 발생할 때마다 OC3A가 자동으로
toggle되도록 설정하자. 이렇게 하면 7 번 코드에서 OCF3A flag을 검사하고, 이 flag을 clear시키고, PE3
핀을 toggle시키는 코드를 모두 삭제해도 된다. timer_init() 함수를 수정해 프로그램을 실행시키고
오실로스코우프로 그 결과를 확인하여라. 그리고 수정한 내용을 설명하여라.
CTC mode는 compare output mode를 선택할 수 있고, table 17-3에 따라 값을 넣어주고, interrupt가 활성화되지 않으므로 수동적으로 compare match interrupt flag가 set 되도록 하였다.
9. 8 번을 마쳤다면 이제 Timer5의 overflow 인터럽트를 사용하도록 코드를 수정하자. Timer5의 overflow
인터럽트를 활성화시키도록 timer_init() 함수를 수정하여라. 그리고 예비 과제에서 작성한 Timer5의
ISR을 파일에 추가한 후 main() 함수에서 Timer5 관련된 내용을 지워라. 이렇게 하면 main() 함수의
while() 루프에서 하는 일은 아무 것도 없게 될 것이다.
10. 지금까지는 Timer5는 Normal 모드로 동작시켰는데 이 동작 모드보다는 CTC 모드가 더 효율적인 방법이다.
이제 Timer5의 prescaler 값은 그대로 유지한 상태에서 CTC 모드로 동작하도록 timer_init() 함수를
수정하자. 동작 모드를 수정한 다음에도 앞에서와 같이 100 Hz의 주파수로 compare match 인터럽트가
발생하도록 OCR5A 값을 설정하여라. 이 때 값을 바로 적지 말고 계산 식을 사용하도록 하여라. 또한 이제
overflow interrupt가 아니라 compare match 인터럽트를 발생시키도록 관련 코드를 수정하고 ISR()의
vector 이름도 바꾸어라. 수정한 프로그램을 실행시켜 보고 출력 신호가 9 번의 그것과 같은지 확인하여라.
수정한 내용을 설명하여라.
CTC mode로 바꾸기 위해 WGM52 bit를 set시키고, output mode는 interrupt 발생 시 toggle 되도록 설정하였으므로 setting 하지 않는다. 그리고 OCR5A의 compare match 값은 주석되어 있는 식에 따라 결정했다
(식 추가)
11.
위상이 90도 빠르게 하려면 원래 신호의 주기의 반을 지연시킨 신호를 출력하면 된다. 이 때 우리는 실험 8에서 Figure 17.1에서 Compare match를 구성하는 회로에서 3개의 비교기가 있음을 알 수 있고, timer에 들어오는 클럭을 다른 핀인 PE4(OC3B)에 다른 조건으로 출력시킬 수 있다.원래 OCR3A의 신호는 250 clk 후 compare match가 발생했다면 그 반인 125clk 후에 신호가 먼저 출력되도록 다음과 같이 설정한다.
( 1/4인 줄 알았는데 검증 결과 이렀다.)
'전자공학 > 마이크로프로세서' 카테고리의 다른 글
[atmega1281] 실험 11. AVR ADC의 활용 (0) | 2024.12.11 |
---|---|
[atmega1281] 실험 10. AVR의 UART를 사용한 비동기 직렬 통신 (0) | 2024.12.02 |
[atmega1281] 실험 9. AVR MCU의 타이머 활용 3 – PWM (1) | 2024.11.27 |
[atmega1281] 실험 8. AVR MCU의 타이머 활용 2 – 스피커 구동 (1) | 2024.11.21 |
[atmega1281] 사진 첨부 해야 함 - 실험 6. AVR MCU의 PCINT 활용 및 스위치 바운싱 (Bouncing) 관측 (0) | 2024.11.06 |