ファンクション・ジェネレータ このプログラムの説明は,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
diff -r 53c0fa8a9aa2 -r 0430f1ed6c2c MSeq16.hpp
--- 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
diff -r 53c0fa8a9aa2 -r 0430f1ed6c2c main.cpp
--- 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