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);
		}
	}
}