![]() |
CPUは小型で比較的高速でメモリ容量も多いATiny85を用いることにします。 この写真は、スピーカー、電池ボックスを接続していない回路部分のみです。非常にシンプルで、スイッチは左から、ON/OFF(赤)、音質選択(黒)、曲選択(白)となっています。 |
ピン番号 | 機能 |
---|---|
1 | reset |
2 | 音質変更スイッチ(PCINT3, PB3) |
3 | スピーカ出力(PB4) |
4 | GND |
5 | 選曲変更スイッチ(PCINT0, PB0) |
6 | スピーカ出力(PB1) |
7 | INT0で電源on/off変更スイッチ(PB2) |
8 | +電源(4.5V) |
矩形波発生プログラム | |
---|---|
#include <avr/interrupt.h> int main(void) { PORTB=0x04; // PB2はsource、PB4,PB1はsinkの出力設定 DDRB=0x1E; // xxxoooox PLLCSR= 6; // PCKE=1(64MHz) PLLE=1 TCCR1=0x51; // PMWA1enable,ToggleOC1Aを出力としてOCR1Cでコンベアマッチ(PB1,pin6), PCK OCR1C=255; // 250kHz // 64MHz/256=250kHz(4μs) OCR1A = 127; // duty cycle 50% // コンベアレジスター OCR1B = 63; // duty cycle 25% // General Timer/Counter Control Register GTCCR=0x50; // PWMBenable(OCR1B,C)、ToggleOC1B (PB4,pin3を出力指定)、カウント開始 OCR0A =64; TCCR0A=0x02; // ClearTimer on Compare Match(CTC) mode TCCR0B=0x02; // Clock Select (clkio/8, from prescaler) TIMSK=_BV(OCIE0A); // Timer Interrupt Mask Register sei(); while (1) { } } uint8_t n=0; int length=20; ISR(TIMER0_COMPA_vect){ if(--length==0) { length=20; // 基本周波数を決める n=~n; if(n==0) OCR1A=250; // PB1(Pin6) パルス幅を変える else OCR1A=10; // Duty Cycleの変化で音質が変わる } } |
1 割り込み処理のため 2 3 4 5 方向レジスタの設定 6 PLLで高速の設定 7 8 9 10 11 12 13 2MHz/64=31.3kHz 14 15 CLKIO/8=2MHz 16 タイマー0からの割り込み許可 17 CPUの割り込み許可 18 永久ループ 19 20 21 22 23 24 25 26 タイマー0からの割り込み処理ルーチン 27 32μs毎に割り込む 28 29 781.25Hzの波形を作る 30 1.0/(40*32e-6)=781.25 31 32 33 34 |
正弦波の音を作る | |
---|---|
#include <avr/interrupt.h> uint8_t wave[]={0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,17,18,20,21,23,25,27,29,31,33,35,37,40, 42,44,47,49,52,54,57,59,62,65,67,70,73,76,79,82,85,88,90,93,97,100,103,106,109,112,115,118,121, 124,127,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173,176,179,182,185,188,190,193, 196,198,201,203,206,208,211,213,215,218,220,222,224,226,228,230,232,234,235,237,238,240,241,243, 244,245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255,255,255,255,255,254,254,254, 253,253,252,251,250,250,249,248,246,245,244,243,241,240,238,237,235,234,232,230,228,226,224,222, 220,218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,176,173,170,167,165,162,158, 155,152,149,146,143,140,137,134,131,128,124,121,118,115,112,109,106,103,100,97,93,90,88,85,82,79, 76,73,70,67,65,62,59,57,54,52,49,47,44,42,40,37,35,33,31,29,27,25,23,21,20,18,17,15,14,12,11,10, 9,7,6,5,5,4,3,2,2,1,1,1,0,0,0}; int main(void) { PORTB=0x04; // PB2はsource、PB4,PB1はsinkの出力設定 DDRB=0x1E; // xxxoooox PLLCSR= 6; // PCKE=1(64MHz) TCCR1=0x51; // PMWA1enable,ToggleOC1Aを出力としてOCR1Cでコンベアマッチ(PB1,pin6), PCK OCR1C=255; // 250kHz // 64MHz/256=250kHz(4μs) OCR1A = 127; // duty cycle 50% // コンベアレジスター OCR1B = 63; // duty cycle 25% // General Timer/Counter Control Register GTCCR=0x50; // PWMBenable(OCR1B,C)、ToggleOC1B (PB4,pin3を出力指定)、カウント開始 OCR0A =64; TCCR0A=0x02; // ClearTimer on Compare Match(CTC) mode TCCR0B=0x02; // Clock Select (clkio/8, from prescaler) TIMSK=_BV(OCIE0A); // Timer Interrupt Mask Register sei(); while (1) { } } uint8_t cnt=0, n=8; ISR(TIMER0_COMPA_vect){ OCR1A = wave[cnt]; cnt+=n; } |
1 割り込みを使う 2 正弦波表 3 128*(1-cos(θ)) 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 nは基本周波数を決める 35 36 タイマーからの割り込み 37 正弦波表の値 38 表を飛び飛びに読み込む 39 |
正弦波強弱プログラム | |
---|---|
#include <avr/io.h> #include <avr/interrupt.h> uint8_t wave[]={0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,17,18,20,21,23,25,27,29,31,33,35,37,40, 42,44,47,49,52,54,57,59,62,65,67,70,73,76,79,82,85,88,90,93,97,100,103,106,109,112,115,118,121, 124,127,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173,176,179,182,185,188,190,193, 196,198,201,203,206,208,211,213,215,218,220,222,224,226,228,230,232,234,235,237,238,240,241,243, 244,245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255,255,255,255,255,254,254,254, 253,253,252,251,250,250,249,248,246,245,244,243,241,240,238,237,235,234,232,230,228,226,224,222, 220,218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,176,173,170,167,165,162,158, 155,152,149,146,143,140,137,134,131,128,124,121,118,115,112,109,106,103,100,97,93,90,88,85,82,79, 76,73,70,67,65,62,59,57,54,52,49,47,44,42,40,37,35,33,31,29,27,25,23,21,20,18,17,15,14,12,11,10, 9,7,6,5,5,4,3,2,2,1,1,1,0,0,0}; int main(void) { PORTB=0x04; // PB2はsource、PB4,PB1はsinkの出力設定 DDRB=0x1E; // xxxoooox PLLCSR= 6; // PCKE=1(64MHz) TCCR1=0x51; // PMWA1enable,ToggleOC1Aを出力としてOCR1Cでコンベアマッチ(PB1,pin6), PCK OCR1C=255; // 250kHz 64MHz/256=250kHz(4μs) OCR1A = 127; // duty cycle 50% コンベアレジスター OCR1B = 63; // duty cycle 25% // General Timer/Counter Control Register GTCCR=0x50; // PWMBenable(OCR1B,C)、ToggleOC1B (PB4,pin3を出力指定)、カウント開始 OCR0A =64; TCCR0A=0x02; // ClearTimer on Compare Match(CTC) mode TCCR0B=0x02; // Clock Select (clkio/8, from prescaler) TIMSK=_BV(OCIE0A); // Timer Interrupt Mask Register sei(); while (1) { } } #define modulate 60 uint8_t cnt=0, n=16,length=modulate,m=0; ISR(TIMER0_COMPA_vect){ // 32μ秒で割り込む if(--length==0){ // 32e-6*60*256=0.5 0.5秒周期でワウワウ m++; length=modulate; } OCR1A = wave[(cnt+m)%256]; OCR1B = wave[cnt]; cnt+=n; } |
1 2 3 割り込みを使う 4 正弦波表 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 変調周期の設定 36 37 38 タイマー0からの割り込み 39 40 41 42 43 低周波で変調するために飛び飛びにする 44 基本の正弦波 45 46 |
減衰正弦波の音を作るプログラム | |
---|---|
#include <avr/io.h> #include <avr/interrupt.h> uint8_t wave[]={0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,17,18,20,21,23,25,27,29,31,33,35,37,40, 42,44,47,49,52,54,57,59,62,65,67,70,73,76,79,82,85,88,90,93,97,100,103,106,109,112,115,118,121, 124,127,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173,176,179,182,185,188,190,193, 196,198,201,203,206,208,211,213,215,218,220,222,224,226,228,230,232,234,235,237,238,240,241,243, 244,245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255,255,255,255,255,254,254,254, 253,253,252,251,250,250,249,248,246,245,244,243,241,240,238,237,235,234,232,230,228,226,224,222, 220,218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,176,173,170,167,165,162,158, 155,152,149,146,143,140,137,134,131,128,124,121,118,115,112,109,106,103,100,97,93,90,88,85,82,79, 76,73,70,67,65,62,59,57,54,52,49,47,44,42,40,37,35,33,31,29,27,25,23,21,20,18,17,15,14,12,11,10, 9,7,6,5,5,4,3,2,2,1,1,1,0,0,0}; volatile uint8_t stop=0; int i; int main(void) { PORTB=0x0C; // DDRB=0x12; // xxxo1iox PLLCSR= 6; // PCKE=1(64MHz) TCCR1=0x51; // PMWA1enable,ToggleOC1Aを出力としてOCR1Cでコンベアマッチ(PB1,pin6), PCK OCR1C=255; // 250kHz 64MHz/256=250kHz(4μs) OCR1A = 127; // duty cycle 50% コンベアレジスター OCR1B = 63; // duty cycle 25% // General Timer/Counter Control Register GTCCR=0x50; // PWMBenable(OCR1B,C)、ToggleOC1B (PB4,pin3を出力指定)、カウント開始 OCR0A =64; TCCR0A=0x02; // ClearTimer on Compare Match(CTC) mode TCCR0B=0x02; // Clock Select (clkio/8, from prescaler) TIMSK=_BV(OCIE0A); // Timer Interrupt Mask Register PCMSK=0; // その他の割り込みoff MCUCR |= 2; // INT0 立ち下がりトリガー GIMSK =(1<<INT0); // INT0 割り込みON sei(); // CPU割り込みON stop=1; while (1) { for(i=0; i<10000; i++); } } #define modulate 80 uint8_t cnt=0, n=16,length=modulate,m=128, k=0; ISR(TIMER0_COMPA_vect){ // 32μ秒で割り込む if(--length==0 && stop){ length=modulate; if(m++==255) { stop=0; m=0; } } if(stop) { OCR1A = wave[(cnt+m)%256]; OCR1B = wave[cnt]; cnt+=n; } } ISR(INT0_vect){ // 外部スイッチ(INT0) cli(); stop=1; length=modulate; cnt=0; m=128; sei(); } |
1 2 3 割り込みを使う 4 正弦波表 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 変調周期の設定 42 mは最大値の位置 43 44 タイマー0からの割り込み 45 半周期で止まるようにする 46 47 最小になった時に停止 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |