UMEHOSHI ITA TOP PAGE    COMPUTER SHIEN LAB

UMEHOSHI IT (my_beep.cとmy_beep.h、debug.c)

my_beep.cのソース

_RB5に繋がる圧電ブザー(基板シルクSP)を鳴らす処理です。
_RB5はD2のLEDや[D4,D5]の赤外線LEDをドライブするトランジスタに繋がっているので、これらを取り付けていると 連動して動作します。
音の発振はデフォルトのコアタイマの割り込み周期を利用してON/OFFの制御します。
その関数が「base_beep()」でデフォルトのコアタイマ割り込み関数「core_timer_sub_1:my_sys.c」で呼び出しています。
また、コアタイマ割り込み関数では、beep_code_switching()関数も呼び出されて、音を鳴らすコードの切り替えを行っています。


それ以外に、beep_cycle_switching()も定義して、こちらは周波数やテンポを
コアタイマの割り込み初期設定は、 main()関数内のループ直前で呼ばれるinit_interrupt関数内のhandlers[_IDX_INIT_CORE_TIMER]();マクロの実行で行われます。
つまり、handlers[_IDX_INIT_CORE_TIMER]を変更することで初期設定を変更することができます。
そして、handlers[_IDX_INIT_CORE_TIMER]の初期値は、init_core_timer_1 関数(my_sys.c)になっています。
このinit_core_timer_1 関数の設定処理で、コアタイマを動作させて、割り込みが許可しています。
割り込みが許可されると、コア割り込みでmy_sys.c内のhandlers[_IDX_CORE_TIMER_FUNC]();のマクロが実行されます。
このhandlers[_IDX_CORE_TIMER_FUNC]記憶内容は、デフォルトが core_timer_sub_1関数(my_sys.c)になっています。


init_core_timer_1 関数の設定処理では、「CPUレジスタCP0」 なお、システム ソフトウェアとCPU の間でステータス情報と制御情報を交換するために、 コプロセッサ0レジスタ(CP0と呼ばれます)を操作します。
そして、コアタイマの操作もこの特殊なレジスタのCP0を介して行われます。
コアタイマに関連するのは「CP0 レジスタ9」のCount レジスタと 「CP0 レジスタ11」のCompare レジスタです。
まずCountレジスタはタイマとして機能し、システムクロック(SYSCLK) の2 サイクル ごと(1/40e6*2秒)にインクリメントします。
そして、CountレジスタとCompareレジスタ値に一致した時、割り込み信号をアサートします。
またCompare レジスタを設定すると、保留中のタイマ割り込みがクリアされ、 先にCountレジスタを設定すべきです。
これらレジスタの設定は、 core_timer_sub_1関数の中で次のようにマクロで行われます。

    _CP0_SET_COUNT(_UM_CP0_SET_COUNT);   
    _CP0_SET_COMPARE(_UM_CP0_SET_COMPARE);

ここで、_UM_CP0_SET_COUNTマクロ変数は0、_UM_CP0_SET_COMPAREマクロ変数には22727uが my_sys.cのinit_main()内init_handle_area()関数呼び出しでデフォルトの設定が行われます。
この設定後、Compare レジスタの0がCompare レジスタに達するまでが音周期の1/2になります。
つまり、1/((1/40e6)*2*2*22727)=440.0052800633608Hzの周波数の発振音です。
そして、_UM_CP0_SET_COUNTと、_UM_CP0_SET_COMPAREマクロ変数は、代入するだけで自由に変更できます。
それにより「ウメ・エディットプログラム」で自由に音色(周波数)を変更できます。(他のコア割り込みすべてに影響します)
通常は、_UM_CP0_SET_COMPAREマクロ変数の変更だけを行うのがよいでしょう。

このソースは、大きく4つ分けることができます。「//===」の区切りで分かれます。
先頭の部分は、コアタイマ割り込み関数から呼び出される音生成のbase_beep()と単発の音を生成する set_beep_period(int period)および、関連変数です。

次のブロックは、音を鳴らすタイミグを管理する記憶域と、それを管理する各種変数と関数定義の部分です。
この記憶域先頭は「ptr_start_beep」で、デフォルトでは、_UM_PTR_BEEP_AREAと_UM_PTR_GOTO_BEEPで参照でします。

次のブロックは、beep_cycle_switching関数と、関連の変数、関数の定義の部分です。
これは、コアタイマの音色でTimer1のテンポで鳴らす音の登録関数と音生成関数定義用です。

