UMEHOSHI ITA TOP PAGE COMPUTER SHIEN LAB
[UMEHOSHI ITA]の制御で使っているIC「PIC32MX270F256B-I/SO」のフラッシュメモリには、テスト用プログラムが書き込まれいています。
以降では、このプログラムを「テスト・ウメ・フラッシュ」と呼ぶことにして解説します。
また、「テスト・ウメ・フラッシュ」を利用したユーザー用のプログラムを
「ウメ・エディットプログラム」と呼ぶことにします。
「ウメ・エディットプログラム」の開発では「umehoshiEditツール」が必要で、
その取得や最初の操作情報は、こちらを参照してください。
(「PICKit3などの書き込みツール」をお持ちの方で、「テスト・ウメ・フラッシュ」を利用しないで、
「MPLAB X IDE」の開発環境ですべてをプログラミングする場合の情報ではありません。)
「テスト・ウメ・フラッシュ」をどのように利用して、「ウメ・エディットプログラム」を
作るかの解説で、「umehoshiEditツール」の使用例を示しています。
各サンプルは、このWebページ上でドラック&コピーして、貼り付けしてご利用ください。
各種確認プログラム | 左記に必要な部品の追加例 |
---|---|
とくに必要ありません。(D1のLEDはあるとよい) | |
PWM対応の部品追加例 | |
ADC 対応の部品追加例 | |
BEEP SWITCH 対応の部品追加例 | |
Reset SW, Type-A, CN2 部品追加例 | |
U20,D4,D5,NPN, D3 部品追加例 | |
CN11,CN-12 ,Bluetoothなどの基板 の部品追加例 | |
CN11,CN-12 部品追加例 | |
U19 部品追加例 | |
U17にRN4020の部品を追加する例 |
ここでは上記の赤マルの圧電スピーカを鳴らします。(ここで使うの部品追加例)
「テスト・ウメ・フラッシュ」では、「マイクロコントローラ (PIC32MX270F256B」内の「CORE TIMER」の周期を利用して、
ビープ音を鳴らすプログラムが組み込まれています。
利用する場合は「_set_beep_code(byteコード)」の呼び出しで行います。
このコードは、キューに登録されて、これを呼び出したプログラムの流れではなく、「CORE TIMER」の割込み処理で音を鳴らします。
音は引数のbyteコードの上位4bitの1と0を、それぞれ長音と短音に対応させて鳴らします。
これを使うと、モールス信号で情報知らせるようなアプリを簡単に作れるでしょう。
以下で、「110」「1011」の情報をループで生成するコード例を示します。
#include <xc.h>//beep_code.c #include <stdlib.h> #include "common.h" #define AdrStart 0x80005000 //下記start関数の起動アドレス __attribute__((address( AdrStart ))) void start (void); void start() { //_set_switching_period( 90 );//短音の間隔 _clear_beep_code(); // 登録を先頭に初期化 _set_beep_code((uint8_t)0b11000011);//最初の音パターンの登録 _set_beep_code((uint8_t)0b10110100);// 次の音パターンの登録 } __attribute__((address( 0x80007000 ))) void clear (void); void clear() { _clear_beep_code(); }
上記の実行でブザーを付けていれば、「110」「1011」の
コードに対応する音として
次のように聞こえるはずです。
ツー・ツー・ト ツー・ト・ツー・ツー
ツーが長音、トが短音です。
そして、長音の長さは短音の3倍で、コード内の音と音の間隔は、短音と同じです。
また一つのパターンの音が終わって、次のパターンの音が始まるまで、「短音の3倍」の間隔があります。
またデフォルトでは、登録したパターンの音生成が終わると、少し待ってから再び始まるループ再生になっています。
最初の音パターンの登録で0b11000011を指定していますが、下位3ビットが生成音のビット数です。
これは、上位ビットの3個のbitを使う意味です。
この 110 で、ツー・ツー・トになります。
_set_beep_codeで指定する1byte引数は、[PTTERN:4bit][CB:1bit][LN:3bit]の構造のパターンになってます。
次の音パターンの登録の0b10110100は、下位3ビットが100より
4個のbitで、それが1011なので
ツー・ト・ツー・ツーになります。
つまり1回の登録は、4bitの音パターンを登録することができます。これで16進の音パターンの登録ができます。
(元々はデバック用に作成したものです。
2回使えば1byte分の情報を音で知ることができます。
set_beep_codeによる最大登録数は42個までできます。)
「CORE TIMER」によるビープ処理は、所定の記憶域のコードで「ブザーON・OFF処理」を行うことで実現しています。
制御チップ内の「CORE Timer」割り込みは、デフォルトで動作しており、440Hz(0.00113635秒周期)でブザーの周期を制御しています。
上記の「_set_switching_period( 90 );」は短音の間隔を 90 に指定するコードです。
(デフォルト値が90なので、上記ではコメントにしています。)
Timer割り込みでは、この値までカウントしたタイミングで音や無音の長さを制御しています。
デフォルトの短音の間隔の90は、(割り込み周期の0.00113635秒)*90=約0.1秒の時間です。
さて、モールス信号のように4ビットを超える場合は[CB:1bit]を1にすることで、連続パターンを指定できます。
例えば、訂正音は「ト・ト・ト・ト・ト・ト・ト・ト」の短音8で、数字の1は「ト・ツー・ツー・ツー・ツー」ですが、
そのコードは次のようになります。
#include <xc.h> #include <stdlib.h> #include "common.h" #define AdrStart 0x80005000 //下記start関数の起動アドレス __attribute__((address( AdrStart ))) void start (void); void start() { //_set_switching_period( 90 );//短音の間隔 _clear_beep_code(); // 登録を先頭に初期化 _set_beep_code((uint8_t)0b00001100);// パターンを次に続ける指定 _set_beep_code((uint8_t)0b00000100);// 次の音パターンの登録(2行で、「ト・ト・ト・ト・ト・ト・ト・ト」の短音を登録) _set_beep_code((uint8_t)0b01111100); _set_beep_code((uint8_t)0b10000001);//前の1行と合わせて[・−−−−]を登録 // _UM_PTR_GOTO_BEEP = NULL;// ループをしない設定 }
なお、上記コードの最後の「_UM_PTR_GOTO_BEEP」の記憶をNULLにすると、ループ再生が無くなります。
「_UM_PTR_GOTO_BEEP」には、set_beep_code関数で登録されたコードの音再生がすべて終わった時に進むべきアドレスを記憶しており、
デフォルトでset_beep_code関数で登録する配列の先頭アドレスが記憶されています。
次のコードで、「ドレミファソラシド」までを繰り返し鳴らすことができます。
#include <xc.h> #include <stdlib.h> #include "common.h" #define AdrStart 0x80005000 //下記start関数の起動アドレス __attribute__((address( AdrStart ))) void start (void); void start() { int i=0; _set_switching_period( 125 );//テンポ(標準値) _set_beep_sound_node(i++,40,4,0);//ド(最初のこの呼び出しで、内部が初期化)〇 _set_beep_sound_node(i++,42,4,0);//レ〇 _set_beep_sound_node(i++,44,4,0);//ミ〇 _set_beep_sound_node(i++,45,4,0);//ファ〇 _set_beep_sound_node(i++,47,4,0);//ソ〇 _set_beep_sound_node(i++,49,4,0);//ラ〇 _set_beep_sound_node(i++,51,4,0);//シ〇 _set_beep_sound_node(i++,52,8,4);//ド〇 T1CONSET =0x8000; // Start timer1(この実行で、演奏がスタートします。) // _UM_PTR_GOTO_BEEP = NULL;// ループをしない設定 }
set_beep_sound_nodeの引数は、『記憶位置の添え字、音色データ、音の長さ、音の後の無音の長さ』になっています。
音を出す振動(音色)は、「CORE TIMER 割込み処理」で行われ、引数はピアノ鍵盤番号です。各鍵盤番号は次のようになっています。
引用元
鍵盤番号 音階 周波数Hz 鍵盤番号 音階 周波数Hz 鍵盤番号 音階 周波数Hz 鍵盤番号 音階 周波数Hz 1 ラ(A0) 27.500 25 ラ2(A2) 110.000 49 ラ4(A4) 440.000 73 ラ6(A6) 1760.000 2 ラ0(A#0) 29.135 26 ラ#2(A#2) 116.541 50 ラ#4(A#4) 466.164 74 ラ#6(A#6) 1864.655 3 シ0(B0) 30.868 27 シ2(B2) 123.471 51 シ4(B4) 493.883 75 シ6(B6) 1975.533 4 ド1(C1) 32.703 28 ド3(C3) 130.813 52 ド5(C5) 523.251 76 ド7(C7) 2093.005 5 ド1#(C#1) 34.648 29 ド#3(C#3) 138.591 53 ド#5(C#5) 554.365 77 ド#7(C#7) 2217.461 6 レ1(D1) 36.708 30 レ3(D3) 146.832 54 レ5(D5) 587.330 78 レ7(D7) 2349.318 7 レ1#(D#1) 38.891 31 レ#3(D#3) 155.563 55 レ#5(D#5) 622.254 79 レ#7(D#7) 2489.016 8 ミ1(E1) 41.203 32 ミ3(E3) 164.814 56 ミ5(E5) 659.255 80 ミ7(E7) 2637.020 9 ファ1(F1) 43.654 33 ファ3(F3) 174.614 57 ファ5(F5) 698.456 81 ファ7(F7) 2793.826 10 ファ1#(F#1) 46.249 34 ファ#3(F#3) 184.997 58 ファ#5(F#5) 739.989 82 ファ#7(F#7) 2959.955 11 ソ1(G1) 48.999 35 ソ3(G3) 195.998 59 ソ5(G5) 783.991 83 ソ7(G7) 3135.963 12 ソ1#(G#1) 51.913 36 ソ#3(G#3) 207.652 60 ソ#5(G#5) 830.609 84 ソ#7(G#7) 3322.438 13 ラ1(A1) 55.000 37 ラ3(A3) 220.000 61 ラ5(A5) 880.000 85 ラ7(A7) 3520.000 14 ラ#1(A#1) 58.270 38 ラ#3(A#3) 233.082 62 ラ#5(A#5) 932.328 86 ラ#7(A#7) 3729.310 15 シ1(B1) 61.735 39 シ3(B3) 246.942 63 シ5(B5) 987.767 87 シ7(B7) 3951.066 16 ド2(C2) 65.406 40 ド4(C4) 261.626 64 ド6(C6) 1046.502 88 ド8(C8) 4186.009 17 ド#2(C#2) 69.296 41 ド#4(C#4) 277.183 65 ド#6(C#6) 1108.731 18 レ2(D2) 73.416 42 レ4(D4) 293.665 66 レ6(D6) 1174.659 19 レ#2(D#2) 77.782 43 レ#4(D#4) 311.127 67 レ#6(D#6) 1244.508 20 ミ2(E2) 82.407 44 ミ4(E4) 329.628 68 ミ6(E6) 1318.510 21 ファ2(F2) 87.307 45 ファ4(F4) 349.228 69 ファ6(F6) 1396.913 22 ファ#2(F#2) 92.499 46 ファ#4(F#4) 369.994 70 ファ#6(F#6) 1479.978 23 ソ2(G2) 97.999 47 ソ4(G4) 391.995 71 ソ6(G6) 1567.982 24 ソ#2(G#2) 103.826 48 ソ#4(G#4) 415.305 72 ソ#6(G#6) 1661.219
また、一つの音長さや無音間隔は、別途変数を参照してON/OFFの制御が行われます。
第3、4の引数の値は、32分音符も長さを1とした値です。
2なら16分音符、4なら8分音符、8なら4分音符(0.5秒)、16が2分音符、32が全音符になります。
4ビットコード音出力の「CORE TIMER 割込み処理」と違って、音符のON・OFFは「TIMER1 割込み処理」で行われます。
「TIMER1 割込み処理」はデフォルトでスタートしていないので「」で起動させる必要があります。
デフォルトのTimer1は、0.5mSで割り込みが発生するようになっています。
_set_switching_period関数で全体のテンポを変更することができます。
上記の125の設定が標準値です。この125の値のカウントで区切られる間隔が32分音符です。
この間隔(32分音符)は、0.5mS ×:125=0.0625秒です。
さて、自身で用意した音データ記憶域を利用することができます。
それは、記憶域を[_UM_PTR_BEEP_AREA] に設定することで可能です。
(ループの移動先[_UM_PTR_GOTO_BEEP]の設定も必要です。)以下に例を示します。
#include <xc.h> #include <stdlib.h> #include "common.h" #define AdrStart 0x80005000 //下記start関数の起動アドレス __attribute__((address( AdrStart ))) void start (void); void start() { static uint8_t area[] = { 28,4,0, 30,4,0, 32,4,0, 33,4,0, 35,4,0, 37,4,0, 39,4,0, 40,8,8, 40,4,0, 39,4,0, 37,4,0, 35,4,0, 33,4,0, 32,4,0, 30,4,0, 28,8,16, 28,4,0, 30,4,0, 32,4,0, 33,4,0, 35,4,0, 37,4,0, 39,4,0, 40,4,0, 42,4,0, 44,4,0, 45,4,0, 47,4,0, 49,4,0, 51,4,0, 52,4,0, 54,4,0, 56,4,0, 57,4,0, 59,4,0, 61,4,0, 63,4,0, 64,8,8, 0 //最後は終わりのマーク }; _set_switching_period( 125 );//テンポ(標準値) _UM_PTR_BEEP_AREA = area; _UM_PTR_GOTO_BEEP = area;// ループをする指定(しない場合はNULLを設定) _set_beep_sound_node(0, 27,4,0);//先頭要素の設定で内部初期化を行う T1CONSET =0x8000; // Start timer1 }
以下の関数群において、bが1で実行すると、cの16進の音が登録されて、そのパターンの音が繰り返しで鳴り始めます。 音のパターンはcの値の16進数で1が長音、0が単音で4つの音を出します。 _debug_hex4が4bit用、_debug_hex8が8ビット用・・・です。 第1引数のnの指定範囲は0から15です。その番号の音が既に鳴っている場合は何も何もせず戻ります。 (_debug_hex4〜_debug_hex32のそれぞれでn番号の音の登録が可能です) _debug_hex4(n,c,b) _debug_hex8(n,c,b) _debug_hex16(n,c,b) _debug_hex32(n,c,b)
音が登録されるか、既に鳴っている時の戻り値が1になります。それを利用して 複数の箇所で使うことで、どちらのコードが先に行われるか判断でき、その例を以下に示します。 下記は、Aの位置を通過した時点で、0000のパターンで音をスタートさせて、 その後に、Bの位置に来た時点で、1111のパターンの音を追加させる場合の例です。 int bA = 0; int bB = 0; とグローバル変数を用意して、 Aの位置で、bA=_debug_hex4(1,0b0011, 1 ); と書いて ・・・・・・ Bの位置に、bB=_debug_hex4(2,0b0101, bA ); と書きます。 プログラムがAの位置を通過していれば、・・― ― のパターンで音がします。 その後で、Bの位置を通過すれば、・・― ― ・―・― のパターンの音が追加して鳴ります。 Aの実行でbAが1になっていない時は、Bの位置を通過しても音が登録されません。
2回通過しているかの判定であれば次のような書き方をします。 int bT0=0,bT1=0; //グローバルで用意します。 判定箇所で、次を書きます。 bT1=_debug_hex4(1,0b0001, bT0 ); // 【C】 bT0=_debug_hex4(0,0b0000, 1 ); // 【D】 【C】、【D】を通過した時、bT0が0なので【C】で音は鳴らずに【D】の音が出てbT0が1に変わります。 再度【C】、【D】を通過した時、bT0が1なので【C】で音が追加登録されてなり始めます。
次の関数は、bが1であれば、この関数がc回通過した時点で、nのパターン(16進)音が出ます。 (nの指定範囲は0から15です) 既に鳴っている場合は、何もせずに1で戻ります。 なお、 音が登録、または鳴っている状態で1、鳴っていなければ0を返します。 _debug_count(n,c,b) 例えば、 _debug_count(5,10,1); と実行させれば、ここを10回実行した時点で、5に対応する・―・―のパターンで鳴りだします。 同じパターンのnの引数で、複数の箇所で使った場合、それぞれの箇所の通過総数がcに達した時点で鳴りだします。 異なるnで使った場合は、それぞれのcの回数だけ実行した時点で、それぞれのnのパターン音で鳴ります。 その場合、通過順で音のパターンが登録され、その順番で音が鳴るので、どちらが先に通過したか判断できます。
#include <xc.h>// beep_debug.c #include <stdlib.h> #include "common.h" int t3=0; void timer()//「割り込みで目的のプログラム行うため処理: 0.00005秒ごとに呼び出される。」 { int b = _debug_count(4 ,300000 , t3);//t3が1であれば、300000回通過したら4のコード音 t3 = _debug_count(3,100000,1);//100000回通過したら3のコード音で、1の戻り値 if(b) { IEC0bits.T4IE = 0;// Timer4 Disable(割込み不許可) T4CONbits.ON = 0;// timer割込みOFF _send_string("Timer STOP\n"); _clear_beep_code();//通知音がクリア } } void restart(){ _HANDLES[_IDX_TIMER_4_FUNC] = timer;//デフォルトで0.00005秒ごとに呼び出しに登録 IEC0bits.T4IE = 1;// Timer4 Enable(割込み許可) T4CONbits.ON = 1;// timer割込みオン _debug_hex4(1,1,1); _send_string("Timer START\n"); } __attribute__((address( 0x80005000 ))) void setting(void); void setting() { _HANDLES[_IDX_INIT_SUB_FUNC] = restart;// リセットで実行する関数の登録 _clear_beep_code();//通知音がクリア _UME_CONFIG |= 1;//LED D2の変化をLED D1に連動させる _debug_hex4(0,0,1); restart(); }
音の再生は、割り込み内の[beep_code_switching()関数]で行っているが、 _clear_beep_code()の実行は、この関数に同期しないで内部ポインタをNULLにすることを行っている。 よって、音の再生割り込みタイミングによって、_clear_beep_code()が働ないタイミングが存在し、 場合によっては、NULLの参照が生じて、予想外のコードに変わることも考えられる。(そうならない考慮はしているが・・) よって、使う場所によっては、割込みとの排他制御が行う必要がある。 なお、_clear_beep_code()を同期させなかった理由は、同期させると、ブザー間隔のタイミングでウェイトがかかるためです。