CQ出版社セミナ,2021/12/07開催「実習・C++言語によるArmマイコンのプログラミング」で使うプログラム.
Dependencies: Array_Matrix mbed SerialTxRxIntr UIT_FFT_Real
Diff: main.cpp
- Revision:
- 0:a80f730d32a8
- Child:
- 2:d28a3f741217
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed Jan 15 12:43:11 2020 +0000 @@ -0,0 +1,108 @@ +//--------------------------------------------------------------------- +// FFT によるスペクルアナライザ (Nucleo-F446RE 用) +// +// ● ST-Link Firmware の V2.J28.M16 で動作確認 +// +// ● ST-Link Firmware のアップグレードには stsw-link07.zip +// に含まれている "ST-LinkUpgrade.exe" を使う +// +// ● PC 側のプログラム: "F446_FFT_Analyzer" +// ● ボーレート: 460800 baud +// ● 受信データの文字列の終了マーク: "\r" +// +// ● 入力: A1 +// ● モニタ用出力:A2 +// +// PC 側のプログラムのフォルダ:プログラム\PC\F446_FFT_Analyzer +// +// 2020/01/13, Copyright (c) 2020 MIKAMI, Naoki +//--------------------------------------------------------------------- + +#include "mbed.h" +#include <string> +#include "Array.hpp" +#include "F446_ADC_Intr.hpp" +#include "F446_DAC.hpp" +#include "FFT_Analyzer.hpp" +#include "DoubleBuffer.hpp" +#include "Coefs_IIR6_LP_8k_Biquad.hpp" // 縦続形 IIR フィルタの係数 +#include "IIR_Cascade.hpp" // 縦続形 IIR フィルタ +#include "Xfer.hpp" +using namespace Mikami; + +const int N_FFT_ = 512; // FFT の点数 +const int N_FRAME_ = N_FFT_/2; // 1フレーム当たり標本化するデータ数 +const int N_FFT_2_ = N_FFT_/2; // FFT の点数の半分 +const int RATIO_ = 10; // オーバーサンプリングの倍率 + +DoubleBuffer<float, N_FRAME_> buf_(0); // AD の結果を保存するバッファ +AdcF446_Intr myAdc_(16*RATIO_, A1); // 標本化周波数: 160 kHz +DacF446 myDac; +IirCascade df_(ORDER_, CK_, G0_); // ダウンサンプリング用 Anti-alias フィルタ + +// ADC 変換終了割り込みに対する割り込みサービス・ルーチン +void AdcIsr() +{ + static int count = 0; + + float xn = myAdc_.Read(); + myDac.Write(xn); // モニタ用 + float yn = df_.Execute(xn); // ダウンサンプリング用 Anti-alias フィルタの実行 + + if (++count >= RATIO_) + { + buf_.Store(yn); // ダウンサンプリングされたデータをバッファへ格納 + count = 0; + buf_.IfFullSwitch(); // バッファが満杯であればバッファを切り替える + } +} + +int main() +{ + SerialRxTxIntr rxTx(32, 460800); // PC との通信用 + Xfer tx(rxTx, N_FFT_/2+1); // PC に転送するためのオブジェクトの生成 + FftAnalyzer analyzer(N_FFT_); // FFT によるスペクトル解析オブジェクトの生成 + + Array<float> sn(N_FFT_, 0.0f); // スペクトル解析の対象となるデータ + Array<float> db(N_FRAME_); // 解析結果:対数スペクトル [dB] + + NVIC_SetPriority(ADC_IRQn, 0); // AD変換終了割り込みの優先度が最高 + NVIC_SetPriority(USART2_IRQn, 1); + + bool ready = false; // スペクトルの計算終了で true + bool okGo = false; // "GO" を受信したら true + + myAdc_.SetIntrVec(&AdcIsr); // AD変換終了割り込みの割り当て + while (true) + { + // PC からのコマンドの解析 + if (rxTx.IsEol()) // 受信バッファのデータが有効になった場合の処理 + { + string str = rxTx.GetBuffer(); + if (str == "FFTAnalyzer") + rxTx.Tx("ACK\n"); // PC からの "FFTAnalyzer" に対して "ACK" を送信 + else if (str == "GO") okGo = true; // データの転送要求あり + } + + if (buf_.IsFull()) // 入力データが満杯の場合,以下の処理を行う + { + for (int n=0; n<N_FFT_2_; n++) // フレームの後半のデータを前半に移動する + sn[n] = sn[n+N_FRAME_]; + for (int n=0; n<N_FRAME_; n++) // フレームの後半には新しいデータを格納する + sn[n+N_FFT_2_] = buf_.Get(n); + + analyzer.Execute(sn, db); // スペクトル解析の実行 + tx.Convert(db); // スペクトル解析の結果を転送する形式に変換 + ready = true; // スペクトル解析終了 + } + + // 転送要求がありスペクトル解析が終了している場合にデータを PC へ転送する + if (okGo && ready) + { + tx.ToPC(); // データを PC へ転送 + ready = false; + okGo = false; + } + } +} +