次のブロックは、beep_code_switching()関数と、関連の変数、関数の定義の部分です。
これはコアタイマだけで短音、長音の音の登録関数と音生成関数定義用です。

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
/*
 * ウメ・エディット・プログラム ビープ音発生ルーチン
 *  以下を実装
 *
 *   beep_code_switching関数は、音長と短音でコードを音にする。(モールス信号へ応用可)
 *      この関数はデフォルトコアタイマで呼び出される
 
 *  beep_cycle_switching()関数は周波数、ビープ音ON・OFF(簡単メロディ演奏に使える。)
 *      この関数はデフォルトTime1(timer1_umeFunc1_1関数)から呼び出される
 */

#include <xc.h>
#include <stdbool.h>//true,false
#include "common.h"

/* =============================================================================
 * ブザーON・OFFの基本となる制御用変数と、ブザー音の周期設定関連
 */
static bool beep_on = false; // ブザーの振動のゲートのon / off 状態
volatile unsigned int beep_period_down_count __attribute__((section("sfrs")));
static bool code_switching_enabled = true;//コードのタイミング制御を有効にする
// code登録時に、処理をスキップさせる試み(これがfalse時は音制御をスキップ)

// 各種ハードウエアのタイマー割込み処理で使うことを想定したブザー音発振の呼び出し関数
// 次の変数を利用してタイミングを作っている。
//int base_beep_period = 1;//ブザーの周波数を決める周期用パラメタ(分周可能にした))
void base_beep()
{
    if( beep_period_down_count > 0){ 
        if(beep_period_down_count-- <= 1){// 1から0の変化時にBeepをOFF
            code_switching_enabled = true;//他のswiting制御が使えるように有効へ戻す。
            beep_on = false;
        }
    }
    if(beep_on && ( _UME_CONFIG & 0x001 ) != 0 ) {
        _RB15 = ! _RB15;// D1    
    }
    if(beep_on && (_UME_CONFIG & 0x0002 ) != 0 ) {
        _RB5 = ! _RB5;// 出力を反転(D2や圧電ブザー)
    }
}

// 現在のコアタイマ周期を利用して、単発的な音を鳴らす関数
// 実行すると、引数で指定した期間だけ音を鳴らしてて、その後で止まります。
// 引数に-1を指定すると、期間無しで永続的に鳴らします。
// 鳴っている途中で変更することもでき、期間を変更できます。(0の指定で止まります)
void set_beep_period(int period){
    beep_period_down_count = period;
    if(period == 0){
        code_switching_enabled = true;// 他のswiting制御が使えるように有効へ戻す。
        beep_on = false;// ブザー停止
    } else {
        code_switching_enabled = false;// 他のswiting制御を無効にする。
        beep_on = true;// ブザー発音
    }
}
// -----上記までが「 ブザーON・OFFの基本となる制御用変数と、ブザー音の周期設定関連」


/* =============================================================================
 * 音を鳴らすタイミグを管理する記憶と、それを管理する各種変数と関数定義
*/
// 下記情報の設定で、beep_cycle_switching()関数やbeep_code_switching関数の音を制御
uint8_t my_beep_area[3*100];// __attribute__((aligned(32)));
// 上記先頭ポインタは、_UM_PTR_BEEP_AREAと_UM_PTR_GOTO_BEEPへパワーONに記憶される。

uint8_t * ptr_start_beep;//ユーザ記憶域変更用のポインタ
// ● beep_cycle_switching関数で使う場合は、各uint8_tが、次のデータの並びになる。
// 『[ビープ周期(鍵盤番号)][beep音ONの期間][beep音ONの期間][beep音ONの期間]』の連続
//  なお、beep_code_switchingの場合は、後述の4bit音(短音か長音)のコードが並ぶ
//  デフォルトのビープ周波数はcoreタイマで、次の指定にする。
//  CP0_SET_COMPARE = (1/hz)/(1/40e6 * 2)/2
//  これは、49の鍵盤番号	(440.000Hz)「ラA4」を基準にして、考えて次をの設定する。
//  CP0_SET_COMPARE = (1/440)/(1/40e6 * 2)/2=22727u
// ● beep_code_switching関数で使う場合は、各uint8_tの1byteが、制御指定データになる。

static uint8_t *ptr_current_beep=NULL;//上記ptr_start_beepが指す記憶内の再生位置
//(NULLで音再生が停止、ptr_start_beepの設定で音生成が始まり、現在の音生成位置を記憶)
//この値はset_beep_sound_nodeまたはset_beep_code登録関数により先頭要素の登録で、
// 設定されます。 その後、音生成とともに指し示す位置が変更され、終わるとNULLに戻る.                    

