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

Dependencies:   Array_Matrix mbed SerialTxRxIntr MyTicker7

Files at this revision

API Documentation at this revision

Comitter:
MikamiUitOpen
Date:
Wed Oct 06 12:20:04 2021 +0000
Parent:
0:53c0fa8a9aa2
Commit message:
2

Changed in this revision

MSeq16.hpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/MSeq16.hpp	Thu Sep 09 08:50:21 2021 +0000
+++ b/MSeq16.hpp	Wed Oct 06 12:20:04 2021 +0000
@@ -1,7 +1,7 @@
 //---------------------------------------------------------
-//  M 系列信号発生器(N = 16)
+//	M 系列信号発生器(N = 16)
 //
-//  2021/08/23, Copyright (c) 2020 MIKAMI, Naoki
+//	2021/09/28, Copyright (c) 2021 MIKAMI, Naoki
 //---------------------------------------------------------
 
 #include "mbed.h"
@@ -11,32 +11,25 @@
 
 namespace Mikami
 {
-    class MSeq16
-    {
-    public:
-        MSeq16() : reg_(1) {}
+	class MSeq16
+	{
+	public:
+		MSeq16() : reg_(1) {}
 
-        // 戻り値: 1 => 1, 0 => -1
-        float Execute()
-        {
-            if ((reg_ & B_M_) == B_M_)
-            {
-                reg_ = ((reg_ ^ XOR_) << 1) | 1;    // 1 の場合の処理
-                return 0.5f;
-            }
-            else
-            {
-                reg_ = reg_ << 1;                   // 0 の場合の処理
-                return -0.5f;
-            }
-        }
-    private:
-        static const uint16_t XOR_ = (1 << (2-1))
-                                   | (1 << (3-1))
-                                   | (1 << (5-1));  // XOR の位置に対応する定数
-        static const uint16_t B_M_ = 1 << (16-1);   // 16 段目に相当するビットを調べる
-        
-        uint16_t reg_;
-    };
+		// 戻り値: 0 => -0.5, 1 => 0.5
+		float Execute()
+		{
+			msb_ = reg_ >> 15;
+			reg_ = ((reg_ ^ XOR_[msb_]) << 1) | msb_;
+			return RET_[msb_];
+		}
+	private:
+		static const uint16_t XOR_[2];	// XOR の一方の入力
+		static const float RET_[2];		// 戻り値として使用
+		uint16_t reg_;	// 16 段の D フリップ・フロップに対応
+		uint16_t msb_;	// 16 段目に相当するビット
+	};
+	const uint16_t MSeq16::XOR_[2] = { 0, 0x16 };
+	const float MSeq16::RET_[2] = { -0.5f, 0.5f };	
 }
-#endif  // MSEQ16_HPP
\ No newline at end of file
+#endif	// MSEQ16_HPP
\ No newline at end of file
--- a/main.cpp	Thu Sep 09 08:50:21 2021 +0000
+++ b/main.cpp	Wed Oct 06 12:20:04 2021 +0000
@@ -1,140 +1,144 @@
 //----------------------------------------------------------------------
-//  ファンクション・ジェネレータ (Nucleo-F446RE 用)
-//  COM ポートの自動検出に対応(9600 baud)
+//	ファンクション・ジェネレータ (Nucleo-F446RE 用)
+//	COM ポートの自動検出に対応(9600 baud)
 //
-//  設定できる項目
-//      波形の種類:  正弦波,矩形波,合成矩形波(フーリエ級数の5倍波までの和)
-//      振幅:         0.00 ~ 1.00 倍
-//      周波数:       10 Hz ~ 10 kHz
-//      ノイズ付加の有無
-//  標本化間隔:2.5 μs
-//  使用タイマ:TIM7
-//  信号出力のピン:      A2
+//	設定できる項目
+//		波形の種類:  正弦波,方形波,合成方形波(フーリエ級数の5倍波までの和)
+//		振幅:		   0.00 ~ 1.00 倍
+//		周波数:	   10 Hz ~ 10 kHz
+//		ノイズ付加の有無
+//	標本化間隔:2.5 μs
+//	使用タイマ:TIM7
+//	信号出力のピン:	  A2
+//  同期信号出力のピン:  A5
 //
