・3軸加速度センサを搭載し、傾ける方向によって曲目が変化する電子オルゴールを作ってみた。
・3軸加速度センサは、本機の傾きを検出して、アナログ信号を出力する。マイコンが、センサの出力をA/Dコンバータでデジタル信号に変換する。さらに、このデジタル信号を判断して、メロディICの選曲信号を出力する。
・メロディICは、クリスマスソングを奏でながらLEDを点滅させる。
・ちょっと変わったお菓子の容器に組み込んでみた。とてもにぎやかなオモチャになった。
※回路図やマイコンのファームウェアのソースコードは、添付ファイルを参照のこと。
3軸加速度センサ KXM52-1050モジュール
AVRマイコン ATMEGA168P
電子オルゴールメロディIC SM6201-4 (クリスマスソング)
LED
トランジスタ 2SC1815
カーボン抵抗 1kΩ, 510kΩ
スピーカ
電池スナップ
電池ボックス(単3型2本用)
ユニバーサル基板 片面ガラス・ユニバーサル基板(ブレッドボード配線パターンタイプ)
適当なケース
・最初にブレッドボード上で動作を確認してから、ユニバーサル基板で製作した。
・今回使用したユニバーサル基板は、ブレッドボードとほぼ同じレイアウトになっており、ブレッドボードを見ながら配線をハンダづけすることができる。間違いが少なく作業効率が大幅に向上した。
・お菓子の容器に組み込んでみた。
// Mega168 A/D Accelaration-sensor-switch// AVR Device : ATmega168// PD0,1,2 : Switch Contact Active low ( 0:ON, 1:OFF )// ADC0, ADC1, ADC2 (PIN23, 24, 25) connect to Accelaration sensor#include <avr/io.h>void wait(volatile long i){ while(i-- > 0);}void sw_high(int id){ switch (id) { case 0: PORTD |= (1<<PD0); break; case 1: PORTD |= (1<<PD1); break; case 2: PORTD |= (1<<PD2); break; case 3: PORTD |= (1<<PD3); break; case 4: PORTD |= (1<<PD4); break; case 5: PORTD |= (1<<PD5); break; default: PORTD |= 0xff; }}void sw_low(int id){ switch (id) { case 0: PORTD &= ~(1<<PD0); break; case 1: PORTD &= ~(1<<PD1); break; case 2: PORTD &= ~(1<<PD2); break; case 3: PORTD &= ~(1<<PD3); break; case 4: PORTD &= ~(1<<PD4); break; case 5: PORTD &= ~(1<<PD5); break; default: PORTD &= 0x00; }}void init_adc(void){ // AD Conv. Enable & Clock ferquency and the input clock to the ADC) ADCSRA = ( (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0) );}unsigned int get_ad(char adcport)// arg: adcport : 0 -{ ADMUX = (1<<ADLAR) | adcport; // AD-Conv. 8-bit precision, Use ADC-PORT0 ADCSRA |= (1<<ADIF); // Set ADC Interrupt flag ADCSRA |= (1<<ADSC); // Start AD Conv. while ( ( ADCSRA & (1<<ADIF) ) == 0); //Wait to complete adc return (unsigned int)ADCH; // 8-bit precision}#define ADC_G_POS 168#define ADC_G_NEG 100#define AXIS_X 0x00#define AXIS_Y 0x01#define AXIS_Z 0x02#define AXIS_NULL 0xffint main(void){ unsigned int adx, ady, adz; // ADC input signal unsigned char mode = AXIS_NULL; init_adc(); // ADC port initialize wait(10000); // wait a moment // PORTD0-5 を出力モード DDRD = (1<<PD5) | (1<<PD4) | (1<<PD3) | (1<<PD2) | (1<<PD1)| (1<<PD0); sw_high(6); while(1) { adx = get_ad(0x00); // ADC0 X-axis ady = get_ad(0x01); // ADC1 Y-axis adz = get_ad(0x02); // ADC2 Z-axis if ( mode != AXIS_X && adx > ADC_G_POS ) { sw_low(0); wait(1000); mode = AXIS_X; sw_high(6); } else if ( mode != AXIS_X && adx < ADC_G_NEG ) { sw_low(0); wait(1000); mode = AXIS_X; sw_high(6); } else if ( mode != AXIS_Y && ady > ADC_G_POS ) { sw_low(1); wait(1000); mode = AXIS_Y; sw_high(6); } else if ( mode != AXIS_Y && ady < ADC_G_NEG ) { sw_low(1); mode = AXIS_Y; wait(1000); sw_high(6); } else if ( mode != AXIS_Z && adz > ADC_G_POS ) { sw_low(2); mode = AXIS_Z; wait(1000); sw_high(6); } else if ( mode != AXIS_Z && adz < ADC_G_NEG ) { sw_low(2); wait(1000); mode = AXIS_Z; sw_high(6); } else { sw_high(6); } } return 0;}# AVR-GCC MakefilePROJECT=mega168-adc012SOURCES=mega168-adc012.cCC=avr-gccOBJCOPY=avr-objcopyMMCU=atmega168TARGETDEV=m168PCFLAGS=-mmcu=$(MMCU) -Wall$(PROJECT).hex: $(PROJECT).out$(OBJCOPY) -j .text -O ihex $(PROJECT).out $(PROJECT).hex
$(PROJECT).out: $(SOURCES)$(CC) $(CFLAGS) -I./ -o $(PROJECT).out $(SOURCES)
program: $(PROJECT).hexsudo avrdude -p $(TARGETDEV) -P usb -c avrispmkII -e -U flash:w:$(PROJECT).hex
clean:rm -f $(PROJECT).out
rm -f $(PROJECT).hex