Realtime sound spectrogram using FFT or linear prediction. Spectrogram is displayed on the display of PC. リアルタイム・スペクトログラム.解析の手法:FFT,線形予測法.スペクトログラムは PC のディスプレー装置に表示される.PC 側のプログラム:F446_Spectrogram.

Dependencies:   Array_Matrix mbed SerialTxRxIntr F446_AD_DA UIT_FFT_Real

Files at this revision

API Documentation at this revision

Comitter:
MikamiUitOpen
Date:
Fri Feb 17 04:55:10 2017 +0000
Child:
1:cc596a8d40c9
Commit message:
1

Changed in this revision

Array_Matrix.lib Show annotated file Show diff for this revision Revisions of this file
F446_AD_DA.lib Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/AnalyzerBase.cpp Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/AnalyzerBase.hpp Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/FFT_Analyzer.cpp Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/FFT_Analyzer.hpp Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/Hamming.hpp Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/LPC_Analyzer.cpp Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/LPC_Analyzer.hpp Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/LinearPrediction.cpp Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/LinearPrediction.hpp Show annotated file Show diff for this revision Revisions of this file
UIT_FFT_Real.lib 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
mbed.bld Show annotated file Show diff for this revision Revisions of this file
myFunctions.cpp Show annotated file Show diff for this revision Revisions of this file
myFunctions.hpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Array_Matrix.lib	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/MikamiUitOpen/code/Array_Matrix/#a25dba17218c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/F446_AD_DA.lib	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/MikamiUitOpen/code/F446_AD_DA/#d1da91aec62f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/AnalyzerBase.cpp	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,27 @@
+//-------------------------------------------------------
+//  Base abstract class for spectrum analysis
+//
+//  2017/02/09, Copyright (c) 2017 MIKAMI, Naoki
+//-------------------------------------------------------
+
+#include "AnalyzerBase.hpp"
+
+namespace Mikami
+{
+    AnalyzerBase::AnalyzerBase(int nData, int nFft, int nUse)
+        : N_DATA_(nData), N_FFT_(nFft),
+          fft_(nFft), wHm_(nData-1, nUse), b1_(1.0f),
+          xData_(nUse), wData_(nUse) {}
+
+    void AnalyzerBase::Execute(const float xn[], float db[])
+    {
+        // 高域強調
+        for (int n=0; n<N_DATA_-1; n++)
+            xData_[n] = xn[n+1] - b1_*xn[n];
+            
+        // 窓掛け
+        wHm_.Execute(xData_, wData_);
+            
+        Analyze(wData_, db);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/AnalyzerBase.hpp	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,52 @@
+//-------------------------------------------------------
+//  Base abstract class for spectrum analysis (Header)
+//
+//  2017/02/09, Copyright (c) 2017 MIKAMI, Naoki
+//-------------------------------------------------------
+
+#ifndef BASE_ANALYZER_HPP
+#define BASE_ANALYZER_HPP
+
+#include "Array.hpp"
+#include "fftReal.hpp"
+#include "Hamming.hpp"
+
+namespace Mikami
+{
+    class AnalyzerBase
+    {
+    public:
+        // nData: Number of data to be analyzed
+        // nFft:  Number of FFT points
+        // nUse:  FFT, cepstrum: window width + zero padding
+        //        Linear prediction: window width
+        AnalyzerBase(int nData, int nFft, int nUse);
+        virtual ~AnalyzerBase() {}
+        void Execute(const float xn[], float db[]);
+        // 高域強調の程度を決める定数の設定(b1 = 1 で差分,b1 = 0 で高域強調なし)
+        void SetHighEmphasizer(float b1) { b1_ = b1; }
+
+    protected:
+        const int N_DATA_;
+        const int N_FFT_;
+
+        FftReal fft_;
+                
+        float Norm(Complex x)
+        { return x.real()*x.real() + x.imag()*x.imag(); }
+
+    private:
+        HammingWindow wHm_;
+        float b1_;
+
+        Array<float> xData_;    // data to be analyzed
+        Array<float> wData_;    // windowd data
+
+        virtual void Analyze(const float wData[], float db[]) = 0;
+
+        // disallow copy constructor and assignment operator
+        AnalyzerBase(const AnalyzerBase& );
+        AnalyzerBase& operator=(const AnalyzerBase& );
+    };
+}
+#endif  // BASE_ANALYZER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/FFT_Analyzer.cpp	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,23 @@
+//-------------------------------------------------------
+//  Class for spectrum analysis using FFT
+//
+//  2017/02/04, Copyright (c) 2017 MIKAMI, Naoki
+//-------------------------------------------------------
+
+#include "FFT_Analyzer.hpp"
+
+namespace Mikami
+{
+    FftAnalyzer::FftAnalyzer(int nData, int nFft)
+        : AnalyzerBase(nData, nFft, nFft),
+          yFft_(nFft/2+1) {}
+
+    void FftAnalyzer::Analyze(const float xn[], float yn[])
+    {
+        fft_.Execute(xn, yFft_);    // Execute FFT
+        
+        // Translate to dB
+        for (int n=0; n<=N_FFT_/2; n++)
+            yn[n] = 10.0f*log10f(Norm(yFft_[n]));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/FFT_Analyzer.hpp	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,31 @@
+//-------------------------------------------------------
+//  Class for spectrum analysis using FFT (Header)
+//
+//  2017/02/04, Copyright (c) 2017 MIKAMI, Naoki
+//-------------------------------------------------------
+
+#ifndef FFT_ANALYZER_HPP
+#define FFT_ANALYZER_HPP
+
+#include "AnalyzerBase.hpp"
+
+namespace Mikami
+{
+    class FftAnalyzer : public AnalyzerBase
+    {
+    public:
+        FftAnalyzer(int nData, int nFft);
+        virtual ~FftAnalyzer() {}
+
+    private:
+        Array<Complex> yFft_;   // output of FFT
+
+        virtual void Analyze(const float xn[], float yn[]);
+
+        // disallow copy constructor and assignment operator
+        FftAnalyzer(const FftAnalyzer& );
+        FftAnalyzer& operator=(const FftAnalyzer& );
+    };
+}
+
+#endif  // FFT_ANALYZER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/Hamming.hpp	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,48 @@
+//-------------------------------------------------------------------
+//  Hamming windowing with zero-padding
+//
+//  2016/07/23, Copyright (c) 2016 MIKAMI, Naoki
+//-------------------------------------------------------------------
+
+#ifndef HAMMING_WINDOW_HPP
+#define HAMMING_WINDOW_HPP
+
+#include "mbed.h"
+#include "Array.hpp"
+
+namespace Mikami
+{
+    class HammingWindow
+    {
+    public:
+        // Constructor
+        HammingWindow(uint16_t nData, uint16_t nFft)
+                : N_(nData), NFFT_(nFft), w_(nData)
+        {
+            float pi2L = 6.283185f/(float)nData;
+            for (int k=0; k<nData; k++)
+                w_[k] = 0.54f - 0.46f*cosf(k*pi2L);
+        }
+        
+        // Destructor
+        virtual ~HammingWindow() {}
+        
+        // Windowing
+        void Execute(const float x[], float y[])
+        {
+            for (int n=0; n<N_; n++) y[n] = x[n]*w_[n];
+            for (int n=N_; n<NFFT_; n++) y[n] = 0;
+        }
+
+    private:
+        const int N_;
+        const int NFFT_;
+                
+        Array<float> w_;
+
+        // disallow copy constructor and assignment operator
+        HammingWindow(const HammingWindow& );
+        HammingWindow& operator=(const HammingWindow& );
+    };
+}
+#endif  // HAMMING_WINDOW_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/LPC_Analyzer.cpp	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,31 @@
+//-------------------------------------------------------
+//  Class for spectrum analysis using linear prediction
+//
+//  2017/02/11, Copyright (c) 2017 MIKAMI, Naoki
+//-------------------------------------------------------
+
+#include "LPC_Analyzer.hpp"
+
+namespace Mikami
+{
+    LpcAnalyzer::LpcAnalyzer(int nData, int nFft, int order)
+        : AnalyzerBase(nData, nFft, nData-1), order_(order),
+          lp_(nData-1, order),
+          an_(order), xFft_(nFft), yFft_(nFft/2+1) {}
+
+    void LpcAnalyzer::Analyze(const float xn[], float yn[])
+    {
+        float em;
+        lp_.Execute(xn, an_, em);
+
+        // To spectrum
+        xFft_[0] = 1.0f;
+        for (int n=0; n<order_; n++) xFft_[n+1] = -an_[n];
+        for (int n=order_+1; n<N_FFT_; n++) xFft_[n] = 0.0f;
+        fft_.Execute(xFft_, yFft_); // execute FFT
+
+        // Translate to dB
+        for (int n=0; n<=N_FFT_/2; n++)
+            yn[n] = 10.0f*log10f(em/Norm(yFft_[n]));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/LPC_Analyzer.hpp	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,36 @@
+//---------------------------------------------------------------
+//  Class for spectrum analysis using linear prediction (Header)
+//
+//  2017/02/11, Copyright (c) 2017 MIKAMI, Naoki
+//---------------------------------------------------------------
+
+#ifndef LPC_ANALYZER_HPP
+#define LPC_ANALYZER_HPP
+
+#include "AnalyzerBase.hpp"
+#include "LinearPrediction.hpp"
+
+namespace Mikami
+{
+    class LpcAnalyzer : public AnalyzerBase
+    {
+    public:
+        LpcAnalyzer(int nData, int nFft, int order);
+        virtual ~LpcAnalyzer() {}
+        
+    private:
+        int order_;
+        LinearPred lp_;
+
+        Array<float> an_;       // predictor coefficient 
+        Array<float> xFft_;     // input for FFT
+        Array<Complex> yFft_;   // output of FFT
+
+        virtual void Analyze(const float xn[], float yn[]);
+
+        // disallow copy constructor and assignment operator
+        LpcAnalyzer(const LpcAnalyzer& );
+        LpcAnalyzer& operator=(const LpcAnalyzer& );
+    };
+}
+#endif  // LPC_ANALYZER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/LinearPrediction.cpp	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,62 @@
+//-----------------------------------------------------
+//  Class for linear prediction
+//
+//  2017/02/11, Copyright (c) 2017 MIKAMI, Naoki
+//-----------------------------------------------------
+
+#include "LinearPrediction.hpp"
+
+namespace Mikami
+{
+    LinearPred::LinearPred(int nData, int order)
+        : N_DATA_(nData), order_(order),
+          r_(order+1), k_(order), am_(order) {}
+
+    // Calculate linear-predictive coefficients
+    bool LinearPred::Execute(const float x[], float a[],
+                             float &em)
+    {
+        AutoCorr(x);
+        return Durbin(a, em);
+    }
+
+    // Calculate auto-correlation
+    void LinearPred::AutoCorr(const float x[])
+    {
+        for (int j=0; j<=order_; j++)
+        {
+            r_[j] = 0.0;
+            for (int n=0; n<N_DATA_-j; n++)
+                r_[j] = r_[j] + x[n]*x[n+j];
+        }
+    }
+
+    // Levinson-Durbin algorithm
+    bool LinearPred::Durbin(float a[], float &em)
+    {
+        // Initialization
+        em = r_[0];
+
+        // Repeat
+        for (int m=0; m<order_; m++)
+        {
+            float w = r_[m+1];
+            for (int j=0; j<=m-1; j++)
+                w = w - r_[m-j]*a[j];
+
+            k_[m] = w/em;
+            em = em*(1 - k_[m]*k_[m]);
+
+            if (em < 0) break;  // Error for negative squared sum of residual
+
+            a[m] = k_[m];
+            for (int j=0; j<=m-1; j++)
+                am_[j] = a[j];
+            for (int j=0; j<=m-1; j++)
+                a[j] = am_[j] - k_[m]*am_[m-j-1];
+        }
+
+        if (em < 0) return false;
+        else        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/LinearPrediction.hpp	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,37 @@
+//-----------------------------------------------------
+//  Class for linear prediction (Header)
+//
+//  2017/02/11, Copyright (c) 2017 MIKAMI, Naoki
+//-----------------------------------------------------
+
+#ifndef LINEAR_PREDICTION_HPP
+#define LINEAR_PREDICTION_HPP
+
+#include "Array.hpp"
+
+namespace Mikami
+{
+    class LinearPred
+    {
+    public:
+        LinearPred(int nData, int order);
+        ~LinearPred() {}
+        bool Execute(const float x[], float a[], float &em);
+    private:
+        const uint16_t N_DATA_;
+
+        uint16_t order_;
+
+        Array<float> r_;    // for auto-correlation
+        Array<float> k_;    // for PARCOR coefficients
+        Array<float> am_;   // working area
+
+        void AutoCorr(const float x[]);
+        bool Durbin(float a[], float &em);
+
+        // disallow copy constructor and assignment operator
+        LinearPred(const LinearPred& );
+        LinearPred& operator=(const LinearPred& );
+    };
+}
+#endif  // LINEAR_PREDICTION_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UIT_FFT_Real.lib	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/MikamiUitOpen/code/UIT_FFT_Real/#9649d0e2bb4a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,192 @@
+//---------------------------------------------------------------------
+//  スペクトログラム (Nucleo-F446RE 用),条件等を PC から受け取るテスト
+//
+//      ● ST-Link Firmware の V2.J28.M16 で動作確認
+//
+//      ● ST-Link Firmware のアップグレードには stsw-link07.zip
+//        に含まれている "ST-LinkUpgrade.exe" を使う 
+//
+//      ● PC 側のプログラム: "F446_Spectrogram"
+//      ● ボーレート: 460800 baud
+//      ● 受信データの文字列の終了マーク: "\r"
+//
+//  2017/02/17, 三上 直樹
+//---------------------------------------------------------------------
+
+#include "mbed.h"
+#include <string>
+#include "myFunctions.hpp"
+#include "Array.hpp"
+#include "F446_ADC_Interrupt.hpp"
+#include "FFT_Analyzer.hpp"
+#include "LPC_Analyzer.hpp"
+using namespace Mikami;
+
+#ifndef __STM32F446xx_H
+#error "Use Nucleo-F446RE"
+#endif
+
+const int N_FFT_ = 512;             // FFT の点数
+const int N_DATA_ = N_FFT_ + 1;     // スペクトル解析に使うデータ数(差分処理を考慮)
+const int N_FRAME_ = N_FFT_/2 + 1;  // 1フレーム当たり標本化するデータ数
+const int N_FFT_2_ = N_FFT_/2;      // FFT の点数の半分
+const float AMP_ = 1.0f/2048.0f;    // uint16_t 型のデータを float 型に変換する際の定数
+
+uint16_t xPing_[N_FRAME_];  // 標本化したデータのバッファ1
+uint16_t xPong_[N_FRAME_];  // 標本化したデータのバッファ2
+uint16_t *inPtr_ = xPing_;  // AD 変換データの格納先を指すポインタ
+uint16_t *outPtr_ = xPing_; // 取り出すデータを指すポインタ
+
+__IO int inCount_ = 0;      // 入力データのカウンタ
+__IO int pingPong_ = 0;     // 入力データの格納先,0: xPing_[], 1: xPong_[]
+__IO bool full_ = false;    // AD 変換データが満杯のとき true
+
+const int FS_ = 16000;      // 標本化周波数: 16 kHz
+AdcDual_Intr myAdc_(FS_);   // "F446_ADC_Interrupt.hpp" で定義
+DacDual myDac_;             // "F446_DAC" で定義
+
+// FFT によるスペクトル解析オブジェクトの生成
+FftAnalyzer *fftAnlz_ = new FftAnalyzer(N_DATA_, N_FFT_);
+// 線形予測法 によるスペクトル解析オブジェクトの生成
+LpcAnalyzer *lpcAnlz_ = new LpcAnalyzer(N_DATA_, N_FFT_, 20);
+AnalyzerBase *analyzer_ = fftAnlz_;
+
+Serial pc_(USBTX, USBRX);   // PC との通信で使うオブジェクト
+DigitalOut myLed_(D10, 1);  // LED1 が使えないので D10 を使う
+
+DigitalOut pulse(D2, 0);    // 時間測定用
+
+const int DATA_SIZE_ = N_FFT_/2 + 1;
+Array<int16_t> txData_(DATA_SIZE_); // 送信用データ
+string rxBuffer_;           // 受信バッファ
+float levelShift_ = 20;     // dB 計算の際のシフト量の初期値
+float empha_ = 0.8f;        // 高域強調器の係数
+
+__IO bool eol_;             // "\r" を受信した場合に true
+
+// 入力チャンネルを選択する関数とそれを割り当てる関数ポインタ
+float InputL(float x1, float x2) { return x1; }
+float InputR(float x1, float x2) { return x2; }
+float InputLR(float x1, float x2) { return (x1 + x2)/2; }
+typedef float (*FP_INPUT)(float, float);
+FP_INPUT InputCurrent = InputLR;    // 最初は左右チャンネルを使う
+FP_INPUT InputNew = InputCurrent;
+
+// ADC 変換終了割り込みに対する割り込みサービス・ルーチン
+void AdcIsr()
+{
+    uint16_t sn1, sn2;
+    myAdc_.Read(sn1, sn2);
+    uint16_t xn = InputCurrent(sn1, sn2);
+    inPtr_[inCount_] = xn;
+    myDac_.Write(xn, xn);
+
+    if (++inCount_ >= N_FRAME_) // データが満杯か調べる
+    {
+        full_ = true;           // データが満杯
+        inCount_ = 0;           // 以降のデータ取得のため
+        pingPong_ = (pingPong_+1) & 0x01;               // バッファの切り替えのため
+        inPtr_ = (pingPong_ == 0) ? xPing_ : xPong_;    // バッファのポインタ指定
+        InputCurrent = InputNew;                // 入力の切り替え
+        analyzer_->SetHighEmphasizer(empha_);   // 高域強調の有無の指令
+    }
+}
+
+int main()
+{
+    float sn[N_DATA_];      // スペクトル解析の対象となるデータ
+    float db[N_FRAME_];     // 解析結果である対数スペクトル [dB]
+    for (int n=0; n<N_DATA_; n++) sn[n] = 0;
+    for (int n=0; n<N_FRAME_; n++) xPong_[n] = 2048;    // uint16_t 型の 0 に対応
+
+    rxBuffer_ = "";     // 受信バッファのクリア
+    eol_ = false;
+
+    pc_.baud(115200*4); // ボーレートの設定
+    pc_.format();       // default: 8 bits, nonparity, 1 stop bit
+
+    NVIC_SetPriority(ADC_IRQn, 1);      // AD変換終了割り込みの優先度が最高
+    NVIC_SetPriority(USART2_IRQn, 2);
+
+    pc_.attach(&Rx);            // 受信割り込みの割り当て
+
+    full_ = false;
+    myAdc_.SetIntrVec(&AdcIsr); // AD変換終了割り込みの割り当て
+
+    __IO bool ready = false;    // スペクトルの計算終了で true
+    __IO bool okGo = false;     // "GO" を受信したら true
+    while (true)
+    {
+        // PC からのコマンド解析
+        if (eol_)
+        {
+            if (rxBuffer_.find("ENQ") != string::npos)
+                pc_.printf("ACK\n");    // "ACK" を PC へ転送
+            else if (rxBuffer_.find("GO") != string::npos)
+            {
+                // rxBuffer_ の内容
+                // [0]  'G'
+                // [1]  'O'
+                // [2]  入力チャンネルの選択:'L', 'R', or '+'
+                // [3]  スペクトルの値のレベルシフト:' ' ~ 'I' が -20 ~ 20 に対応
+                // [4]  高域強調器の有無:'Y', 'N'
+                // [5]  解析方法  F: FFT,L: 線形予測法
+
+                switch (rxBuffer_[2])   // 'L', 'R', or '+'
+                {
+                    case 'L': InputNew = InputL;  break;
+                    case 'R': InputNew = InputR;  break;
+                    case '+': InputNew = InputLR; break;
+                    default : InputNew = InputLR; break;
+                }
+
+                levelShift_ = (float)(rxBuffer_[3] - ' ');  // dB 計算の際のシフト量
+
+                if (rxBuffer_[4] == 'Y') empha_ = 0.8f;     // 高域強調器は有
+                else                     empha_ = 0;        // 高域強調器は無
+
+                if (rxBuffer_[5] == 'F') analyzer_ = fftAnlz_;  // FFT
+                else                     analyzer_ = lpcAnlz_;  // 線形予測法
+ 
+                okGo = true;            // データの転送要求あり
+            }
+
+            eol_ = false;
+            rxBuffer_ = "";     // 受信バッファのクリア
+            wait_ms(1);
+        }
+
+        if (full_)  // 入力データが満杯かどうか調べる
+        {
+            full_ = false;
+
+            outPtr_ = (pingPong_ == 1) ? xPing_ : xPong_;
+            // フレームの後半のデータを前半に移動する
+            for (int n=0; n<N_FFT_2_; n++)
+                sn[n] = sn[n+N_FRAME_];
+            // フレームの後半には新しいデータを格納する
+            for (int n=0; n<N_FRAME_; n++)
+                sn[n+N_FFT_2_] = AMP_*(outPtr_[n] - 2048);
+
+            analyzer_->Execute(sn, db); // スペクトル解析の実行
+
+            const float FACTOR = 4095.0f/60.0f;     // 表示範囲: 0 ~ 60 dB
+            for (int n=0; n<DATA_SIZE_; n++)
+            {
+                int16_t spc = (int16_t)(FACTOR*(db[n] + 30.0f + levelShift_));
+                if (spc > 4095) spc = 4095;
+                if (spc < 0) spc = 0;
+                txData_[n] = spc;
+            }
+            ready = true;       // スペクトル解析終了
+        }
+
+        // 転送要求がありスペクトル解析が終了している場合にデータを PC へ転送する
+        if (okGo && ready)
+        {
+            Xfer(txData_);      // データを PC へ転送
+            ready = false;
+            okGo = false;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/ef9c61f8c49f
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/myFunctions.cpp	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,31 @@
+#include "myFunctions.hpp"
+
+// シリアル・ポートの受信割り込み
+void Rx()
+{
+    unsigned char chr = pc_.getc();
+    // '\r' を受信した場合はメッセージの終了とする
+    // '\r' は,rxBuffer_ には追加されない
+    if (chr == '\r') eol_ = true;
+    else             rxBuffer_ += chr;  // '\r' が来るまで文字が追加される
+
+    // 受信するメッセージの文字数のチェック
+    if (rxBuffer_.size() > RX_MAX_)
+        while (true)    // 文字数がオーバーの場合 LED が点滅する
+        {
+            myLed_ = !myLed_;
+            wait(0.1f);
+        }
+}
+
+// データを PC へ転送(12 ビットを 2 文字で表すコード化を利用)
+void Xfer(Array<int16_t> &xn)
+{
+    for (int n=0; n<xn.Length(); n++)
+        pc_.printf("%c%c", ((xn[n] & 0xFC0) >> 6) + ' ',
+                           (xn[n] & 0x3F) + ' ');
+
+    pc_.printf("\n");       // データの最後を通知
+    wait_ms(1);             // これは必須
+    pc_.printf("EOT\n");    // 転送終了であることを送信
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/myFunctions.hpp	Fri Feb 17 04:55:10 2017 +0000
@@ -0,0 +1,22 @@
+#include "mbed.h"
+#include <string>
+#include "Array.hpp"
+using namespace Mikami;
+
+#ifndef MY_FUNCTIONS_HPP
+#define MY_FUNCTIONS_HPP
+
+const int RX_MAX_ = 32;     // 受信バッファの文字数の最大値
+
+extern string rxBuffer_;    // 受信バッファ
+extern __IO bool eol_;      // "\r" を受信した場合に true
+
+extern Serial pc_;
+extern DigitalOut myLed_;
+
+// シリアル・ポートの受信割り込み
+void Rx();
+// データを PC へ転送
+void Xfer(Array<int16_t> &xn);
+
+#endif  // MY_FUNCTIONS_HPP