// 上記のptr_start_beepを切り替えるタイミング指定用変(リズムのテンポ管理)
static  switching_period = 90;//ブザーON/OFFの 切り替えを決める周期用パラメタ
    // (beep_cycle_switching()関数と beep_code_switching()関数が 兼用)
    //  beep_cycle_switching()関数の場合は、Time1の割り込み間隔に依存し、
    //  32分音符=0.0625秒=62.5msで、この周期指定は、62.5/0.5=125になる。
    //  なお初期値の90は、 beep_code_switching()用で、これを呼び出すコアタイマの
    //   周期 × 90 の時間が短音の長さになる。(長音はその3倍になる)

// 上記のswitching_period(切り替え間隔)を変更するグローバル関数
void set_switching_period(int period){
    switching_period=period;//(リズムのテンポ管理)
}

//  beep_onのタイミング用で、beep_cycle_switching()やbeep_code_switching()兼用
//      の関数で、それぞれのタイマ割り込みサイクルで呼ばれるサブ関数
// 内部countが0であれば、on_offのブザー状態をセットします。
//  内部countが引数のperiodに達するると、設定期間が終わりのtrueを返します。
//  (内部countが0で、periodが0でないon_offのブザー設定呼び出しは、falseを返す。)
//  (つまり、periodが0の設定時は、trueを返す。)
static bool set_beep_switch(bool on_off, int period){
    static int count = 0;
    if(count == 0 || period == 0) { //初期設定
        beep_on = on_off;// ブザーONまたはOFFの切り替えを設定
        if( period == 0) return true;
        count = 1;
        return false; 
    } else if( count >= period ){ //periodの期間に達したタイミングである!
        count = 0; 
        return true;
    }
    count++;
    return false;
}

// 音を登録し再生する関数群を停止して、関連変数を初期化するの予約関数と変数定義
void clear_beep_code_actually();//実際にクリアする関数
bool clear_beep_code_flag __attribute__((section("sfrs")));
void clear_beep_code(){
    if(ptr_current_beep == NULL){// 再生が行われていない場合
        clear_beep_code_actually();//直接に初期化する。
    } else {
        // 既にに音の再生が行われている場合、それを止める処理なので、
        // 割り込み内 clear_beep_code_actually()で行うように指示する。、
        clear_beep_code_flag = true;
        // 実際の初期化処理は、 割り込みで行うので遅延が生じる
        // この関数の直後の音の登録を可能にするため、すこし待つ
        core_wait(200);//(設定によって足りない場合あり)
    }
}

/* =============================================================================
 * beep_cycle_switching関数と、関連の変数、関数の定義
 * uint8_t * ptr_start_beepは、次のデータの並びになる。
 * 『[ビープ周期(鍵盤番号)][beep音ONの期間][beep音ONの期間][beep音ONの期間]』の連続
 */

