CQエレクトロニクス・セミナで使用するファンクション・ジェネレータの プログラム
Dependencies: Array_Matrix mbed SerialTxRxIntr MyTicker7
main.cpp
- Committer:
- MikamiUitOpen
- Date:
- 2022-02-25
- Revision:
- 0:8c8bc21159d9
File content as of revision 0:8c8bc21159d9:
//---------------------------------------------------------------------- // ファンクション・ジェネレータ (Nucleo-F446RE 用) // COM ポートの自動検出に対応(9600 baud) // // 設定できる項目 // 波形の種類: 正弦波,方形波,合成方形波(フーリエ級数の5倍波までの和) // 振幅: 0.00 ~ 1.00 倍 // 周波数: 10 Hz ~ 10 kHz // ノイズ付加の有無 // 標本化間隔:2.5 μs // 使用タイマ:TIM7 // 信号出力のピン: A2 // 同期信号出力のピン: A5 // // PC 側のプログラム // CQ_FunctionGenerator // // 2021/09/29, Copyright (c) 2021 MIKAMI, Naoki // // セミナで使うため,白色雑音を生成する際の LPF の遮断周波数を低くしたバージョン // PC 側のプログラム // Seminar_FunctionGenerator // // 2022/01/20, Copyright (c) 2022 MIKAMI, Naoki //---------------------------------------------------------------------- #include "F446_DAC.hpp" // DA 変換器用 #include "SerialRxTxIntr.hpp" // シリアル通信用 #include "MyTicker7.hpp" // タイマ用 #include "FastSin.hpp" // 高速低精度 sin 関数 #include "MSeq16.hpp" // ノイズ発生器で使う M 系列信号発生器 #include "IirCascade.hpp" // ノイズ発生器で使う低域通過フィルタ #include "CoefficientsLp4.hpp" // 低域通過フィルタの係数 #include <cctype> // isalpha() で使用 using namespace Mikami; #ifndef __STM32F446xx_H #error "Use Nucleo-F446RE" #endif const float T0_ = 2.5f; // 出力の標本化間隔: 2.5 μs const float C0_ = 4.0f; const float C0_2_ = C0_/2.0f; const float C0T0_ = C0_*T0_*1.0e-6f; MyTicker7 timer_(T0_); // タイマ割り込み用クラスのオブジェクト,TIM7 を利用 DigitalOut sync_(A5); // 同期信号出力用 float phi_ = 0; float dPhi_ = C0T0_*1000; // 周波数決める変数,開始時は 1 kHz; float volume_ = 0.9f*0.5f; // 出力の振幅を決める変数,開始時は 0.45 float volNoise_ = 0.5f; // ノイズの大きさを決める変数 // DA 変換器に関する関数等 DacF446 dac_; // DA 変換器オブジェクト void DacOut(float x) { dac_.Write(x); } // 引数の値を出力 void DacZero(float x) { dac_.Write(0.0f); } // 0 を出力 void (*fpDa)(float) = DacZero; // 起動時は 0 を出力 // ノイズ付加に関する関数等 MSeq16 mSeq_; // M 系列発生器 IirCascade filter_(ORDER_, hk_, G0_); // 低域通過フィルタ float Noise() { return volNoise_*filter_.Execute(mSeq_.Execute()); } float NoiseFree() { return 0; } float (*fpN)() = NoiseFree; // 起動時はノイズなし // 発生する信号を定義する関数 // 正弦波 float Sin(float sinx) { return volume_*sinx + fpN(); } // 方形波 float Rect(float sinx) { float x = (sinx >= 0) ? volume_ : -volume_; return x + fpN(); } // 合成方形波(5倍波まで) float Syn(float sinx) { static const float ONE_3 = 1.0f/3.0f; // フーリエ合成で使用 static const float ONE_5 = 0.2f; // フーリエ合成で使用 float sinx2 = sinx*sinx; float sin3x = (-4.0f*sinx2 + 3.0f)*sinx; float sin5x = ((16.0f*sinx2 - 20.0f)*sinx2 + 5.0f)*sinx; return volume_*(sinx + ONE_3*sin3x + ONE_5*sin5x) + fpN(); } float (*fpS)(float) = Sin; // 起動時は正弦波 // ラジオボタン,チェックボックスに対応する処理 void Select(string str) { if (str == "On") fpDa = DacOut; // 選択された信号の出力 if (str == "Off") fpDa = DacZero; // 0 を出力 if (str == "Sin") fpS = Sin; // 正弦波 if (str == "Rect") fpS = Rect; // 方形波 if (str == "Syn") fpS = Syn; // 合成方形波 if (str == "NsOn") fpN = Noise; // ノイズ付加 if (str == "NsOff") fpN = NoiseFree; // ノイズなし } // スライダ(TrackBar)に対応する処理 void NumericCtrl(string str) { char c1 = str[0]; // 先頭の文字を取得 float x = atof(str.substr(1).c_str()); if (c1 == '#') volume_ = x*0.9f; // 出力振幅の変更 if (c1 == '$') dPhi_ = C0T0_*x; // 周波数の変更 if (c1 == '%') volNoise_ = x; // ノイズの大きさの変更 } // タイマ割り込みに対する割込みサービス・ルーチン void TimerIsr() { float sinx = FastSin(phi_); // 基本波発生 fpDa(fpS(sinx)); // 指定された信号を出力 GPIOC->BSRR = (sinx >= 0) ? // 同期信号を出力 0x1 : 0x10000; phi_ += dPhi_; if (phi_ >= C0_2_) phi_ -= C0_; // オーバーフロー防止 } int main() { SerialRxTxIntr rxTx; // PC との通信用,9600 baud // 以下の割り込み優先順位の設定を忘れないこと NVIC_SetPriority(TIM7_IRQn, 0); // 最優先 NVIC_SetPriority(USART2_IRQn, 1); // USART2 割り込み:次に優先 timer_.Attach(&TimerIsr); // タイマ割り込み設定 while (true) // PC からの指令に対応する処理 { if (rxTx.IsEol()) // 受信バッファのデータが有効になった場合の処理 { string str = rxTx.GetBuffer(); if (str == "FG_Seminar") rxTx.TxString("ACK\n"); // PC からの "FG" に対して "ACK" を送信する else if (isalpha(str[0])) // 先頭が A ~ Z, a ~ z の場合 Select(str); else // 先頭が A ~ Z, a ~ z 以外の場合 NumericCtrl(str); } } }