ファンクション・ジェネレータ.出力信号:正弦波,矩形波,矩形波 (5倍波まで).ノイズの付加が可能.

Dependencies:   mbed SerialTxRxIntr Random

main.cpp

Committer:
MikamiUitOpen
Date:
2018-11-30
Revision:
5:5dca27575a3d
Parent:
4:925a2ab34c03
Child:
6:acd06b435799

File content as of revision 5:5dca27575a3d:

//----------------------------------------------------------------------
//  ファンクション・ジェネレータ (Function generator)
//
//  設定できる項目
//      波形の種類:  正弦波,矩形波,矩形波(フーリエ級数の5倍波までの和)
//      振幅:         0.00 ~ 1.00 倍
//      周波数:       10 Hz ~ 5 kHz
//      ノイズ付加の有無
//  標本化間隔:5 μs
//  使用タイマ:TIM7
//  信号出力のピン:    A3
//  同期信号出力のピン:  A5
//
//  PC 側のプログラム
//      F446_FunctionGenerator
//      端末エミュレータでも使用可能(確認しているのは Tera Term のみ)
//
//  注意
//      コマンド等が不正であるかどうかは,PC 側の処理にゆだねられている.そのため,
//      端末エミュレータから操作する場合,不正なコマンド等に対しては,基本的に無視す
//      るようなプログラムになっている.
//      端末エミュレータからの Back Space キーの入力には対応していない.
//
//  2018/11/30, Copyright (c) 2018 MIKAMI, Naoki
//----------------------------------------------------------------------

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

using namespace Mikami;
                        
const int T0_ = 5;              // 出力の標本化間隔: 5 μs
const float TS_ = T0_*1.0e-6;
const float PI2_ = 3.141593f*2;
const float ONE_3_ = 1.0f/3.0f; // フーリエ級数の計算で使用
const float ONE_5_ = 0.2f;      // フーリエ級数の計算で使用

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

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

// ノイズ付加に関する関数等
GaussRand rnd(0.3f, 0);
float Noise() { return volNoize_*rnd.Next(); }
float NoiseFree() { return 0; }
float (*fpNoize[])() = { Noise, NoiseFree };
float (*fpN)() = fpNoize[1];    // 起動時はノイズなし 

// 発生する信号を定義する関数
// 正弦波
float Sin(float sinx) { return volume_*sinx + volNoize_*fpN(); }
// 矩形波
float Rect(float sinx)
{
    sinx = (sinx >= 0) ? volume_ : -volume_;
    return sinx + volNoize_*fpN();
}
// 矩形波(5倍波まで)
float Compo(float sinx)
{   return volume_*(sinx + ONE_3_*sinf(3*phi_) + ONE_5_*sinf(5*phi_))
           + volNoize_*fpN(); }

float (*fp[])(float x) = { Sin, Rect, Compo };
float (*fpS)(float x) = fp[0];  // 起動時は正弦波

// タイマ割り込みに対する割込みサービス・ルーチン
void TimerIsr()
{
    float sinx = sinf(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_ >= PI2_) phi_ = phi_ - PI2_;   // オーバーフロー防止
}

int main()
{
    // 以下の割り込み優先順位の設定を忘れないこと
    NVIC_SetPriority(TIM7_IRQn, 0);
    NVIC_SetPriority(USART2_IRQn, 1);   // USART2 割り込み:次に優先
    
    rxTx_.EchobackEnable();     // エコーバックを有効にする

    printf("\r\n\n+-------------------------------------------------------------------+\r\n");
    printf("| Microcontroller-based function generator, (C) MIKAMI, Naoki 2018. |\r\n");
    printf("|     You can alse use with terminal emulator like Tera Term.       |\r\n");
    printf("|     You can use lowercase letters as command.                     |\r\n");
    printf("+-------------------------------------------------------------------+\r\n\n");
    printf("<Command>\r\n");
    printf("ON    Ountput enabled.\r\n");
    printf("OFF   Ountput disabled.\r\n");
    printf("SIN   Output: Sinusoidal wave.\r\n");
    printf("RECT  Output: Square wave.\r\n");
    printf("COMPO Output: Square wave (Sum of up to 5th harmonics).\r\n");
    printf("NsOn  With noize.\r\n");
    printf("NsOff Without noise.\r\n\n");
    printf("<Command with numeric value (n: 0 to 9)>\r\n");
    printf("#+'n.nn'  Relative ampliude of output: 0.00 to 1.00.\r\n");
    printf("$+'nnnn'  Frequency: 10 to 5000 [Hz].\r\n");
    printf("%%+'n.nn'  Relative magnitude of noize: 0.00 to 1.00.\r\n\n");
    rxTx_.Tx("? ");
    
    timer_.Attach_us(&TimerIsr, T0_);   // タイマ割り込み設定
    
    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_.Tx("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 < 1.0f) ? x : 1.0f;
                    if (c1 == '$')              // 周波数の変更
                    {
                        x = (x < 10) ? 10 : x;
                        x = (x > 5000) ? 5000 : x;
                        dPhi_ = PI2_*x*TS_;
                    }
                    if (c1 == '%')              // ノイズの大きさの変更
                        volNoize_ = (x < 1.0f) ? x : 1.0f;
                }
            }
            rxTx_.Tx("? ");
        }
    }
}