// [ビープ周期(鍵盤番号)]に対するCP0のCOMPAREの設定値の表テーブル
// 周波数(Hz)=1/((1/40e6)*2*2*piano_key_board[i])
// 例:49 A4 ラ 周波数(Hz)=1/((1/40e6)*2*2*22727)=440.0052800633608
#define ADJ (0) // 調整用の値(0の値で、本来の周波数を作る割り込みになる)
uint32_t piano_key_board[]={
0u, // データ無しのマーク
363636u +ADJ, // 1 A0 ラ 〇
343230u +ADJ, // 2 A#0  〇
323960u +ADJ, // 3 B0 シ 〇
305782u +ADJ, // 4 C1 ド 〇
288617u +ADJ, // 5 C#1  〇
272420u +ADJ, // 6 D1 レ 〇
257129u +ADJ, // 7 D#1  〇
242701u +ADJ, // 8 E1 ミ 〇
229074u +ADJ, // 9 F1 ファ 〇
216221u +ADJ, // 10 F#1  〇
204086u +ADJ, // 11 G1 ソ 〇
192630u +ADJ, // 12 G#1  〇
181818u +ADJ, // 13 A1 ラ 〇
171615u +ADJ, // 14 A#1  〇
161983u +ADJ, // 15 B1 シ 〇
152891u +ADJ, // 16 C2 ド 〇
144308u +ADJ, // 17 C#2  〇
136210u +ADJ, // 18 D2 レ 〇
128564u +ADJ, // 19 D#2  〇
121349u +ADJ, // 20 E2 ミ 〇
114538u +ADJ, // 21 F2 ファ 〇
108109u +ADJ, // 22 F#2  〇
102042u +ADJ, // 23 G2 ソ 〇
96315u +ADJ, // 24 G#2  〇
90909u +ADJ, // 25 A2 ラ 〇
85807u +ADJ, // 26 A#2  〇
80991u +ADJ, // 27 B2 シ 〇
76445u +ADJ, // 28 C3 ド 〇
72155u +ADJ, // 29 C#3  〇
68105u +ADJ, // 30 D3 レ 〇
64283u +ADJ, // 31 D#3  〇
60674u +ADJ, // 32 E3 ミ 〇
57269u +ADJ, // 33 F3 ファ 〇
54055u +ADJ, // 34 F#3  〇
51021u +ADJ, // 35 G3 ソ 〇
48157u +ADJ, // 36 G#3  〇
45455u +ADJ, // 37 A3 ラ 〇
42903u +ADJ, // 38 A#3  〇
40495u +ADJ, // 39 B3 シ 〇
38223u +ADJ, // 40 C4 ド 〇
36077u +ADJ, // 41 C#4  〇
34052u +ADJ, // 42 D4 レ 〇
32141u +ADJ, // 43 D#4  〇
30337u +ADJ, // 44 E4 ミ 〇
28635u +ADJ, // 45 F ファ 〇
27027u +ADJ, // 46 F#4  〇
25511u +ADJ, // 47 G4 ソ 〇
24079u +ADJ, // 48 G#4  〇
22727u +ADJ, // 49 A4 ラ ●基準
21452u +ADJ, // 50 A#4  〇
20248u +ADJ, // 51 B4 シ 〇
19111u +ADJ, // 52 C5 ド 〇
18039u +ADJ, // 53 C#5  〇
17026u +ADJ, // 54 D5 レ 〇
16071u +ADJ, // 55 D#5  〇
15169u +ADJ, // 56 E5 ミ 〇
14317u +ADJ, // 57 F5 ファ 〇
13514u +ADJ, // 58 F#5  〇
12755u +ADJ, // 59 G5 ソ 〇
12039u +ADJ, // 60 G#5  〇
11364u +ADJ, // 61 A5 ラ 〇
10726u +ADJ, // 62 A#5  〇
10124u +ADJ, // 63 B5 シ 〇
9556u +ADJ, // 64 C6 ド 〇
9019u +ADJ, // 65 C#6  〇
8513u +ADJ, // 66 D6 レ 〇
8035u +ADJ, // 67 D#6  〇
7584u +ADJ, // 68 E6 ミ 〇
7159u +ADJ, // 69 F6 ファ 〇
6757u +ADJ, // 70 F#6  〇
6378u +ADJ, // 71 G6 ソ 〇
6020u +ADJ, // 72 G#6  〇
5682u +ADJ, // 73 A6 ラ 〇
5363u +ADJ, // 74 A#6  〇
5062u +ADJ, // 75 B6 シ 〇
4778u +ADJ, // 76 C7 ド 〇
4510u +ADJ, // 77 C#7  〇
4257u +ADJ, // 78 D7 レ 〇
4018u +ADJ, // 79 D#7  〇
3792u +ADJ, // 80 E7 ミ 〇
3579u +ADJ, // 81 F7 ファ 〇
3378u +ADJ, // 82 F#7  〇
3189u +ADJ, // 83 G7 ソ 〇
3010u +ADJ, // 84 G#7  〇
2841u +ADJ, // 85 A7 ラ 〇
2681u +ADJ, // 86 A#7  〇
2531u +ADJ, // 87 B7 シ 〇
2389u +ADJ, // 88 C8 ド 〇
}; 

// 音色の音符でサウンドの登録する関数 
void set_beep_sound_node(int idx,//登録位置指定用添え字(フォルトで?99の範囲)
        uint8_t keyNo,uint8_t onPeriod,uint8_t offPeriod){
    //  keyNo ピアノの鍵盤の番号
    //  onPeriodとoffPeriodは、32分音符:0.0625秒を1とした指定
    // (2なら16分音符、4なら8分音符、8なら4分音符(0.5秒)、16が2分音符、32が全音符)
    //  Timer1の周期が0.5mS 周期、switching_period = 125として使う前提
    if( idx == 0 ) {
        ptr_start_beep = _UM_PTR_BEEP_AREA;
        ptr_current_beep = _UM_PTR_BEEP_AREA;//my_beep_area;// 起動を意味する。
    }
    ptr_start_beep[idx*3+0] = keyNo;// ピアノの鍵盤の番号に対応する添え字
    ptr_start_beep[idx*3+1] = onPeriod;
    ptr_start_beep[idx*3+2] = offPeriod;
}