-//  PC 側のプログラム
-//      CQ_FunctionGenerator
+//	PC 側のプログラム
+//		CQ_FunctionGenerator
 //
-//  2021/09/05, Copyright (c) 2021 MIKAMI, Naoki
+//	2021/09/29, Copyright (c) 2021 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() で使用
+#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 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 を利用
+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;         // ノイズの大きさを決める変数
+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); }     // 引数の値を出力
+DacF446 dac_;					// DA 変換器オブジェクト
+void DacOut(float x) { dac_.Write(x); }		// 引数の値を出力
 void DacZero(float x) { dac_.Write(0.0f); } // 0 を出力
-void (*fpDa)(float) = DacZero;  // 起動時は 0 を出力
+void (*fpDa)(float) = DacZero;	// 起動時は 0 を出力
 
 // ノイズ付加に関する関数等
-MSeq16 mSeq_;                   // M 系列発生器
-IirCascade filter_(ORDER_, hk_, G0_);   // 低域通過フィルタ
+MSeq16 mSeq_;					// M 系列発生器
+IirCascade filter_(ORDER_, hk_, G0_);	// 低域通過フィルタ
 float Noise() { return volNoise_*filter_.Execute(mSeq_.Execute()); }
 float NoiseFree() { return 0; }
-float (*fpN)() = NoiseFree;     // 起動時はノイズなし 
+float (*fpN)() = NoiseFree;		// 起動時はノイズなし 
 
 // 発生する信号を定義する関数
 // 正弦波
 float Sin(float sinx) { return volume_*sinx + fpN(); }
-// 矩形波
+// 方形波
 float Rect(float sinx)
 {
-    float x = (sinx >= 0) ? volume_ : -volume_;
-    return x + fpN();
+	float x = (sinx >= 0) ? volume_ : -volume_;
+	return x + fpN();
 }
-// 矩形波(合成,5倍波まで)
+// 合成方形波(5倍波まで)
 float Syn(float sinx)
 {
-    static const float ONE_3 = 1.0f/3.0f;   // フーリエ合成で使用
-    static const float ONE_5 = 0.2f;        // フーリエ合成で使用
+	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;
+	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();
+	return volume_*(sinx + ONE_3*sin3x + ONE_5*sin5x) + fpN();
 }
-float (*fpS)(float) = Sin;      // 起動時は正弦波
+float (*fpS)(float) = Sin;		// 起動時は正弦波
 
 // ラジオボタン,チェックボックスに対応する処理
 void Select(string str)
 {
-    if (str == "On")    fpDa = DacOut;      // 選択された信号の出力
-    if (str == "Off")   fpDa = DacZero;     // 0 を出力
+	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;          // 矩形波(5倍波まで)
+	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;    // ノイズなし
+	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());
+	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;       // ノイズの大きさの変更
+	if (c1 == '#') volume_ = x*0.9f;	// 出力振幅の変更
+	if (c1 == '$') dPhi_ = C0T0_*x;		// 周波数の変更
+	if (c1 == '%') volNoise_ = x;		// ノイズの大きさの変更
 }
 
 // タイマ割り込みに対する割込みサービス・ルーチン
 void TimerIsr()
 {
-    float sinx = FastSin(phi_); // 基本波発生
-    fpDa(fpS(sinx));            // 指定された信号を出力
+	float sinx = FastSin(phi_); // 基本波発生
+	fpDa(fpS(sinx));			// 指定された信号を出力
+	GPIOC->BSRR = (sinx >= 0) ?	// 同期信号を出力
+				  0x1 : 0x10000;
 
-    phi_ += dPhi_;
-    if (phi_ >= C0_2_) phi_ -= C0_; // オーバーフロー防止
+	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 割り込み:次に優先
+	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")
-                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);
-        }
-    }
+	timer_.Attach(&TimerIsr);		// タイマ割り込み設定
+	
+	while (true)	// PC からの指令に対応する処理
+	{
+		if (rxTx.IsEol())			// 受信バッファのデータが有効になった場合の処理
+		{
+			string str = rxTx.GetBuffer();
+			if (str == "FG")
+				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);
+		}
+	}
 }
\ No newline at end of file