Active Buzzer vs. Passive Buzzer
Active Buzzer는 전원만 인가하면 소리가 난다.
Passive Buzzer는 특정 주파수를 직접 인가해야 소리가 난다.
그러니까, Waveform Generation 기능을 이용해 보려면 Passive Buzzer를 선택해야 한다.
직접 주파수를 인가하기 때문에 원하는 음을 낼 수 있다.
그렇다면 연주 같은 것도 가능하겠지.
먼저... Timer랑 Counter가 왜 묶여 있지?
16-bit Timer/Counter라고 해 보자
클럭은 16MHz라고 해 보자.
1초에 16,000,000번 클럭이 인가된다는 건데...
좋다. 클럭이 한 번 인가될 때마다 Counter를 1씩 증가시키다가 16,000,000이 되면 1초가 지났다고 하면 되겠군!
...안타깝지만 16비트 Timer/Counter에는 0-65535까지만 저장이 가능한데 되겠나?
이번엔 Prescaler에 대해 간단히 알아야 한다.
'분주기'라고, n Clock을 1 Clock으로, 클럭을 나눠주는 장치다.
예를 들어, ATmega128A의 Timer/Counter1의 Prescaler는 아래 값 중 하나를 선택할 수 있다.
8, 32, 64, 128, 256, 1024
Prescaler 값으로 1024를 택했다고 해 보자.
16,000,000Hz를 1024로 나누면?
15625
분주기를 거친 클럭이 15625번 인가되면 1초가 지난 것이군!!!!!!
아하!!!!!!! TCNT1이 15625가 되면 1초!!!!!!!
아하!!!!!
얼마나 긴 시간을 잴 것인지 등등... 목적에 맞게 Prescaler를 설정하면 될 것.
Timer/Counter랑 Waveform Generation이 무슨 상관이지?
Timer/Counter는...
카운터가 다 차서 오버플로우가 발생할 때마다 인터럽트가 발생토록 할 수 있다.
Normal Mode
물론 Normal Mode를 Waveform Generate용으로 사용하는 건 Not-recommended라고 써져 있긴 하다.
혹은 OCRnA Register에 값을 세팅해 놓고, TCNTn의 값이 OCRnA의 값과 같아졌을 때마다 인터럽트가 발생하게 할 수 있다.
CTC Mode, Clear Timer on Compare match Mode.
TCNTn : Timer/Counter n이 가지고 있는 카운터 Register.
OCRnA : Output Compare Register. 비교할 값이 담긴 Register.
이 인터럽트 때마다(혹은 어떤 이벤트마다) OCn 핀의 신호를 올리고 내리면...?
Waveform Generation!!!
HC12G-1PA Buzzer (= IMT12D2001AP)
주요 Spec - Passive Buzzer
85db(min) at 10cm
철로변/지하철 소음 수준?
Rated Voltage: 1.5v
ATmega128A에선 5V output이 나오니까, 저항을 잘 활용해줘야 할 것.
나는 1/4W 100옴 + 15옴 = 115옴 저항을 두었다.
R = V / I
1.5v 사용하니까, V = 5v - 1.5v = 3.5v
아래의 Max Current Consumption, I = 30mA
3.5 / 0.03 = 116.666...옴.
115옴 쓰자!
전력 P = IV = 3.5 * 0.03 = 0.105
1/8W가 채 안 되는군!
Operating Voltage: 1 - 2v
이 사이에서 전압을 흔들어서 주파수를 주면 된다는 거지...?
Resonant Frequency: 2048Hz
이 주파수에서 소리가 가장 크다? 공명주파수.
Max Current Consumption: 30mA
at 2048Hz, 1/2 Duty Square Wave
실험 1. 그냥 Power Supply에 연결해 보기.
아무 소리도 안 난다.
전극을 뗐다 붙였다 하면 지지직거리긴 한다.
MOSFET 같은 걸 이용해서 소리낼 수도 있겠군. 난 CTC 쓸 거지만...
CTC, Clear Timer on Compare Match Mode (WGM01:0 = 2) - 8bit Timer/Counter0
개요
OCR0 Register의 값과 TCNT0 값이 일치하면 Counter가 Clear된다.
그러니까, OCR0 값이 곧 Counter의 TOP Value다.
TOP Value : 각 동작 모드에서 카운터가 도달하는 최댓값.
설정될 수 있다.
MAX Value : 각 동작 모드에서 카운터가 가질 수 있는 최댓값.
8bit 기준 0xFF... 아시잖아요?
BOTTOM Value : 카운터가 가질 수 있는 최솟값.
대개 0. 특수한 경우가 아니면.
OCF0 Flag를 이용하면 카운터 값이 TOP Value에 도달할 때마다 인터럽트를 발생시킬 수 있다.

사실 나는 이건 관심 없다
Waveform을 Generate하지만 PWM은 아니다.
Duty Ratio 50% 고정.
CTC Mode에서 COM01:0 = 1로 설정하면...
OC0 핀의 출력이 계속 Toggle된다!
OCn Interrupt 발생 시마다 Toggle.
만들어낼 수 있는 주파수는?
.
N은 Prescaler Factor.
1, 8, 32, 64, 128, 256, 1024
Prescaler Factor를 1(미사용)로 두고... OCRn을 1로 두면 40,000Hz = 40KHz
주의할 것은...
Counter가 돌고 있는 중에 TOP Value(OCR0)를 BOTTOM에 가깝게 옮길 때 조심.
Counter가 Compare Match를 놓칠 수 있다.
그렇게 되면 TCNT0이 0xFF까지 갔다가 BOTTOM으로 내려온 후부터 제대로 동작한다.
분주비 N과 OCRn의 값을 잘 조정하며 주파수를 제어하면 될 것.
CTC Mode로 Buzzer 다루기
코드
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
int main(void){
DDRA = 0x01; // 개발보드 상태확인용
DDRB = 0x10; // PB4만 Out...
PORTB = 0x00;
TCCR0 = 0x1C; // 0001 1100, Prescale(64)
OCR0 = 60; // 여기까지 하면 2048Hz에 근접. 대략 2049.18Hz.
while(1){
// 개발보드 상태확인용
PORTA = 0x01;
_delay_ms(1000);
PORTA = 0x00;
_delay_ms(1000);
}
}설명
DDRA와 While문
내가 쓰는 개발보드는 PA0의 Pin-Out이 보드의 LED를 깜빡거리도록 하기 때문에, 개발보드가 잘 돌고 있나 상태 확인을 위해 넣어준 것뿐이다.
DDRB = 0x10 -> 0b 0001 0000
PB4(OC0) 핀을 Output Pin으로 설정한 것이다.
PORTB = 0x00
평범한 기본값 설정이다.
TCCR0 = 0x1C -> 0b 0001 1100
이게 중요하다!!!

TCCR0은 이렇게 생겨먹었다. 데이터시트에 오류가 있는지 6번 비트와 3번 비트가 바뀌어 있다(...).
WGM01:0 = 2라고 했으므로...
WGM01 비트 위치에 1
WGM00 비트 위치에 0
COM01:0은...
난 Toggle 하고 싶으니까...

COM01 비트 위치에 0
COM00 비트 위치에 1
CS02:0은 Prescaler 설정하는 영역이다.

난 분주비 64 쓰고 싶으니까...
CS02 위치에 1
CS01 위치에 0
CS00 위치에 0
OCR0 = 60
Output Compare Register#1을 60으로...
위~~~에 있는 수식에 넣고 돌려보니 이렇게 설정해야 2048Hz에 가장 가까운 주파수가 나오드라구용.
결과
여담 - 이걸로 이틀을 삽질한 이유



