2015-02-15

Buzzer로 산토끼 노래 만들기 강좌

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

Total Pageviews