// デフォルトのTimer1割り込みから呼ばれ、登録情報で音色と音符の制御を行う。
static int cycle_switching_timing_count = 0; //タイミング管理
static int cycle_switching_status  = 0;//状態管理
void beep_cycle_switching()
{
    if(ptr_current_beep == NULL || *ptr_current_beep == 0) return;//終了
    cycle_switching_timing_count++;
    if(cycle_switching_timing_count < switching_period){
        return;//音のスイッチ切り替えのタイミングでない。
    }
    cycle_switching_timing_count = 0;
    // 切り替えのタイミングである。
    
    if( cycle_switching_status == 0 ){ // ONにする処理?
         _UM_CP0_SET_COMPARE = piano_key_board[ptr_current_beep[0]];//周波数設定
         if(set_beep_switch(true, ptr_current_beep[1])){ //ONの長さに達したか?
             cycle_switching_status  = 1;
         }
    } else if( cycle_switching_status == 1 ){   // OFFににする処理
         if(ptr_current_beep[2] == 0 ||
                 set_beep_switch(false, ptr_current_beep[2])){//OFFの長さに達したか?
             ptr_current_beep += 3;
             cycle_switching_status  = 0;
             if( *ptr_current_beep == 0 && _UM_PTR_GOTO_BEEP != NULL){
                 ptr_current_beep = (uint8_t *)_UM_PTR_GOTO_BEEP;//次の登録バッファ
             }
         }
    }
}
// -----------------以上までが、beep_cycle_switching関数と、関連の変数、関数の定義


/* =============================================================================
 * 音長と短音で構成するコードの音を登録して鳴ら関数、変数群。(モールス信号の応用化)
 * ビープ音のパターンを所定の記憶域に記憶して、
 * ビープ音のパターは次の通り バイトの配列で指定する。
 * 上位4ビットの1が長音、0が短音、下位4ビットは[CB:1][LN:3]になっている。
 * [CBの1ビット]前のバイトに続く音の場合は1、前のバイトと音と離れる場合は0
 * [LNの3ビット]上位4ビットの音長を意味する1や0の有効なビット数
 * 例 Gのモールスコードであれば	「? ? -」で、次のビット列となる。 
 *                               11000011 
 * 上位4ビット「1100」、CBが「0」、LNが「011」を意味する。
 * なお、CBが「1」である時、これが続くバイトの範囲を繰り返す。
 * また、0b11110000にすると、長い区切り用の無音が登録
 */

// 4bitのコードの1と0をそれぞれ長音と単音で鳴らすコードの登録関数 
static int index_set_beep_code_pos = -1;// これが -1でない時に機能する.
void set_beep_code(uint8_t code){
    code_switching_enabled = false;
    if( index_set_beep_code_pos == -1 ) {
        //最初の登録でbeep_code_switching機能を有効にする
        index_set_beep_code_pos = 0;
    }
    if( ptr_current_beep == NULL ) {
        ptr_start_beep = _UM_PTR_BEEP_AREA;
        ptr_current_beep = _UM_PTR_BEEP_AREA;//my_beep_area;       
    }
    ptr_start_beep[index_set_beep_code_pos++] = code;
    ptr_start_beep[index_set_beep_code_pos] = 0;    
    code_switching_enabled = true;
}

// code の16bit情報で、上位ビットから1が長音、0が短音で16個の音を生成
void set_hex_beep(uint16_t code){
    set_beep_code( code >> 8 & 0x0f0 | 0x04 );
    set_beep_code( code >> 4 & 0x0f0 | 0x04 );
    set_beep_code( code & 0x0f0 | 0x04 );
    set_beep_code( code << 4 & 0x0f0 | 0x04 );
}

// beep_code_switching()の実装用サブ関数と関連変数定義
static uint8_t current_beep_code;// このデータで4ビットのスイッチングする。
static int current_beep_code_down_count=0;//[LN:3]の値で、0?7(0でコード出力終了)
static int current_beep_code_mask; //処理ビット抽出用マスク
static bool current_beep_code_switch()//beep_codeの音の再生、音生成終了でtrueを返す
{
    static int _change_down_count = 0;//長音なら3、単音なら1がセット

    if(! beep_on && current_beep_code_down_count <= 0) {
        _change_down_count = 0;
        return true;// コード出力終了
    } 
    if(! beep_on && _change_down_count <= 0){//長音なら3、単音なら1をセット
        if((current_beep_code & current_beep_code_mask) != 0){
            _change_down_count = 3;
        } else {
            _change_down_count = 1;
        }
        beep_on = true;//音をオン
        current_beep_code_mask >>=1;// 次のビットへ
        current_beep_code_down_count--;
        return false;
    }

    _change_down_count--;
    if(_change_down_count <= 0){
        beep_on = false;//音をオフ
    }
    return false;
}

