buzzer로 노래 만들기 강좌에 질문한 내용을 정리한 글입니다.
출처 : cafe.naver.com/laydigital/
4-3. 버저로 산토끼 노래하기 [강좌]- 질문1,2
질문1)) 연습용 코드 (비교매치모드, Critical section)
1. TCCR0 |= (0<<COM01)|(0<<COM00); 이부분은 00, 01, 10, 11 중 아무거나 선택해도 동작구현에 전혀 영향이 없어 보이는데,
실제 회로도에 PB4핀(OC0) 은 buzzer 와 TR로 연결 되어져 있는데 무슨 차이점이 생기는건지 궁금합니다.
2. Critical section 부분에서 아래 작성한 방식으로 하는것이 맞는건지 알려주시면 감사하겠습니당.
3. tone = EOS 값일때 발생음이 생기는데 왜 발생하는지 궁금합니다.
/------------------------------------------------------------------------------------------------/
/*use timer counter 0 */
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#define OFF 0 //isr state compare value
#define ON 1 //isr state compare value
#define DO 0
#define RE 1
#define MI 2
#define FA 3
#define SO 4
#define RA 5
#define SI 6
#define DO_H 7
#define EOS 255 //(End of song)
// C(도) 523
// D(레) 587
// E(미) 659
// F(파) 699
// G(솔) 784
// A(라) 880
// B(시) 988
// C_H(도) 1047
char cb[]={238,212,189,178,158,141,126,118}; //8bit compare_interrupt:(compare TCNT0 and OCR0(use value)).
unsigned char mz[]={SO, MI, MI, SO, MI, DO, RE, MI, RE, DO, MI, SO, DO_H, SO, DO_H, SO, DO_H, SO, MI, SO, RE, FA, MI, RE, DO, EOS};
volatile unsigned char init_state = OFF, tone;
// e.g: duty cycle : 50% half: 0 or 1.(T/2) atmel128 16MHZ T: 0.0625us prescale: 64 T: 4us. 8bit timer&counter : 256ea
void init_buzzer();
void comparei_CTC_bit_set();
int main(void)
{
int i=0;
init_buzzer();
comparei_CTC_bit_set();
do{
cli();
tone= mz[i++]; //critical section. // for문으로 변경하여 변수인자형을 unsigned char (256)값으로 한정.
sei();
PORTA = tone; //mz 값 확인용.
_delay_ms(300);
}while(tone!=EOS);
}
ISR(TIMER0_COMP_vect)
{
OCR0 = cb[tone];
if(init_state==OFF)
{
PORTB |= (1<<PB4);
init_state = ON;
}
else
{
PORTB &= ~(1<<PB4);
init_state = OFF;
}
}
void init_buzzer()
{
DDRA = 0xff;
DDRB = (1<<PB4);
}
void comparei_CTC_bit_set()
{
TCCR0 = 0;
TCCR0 |= (1<<WGM01)|(0<<WGM00); //waveforme generate : CTC ,TOP: OCR0, update: immeiate, Max. 00, 01, (10) 11.
TCCR0 |= (0<<COM01)|(1<<COM00); // Toggle OC0 on compare match. (non-PWM mode) 00, 01, 10, 11 don't care in //this code.
TCCR0 |= (1<<CS2)|(0<<CS1)|(0<<CS0); // prescale:64, 000:source clock 011:32, 100:64, 101:128, 110:256, 111:1024
TIMSK = 0;
TIMSK |= (1<<OCIE0); // interrupt by Compare tcnt0 (0~0xff) and OC0 (user value)valuse.
TCNT0 = 0;
sei(); // enable global interrupt.
}
1. non PWM 일 경우 (위 사용예), COM01,COM00 에 의해 아래 기능이 선택됩니다.
COM01 COM00 Description
0 0 Normal port operation, OC0 disconnected.
0 1 Toggle OC0 on compare match
1 0 Clear OC0 on compare match
1 1 Set OC0 on compare match
00 인 경우 OC0 핀은 sw로 구동해야 하고
01 인 경우에는 OC0핀은 인터럽트 루틴에서 해당핀을 구동하지 않아도 자동으로 토글됩니다.
나머지 두 경우에도 이해 가능할겁니다.
2. critical section은 그렇게 사용하시면 됩니다.
tone이 char 라면 위의 경우에는 critical section을 빼도 별 문제는 없습니다.
3. 엄밀하게 제어 한다면
do {
cli();
tone = song[i++]; // 노래 음계
if(tone == EOS) { TCCR0 = 0; 또는 break;} //
sei();
_delay_ms(500); // 한 계명당 지속 시간
}while(1);
이렇게 하는게 맞겟죠.
EOS일때에도 타이머 인터럽트가 걸리는건 바람직하지 않으므로
TIMSK 또는 cli 상태 또는 TCCR0 에 clock 부분을 000 으로 설정해서 타이머 중단하는게
좋겠죠.
타이머 0를
CTC 모드로 사용하고
OC0핀을 compare 시 match 되게 하면
COMPARE match 인터럽트를 사용하지 않아도 위의 응용을 만들 수 있습니다.
OC0 핀이 TR로 들어가는건,
OC0가 직접 buzzer를 구동하면 전류 부족해서
TR을 통해 전류 구동을 하는 겁니다.
No comments:
Post a Comment