ファンクション・ジェネレータ このプログラムの説明は,CQ出版社「トランジスタ技術」の2021年10月号から開始された連載記事「STM32マイコンではじめるPC計測」の中にあります.このプログラムといっしょに使うPC側のプログラムについても同誌を参照してください.

Dependencies:   Array_Matrix mbed SerialTxRxIntr MyTicker7

Committer:
MikamiUitOpen
Date:
Wed Oct 06 12:20:04 2021 +0000
Revision:
1:0430f1ed6c2c
Parent:
0:53c0fa8a9aa2
2

Who changed what in which revision?

UserRevisionLine numberNew contents of line
MikamiUitOpen 0:53c0fa8a9aa2 1 //----------------------------------------------------------------------
MikamiUitOpen 1:0430f1ed6c2c 2 // ファンクション・ジェネレータ (Nucleo-F446RE 用)
MikamiUitOpen 1:0430f1ed6c2c 3 // COM ポートの自動検出に対応(9600 baud)
MikamiUitOpen 0:53c0fa8a9aa2 4 //
MikamiUitOpen 1:0430f1ed6c2c 5 // 設定できる項目
MikamiUitOpen 1:0430f1ed6c2c 6 // 波形の種類: 正弦波,方形波,合成方形波(フーリエ級数の5倍波までの和)
MikamiUitOpen 1:0430f1ed6c2c 7 // 振幅: 0.00 ~ 1.00 倍
MikamiUitOpen 1:0430f1ed6c2c 8 // 周波数: 10 Hz ~ 10 kHz
MikamiUitOpen 1:0430f1ed6c2c 9 // ノイズ付加の有無
MikamiUitOpen 1:0430f1ed6c2c 10 // 標本化間隔:2.5 μs
MikamiUitOpen 1:0430f1ed6c2c 11 // 使用タイマ:TIM7
MikamiUitOpen 1:0430f1ed6c2c 12 // 信号出力のピン: A2
MikamiUitOpen 1:0430f1ed6c2c 13 // 同期信号出力のピン: A5
MikamiUitOpen 0:53c0fa8a9aa2 14 //
MikamiUitOpen 1:0430f1ed6c2c 15 // PC 側のプログラム
MikamiUitOpen 1:0430f1ed6c2c 16 // CQ_FunctionGenerator
MikamiUitOpen 0:53c0fa8a9aa2 17 //
MikamiUitOpen 1:0430f1ed6c2c 18 // 2021/09/29, Copyright (c) 2021 MIKAMI, Naoki
MikamiUitOpen 0:53c0fa8a9aa2 19 //----------------------------------------------------------------------
MikamiUitOpen 0:53c0fa8a9aa2 20
MikamiUitOpen 1:0430f1ed6c2c 21 #include "F446_DAC.hpp" // DA 変換器用
MikamiUitOpen 1:0430f1ed6c2c 22 #include "SerialRxTxIntr.hpp" // シリアル通信用
MikamiUitOpen 1:0430f1ed6c2c 23 #include "MyTicker7.hpp" // タイマ用
MikamiUitOpen 1:0430f1ed6c2c 24 #include "FastSin.hpp" // 高速低精度 sin 関数
MikamiUitOpen 1:0430f1ed6c2c 25 #include "MSeq16.hpp" // ノイズ発生器で使う M 系列信号発生器
MikamiUitOpen 1:0430f1ed6c2c 26 #include "IirCascade.hpp" // ノイズ発生器で使う低域通過フィルタ
MikamiUitOpen 1:0430f1ed6c2c 27 #include "CoefficientsLp4.hpp" // 低域通過フィルタの係数
MikamiUitOpen 1:0430f1ed6c2c 28 #include <cctype> // isalpha() で使用
MikamiUitOpen 0:53c0fa8a9aa2 29 using namespace Mikami;
MikamiUitOpen 0:53c0fa8a9aa2 30
MikamiUitOpen 0:53c0fa8a9aa2 31 #ifndef __STM32F446xx_H
MikamiUitOpen 0:53c0fa8a9aa2 32 #error "Use Nucleo-F446RE"
MikamiUitOpen 0:53c0fa8a9aa2 33 #endif
MikamiUitOpen 0:53c0fa8a9aa2 34
MikamiUitOpen 1:0430f1ed6c2c 35 const float T0_ = 2.5f; // 出力の標本化間隔: 2.5 μs
MikamiUitOpen 0:53c0fa8a9aa2 36 const float C0_ = 4.0f;
MikamiUitOpen 0:53c0fa8a9aa2 37 const float C0_2_ = C0_/2.0f;
MikamiUitOpen 0:53c0fa8a9aa2 38 const float C0T0_ = C0_*T0_*1.0e-6f;
MikamiUitOpen 0:53c0fa8a9aa2 39
MikamiUitOpen 1:0430f1ed6c2c 40 MyTicker7 timer_(T0_); // タイマ割り込み用クラスのオブジェクト,TIM7 を利用
MikamiUitOpen 1:0430f1ed6c2c 41 DigitalOut sync_(A5); // 同期信号出力用
MikamiUitOpen 0:53c0fa8a9aa2 42
MikamiUitOpen 0:53c0fa8a9aa2 43 float phi_ = 0;
MikamiUitOpen 1:0430f1ed6c2c 44 float dPhi_ = C0T0_*1000; // 周波数決める変数,開始時は 1 kHz;
MikamiUitOpen 1:0430f1ed6c2c 45 float volume_ = 0.9f*0.5f; // 出力の振幅を決める変数,開始時は 0.45
MikamiUitOpen 1:0430f1ed6c2c 46 float volNoise_ = 0.5f; // ノイズの大きさを決める変数
MikamiUitOpen 0:53c0fa8a9aa2 47
MikamiUitOpen 0:53c0fa8a9aa2 48 // DA 変換器に関する関数等
MikamiUitOpen 1:0430f1ed6c2c 49 DacF446 dac_; // DA 変換器オブジェクト
MikamiUitOpen 1:0430f1ed6c2c 50 void DacOut(float x) { dac_.Write(x); } // 引数の値を出力
MikamiUitOpen 0:53c0fa8a9aa2 51 void DacZero(float x) { dac_.Write(0.0f); } // 0 を出力
MikamiUitOpen 1:0430f1ed6c2c 52 void (*fpDa)(float) = DacZero; // 起動時は 0 を出力
MikamiUitOpen 0:53c0fa8a9aa2 53
MikamiUitOpen 0:53c0fa8a9aa2 54 // ノイズ付加に関する関数等
MikamiUitOpen 1:0430f1ed6c2c 55 MSeq16 mSeq_; // M 系列発生器
MikamiUitOpen 1:0430f1ed6c2c 56 IirCascade filter_(ORDER_, hk_, G0_); // 低域通過フィルタ
MikamiUitOpen 0:53c0fa8a9aa2 57 float Noise() { return volNoise_*filter_.Execute(mSeq_.Execute()); }
MikamiUitOpen 0:53c0fa8a9aa2 58 float NoiseFree() { return 0; }
MikamiUitOpen 1:0430f1ed6c2c 59 float (*fpN)() = NoiseFree; // 起動時はノイズなし
MikamiUitOpen 0:53c0fa8a9aa2 60
MikamiUitOpen 0:53c0fa8a9aa2 61 // 発生する信号を定義する関数
MikamiUitOpen 0:53c0fa8a9aa2 62 // 正弦波
MikamiUitOpen 0:53c0fa8a9aa2 63 float Sin(float sinx) { return volume_*sinx + fpN(); }
MikamiUitOpen 1:0430f1ed6c2c 64 // 方形波
MikamiUitOpen 0:53c0fa8a9aa2 65 float Rect(float sinx)
MikamiUitOpen 0:53c0fa8a9aa2 66 {
MikamiUitOpen 1:0430f1ed6c2c 67 float x = (sinx >= 0) ? volume_ : -volume_;
MikamiUitOpen 1:0430f1ed6c2c 68 return x + fpN();
MikamiUitOpen 0:53c0fa8a9aa2 69 }
MikamiUitOpen 1:0430f1ed6c2c 70 // 合成方形波(5倍波まで)
MikamiUitOpen 0:53c0fa8a9aa2 71 float Syn(float sinx)
MikamiUitOpen 0:53c0fa8a9aa2 72 {
MikamiUitOpen 1:0430f1ed6c2c 73 static const float ONE_3 = 1.0f/3.0f; // フーリエ合成で使用
MikamiUitOpen 1:0430f1ed6c2c 74 static const float ONE_5 = 0.2f; // フーリエ合成で使用
MikamiUitOpen 0:53c0fa8a9aa2 75
MikamiUitOpen 1:0430f1ed6c2c 76 float sinx2 = sinx*sinx;
MikamiUitOpen 1:0430f1ed6c2c 77 float sin3x = (-4.0f*sinx2 + 3.0f)*sinx;
MikamiUitOpen 1:0430f1ed6c2c 78 float sin5x = ((16.0f*sinx2 - 20.0f)*sinx2 + 5.0f)*sinx;
MikamiUitOpen 0:53c0fa8a9aa2 79
MikamiUitOpen 1:0430f1ed6c2c 80 return volume_*(sinx + ONE_3*sin3x + ONE_5*sin5x) + fpN();
MikamiUitOpen 0:53c0fa8a9aa2 81 }
MikamiUitOpen 1:0430f1ed6c2c 82 float (*fpS)(float) = Sin; // 起動時は正弦波
MikamiUitOpen 0:53c0fa8a9aa2 83
MikamiUitOpen 0:53c0fa8a9aa2 84 // ラジオボタン,チェックボックスに対応する処理
MikamiUitOpen 0:53c0fa8a9aa2 85 void Select(string str)
MikamiUitOpen 0:53c0fa8a9aa2 86 {
MikamiUitOpen 1:0430f1ed6c2c 87 if (str == "On") fpDa = DacOut; // 選択された信号の出力
MikamiUitOpen 1:0430f1ed6c2c 88 if (str == "Off") fpDa = DacZero; // 0 を出力
MikamiUitOpen 0:53c0fa8a9aa2 89
MikamiUitOpen 1:0430f1ed6c2c 90 if (str == "Sin") fpS = Sin; // 正弦波
MikamiUitOpen 1:0430f1ed6c2c 91 if (str == "Rect") fpS = Rect; // 方形波
MikamiUitOpen 1:0430f1ed6c2c 92 if (str == "Syn") fpS = Syn; // 合成方形波
MikamiUitOpen 0:53c0fa8a9aa2 93
MikamiUitOpen 1:0430f1ed6c2c 94 if (str == "NsOn") fpN = Noise; // ノイズ付加
MikamiUitOpen 1:0430f1ed6c2c 95 if (str == "NsOff") fpN = NoiseFree; // ノイズなし
MikamiUitOpen 0:53c0fa8a9aa2 96 }
MikamiUitOpen 0:53c0fa8a9aa2 97
MikamiUitOpen 0:53c0fa8a9aa2 98 // スライダ(TrackBar)に対応する処理
MikamiUitOpen 0:53c0fa8a9aa2 99 void NumericCtrl(string str)
MikamiUitOpen 0:53c0fa8a9aa2 100 {
MikamiUitOpen 1:0430f1ed6c2c 101 char c1 = str[0]; // 先頭の文字を取得
MikamiUitOpen 1:0430f1ed6c2c 102 float x = atof(str.substr(1).c_str());
MikamiUitOpen 0:53c0fa8a9aa2 103
MikamiUitOpen 1:0430f1ed6c2c 104 if (c1 == '#') volume_ = x*0.9f; // 出力振幅の変更
MikamiUitOpen 1:0430f1ed6c2c 105 if (c1 == '$') dPhi_ = C0T0_*x; // 周波数の変更
MikamiUitOpen 1:0430f1ed6c2c 106 if (c1 == '%') volNoise_ = x; // ノイズの大きさの変更
MikamiUitOpen 0:53c0fa8a9aa2 107 }
MikamiUitOpen 0:53c0fa8a9aa2 108
MikamiUitOpen 0:53c0fa8a9aa2 109 // タイマ割り込みに対する割込みサービス・ルーチン
MikamiUitOpen 0:53c0fa8a9aa2 110 void TimerIsr()
MikamiUitOpen 0:53c0fa8a9aa2 111 {
MikamiUitOpen 1:0430f1ed6c2c 112 float sinx = FastSin(phi_); // 基本波発生
MikamiUitOpen 1:0430f1ed6c2c 113 fpDa(fpS(sinx)); // 指定された信号を出力
MikamiUitOpen 1:0430f1ed6c2c 114 GPIOC->BSRR = (sinx >= 0) ? // 同期信号を出力
MikamiUitOpen 1:0430f1ed6c2c 115 0x1 : 0x10000;
MikamiUitOpen 0:53c0fa8a9aa2 116
MikamiUitOpen 1:0430f1ed6c2c 117 phi_ += dPhi_;
MikamiUitOpen 1:0430f1ed6c2c 118 if (phi_ >= C0_2_) phi_ -= C0_; // オーバーフロー防止
MikamiUitOpen 0:53c0fa8a9aa2 119 }
MikamiUitOpen 0:53c0fa8a9aa2 120
MikamiUitOpen 0:53c0fa8a9aa2 121 int main()
MikamiUitOpen 0:53c0fa8a9aa2 122 {
MikamiUitOpen 1:0430f1ed6c2c 123 SerialRxTxIntr rxTx; // PC との通信用,9600 baud
MikamiUitOpen 1:0430f1ed6c2c 124 // 以下の割り込み優先順位の設定を忘れないこと
MikamiUitOpen 1:0430f1ed6c2c 125 NVIC_SetPriority(TIM7_IRQn, 0); // 最優先
MikamiUitOpen 1:0430f1ed6c2c 126 NVIC_SetPriority(USART2_IRQn, 1); // USART2 割り込み:次に優先
MikamiUitOpen 0:53c0fa8a9aa2 127
MikamiUitOpen 1:0430f1ed6c2c 128 timer_.Attach(&TimerIsr); // タイマ割り込み設定
MikamiUitOpen 1:0430f1ed6c2c 129
MikamiUitOpen 1:0430f1ed6c2c 130 while (true) // PC からの指令に対応する処理
MikamiUitOpen 1:0430f1ed6c2c 131 {
MikamiUitOpen 1:0430f1ed6c2c 132 if (rxTx.IsEol()) // 受信バッファのデータが有効になった場合の処理
MikamiUitOpen 1:0430f1ed6c2c 133 {
MikamiUitOpen 1:0430f1ed6c2c 134 string str = rxTx.GetBuffer();
MikamiUitOpen 1:0430f1ed6c2c 135 if (str == "FG")
MikamiUitOpen 1:0430f1ed6c2c 136 rxTx.TxString("ACK\n"); // PC からの "FG" に対して "ACK" を送信する
MikamiUitOpen 1:0430f1ed6c2c 137 else
MikamiUitOpen 1:0430f1ed6c2c 138 if (isalpha(str[0])) // 先頭が A ~ Z, a ~ z の場合
MikamiUitOpen 1:0430f1ed6c2c 139 Select(str);
MikamiUitOpen 1:0430f1ed6c2c 140 else // 先頭が A ~ Z, a ~ z 以外の場合
MikamiUitOpen 1:0430f1ed6c2c 141 NumericCtrl(str);
MikamiUitOpen 1:0430f1ed6c2c 142 }
MikamiUitOpen 1:0430f1ed6c2c 143 }
MikamiUitOpen 0:53c0fa8a9aa2 144 }