// デファオルのコアタイマから呼び出され、登録情報から短音、長音の音を生成する関数
// switching_period の設定が基本的な音と音の間隔。
// これが90で、COREタイマ([ラ]のデフォルト値440Hz)をを使うと、1/440/2*90=約0.017秒
// これは(短音と同じの長さ)なお音長は短音の3倍の長さ
static int beep_code_switching_status  = 0;
void beep_code_switching()
{
    if( clear_beep_code_flag ){//音登録の再生情報のクリア指示があれば、それを実行.
        clear_beep_code_actually();
        clear_beep_code_flag = false;
        return;
    }
    if( code_switching_enabled == false) return;
    
    if(index_set_beep_code_pos == -1)return;//音が未登録
            
    static int _base_change_count = 0;// ON/OFF切り替えを待つタイミングカウンタ
    if(ptr_current_beep == NULL || *ptr_current_beep == 0) return;//終了
    _base_change_count++;
    if(_base_change_count < switching_period) return;
    _base_change_count = 0;
    
    // ここまで進んだ時点が音の切り替えタイミング(短音の間隔)
    // 切り替え周期に達したので、その切り替え処理
    if( beep_code_switching_status == 0 ){ //初期起動
        current_beep_code = *ptr_current_beep;
        current_beep_code_down_count = current_beep_code & 0x07;
        current_beep_code_mask = 0x080;
        beep_code_switching_status = 1;
    } else if(beep_code_switching_status  == 1){ //コード送出の待機 
        if(current_beep_code_switch()) {
            if((current_beep_code & 0x08) != 0) {
                current_beep_code = *++ptr_current_beep;
                current_beep_code_down_count = current_beep_code & 0x07;
                current_beep_code_mask = 0x080;
                beep_code_switching_status  = 1; // 連続音
                current_beep_code_switch();
            }
            else if(current_beep_code & 0x08 == 0){// 音の指定がゼロ
                current_beep_code = *++ptr_current_beep;
                beep_code_switching_status  = 3; // 区切り用の長い無音               
            }
            else beep_code_switching_status  = 2;
        }
    } else if(beep_code_switching_status  == 2){ //無音の間隔 
        if(set_beep_switch(false, 2)) {
            ++ptr_current_beep;
            if( * ptr_current_beep == 0){//次のコードがあるかチェック
                if( _UM_PTR_GOTO_BEEP != NULL){//次のコードがある。
                    ptr_current_beep = (uint8_t *) _UM_PTR_GOTO_BEEP;
                    beep_code_switching_status  = 3;
                    return;
                }
                ptr_current_beep = NULL;//送信終了(次のコードがない。)
            }
            beep_code_switching_status  = 0;
        }
    } else if(beep_code_switching_status  == 3){ //ループする直前の少し長い無音の間隔 
        if(set_beep_switch(false, 7)) beep_code_switching_status  = 0;
    } 
}
//----------------ここまで 音長と短音で構成するコードの音を登録して鳴ら関数、変数群


// 音を登録し再生する関数群を停止して、関連変数を初期化する(再び音登録、再生を可能へ)
void clear_beep_code_actually()
{
    ptr_current_beep == NULL;
    beep_on = false;//音の振動用スイッチングを止める
    
    if((_UME_CONFIG & 0x02) != 0){
        _RB5 = 0;//ブザー端子(LED2連動)をLOWにセット
        asm("nop");
    }

    //  beep_cycle_switching() 関連用.
    cycle_switching_timing_count=0;//set_beep_sound_node(i,c,s,n)利用するまで無効
    // これが、0の場合はbeep_cycle_switching()が機能しない。
    cycle_switching_status=0;
   
    // beep_code_switching()関連.
    index_set_beep_code_pos = -1;//set_beep_code(d)を使うまで機能が無効
    // これが、-1の場合はbeep_code_switching()が機能しない。
    // set_beep_codeの登録で、-1以外が設定される。
    beep_code_switching_status=0;
    
    // my_beep_area をクリアする。
    int i=0;
    for(i = 0; i < sizeof(my_beep_area); i++){
        my_beep_area[i] = 0;
    }
    
     void debug_beep_claer(); // debug_XXX 関連の記憶域初期化とエラー復帰
     debug_beep_claer();
    //特記事項: _UM_PTR_BEEP_AREAに自身で用意している記憶域を指定している場合、
    // その記憶域を、別途に初期化する必要がある。
}

my_beep.hのソース(debug.cの宣言を含む)

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
#ifndef _BEEP_H    /* Guard against multiple inclusion */
#define _BEEP_H

// my_beep.cの定義関連 ---------------------------------------------------------
#define _UME_CONF_ERR_NOTICE_BIT 0x0004 //エラー通知ONの_UME_CONFIG用ビット

void set_beep_period(int period);
void clear_beep_code();//音を止めて、debug_beep_claer()を含めた音関連の初期化

