Arduino Nano로 AM 음악 송신기 만들기
부품 및 소모품
| Arduino Nano R3 |
1개 |
| 저항 10k옴 |
2개 |
| 커패시터 10µF |
1개 |
| 브레드보드 |
1개 |
앱 및 온라인 서비스
프로젝트 소개
ATmega MCU로 멋진 것들을 만들 수 있습니다. 그래서 Arduino Nano(다른 아두이노도 가능)로 AM 송신기를 만들어보자는 아이디어가 떠올랐습니다.
문제는 디지털 장치에서 진폭 변조(AM)를 어떻게 구현하느냐입니다. AM은 전달하려는 입력 신호의 진폭에 따라 반송파 주파수의 진폭을 변화시키는 것입니다. 수학적으로 말하면 반송파에 입력 신호를 곱하는 것입니다. 하지만 ATmega는 디지털 출력만 있어 HIGH와 LOW 두 값만 출력할 수 있습니다. 솔직히 말해 아두이노로 진짜 AM을 구현하는 방법은 없습니다.
그럼에도 일반적인 AM 라디오 수신기로 또렷하게 들을 수 있는 출력 신호를 생성하는 것은 가능합니다!
해결책은 아날로그 입력 신호를 PWM 신호로 변환하는 것입니다. ATmega MCU의 ADC와 16비트 타이머/카운터1을 사용합니다.
타이머/카운터2가 반송파 신호를 생성하며, 31kHz에서 8MHz 사이의 넓은 범위에서 조절 가능합니다.
이 반송파 신호는 PWM 신호의 리듬에 맞춰 D11 핀으로 출력됩니다. AM 라디오는 PWM에 대해 로우패스 필터 역할을 하므로, 그곳에서 원래 오디오 신호를 복원할 수 있습니다.
이것은 개념 증명이므로 단순하게 유지했습니다. 실제로 RF 송신기로 사용하려면 오디오 입력에 안티앨리어싱용 로우패스 필터를, RF 출력에는 고조파 대책용 로우패스 필터를 추가해야 합니다.
코드
Arduino AM 송신기 C/C++
/* 이 저작물은 Creative Commons Attribution-ShareAlike 4.0 International License 하에 라이선스됩니다.
라이선스 사본은 https://creativecommons.org/licenses/by-sa/4.0/에서 확인하세요. */
#define ANTENNA_PIN PB3 // Arduino Nano/Uno D11
void setup() {
Serial.begin(115200);
// 반송파 주파수 생성
uint32_t fTransmit = 600; // kHz
DDRB |= (1 << ANTENNA_PIN);
TCCR2A = (0 << COM2A1) + (1 << COM2A0); // 비교 매치 시 OC0A 토글
TCCR2A |= (1 << WGM21) + (0 << WGM20); // CTC 모드
TCCR2B = (0 << CS22) + (0 << CS21) + (1 << CS20); // 프리스케일러 없음
OCR2A = F_CPU / (2000 * fTransmit) - 1;
char strbuf[255];
sprintf(strbuf, "Will broadcast at %d KHz", (F_CPU / (2 * (1 + OCR2A)) / 1000));
Serial.println(strbuf);
// PWM 신호 생성
// TCCR1A |= (0 << WGM11) + (1 << WGM10); // Fast PWM 8비트
// TCCR1A |= (1 << WGM11) + (0 << WGM10); // Fast PWM 9비트
TCCR1A |= (1 << WGM11) + (1 << WGM10); // Fast PWM 10비트
TCCR1B = (1 << WGM12);
TCCR1B |= (0 << CS12) + (0 << CS11) + (1 << CS10); // 프리스케일러 없음
TIMSK1 = (1 << OCIE1A) + (1 << TOIE1);
// ADC 설정
ADMUX = (1 << REFS1) + (1 << REFS0); // 내부 1.1V 레퍼런스
ADCSRA = (1 << ADEN) + (1 << ADSC) + (1 << ADATE); // 자동 트리거 활성화, 프리러닝
ADCSRA |= (1 << ADPS2) + (1 << ADPS1) + (0 << ADPS0); // 64분주 -> 18.5k 샘플링 레이트
DIDR0 = (1 << ADC0D);
}
ISR(TIMER1_OVF_vect) {
uint8_t adcl = ADCL;
uint8_t adch = ADCH;
OCR1A = (adch << 8) + adcl;
DDRB |= (1 << ANTENNA_PIN);
}
ISR(TIMER1_COMPA_vect) {
DDRB &= ~(1 << ANTENNA_PIN);
}
void loop() {
// 메인 루프는 비워둠 (인터럽트 기반 동작)
}
회로도