ファンクション・ジェネレータ

Dependencies:   mbed SerialTxRxIntr MyTicker7 Array_Matrix

main.cpp

Committer:
MikamiUitOpen
Date:
2020-12-23
Revision:
1:ea5aa7f3d68c
Parent:
0:17c762b41fc7

File content as of revision 1:ea5aa7f3d68c:

//----------------------------------------------------------------------
//  ファンクション・ジェネレータ (Nucleo-F446RE 用)
//
//  設定できる項目
//      波形の種類:  正弦波,矩形波,合成矩形波(フーリエ級数の5倍波までの和)
//      振幅:         0.00 ~ 1.00 倍
//      周波数:       10 Hz ~ 10 kHz
//      ノイズ付加の有無
//  標本化間隔:2.5 μs
//  使用タイマ:TIM7
//  信号出力のピン:      A2
//  同期信号出力のピン:  A5
//
//  このプログラムの前のバージョン:F446_FunctionGenerator_7
//
//  PC 側のプログラム
//      F446_FunctionGenerator
//
//  注意
//      PC から送信されるコマンド等が不正かどうかはチェックしていない
//
//  2020/12/23, Copyright (c) 2020 MIKAMI, Naoki
//----------------------------------------------------------------------

#include "F446_DAC.hpp"
#include "SerialRxTxIntr.hpp"
#include "MyTicker7.hpp"
#include "FastSin.hpp"
#include "MSeq16.hpp"
#include "IIR_Cascade.hpp"
#include "CoefficientsIIR_Cascade.hpp"
#include  <cctype>          // isalpha() で使用
#pragma diag_suppress 870   // マルチバイト文字使用の警告抑制のため

using namespace Mikami;
                        
const float T0_ = 2.5f;         // 出力の標本化間隔: 2.5 μs
const float TS_ = T0_*1.0e-6f;
const float C0_ = 4.0f;
const float C0_2_ = C0_/2.0f;

DacF446 dac_;                   // DA 変換器オブジェクト
MyTicker7 timer_(T0_);          // タイマ割り込み用クラスのオブジェクト,TIM7 を利用
SerialRxTxIntr rxTx_;           // Serial クラスの受送信割込み用オブジェクト
DigitalOut syncOut_(A5);        // 同期信号出力用

float phi_ = 0;
float dPhi_ = C0_*1000*TS_;     // 周波数決める変数,開始時は 1 kHz;
float volume_ = 0.5f;           // 出力の振幅を決める変数,開始時は 0.5
bool sw_ = false;               // 出力 ON/OFF のスイッチ,開始時は off
float volNoize_ = 0.5f;         // ノイズの大きさを決める変数

// ノイズ付加に関する関数等
MSeq16 mSeq_;
IirCascade filter_(ORDER_, hk_, G0_);
float Noise() { return volNoize_*filter_.Execute(0.5f*mSeq_.Execute()); }
float NoiseFree() { return 0; }
float (*fpNoize[])() = { Noise, NoiseFree };
float (*fpN)() = fpNoize[1];    // 起動時はノイズなし 

// 発生する信号を定義する関数
// 正弦波
float Sin(float sinx) { return volume_*sinx + fpN(); }
// 矩形波
float Rect(float sinx)
{
    float x = (sinx >= 0) ? volume_ : -volume_;
    return x + fpN();
}
// 矩形波(5倍波まで)
float Compo(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 (*fp[])(float x) = { Sin, Rect, Compo };
float (*fpS)(float x) = fp[0];  // 起動時は正弦波

// タイマ割り込みに対する割込みサービス・ルーチン
void TimerIsr()
{
    float sinx = FastSin(phi_); // 基本波発生
    float yn = fpS(sinx);       // 指定した信号を発生
    
    // 同期信号出力
    syncOut_ = (sinx >= 0) ? 1 : 0;

    if (sw_) dac_.Write(yn);    // 出力:ON
    else     dac_.Write(0.0f);  // 出力:OFF

    phi_ += dPhi_;
    if (phi_ >= C0_2_) phi_ = phi_ - C0_;   // オーバーフロー防止
}

int main()
{
    // 以下の割り込み優先順位の設定を忘れないこと
    NVIC_SetPriority(TIM7_IRQn, 0);
    NVIC_SetPriority(USART2_IRQn, 1);   // USART2 割り込み:次に優先

    timer_.Attach(&TimerIsr);       // タイマ割り込み設定
    
    while (true)    // PC からの指令に対応する処理
    {
        if (rxTx_.IsEol())          // 受信バッファのデータが有効になった場合の処理
        {
            string str = rxTx_.GetBuffer();
            for (int n=0; n<str.size(); n++) str[n] = toupper(str[n]);
            if (isalpha(str[0]))    // 先頭が A ~ Z, a ~ z の場合
            {
                if (str == "FG")
                    rxTx_.TxString("ACK\n");    // PC からの "FG" に対して "ACK" を送信する

                if (str == "ON")    sw_ = true;
                if (str == "OFF")   sw_ = false;  

                if (str == "SIN")   fpS = fp[0];
                if (str == "RECT")  fpS = fp[1];
                if (str == "COMPO") fpS = fp[2];

                if (str == "NSON")  fpN = fpNoize[0];
                if (str == "NSOFF") fpN = fpNoize[1];
            }
            else                    // 先頭が A ~ Z, a ~ z 以外の場合
            {
                char c1 = str[0];   // 先頭の文字を取得
                float x = atof(str.substr(1, str.size()-1).c_str());
                if (x >= 0.0f)
                {
                    if (c1 == '#')              // 出力振幅の変更
                        volume_ = x*0.9f;
                    if (c1 == '$')              // 周波数の変更
                    {
                        x = (x < 10) ? 10 : x;
                        x = (x > 10000) ? 10000 : x;
                        dPhi_ = C0_*x*TS_;
                    }
                    if (c1 == '%')              // ノイズの大きさの変更
                        volNoize_ = (x < 1.0f) ? x : 1.0f;
                }
            }
        }
    }
}