・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 0xff
int 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 Makefile
PROJECT=mega168-adc012
SOURCES=mega168-adc012.c
CC=avr-gcc
OBJCOPY=avr-objcopy
MMCU=atmega168
TARGETDEV=m168P
CFLAGS=-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).hex
sudo avrdude -p $(TARGETDEV) -P usb -c avrispmkII -e -U flash:w:$(PROJECT).hex
clean:
rm -f $(PROJECT).out
rm -f $(PROJECT).hex