// debug function --------------------------------------------------------------
bool debug_count(int nn,int count_val, bool count_enable);
int debug_hex4(int nn, uint8_t data, bool enable);
int debug_hex8(int nn, uint8_t data, bool enable);
int debug_hex16(int nn, uint16_t data, bool enable);
int debug_hex32(int nn, uint32_t data, bool enable);
 bool debug_point(int nn, int count);
void error_notice_beep(); // エラーを音で知らせる関数(My_APP_Tasksなどで実行)
void debug_beep_claer(); //  デバック用に音を登録する記憶域やエラー情報の初期化

#endif /* _BEEP_H */

debug.cのソース

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*
 * ウメ・エディット・プログラム デバック関連
 * デバック用の音生成関数群(my_beep.cのset_switching_period(d)関数の利用で実現)
 */
#include <xc.h>
#include <stdbool.h>
#include "common.h"
#include "my_beep.h"

#define ERROR_INFO_ARRAY_SIZE 20 // debug_hexXで使うID番号記憶域の個数

// error_notice_beepで使うbeep識別番号
#define ERROR_BEEP_ID_NO (ERROR_INFO_ARRAY_SIZE-1) 

// エラーを知らせるビープ音発生関数(My_APP_Tasksなどで実行)
void error_notice_beep() {
    if ((_UME_CONFIG & _UME_CONF_ERR_NOTICE_BIT) == 0) {
        return;
    }
    extern uint16_t my_app_err; // my_app.c でのエラー情報
    if (my_app_err != 0) {
        debug_hex4(ERROR_BEEP_ID_NO, 0x01, 1);
        debug_hex16(ERROR_BEEP_ID_NO, my_app_err, 1);
    }

    extern uint16_t my_uart_err; // my_uart.c でのエラー情報
    if (my_uart_err != 0) {
        debug_hex4(ERROR_BEEP_ID_NO, 0x02, 1);
        debug_hex16(ERROR_BEEP_ID_NO, my_uart_err, 1);
    }

    extern uint16_t my_adc_err; // my_adc.c でのエラー情報
    if (my_adc_err != 0) {
        debug_hex4(ERROR_BEEP_ID_NO, 0x03, 1);
        debug_hex16(ERROR_BEEP_ID_NO, my_adc_err, 1);
    }
}

// 非公開デバック用  debug_countと違って共通のカウンタを使う
// 複数の箇所で使うと、共通のカウンタを使うので、どちらを先に行うか比較に使えます。
//(内部の共通カウンタが複数個所でカントアップするので使い方が難しい)
// 引数numberチェック番号(0から15)で対応する音の登録が終わっていなければ
// [内部の共通カウンタの計数]を行います。
// その計数値が、引数count_valと一致したらnn の16進値ビープ音を登録しします。
// [内部カウンタの計数]値が、count_valを超えるとエラーbeepを登録して、
// それ以降の処理は、無くなります。 count_valの指定は十分に検討して使う。
// count_val が1で初回と数える指定
bool debug_count_compare(int number, int count_val, bool count_enable) {
    static bool diff = false;
    if (diff) return false; // 予想が外れた引数を使うと、何もしない。

    static bool memo[16];

    if (memo[number]) return true; //既に鳴っている。
    if (!count_enable) return false;

    // まだ鳴っていない。
    static int count = 0;
    if (++count == count_val) {//[内部カウンタの計数] 
        set_beep_code(number << 4 & 0x0f0 | 0x04); // 登録。
        memo[number] = true;
        return true;
    } else if (count > count_val) {
        diff = true;
        set_beep_code(0b00001100);
        set_beep_code(0b00000100); // 短音8つ エラー。
        set_beep_code(number << 4 & 0x0f0 | 0x04); // 登録。 
        set_hex_beep((uint16_t) count);
        return true;
    }
    return false;
}

// numberのidで、count_valの回数通過したかを調べる関数
// count_val が1で初回と数える指定
// count_val が0でcount_enableをtrueにすると、各内部配列を初期化する。
// numberのチェック番号の音登録が終わっていれば、1を返す。
/* 使い方例
static bool b0,b1,b2; 
b0=debug_count(0, 100, true);//この命令を100回通過した時にb0がtrueで、0の4bit音登録
// ・・・・・・・・・・・・
b1=debug_count(1, 50, b0);//b0がtrueで、50回通過した時に、b1がtrueで、1の4bit音登録
// ・・・・・・・・・・・・
debug_count(2, 1, b1);//b1がtrueで、1回通過した時に、、2bitの4bitパターン音が登録
 */
