CQエレクトロニクス・セミナで使用するファンクション・ジェネレータの プログラム

Dependencies:   Array_Matrix mbed SerialTxRxIntr MyTicker7

Revision:
0:8c8bc21159d9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Feb 25 02:36:55 2022 +0000
@@ -0,0 +1,150 @@
+//----------------------------------------------------------------------
+//	ファンクション・ジェネレータ (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);
+		}
+	}
+}