子供向けの簡単なおもちゃを作る(ATTiny85のPWMで音を出す)
ProjectArduino, ATTiny, Embedded, HW, Japanese
姪と甥に会いに行くのだけど、姪へのお土産はあるが、甥へのお土産がないので、作ってみた。対象年齢2歳ぐらい。
MakerFaireTokyoの帰り道、ボタンを押すとLEDが光るおもちゃを、知人の子が割と面白そうに触っていたので、それを真似して、とりあえず光らせて、音を出してみようと思った。
材料
- ATTiny85
ArduinoというかAVRで自前で音出したことなかったので、練習に。 - ケース
USBスピーカーのケースがちょうど良かった。むき出しにすると破壊されたり、部品を誤飲されたりする危険とかあるので。むしろこのケースみてこれを思いついた。
https://jp.creative.com/p/speakers/creative-muvo-2c - 電池ボックス
ATTiny85は動作電圧:2.7V ~ 5.5Vなので、単4x3の、約4.5Vを直接つないだ。 - スピーカー
以前どこかで買っていた圧電スピーカー - LED
- LEDで光らせる対象
透明PLAフィラメントを使い、フリーの素材を3Dプリンタで印刷した - タクタイルスイッチ
子供が押しやすいように大きめのものを
開発環境
Arduinoを書き込み機として用いて、ArduinoIDE上で開発します。
音の出し方
tone関数が使えなかったので、SIN波を狙った周波数でPWMにセットするようなものを作った。
基準となるSIN波はあらかじめ計算して配列に格納しておく。
あとは、ボタンと連動させて、ドレミの音階を変えたり、LEDを光らせたりすればOK
動かしてみた様子
甥殿への手土産ができた。attiny85でsin波を作る練習をした。
ケースには昔買ったUSBスピーカーのケースを利用。 pic.twitter.com/dh1UTVbTyN— kishima (@kishima) August 15, 2018
参考
- PWMと割り込みの設定法
http://www.technoblogy.com/show?QBB
http://usicolog.nomaki.jp/engineering/avr/avrInterrupt.html#howToUse
ソースコード
#include <avr/pgmspace.h>
const uint8_t sin_wav[] PROGMEM = {
140,153,165,177,189,199,210,219,227,235,241,246,250,253,255,255,254,252,248,243,238,231,223,214,204,193,182,170,158,145,133,
120,107,95,83,71,60,49,40,31,23,16,11,6,3,1,0,0,2,5,9,15,21,29,38,47,57,68,80,92,104,117,
};
const int msc_freq[] = {//Scale Hz CDEFGAC
261,293,329,349,391,440,492,523
};
const uint8_t sin_wav_len = 62;
volatile uint8_t msc = 0;//CDEFGA(440Hz)BC
volatile int msc_cnt=0;
volatile int msc_cnt_max = 1;
volatile char btn_stat=0;
volatile char sound_stat=0;
volatile int sound_duration=0;
const int int_freq=20000;//20KHz
#define PIN_BTN 0
#define PIN_LED 3
#define PIN_PWM1 1
#define PIN_PWM2 4
void button(){
btn_stat = !btn_stat;
digitalWrite(PIN_LED,btn_stat);
msc_cnt_max = int_freq / msc_freq[msc%8];
msc++;
sound_stat=1;
}
void setup () {
msc_cnt_max = int_freq / msc_freq[0];
pinMode(PIN_LED, OUTPUT); //LED
pinMode(PIN_BTN, INPUT_PULLUP); //Button
digitalWrite(PIN_LED,btn_stat);
//PWM and Interruption Setting
PLLCSR = 1<<PCKE | 1<<PLLE;
TIMSK = 0;
TCCR1 = 1<<PWM1A | 2<<COM1A0 | 1<<CS10;
GTCCR = 1<<PWM1B | 2<<COM1B0;
OCR1A = 128; OCR1B = 128;
TCCR0A = 3<<WGM00;
TCCR0B = 1<<WGM02 | 2<<CS00;
TIMSK = 1<<OCIE0A;
OCR0A = (1000000 / int_freq)-1; //20KHz
pinMode(PIN_PWM2, OUTPUT); //PWM
pinMode(PIN_PWM1, OUTPUT); //PWM
}
void loop () {
//Check button status
static char last=0;
static uint8_t bcnt=0;
char s = digitalRead(PIN_BTN);
if(s==0){
if(last==0){
bcnt++;
if(bcnt>250)bcnt=250;
}
last=0;
}else{
if(bcnt>240){
button();
}
last=1;
bcnt=0;
}
}
ISR (TIMER0_COMPA_vect) {
if(sound_stat==0) return;
sound_duration++;
if(sound_duration>int_freq){
sound_duration=0;
sound_stat=0;
}
int point = ((int)sin_wav_len * msc_cnt) / msc_cnt_max;
char val = pgm_read_byte(&sin_wav[point]);
OCR1A = val;
OCR1B = val ^ 255;
msc_cnt++;
if (msc_cnt >= msc_cnt_max) {
msc_cnt=0;
}
}
中身と配線
関連記事
直近の活動予定
直近の対外的な活動予定を記載しています。 今後のイベント 特になし (技術書、も ...
独習mrubyバイトコード[SETGLOBAL]
OP_SETGLOBAL Arguments A: レジスタ番号 Bx: シンボ ...
Wio LTEのブロック図と電源の系統図をメモしてみた
WioLTEの消費電力を考えるにあたって、どんな配線になっているのかを自分な ...
独習mrubyバイトコード[OP_MOVE]
OP_MOVE Arguments A:レジスタ番号 B:レジスタ番号 How ...
技術書典5振り返り~技術同人誌の書き方覚書~
技術書典5ご報告 技術書典5、弊サークル(Kishima Craft Works ...
Wio LTEでmruby/cを動かすArduinoライブラリを作った
英語版はこちら。 先日、第60回 kawasaki.rbで↓のようなLTしてきま ...
ディスカッション
コメント一覧
まだ、コメントがありません