// number は音登録の識別番号で、1から15が指定でき、鳴らせる音の16進パターンでもある。
// 音は、この関数の通過回数が、count_valになったら鳴る。
// 音が登録、または鳴っている状態で1、鳴っていなければ0を返します
static bool debug_count_memo[16];
static int debug_count_area[16] = {0};
bool debug_count(int number, int count_val, bool count_enable) {
    if (number >= 16) return false;
    if (count_val == 0 && count_enable) {
        debug_count_memo[number] = 0; //クリア
        debug_count_area[number] = 0;
        return false;
    }

    if (debug_count_memo[number]) return true; //既に鳴っている。
    if (!count_enable) return false;

    // まだ鳴っていない。
    if (++debug_count_area[number] >= count_val) {//[内部カウンタの計数] 
        set_beep_code(number << 4 & 0x0f0 | 0x04); // ビープ登録。
        debug_count_memo[number] = true;
        return true;
    }
    return false;
}

// enableが1の時、nnの識別番号で、dataの下位4ビットの音を登録します。
static bool debug_memo_hex4[ERROR_INFO_ARRAY_SIZE];
int debug_hex4(int nn, uint8_t data, bool enable) {
    if (nn >= ERROR_INFO_ARRAY_SIZE) return 0;
    if (!enable) return 0;
    if (debug_memo_hex4[nn]) return 1; //既に鳴っている。
    debug_memo_hex4[nn] = true;
    set_beep_code(data << 4 & 0x0f0 | 0x04); // 登録。
    return 1;
}

// enableが1の時、nnの識別番号で、dataの下位8ビットの音を登録します。
static bool debug_memo_hex8[ERROR_INFO_ARRAY_SIZE];
int debug_hex8(int nn, uint8_t data, bool enable) {
    if (nn >= ERROR_INFO_ARRAY_SIZE) return 0;
    if (!enable) return 0;
    if (debug_memo_hex8[nn]) return 1; //既に鳴っている。
    debug_memo_hex8[nn] = true;
    set_beep_code(data & 0x0f0 | 0x04); // 登録。  
    set_beep_code(data << 4 & 0x0f0 | 0x04); // 登録。
    return 1;
}

// enableが1の時、nnの識別番号で、dataの下位16ビットの音を登録します。
static bool debug_memo_hex16[ERROR_INFO_ARRAY_SIZE];
int debug_hex16(int nn, uint16_t data, bool enable) {
    if (nn >= ERROR_INFO_ARRAY_SIZE) return 0;
    if (!enable) return 0;
    if (debug_memo_hex16[nn]) return 1; //既に鳴っている。
    debug_memo_hex16[nn] = true;
    set_hex_beep(data);
    return 1;
}

// enableが1の時、nnの識別番号で、dataの32ビットの音を登録します。
static bool debug_memo_hex32[ERROR_INFO_ARRAY_SIZE];
int debug_hex32(int nn, uint32_t data, bool enable) {
    if (nn >= ERROR_INFO_ARRAY_SIZE) return 0;
    if (!enable) return 0;
    if (debug_memo_hex32[nn]) return 1; //既に鳴っている。
    debug_memo_hex32[nn] = true;
    set_hex_beep((uint16_t) (data >> 16));
    set_hex_beep((uint16_t) data);
    return 1;
}

// nnの番号順で予想通りの記述位置をcount回数動作しているか調べる関数
// nnが0の所をcount回以上通過すると、1の通過を通過がチェックされる
// nnが1の所をcount回以上通過すると、2の通過を通過がチェックされる
// nnが2の所をcount回以上通過すると、3の通過を通過がチェックされる・・と動作する。
// 各check_pointの所で、指定count回以上通過の所で、nnのビットパターンの音登録を
// debug_countで行っている。
static bool debug_point_array[16];
bool debug_point(int nn, int count) {
    if (nn >= 16) return 0;
    if (nn == 0) {
        debug_point_array[0] = debug_count(0, count, 1); ///依存なしで音の登録
        return debug_point_array[0];
    } else {
        // debug_point_array[nn-1]が1の場合だけ音の登録
        debug_point_array[nn] = debug_count(nn, count, debug_point_array[nn - 1]);
        return debug_point_array[nn];
    }
}

void debug_beep_claer() {
    int i;
    //debug_hexXXエリアのクリア
    for (i = 0; i < ERROR_INFO_ARRAY_SIZE; i++) {
        debug_memo_hex4[i] = 0;
        debug_memo_hex8[i] = 0;
        debug_memo_hex16[i] = 0;
        debug_memo_hex32[i] = 0;
    }

    //debug_count用情報のクリア
    for (i = 0; i < 16; i++) {
        debug_count_memo[i] = 0;
        debug_count_area[i] = 0;
        debug_point_array[i] = 0;
    }
    // エラーを復帰させるコード
    U1STAbits.OERR = 0; // 受信バッファオーバーランエラーの復帰
}