メインプログラム:LCD_VU_Display.c
メインプログラムは以下の関数から構成されます。
音声レベルと対数変換について
音声信号のレベル(音量)は直線的ではありません。音声周波数と同じで対数になっていますので簡単に解説します。
音声周波数の場合、ピアノの鍵盤の一番左の”ファ-1”の音と1オクターブ上の”ファ-2”の音では周波数がちょうど2倍になっています。更に1オクターブ上の”ファ-3”は”ファ-2”に対して2倍の周波数です。”ファ-3”は”ファ-1”に対して4倍の周波数になります。
音量も同じで、例えばボリュームが一段上がったら音量が2倍になるとすると、もう一段上がると4倍にしないと同じだけ、音量が上がったと感じません。
これを表現するのがdB(デシベル)です。AMPの増幅度が2倍の場合、増幅度は6dBである。というように使います。デシベルは相対的な表現なので、増幅度で言うと入力レベルに対して出力レベルが?dBと表現します。
計算式は20log^出力/入力です。Windowsのアクセサリに電卓がありますので表示で関数電卓をチェックすると簡単に計算できます。
先ほどのAMPの増幅度は出力/入力が2(2倍)ですから 2、log、×20と打てば=6.02059と出てきます。約+6dBです。
逆に半分になったとすると 0.5、log、×20、=-6.02059 -6dBという事です。元の数に対して増えると+、減ると - になります。
4倍と8倍も計算してみてください。12dB、18dBと6dBづつ増加している事が解ります。10倍で20dB、1/10で-20dBです。
次は音声電気信号の単位としてのデシベルですが、dBが相対値である事に対して、後ろにもう一文字追加されます。
これは発明王グラハム・ベルの時代に作られました。もう100年以上前の代物です。
実はこの種類が100年の間に実に多くなって大変なので、ちょっとだけ紹介するとdBm・dBs・dBv・dBV・dBW・dB SPL・dBu・dBA・dBB・dBC…もーーー!ヤダーー!
気を取り直して、dBm(デービーエム)は600Ωのインピーダンス負荷に対して1mWの電力を発生させる信号電圧を0dBmと規定しています。
電圧は0.776Vrmsであり約2.2Vp−pです。なんと中途半端な電圧なんでしょう。
これは推測なのですが、100年前の電話用ケーブルはインピーダンス600Ωが一番作り易かったようです。同軸ケーブルも50Ωが作り易かったから同軸ケーブルのインピーダンスは50オームとして機器側を設計したようです。次に作り易いのは75Ωだそうです。
電話の場合、長ーい距離を伝送しなければならないので伝送インピーダンスの一致は大原則となります。そのような理由で音声系の電気信号はかなり最近まで600Ωが主流でした。600Ωトランスで受け渡しする平衡2線式伝送路は簡単ですが外来ノイズに強く素晴らしい回路です。LANケーブルの規格もインピーダンスの違いはありますがほぼ同じです。
プロ用のXLRコネクタを使用した機器はこの単位で運用されていましたが、最近はインピーダンスを無視して、信号電圧を0.776Vrmsが0dBuと規定しています。
一般的にはミニコンポの背面にあるLINE OUTという赤と白のRCAコネクタは規定レベルが-20dBuとなっています。電圧で言うと0.22Vp-pになります。
最近のプロ用機器の規定レベルは+4dBuです。これはVUメーターの0VUが1.228Vrmsで3.97dBmになる事から規定されているようです。本機では-20dBu〜+4dBuまで対応可能です。入力調整用半固定抵抗で設定します。
iPodの様なPHONO出力しか無い機器でも信号電圧が-20dBu程度であれば十分に表示できるので、iPodのボリューム合わせてください。
対数変換表示テーブル関数
BAR_TABLE(引数)
AD変換値を元に、BAR表示用レジスタを設定して戻ります。
引数はAD変換で取得されたLch_DATA/Rch_DATAです。
例
BAR_TABLE(Lch_DATA);
戻り値はありません。
/************************
* 対数変換表示テーブル関数 *
*************************/ // AD変換結果を対数変換し、表示パラメータを設定するテーブル
void BAR_TABLE(long DATA){
if(DATA >= 1023){ // -44dB以下
BAR_COUNT = 0;
BAR_TYPE = 0x20;
SPACE_COUNT = 10;
MARK_TYPE = 0x02;
RED_ZONE_TYPE = 0x20;
return;
}
if(DATA >= 1022){ // -42dB
BAR_COUNT = 0;
BAR_TYPE = 0;
SPACE_COUNT = 10;
MARK_TYPE = 0x02;
RED_ZONE_TYPE = 0x20;
return;
}
if(DATA >= 1){ // +6db
BAR_COUNT = 10;
BAR_TYPE = 1;
SPACE_COUNT = 0;
MARK_TYPE = 0x04;
RED_ZONE_TYPE = 0x00;
return;
}
if(DATA >= 0){ // Range Over
BAR_COUNT = 10;
BAR_TYPE = 1;
SPACE_COUNT = 0;
MARK_TYPE = 0x04;
RED_ZONE_TYPE = 0x01;
return;
}
}
入力信号が無い時、AD変換には+3.3Vが入力されます。また+6dBu入力されると0Vになるように入力レベル調整用半固定抵抗を設定しています。
入力信号とAD変換値の関係を下表に示します。入力レベルが小さくなると変化量も小さくなることが解ります。
入力レベル 計算値
(mVp-p)実測値
AD変換値入力レベル 計算値
(mVp-p)実測値
AD変換値+6dBu 440 16 -20dBu 22 976 +4dBu 349 175 -22dBu 18 987 +2dBu 277 343 -24dBu 14 996 0dBu 220 489 -26dBu 11 1001 -2dBu 175 602 -28dBu 9 1005 -4dBu 139 690 -30dBu 7 1009 -6dBu 110 761 -32dBu 6 1012 -8dBu 88 816 -34dBu 4 1015 -10dBu 70 858 -36dBu 3.5 1017 -12dBu 55 894 -38dBu 2.8 1019 -14dBu 44 922 -40dBu 2.2 1021 -16dBu 35 943 -42dBu 1.7 1022 -18dBu 28 960 -44dBu 1.4 1023
BAR表示関数
LCD_Display()
以下の5つのBAR表示用レジスタを使って表示しています。
BAR_COUNTはの数(0〜11)
BAR_TYPEはが連続した一番右のBARのタイプ(
は0,
は1)
SPACE_COUNTは0dBマーカーまでの数
MARK_TYPEは0dBマーカーのタイプ(は0x02,
は0x03,
は0x04)
RED_ZONE_TYPE レッドゾーン部のBARタイプ(は0x00,
は0x01,
は0x20)
表示手順
step 1: LかRを表示し、BAR_COUNTの数だけで埋めます。
step 2:BAR_TYPEに応じたか
を表示します。
step 3:SPACE_COUNTの数だけで埋めます。
step 4:MARK_TYPEか
または
を表示します。
step 5:RED_ZONE_TYPEに応じたか
または
を表示する。
step 6:を2個表示して終了です。
表示例
Lch Rch BAR_COUNT 10 9 BAR_TYPE 1 0 SPACE_COUNT 0 1 MARK_TYPE 0x04 0x02 RED_ZONE_TYPE 0x01 0x20
引数はありません。戻り値もありません。
/**************
* BAR表示関数 *
***************/
void LCD_Display(void){
for(i=0;i<BAR_COUNT;i++){ // [| |]を表示
LCD_putc(0x01);
}
LCD_putc(BAR_TYPE); // [| |]/[| ]を表示
for(i=0;i<SPACE_COUNT;i++){
LCD_putc(0x20);
}
LCD_putc(MARK_TYPE); // 0dBマークの部分を表示[ ' ]/[|' ]/[|'|]
LCD_putc(RED_ZONE_TYPE); // +3,+6dB部分を表示[| |]/[| ]
for(i=0;i<2;i++){ // 右端の2文字に" "スペースを表示
LCD_putc(0x20);
}
}
AD変換関数
AD_START(引数)
この関数の引数はAD変換するチャンネルを指定します。RchかLchを指定してください。
例
AD_START(Rch);
Beanで自動生成されたVUin.cにsetReg8(ADCSC1,xch)関数があります。この関数を実行すると指定チャンネルのAD変換が開始されます。
while (!ADCSC1_COCO){} 関数でAD変換が終了するまで待ちます。変換値の上位バイトを下位バイトに加算して16ビットデータにします。
変換値をAD_DATA[ ]テーブルに格納し、3回繰り返して平均化したデータを各チャンネルレジスタRch_DATA/Lch_DATAに格納して戻ります。
戻り値はありません。
/************
* AD変換関数 *
*************/ // AD変換チャンネル xch にRchかLchを入れて呼び出す
void AD_START(char xch){ // 変換結果はRch(Lch)_DATAに格納される
for(i=0;i<4;i++){
setReg8(ADCSC1, xch); // 指定チャンネルのAD変換を開始
while (!ADCSC1_COCO){} // AD変換終了待ち
DATA = (ADCRH*256)+ADCRL;
AD_DATA[i] = DATA;
}
for(i=0;i<2;i++){
DATA = (AD_DATA[i]+AD_DATA[i+1])/2; // 平均化
}
/**** 結果格納 *****/
if(xch == Rch){ // 指定チャンネルにAD変換結果を格納
Rch_DATA = DATA;
}
if(xch == Lch){
Lch_DATA = DATA; // 指定チャンネルにAD変換結果を格納
}
return;
}
メイン関数
main();
メイン関数です。
PE_lowlevel_init();
プロセッサーエキスパートが自動生成したCPU.cの初期化関数群。引数および戻り値はありません。
LCD_Init();
LCDキャラクタキャラクタディスプレーライブラリの初期化関数群。引数および戻り値はありません。
Cpu_Delay100US(引数);
プロセッサーエキスパートが自動生成したCPU.cのディレー関数です。引数は待ち時間を100uS単位で入れます。10で1mS、10000で1秒です。
メインループ
Rch、LchそれぞれをAD変換し、対数変換表示テーブルで準備したBARを、2行とも表示して100mS待機してループします。
LCDは応答速度が遅いため書き換えサイクルが早すぎると画面がチラついて見ずらくなります。今回使用したSC1602BSLBはTNタイプなので応答速度は立ち上がり120mS、立下り90mSです。使用するキャラクタディスプレーの表示状況を見てから待機時間は調整してください。
/***********
* メイン関数 *
************/
void main(void)
{
/* Write your local variable definition here */
/*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
PE_low_level_init();
/*** End of Processor Expert internal initialization. ***/
/* Write your code here */
LCD_Init();
LCD_CG_init();
Cpu_Delay100US(1);
LCD_PrintDisplay(Line_0," LCD VU Display "); // オープニングメッセージ1行目を書込む
Cpu_Delay100US(1);
LCD_PrintDisplay(Line_1,"Ver1 デンシコウサクノモリ"); // オープニングメッセージ2行目を書込む
Cpu_Delay100US(20000); // 2秒待ち
LCD_WriteData(LCD_CMD_CLAR,LCD_CMD_RS); // 表示クリア
Cpu_Delay100US(50);
/***** メインループ *****/
for(;;)
{
AD_START(Rch); // Rch AD変換
AD_START(Lch); // Lch AD変換
/***** Lch BAR表示 *****/
BAR_TABLE(Lch_DATA);
LCD_WriteData(Line_0,LCD_CMD_RS); // 1行目の先頭に移動
LCD_putc(0x06); // "L"を表示
LCD_Display(); // BARを表示
/***** Rch BAR表示 *****/
BAR_TABLE(Rch_DATA);
LCD_WriteData(Line_1,LCD_CMD_RS); // 2行目の先頭に移動
LCD_putc(0x05); // "R"を表示
LCD_Display(); // BARを表示
Cpu_Delay100US(1000); // 100mS Wait! 液晶の応答速度に合わせる。
}
}