CW Decoder (Morse code decoder) 1st release version. Only run on Nucleo-F446RE mbed board.
Dependencies: Array_Matrix F446_AD_DA ST7565_SPI_LCD TextLCD UIT_FFT_Real
Fork of F446_MySoundMachine by
Base on F446_MySoundMachine program created by 不韋 呂-san.
Thanks to 不韋 呂-san making fundamental part such as FFT and ADC high speed interrupt driven program.
I just combined LCD and show CW code.
Revision 6:5e21ac9f0550, committed 2017-02-05
- Comitter:
- kenjiArai
- Date:
- Sun Feb 05 08:02:54 2017 +0000
- Parent:
- 5:503bd366fd73
- Commit message:
- CW Decoder (Morse code decoder) 1st release version. Only run on Nucleo-F446RE mbed board.
Changed in this revision
--- a/F446_AD_DA.lib Tue Jan 31 12:52:35 2017 +0000 +++ b/F446_AD_DA.lib Sun Feb 05 08:02:54 2017 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/MikamiUitOpen/code/F446_AD_DA/#d1da91aec62f +https://developer.mbed.org/users/kenjiArai/code/F446_AD_DA/#03e91e464ce5
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MySpectrogram/AnalysisBase.cpp Sun Feb 05 08:02:54 2017 +0000 @@ -0,0 +1,27 @@ +//------------------------------------------------------- +// Base abstract class for spectrum analysis +// +// 2016/07/23, Copyright (c) 2016 MIKAMI, Naoki +//------------------------------------------------------- + +#include "AnalysisBase.hpp" + +namespace Mikami +{ + AnalyzerBase::AnalyzerBase(int nData, int nFft, int nUse) + : N_DATA_(nData), N_FFT_(nFft), + fft_(nFft), wHm_(nData-1, nUse), + xData_(nUse), wData_(nUse) {} + + void AnalyzerBase::Execute(const float xn[], float db[]) + { + // Differencing + for (int n=0; n<N_DATA_-1; n++) + xData_[n] = xn[n+1] - 0.8f*xn[n]; + + // Windowing + wHm_.Execute(xData_, wData_); + + Analyze(wData_, db); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MySpectrogram/AnalysisBase.hpp Sun Feb 05 08:02:54 2017 +0000 @@ -0,0 +1,50 @@ +//------------------------------------------------------- +// Base abstract class for spectrum analysis (Header) +// +// 2016/07/23, Copyright (c) 2016 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[]); + + 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_; + + 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_Analysis.cpp Sun Feb 05 08:02:54 2017 +0000 @@ -0,0 +1,23 @@ +//------------------------------------------------------- +// Class for spectrum analysis using FFT +// +// 2016/07/23, Copyright (c) 2015 MIKAMI, Naoki +//------------------------------------------------------- + +#include "FFT_Analysis.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_Analysis.hpp Sun Feb 05 08:02:54 2017 +0000 @@ -0,0 +1,31 @@ +//------------------------------------------------------- +// Class for spectrum analysis using FFT (Header) +// +// 2016/07/23, Copyright (c) 2016 MIKAMI, Naoki +//------------------------------------------------------- + +#ifndef FFT_ANALYZER_HPP +#define FFT_ANALYZER_HPP + +#include "AnalysisBase.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 Sun Feb 05 08:02:54 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/MethodCollection.hpp Sun Feb 05 08:02:54 2017 +0000 @@ -0,0 +1,104 @@ +//-------------------------------------------------------------- +// スペクトログラムで使う大域関数 +// +// 2016/08/11, Copyright (c) 2016 MIKAMI, Naoki +//-------------------------------------------------------------- + +#ifndef METHOD_COLLECTION_HPP +#define METHOD_COLLECTION_HPP + +#include "mbed.h" +#include "NumericLabel.hpp" +#include "Matrix.hpp" +#include "FFT_Analysis.hpp" + +namespace Mikami +{ + // 色相の違いで表示 + // 0.0 <= x <= 1.0 + uint32_t HueScale(float x) + { + if (x >= 1) return LCD_COLOR_WHITE; + int r = 0; + int b = 0; + + if (x<0.5f) b = (x<0.33f) ? 255 : -(int)(1500.0f*x) + 750; + else r = (0.67f<x) ? 255 : (int)(1500.0f*x) - 750; + int g = 255 - (int)(1020.0f*(x - 0.5f)*(x - 0.5f)); + + return 0xFF000000 | (((r << 8) | g) << 8) | b; + } + + // 座標軸 + void DrawAxis(int x0, int y0, int w0, int h0, uint32_t axisColor, + uint16_t ms100, uint16_t px1kHz, LCD_DISCO_F746NG *lcd) + { + const uint16_t TICK = 5; // 目盛線の長さ + // 横標軸 + lcd->SetTextColor(axisColor); + lcd->DrawHLine(x0, y0+TICK, w0); + for (int n=0; n<=w0/ms100; n++) + if ((n % 10)== 0) lcd->DrawVLine(x0+n*ms100, y0, 5); + else lcd->DrawVLine(x0+n*ms100, y0+3, 2); + for (int n=0; n<=w0/ms100; n+=10) + NumericLabel<int> num(x0+n*ms100, y0+TICK+3, + "%1d", (int)(n*0.1f), Label::CENTER); + Label time(x0+w0/2, y0+22, "TIME [s]", Label::CENTER); + + // 縦標軸 + lcd->SetTextColor(axisColor); + lcd->DrawVLine(x0-TICK, y0-h0, h0); + for (int n=0; n<=h0/px1kHz; n++) + lcd->DrawHLine(x0-TICK, y0-n*px1kHz, TICK); + for (int n=0; n<=h0/px1kHz; n++) + NumericLabel<int> num(x0-TICK-12, y0-n*px1kHz-5, "%1d", n); + Label hz(x0-32, y0-5*px1kHz-20, "[kHz]"); + } + + // 色と dB の関係の表示 + void ColorDb(int y0, uint32_t axisColor, LCD_DISCO_F746NG *lcd) + { + lcd->SetTextColor(axisColor); + lcd->DrawVLine(455, y0-100, 100); + for (int n=0; n<=8; n++) + lcd->DrawHLine(455, y0-(n*100)/8, 4); + for (int n=0; n<=4; n++) + NumericLabel<int> num(440, y0-(n*100)/4-5, "%2d", n*20); + Label dB(432, y0-120, "[dB]"); + + for (int n=0; n<=100; n++) + { + lcd->SetTextColor(HueScale(n/100.0f)); + lcd->DrawHLine(460, y0-n, 16); + } + } + + // スペクトルの更新 + void SpectrumUpdate(Matrix<uint32_t> &x, FftAnalyzer &analyzer, + const Array<float> &sn, const Array<float> &db) + { + // 過去のスペクトルを一つずらす + for (int n=0; n<x.Rows()-1; n++) + for (int k=0; k<x.Cols(); k++) + x[n][k] = x[n+1][k]; + + // 新しいスペクトル + analyzer.Execute(sn, db); + const float FACTOR = 1.0f/80.0f; // 表示範囲: 0 ~ 80 dB + for (int k=0; k<=x.Cols(); k++) + x[x.Rows()-1][k] = HueScale(FACTOR*((db[k] > 20) ? db[k]-20 : 0)); + } + + // スペクトルの表示 + void DisplaySpectrum(const Matrix<uint32_t> &x, int x0, int y0, + int hBar, LCD_DISCO_F746NG *lcd) + { + for (int n=0; n<x.Rows(); n++) + for (int k=0; k<x.Cols(); k++) + { + lcd->SetTextColor(x[n][k]); + lcd->DrawHLine(x0+n*hBar, y0-k, hBar); + } + } +} +#endif // METHOD_COLLECTION_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ST7565_SPI_LCD.lib Sun Feb 05 08:02:54 2017 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/kenjiArai/code/ST7565_SPI_LCD/#7d03976a0cb3
--- a/SignalProcessing/BilinearDesignLH.cpp Tue Jan 31 12:52:35 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -//------------------------------------------------------------------------ -// Design of Butterworth LPF and HPF using bilinear transform -// -// 2016/03/31, Copyright (c) 2016 MIKAMI, Naoki -//------------------------------------------------------------------------ - -#include "BilinearDesignLH.hpp" - -namespace Mikami -{ - // Execute design - // input - // fc: Cutoff frequency - // pb: Passband (LPF or HPF) - // output - // c : Coefficients for cascade structure - // g : Gain factor for cascade structure - void BilinearDesign::Execute(float fc, Type pb, Coefs c[], float& g) - { - Butterworth(); - Bilinear(fc); - ToCascade(pb); - GetGain(pb); - GetCoefs(c, g); - } - - // Get poles for Butterworth characteristics - void BilinearDesign::Butterworth() - { - float pi_2order = PI_/(2.0f*ORDER_); - for (int j=0; j<ORDER_/2; j++) // Pole with imaginary part >= 0 - { - float theta = (2.0f*j + 1.0f)*pi_2order; - sP_[j] = Complex(-cosf(theta), sinf(theta)); - } - } - - // Bilinear transform - // fc: Cutoff frequency - void BilinearDesign::Bilinear(float fc) - { - float wc = tanf(fc*PI_FS_); - for (int k=0; k<ORDER_/2; k++) - zP_[k] = (1.0f + wc*sP_[k])/(1.0f - wc*sP_[k]); - } - - // Convert to coefficients for cascade structure - void BilinearDesign::ToCascade(Type pb) - { - for (int j=0; j<ORDER_/2; j++) - { - ck_[j].a1 = 2.0f*real(zP_[j]); // a1m - ck_[j].a2 = -norm(zP_[j]); // a2m - ck_[j].b1 = (pb == LPF) ? 2.0f : -2.0f; // b1m - ck_[j].b2 = 1.0f; // b2m - } - } - - // Calculate gain factor - void BilinearDesign::GetGain(Type pb) - { - float u = (pb == LPF) ? 1.0f : -1.0f; - float g0 = 1.0f; - for (int k=0; k<ORDER_/2; k++) - g0 = g0*(1.0f - (ck_[k].a1 + ck_[k].a2*u)*u)/ - (1.0f + (ck_[k].b1 + ck_[k].b2*u)*u); - gain_ = g0; - } - - // Get coefficients - void BilinearDesign::GetCoefs(Coefs c[], float& gain) - { - for (int k=0; k<ORDER_/2; k++) c[k] = ck_[k]; - gain = gain_; - } -}
--- a/SignalProcessing/BilinearDesignLH.hpp Tue Jan 31 12:52:35 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -//------------------------------------------------------------------------ -// Design of Butterworth LPF and HPF using bilinear transform -- Header -// -// 2016/03/31, Copyright (c) 2016 MIKAMI, Naoki -//------------------------------------------------------------------------ - -#ifndef BILINEAR_BUTTERWORTH_HPP -#define BILINEAR_BUTTERWORTH_HPP - -#include "mbed.h" -#include <complex> // requisite -#include "Array.hpp" - -namespace Mikami -{ - typedef complex<float> Complex; // define "Complex" - - class BilinearDesign - { - public: - struct Coefs { float a1, a2, b1, b2; }; - enum Type { LPF, HPF }; - - // Constructor - BilinearDesign(int order, float fs) - : PI_FS_(PI_/fs), ORDER_(order), - sP_(order/2), zP_(order/2), ck_(order/2) {} - - // Destractor - virtual ~BilinearDesign() {} - - // Execution of design - void Execute(float fc, Type pb, Coefs c[], float& g); - - private: - static const float PI_ = 3.1415926536f; - const float PI_FS_; - const int ORDER_; - - Array<Complex> sP_; // Poles on s-plane - Array<Complex> zP_; // Poles on z-plane - Array<Coefs> ck_; // Coefficients of transfer function for cascade form - - float gain_; // Gain factor for cascade form - - void Butterworth(); - void Bilinear(float fc); - void ToCascade(Type pb); - void GetGain(Type pb); - void GetCoefs(Coefs c[], float& gain); - }; -} -#endif // BILINEAR_BUTTERWORTH_HPP
--- a/SignalProcessing/Biquad.hpp Tue Jan 31 12:52:35 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -//-------------------------------------------------------------- -// 縦続形 IIR フィルタで使う 1D タイプの 2 次のフィルタ -// Biquad filter of 1D type for IIR filter of cascade structure -// このクラスでは,係数は実行中に書き換えられることを想定している -// -// u[n] = x[n] + a1*u[n-1] + a2*u[n-2] -// y[n] = u[n] + b1*u[n-1] + b2*u[n-2] -// x[n] : input signal -// y[n] : output signal -// b0 = 1 -// -// 2017/01/26, Copyright (c) 2017 MIKAMI, Naoki -//-------------------------------------------------------------- - -#ifndef IIR_BIQUAD_HPP -#define IIR_BIQUAD_HPP - -#include "mbed.h" - -// 2nd order IIR filter -namespace Mikami -{ - class Biquad - { - public: - struct Coefs { float a1, a2, b1, b2; }; - - Biquad(const Coefs ck = (Coefs){0, 0, 0, 0}) - { - SetCoefs(ck); - Clear(); - } - - void SetCoefs(const Coefs cf) { cf_ = cf; } - - void GetCoefs(Coefs &cf) { cf = cf_; } - - float Execute(float xn) - { - float un = xn + cf_.a1*un1_ + cf_.a2*un2_; - float yn = un + cf_.b1*un1_ + cf_.b2*un2_; - - un2_ = un1_; - un1_ = un; - - return yn; - } - - void Clear() { un1_ = un2_ = 0; } - - private: - Coefs cf_; - float un1_, un2_; - - // disallow copy constructor and assignment operator - Biquad(const Biquad&); - Biquad& operator=(const Biquad&); - }; -} -#endif // IIR_BIQUAD_HPP
--- a/SignalProcessing/Coefficients.hpp Tue Jan 31 12:52:35 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -//-------------------------------------------------------------- -// Weaver 変調器を使う周波数シフタで使っているフィルタの係数 -//-------------------------------------------------------------- - -#include "Biquad.hpp" - -using namespace Mikami; - -//-------------------------------------------------------------- -// 直流分除去フィルタの係数 -//-------------------------------------------------------------- -// 高域通過フィルタ -// バタワース特性 -// 次数 :2 次 -// 標本化周波数: 24.00 kHz -// 遮断周波数 : 0.05 kHz -const Mikami::Biquad::Coefs weaver_c1_ = - { 1.981489E+00f, -9.816583E-01f, -2.0f, 1.0f}; - -const float weaver_g0_ = 9.907867E-01f; - -//-------------------------------------------------------------- -// Weaver 変調器で使う低域通過フィルタの係数 -//-------------------------------------------------------------- -// 低域通過フィルタ -// 連立チェビシェフ特性 -// 次数 :8 次 -// 標本化周波数: 24.00 kHz -// 遮断周波数 : 4.90 kHz -// 通過域のリップル: 0.50 dB -// 阻止域の減衰量 :60.00 dB -const int WEAVER_ORDER_ = 8; // 次数 -const Biquad::Coefs weaver_ck_[WEAVER_ORDER_/2] = { - { 1.160215E+00f, -4.185278E-01f, 1.616618E+00f, 1.0f}, // 1段目 - { 8.636285E-01f, -6.678471E-01f, 3.656119E-01f, 1.0f}, // 2段目 - { 6.381001E-01f, -8.651304E-01f, -1.685791E-01f, 1.0f}, // 3段目 - { 5.524897E-01f, -9.656778E-01f, -3.300526E-01f, 1.0f} }; // 4段目 -const float weaver_g0Lpf_ = 1.299688E-02f; // 利得定数
--- a/SignalProcessing/IIR_Cascade.hpp Tue Jan 31 12:52:35 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -//-------------------------------------------------------------- -// IIR filter ---- Cascade structure - -// 2017/01/26, Copyright (c) 2017 MIKAMI, Naoki -//-------------------------------------------------------------- - -#ifndef IIR_CASCADE_HPP -#define IIR_CASCADE_HPP - -#include "mbed.h" -#include "Biquad.hpp" -#include "Array.hpp" -using namespace Mikami; - -namespace Mikami -{ - // IIR filter -- Cascade structure - class IirCascade - { - public: - IirCascade(int order, float g0 = 1, - const Biquad::Coefs ck[] = NULL) - : ORDER2_(order/2), hk_(order/2) - { - if (ck != NULL) SetCoefs(g0, ck); - else g0_ = g0; - } - - void SetCoefs(float g0, const Biquad::Coefs ck[]) - { - g0_ = g0; - for (int k=0; k<ORDER2_; k++) hk_[k].SetCoefs(ck[k]); - } - - void GetCoefs(float &g0, Biquad::Coefs ck[]) - { - g0 = g0_; - for (int k=0; k<ORDER2_; k++) hk_[k].GetCoefs(ck[k]); - } - - float Execute(float xn) - { - float yn = g0_*xn; - for (int k=0; k<ORDER2_; k++) - yn = hk_[k].Execute(yn); - - return yn; - } - - void Clear() - { - for (int k=0; k<ORDER2_; k++) - hk_[k].Clear(); - } - - private: - const int ORDER2_; - Array<Biquad> hk_; // Elements of cascade structure - float g0_; // gain factor - - // disallow copy constructor and assignment operator - IirCascade(const IirCascade&); - IirCascade& operator=(const IirCascade&); - }; -} -#endif // IIR_CASCADE_HPP
--- a/SignalProcessing/MyFunctions.hpp Tue Jan 31 12:52:35 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -//-------------------------------------------------------------------- -// STM32F446 と信号処理用ボードによるデモプログラムで使うグローバル関数 -// -// 2017/01/30, Copyright (c) 2017 MIKAMI, Naoki -//-------------------------------------------------------------------- - -#include "SignalProcessing.hpp" // 信号処理の抽象基底クラスなど -#include "AQM1602.hpp" -using namespace Mikami; - -extern SignalProcessing *spPtr_; // 処理に対応するポインタ - -// 機能の割り当てと表示 -void AssignDisplay(SignalProcessing &func, Aqm1602 &lcd, - char str[], float val = -1) -{ - spPtr_ = &func; // 機能の割り当て - - // 表示 - lcd.ClearLine(0); - lcd.ClearLine(1); - printf("%s", str); - lcd.WriteStringXY(str, 0, 0); - - if (val != -1) - { - printf(", %4.0f Hz", val); - lcd.WriteValueXY("%4.0f Hz", val, 0, 1); - } - printf("\r\n"); -} - -// 周波数変化が基準値より大きい場合に true を返す -// min <= frq <= max -// th : 基準値 -bool FrChange(AnalogIn &aIn, float min, float max, float th, float &frq) -{ - static float frqCurrent = 0; - frq = (max - min)*aIn.read() + min; - if (fabs(frq - frqCurrent) > th) - { - frqCurrent = frq; - return true; - } - else - return false; -}
--- a/SignalProcessing/ReverbUnit.hpp Tue Jan 31 12:52:35 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -//-------------------------------------------------------------- -// Reverb unit -// 2017/01/31, Copyright (c) 2017 MIKAMI, Naoki -//-------------------------------------------------------------- - -#ifndef REVERB_UNIT_HPP -#define REVERB_UNIT_HPP - -#include "mbed.h" -#include "Array.hpp" -namespace Mikami -{ - // Base class for reverb unit - class Reverb - { - public: - // Constructor - Reverb(int delay) : DELAY_(delay), un_(delay) - { - ptr_ = 0; - Clear(); - } - - ~Reverb() {} - - // Execute of filter (pure virtual function) - virtual float Execute(float x) = 0; - - // Clear internal delay elements - void Clear() - { for (int n=0; n<DELAY_; n++) un_[n] = 0; } - - protected: - float Get() { return un_[ptr_]; } - - void Set(float x) - { - un_[ptr_] = x; - if (++ptr_ >= DELAY_) ptr_ = 0; - } - - private: - const int DELAY_; - Array<float> un_; // for delay - int ptr_; - - // disallow copy constructor and assignment operator - Reverb(const Reverb&); - Reverb& operator=(const Reverb&); - }; - - // Reverb unit using comb filter - class CombFilter : public Reverb - { - public: - // Constructor - CombFilter(float g, int delay) - : Reverb(delay), G0_(g) {} - - // Execute comb filter - virtual float Execute(float x) - { - float yn = Reverb::Get(); - Reverb::Set(x + G0_*yn); - return yn; - } - - private: - const float G0_; - }; - - // Reverb unit using allpass filter - class AllPassFilter : public Reverb - { - public: - // Constructor - AllPassFilter(float g, int delay) - : Reverb(delay), G0_(g) {} - - // Execute allpass filter - virtual float Execute(float x) - { - float un = x + G0_*Reverb::Get(); - float yn = -G0_*un + Reverb::Get(); - Reverb::Set(un); - return yn; - } - - private: - const float G0_; - }; -} -#endif // REVERB_UNIT_HPP
--- a/SignalProcessing/Reverbrator.hpp Tue Jan 31 12:52:35 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -//-------------------------------------------------------------- -// 残響生成器 -// -// 2017/01/31, Copyright (c) 2017 MIKAMI, Naoki -//-------------------------------------------------------------- - -#ifndef ECHO_SYSTEM_HPP -#define ECHO_SYSTEM_HPP - -#include "ReverbUnit.hpp" - -class EchoSystem : public SignalProcessing -{ -public: - EchoSystem(float gC = 0.8f, float gA = 0.6f) - : G0_(1.0f - gC), - cmF1_(gC, 1759), cmF2_(gC, 1543), - cmF3_(gC, 1319), cmF4_(gC, 1301), - apF1_(gA, 241), apF2_(gA, 173) {} - - virtual float Execute(float xn1, float xn2) - { - float xn = G0_*(xn1 + xn2)*0.5f; - float yn = cmF1_.Execute(xn) + cmF2_.Execute(xn) - + cmF3_.Execute(xn) + cmF4_.Execute(xn); - yn = apF2_.Execute(apF1_.Execute(yn)); - yn = yn + xn; // add direct input signal - return yn; - } - -private: - const float G0_; - - CombFilter cmF1_, cmF2_, cmF3_, cmF4_; - AllPassFilter apF1_, apF2_; -}; -#endif // ECHO_SYSTEM_HPP
--- a/SignalProcessing/SignalProcessing.hpp Tue Jan 31 12:52:35 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -//-------------------------------------------------------------- -// 信号処理の抽象基底クラスおよびその派生クラスの中で簡単なクラス -// -// 2017/01/30, Copyright (c) 2017 MIKAMI, Naoki -//-------------------------------------------------------------- - -#ifndef SIGNAL_PROSECCING_BASE_CLASS_HPP -#define SIGNAL_PROSECCING_BASE_CLASS_HPP - -// 信号処理の抽象基底クラス -class SignalProcessing -{ -public: - virtual float Execute(float xn1, float xn2) = 0; -}; - -//--------------------------------------- -// 以下は派生クラス -//--------------------------------------- - -// 入力をそのまま出力する -class Through : public SignalProcessing -{ -public: - virtual float Execute(float xn1, float xn2) - { return (xn1 + xn2)*0.5f; } -}; - -// ボーカルキャンセラ -class VocalCanceller : public SignalProcessing -{ -public: - virtual float Execute(float xn1, float xn2) - { return xn1 - xn2; } -}; -#endif // SIGNAL_PROSECCING_BASE_CLASS_HPP
--- a/SignalProcessing/VariableLpHp.hpp Tue Jan 31 12:52:35 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -//-------------------------------------------------------------- -// 遮断周波数可変フィルタ,LPF と HPF -// -// 2017/01/30, Copyright (c) 2017 MIKAMI, Naoki -//-------------------------------------------------------------- - -#ifndef VARIABLE_LOWPASS_HIGHPASS_FILTER_HPP -#define VARIABLE_LOWPASS_HIGHPASS_FILTER_HPP - -#include "IIR_Cascade.hpp" -#include "SignalProcessing.hpp" -#include "BilinearDesignLH.hpp" -#include "Array.hpp" -using namespace Mikami; - -class VariableLpHp : public SignalProcessing -{ -public: - VariableLpHp(int order, float fs) - : ORDER2_(order/2), coefs_(order/2), coefsIir_(order/2), - designer_(order, fs), filter_(order) {} - - virtual float Execute(float xn1, float xn2) - { return filter_.Execute((xn1 + xn2)*0.5f); } - - void Design(float fc, BilinearDesign::Type passBand) - { - float g0; - designer_.Execute(fc, passBand, coefs_, g0); - for (int n=0; n<ORDER2_; n++) - coefsIir_[n] = *(Biquad::Coefs *)&coefs_[n]; - - filter_.SetCoefs(g0, coefsIir_); - filter_.Clear(); - } - -private: - const int ORDER2_; - - Array<BilinearDesign::Coefs> coefs_; - Array<Biquad::Coefs> coefsIir_; - - BilinearDesign designer_; - IirCascade filter_; -}; -#endif // VARIABLE_LOWPASS_HIGHPASS_FILTER_HPP
--- a/SignalProcessing/WeaverModulator.hpp Tue Jan 31 12:52:35 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -//-------------------------------------------------------------- -// Weaver 変調器 -// 入力信号の帯域: 0.1 kHz ---- 9.9 kHz -// 帯域中央の周波数: 5.0 kHz -// 低域通過フィルタの遮断周波数: 4.9 kHz - -// 2017/01/31, Copyright (c) 2017 MIKAMI, Naoki -//-------------------------------------------------------------- - -#ifndef WEAVER_MODULATOR_HPP -#define WEAVER_MODULATOR_HPP - -#include "IIR_Cascade.hpp" -#include "Coefficients.hpp" // Coeffisients of LPF and DC-cut filter -#include "Array.hpp" -using namespace Mikami; - -class FrqShifter : public SignalProcessing -{ -public: - FrqShifter(float fS) - : lpfC_(WEAVER_ORDER_, weaver_g0Lpf_, weaver_ck_), - lpfS_(WEAVER_ORDER_, weaver_g0Lpf_, weaver_ck_), - dcCut_(weaver_c1_), - FS_(fS), F_B_(5000) - { - lpfC_.Clear(); - lpfS_.Clear(); - - dPhi1_ = F_B_*PI2_/FS_; - dPhi2_ = dPhi1_; - phi1_ = 0; - phi2_ = 0; - } - - virtual float Execute(float xn1, float xn2) - { - float xn = (xn1 + xn2)*0.5f; - xn = dcCut_.Execute(weaver_g0_*xn); // DC 成分除去 - - float mpyC = xn*cosf(phi1_); - float mpyS = xn*sinf(phi1_); - - // LPF - float mpyC_Lpf = lpfC_.Execute(mpyC); - float mpyS_Lpf = lpfS_.Execute(mpyS); - - float mpyC_C = mpyC_Lpf*cosf(phi2_); - float mpyS_S = mpyS_Lpf*sinf(phi2_); - - float yn = 2.0f*(mpyC_C + mpyS_S); - - phi1_ = phi1_ + dPhi1_; - if (phi1_ > PI2_) phi1_ = phi1_ - PI2_; - phi2_ = phi2_ + dPhi2_; - if (phi2_ > PI2_) phi2_ = phi2_ - PI2_; - - return yn; - } - - // 周波数のシフト量を設定 - void SetFrequensy(float fShift) - { dPhi2_ = (fShift + F_B_)*PI2_/FS_; } - -private: - // Weaver 変調器で使う低域通過フィルタ - IirCascade lpfC_; - IirCascade lpfS_; - // 直流分除去フィルタ - Biquad dcCut_; - - static const float PI2_ = 3.1415926536f*2; - const float FS_; - const float F_B_; // 中心周波数 - - float phi1_, dPhi1_; - float phi2_, dPhi2_; -}; -#endif // WEAVER_MODULATOR_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TextLCD.lib Sun Feb 05 08:02:54 2017 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/kenjiArai/code/TextLCD/#986538f94abe
--- a/UIT_AQM1602.lib Tue Jan 31 12:52:35 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/MikamiUitOpen/code/UIT_AQM1602/#6e6c0f24e81f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UIT_FFT_Real.lib Sun Feb 05 08:02:54 2017 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/MikamiUitOpen/code/UIT_FFT_Real/#9649d0e2bb4a
--- a/main.cpp Tue Jan 31 12:52:35 2017 +0000 +++ b/main.cpp Sun Feb 05 08:02:54 2017 +0000 @@ -1,111 +1,479 @@ -//-------------------------------------------------------- -// STM32F446 と信号処理用ボードによる信号処理のデモプログラム -// -// SW: 偶数 入力をそのまま出力 -// 1: 遮断周波数可変 LPF -// 3: 遮断周波数可変 HPF -// 5: ボーカルキャンセラ -// 7: ピッチシフタ -// 9: 残響生成器 -// -// 2017/01/31, Copyright (c) 2017 MIKAMI, Naoki -//-------------------------------------------------------- +/* + * mbed program / cwdecoder using the FFT Algorithm + * tested on Nucleo-F446RE mbed board + * + * Modified by Kenji Arai + * http://www.page.sannet.ne.jp/kenjia/index.html + * http://mbed.org/users/kenjiArai/ + * + * Started: Feburary 1st, 2017 + * Revised: Feburary 5th, 2017 + * + * Reference program: + * 1) 2016/10/02, Copyright (c) 2016 MIKAMI, Naoki + * https://developer.mbed.org/users/MikamiUitOpen/code/F746_Spectrogram/ + * 2017/01/31, Copyright (c) 2017 MIKAMI, Naoki + * https://developer.mbed.org/users/MikamiUitOpen/code/F446_MySoundMachine/ + * 2) http://skovholm.com/cwdecoder + * by Hjalmar Skovholm Hansen OZ1JHM + */ + +// Include -------------------------------------------------------------------- +#include "mbed.h" +#include "Matrix.hpp" +#include "FFT_Analysis.hpp" +#include "F446_ADC_Interrupt.hpp" +#include "TextLCD.h" +#include "ST7565_SPI_LCD.h" + +// Definition ----------------------------------------------------------------- +#define METHOD_COLLECTION_HPP // MethodCollection.hpp will NOT use -#include "F446_ADC_Interrupt.hpp" // AD, DA -#include "AQM1602.hpp" // LCD 表示器 -#include "MyFunctions.hpp" // グローバル関数 -#include "SignalProcessing.hpp" // 信号処理の抽象基底クラスなど -#include "VariableLpHp.hpp" // 遮断周波数可変フィルタ -#include "WeaverModulator.hpp" // ピッチシフタ -#include "Reverbrator.hpp" // 残響生成器用 +#define HIGH 1 +#define LOW 0 +#define MILLIS() t.read_ms() + +#define ONE_LINE 20 +#define LINES 4 + +#define USE_COM +//#define USE_DEBUG + +#ifdef USE_COM +#define BAUD(x) pc.baud(x) +#define GETC(x) pc.getc(x) +#define PUTC(x) pc.putc(x) +#define PRINTF(...) pc.printf(__VA_ARGS__) +#define READABLE(x) pc.readable(x) +#else +#define BAUD(x) {;} +#define GETC(x) {;} +#define PUTC(x) {;} +#define PRINTF(...) {;} +#define READABLE(x) {;} +#endif + +#ifdef USE_DEBUG +#define DEBUG(...) pc.printf(__VA_ARGS__) +#else +#define DEBUG(...) {;} +#endif + using namespace Mikami; -const int FS_ = 24000; // 標本化周波数: 24 kHz -AdcDual_Intr myAdc_(FS_); // 参照:"F446_ADC_Interrupt.hpp" -DacDual myDac_; // 参照:"F446_DAC.hpp" +// ROM / Constant data -------------------------------------------------------- +const int FS = 48000; +const int N_FFT = 512; +#define SLOT_750HZ 8 // 48KHz /512 * 8 = 750Hz + +/* Tried other conditions +#if 0 +const int FS = 24000; +const int N_FFT = 256; +#define SLOT_750HZ 8 // 24KHz /256 * 8 = 750Hz +#endif +#if 0 +const int FS = 48000; +const int N_FFT = 256; +#define SLOT_750HZ 4 // 48KHz /256 * 4 = 750Hz +#endif +*/ -Through through_; // そのまま出力 -VariableLpHp filter_(10, FS_); // 遮断周波数可変 IIR フィルタ -VocalCanceller vCancel_; // ボーカルキャンセラ -FrqShifter fShifter_(FS_); // ピッチシフタ -EchoSystem echo_; // 残響生成器 -// 割り込みが有効になる前にポインタに割り当てておく必要がある -SignalProcessing *spPtr_ = &through_; +// RAM ------------------------------------------------------------------------ +float magnitude ; +int16_t magnitudelimit = 100; +int16_t magnitudelimit_low = 100; +int16_t realstate = LOW; +int16_t realstatebefore = LOW; +int16_t filteredstate = LOW; +int16_t filteredstatebefore = LOW; +int16_t nbtime = 2; // ms noise blanker +int32_t starttimehigh; +int32_t highduration; +int32_t lasthighduration; +int32_t hightimesavg; +int32_t lowtimesavg; +int32_t startttimelow; +int32_t lowduration; +int32_t laststarttime = 0; +char code[32]; +int16_t stop = LOW; +int16_t wpm; +uint32_t cycle = 0; +Array<float> sn(N_FFT+1); +Array<float> db(N_FFT/2+1); +uint16_t adc_bf0[N_FFT + 8]; +uint16_t adc_bf1[N_FFT + 8]; +uint8_t adc_select = 0; +uint16_t bf0_n = 0; +uint16_t bf1_n = 0; +volatile bool adc_bf0_full = false; +volatile bool adc_bf1_full = false; +volatile bool adc_data_full = false; +uint8_t msg_lcd[LINES][36]; +uint8_t num_last_line = 0; -// ADC 変換終了割り込みに対する割り込みサービス・ルーチン + +// Object --------------------------------------------------------------------- +Timer t; +DigitalOut myled(LED1); +DigitalOut morse(PC_4); +DigitalOut irq_job(D4); +DigitalOut data_in(D5); +DigitalOut loop_trg(D6); +DigitalOut out_code(D7); +Serial pc(USBTX, USBRX); +FftAnalyzer fftAnalyzer(N_FFT+1, N_FFT); +AdcSingle_Intr Adc_in(FS); +// rs, e, d4, d5, d6, d7 +TextLCD lcd(PB_0, PH_1, PC_0, PC_1, PC_2, PC_3, TextLCD::LCD20x4); +// mosi, sck, reset, a0, ncs +ST7565 glcd(PB_5, PB_3, PB_13, PB_14, PB_15, ST7565::AD12864SPI); + +// Function prototypes -------------------------------------------------------- +void setup(void); +void loop(void); +void docode(void); +void printascii(char); +void adc_convert(void); +float SpectrumUpdate(FftAnalyzer &analyzer, + const Array<float> &sn, const Array<float> &db); + +//------------------------------------------------------------------------------ +// Control Program +//------------------------------------------------------------------------------ void AdcIsr() { - float xn1, xn2, yn; - myAdc_.Read(xn1, xn2); // 入力 - yn = spPtr_->Execute(xn1, xn2); // 信号処理の実行 - myDac_.Write(yn, yn); // 出力 + irq_job = 1; + if (adc_select == 0){ + Adc_in.Read(adc_bf0[bf0_n]); + bf0_n++; + if (bf0_n >= N_FFT){ + adc_bf0_full = true; + adc_select = 1; + bf1_n = 0; + } + } else { + Adc_in.Read(adc_bf1[bf1_n]); + bf1_n++; + if (bf1_n >= N_FFT){ + adc_bf1_full = true; + adc_select = 0; + bf0_n = 0; + } + } + irq_job = 0; } int main() { - printf("\r\nDemonstration for digital signal processing\r\n"); - - BusIn sws(D6, D7, D8, D9); // ロータリ・ディップ・スイッチ用 - sws.mode(PullDown); - - AnalogIn a3In(A3); // VR からの電圧読み取り用 - Aqm1602 lcd; // LCD 表示器 - - // 出力の LPF の遮断周波数を 10 kHz に設定 - myDac_.ScfClock(10000*100); - - // ADC 変換終了割り込みに対する割り込みサービス・ルーチン割り当て - myAdc_.SetIntrVec(&AdcIsr); - - int kind = -1; // 処理の種類 - float frq; // VR で設定された周波数 - - while (true) - { - int sw; // 現在の機能切り替えスイッチの状態 - do - { - sw = sws.read(); - wait_ms(50); - } while (sw != sws.read()); - - switch (sw) - { - case 1: // 遮断周波数可変 LPF - if (FrChange(a3In, 200, 2000, 10, frq) || (sw != kind)) - { - filter_.Design(frq, BilinearDesign::LPF); - AssignDisplay(filter_, lcd, "LPF", frq); + wait(1.0); + lcd.locate(0, 0); + lcd.printf("CW DECODER(FFT) V0.1"); + lcd.locate(0, 1); + lcd.printf(" by JH1PJL Feb. 2017"); + lcd.locate(0, 2); + lcd.printf("Center Freq = 750Hz "); + lcd.locate(0, 3); + lcd.printf(" "); + glcd.cls(); + glcd.locate(0, 0); + glcd.printf(" ----- CW DECODER -----\r\n"); + glcd.printf(" "__DATE__"("__TIME__")\r\n"); + glcd.printf(" Center freq. = 750Hz\r\n"); + glcd.printf(" mbed Nucleo-F446RE\r\n"); + glcd.printf(" Base: Demo_F446_AD_DA\r\n"); + glcd.printf(" Kenji Arai / JH1PJL\r\n" ); + glcd.printf(" kenjia@sannet.ne.jp "); + PRINTF("\r\nCW Decoder(FFT) by JH1PJL\r\n"); + printf("Sys=%u\r\n", SystemCoreClock); + Adc_in.SetIntrVec(&AdcIsr); + t.start(); + while (true){ + loop_trg = !loop_trg; + data_in = 1; + adc_data_full = false; + while (adc_data_full == false){ + if (adc_bf0_full == true){ + for (int n=0; n < N_FFT; n++){ + int32_t xData; + xData = (int32_t)adc_bf0[n] - 0x00007fff; + sn[n] = (float)xData; + } + adc_bf0_full = false; + adc_data_full = true; + } else if (adc_bf1_full == true){ + for (int n=0; n < N_FFT; n++){ + int32_t xData; + xData = (int32_t)adc_bf1[n] - 0x00007fff; + sn[n] = (float)xData; } - break; - case 3: // 遮断周波数可変 HPF - if (FrChange(a3In, 200, 2000, 10, frq) || (sw != kind)) - { - filter_.Design(frq, BilinearDesign::HPF); - AssignDisplay(filter_, lcd, "HPF", frq); + adc_bf1_full = false; + adc_data_full = true; + } + } + data_in = 0; + //magnitude = SpectrumUpdate(spectra, fftAnalyzer, sn, db); + magnitude = SpectrumUpdate(fftAnalyzer, sn, db); + //printf("%f\r\n", magnitude); + if (magnitude > magnitudelimit_low){ // magnitude limit automatic + magnitudelimit = // moving average filter + (magnitudelimit +((magnitude - magnitudelimit) / 6.0f)); + } + if (magnitudelimit < magnitudelimit_low){ + magnitudelimit = magnitudelimit_low; + } + // check for the magnitude + if(magnitude > magnitudelimit * 0.9f){ // just to have some space up + realstate = HIGH; + } else { + realstate = LOW; + } + // clean up the state with a noise blanker + if (realstate != realstatebefore){ + laststarttime = MILLIS(); + } + if ((MILLIS()-laststarttime)> nbtime){ + if (realstate != filteredstate){ + filteredstate = realstate; + } + } + // durations on high and low + if (filteredstate != filteredstatebefore){ + if (filteredstate == HIGH){ + starttimehigh = MILLIS(); + lowduration = (MILLIS() - startttimelow); + } + if (filteredstate == LOW){ + startttimelow = MILLIS(); + highduration = (MILLIS() - starttimehigh); + if (highduration < (2.0f *hightimesavg) || hightimesavg == 0.0f){ + // now we know avg dit time ( rolling 3 avg) + hightimesavg = (highduration+hightimesavg+hightimesavg) / 3.0f; + } + if (highduration > (5.0f * hightimesavg) ){ + // if speed decrease fast .. + hightimesavg = highduration+hightimesavg; } - break; - case 5: // ボーカルキャンセラ - if (sw != kind) - AssignDisplay(vCancel_, lcd, "Vocal Calceller"); - break; - case 7: // ピッチシフタ - if (FrChange(a3In, 0, 200, 1, frq) || (sw != kind)) - { - fShifter_.SetFrequensy(frq); - AssignDisplay(fShifter_, lcd, "Pitch Shifter", frq); + } + } + // now we will check which kind of baud we have - dit or dah + // and what kind of pause we do have 1 - 3 or 7 pause + // we think that hightimeavg = 1 bit + if (filteredstate != filteredstatebefore){ + stop = LOW; + if (filteredstate == LOW){ //// we did end a HIGH + // 0.6 filter out false dits + if (highduration < (hightimesavg * 2.0f) + && highduration > (hightimesavg * 0.6f)){ + strcat(code,"."); + DEBUG("."); + } + if (highduration > (hightimesavg*2) + && highduration < (hightimesavg * 6.0f)){ + strcat(code,"-"); + DEBUG("-"); + wpm = (wpm + (1200/((highduration)/3)))/2; + DEBUG("<%dwpm>", wpm); } - break; - case 9: // 残響生成器 - if (sw != kind) - AssignDisplay(echo_, lcd, "Reverbrator"); - break; - default: - if (sw != kind) - AssignDisplay(through_, lcd, "Through"); - break; + } + if (filteredstate == HIGH){ // we did end a LOW + float lacktime = 1; + // when high speeds we have to have a little more pause + // before new letter or new word + if(wpm > 25){ lacktime = 1.0f;} + if(wpm > 30){ lacktime = 1.2f;} + if(wpm > 35){ lacktime = 1.5f;} + if(wpm > 40){ lacktime = 1.8f;} + if(wpm > 45){ lacktime = 2.2f;} + if(wpm > 50){ lacktime = 2.5f;} + if (lowduration > (hightimesavg*(2.0f * lacktime)) + && lowduration < hightimesavg*(5.0f * lacktime)){ + docode(); + code[0] = '\0'; + DEBUG("/"); + } + if (lowduration >= hightimesavg*(5.0f * lacktime)){ // word space + docode(); + code[0] = '\0'; + printascii(' '); + DEBUG("\r\n"); + } + } } - kind = sw; - wait(0.2f); + // write if no more letters + if ((MILLIS() - startttimelow) > (highduration * 6.0f) && stop == LOW){ + docode(); + code[0] = '\0'; + stop = HIGH; + } + // we will turn on and off the LED + // and the speaker + if(filteredstate == HIGH){ + morse = HIGH; + } else { + morse = LOW; + } + // the end of main loop clean up + realstatebefore = realstate; + lasthighduration = highduration; + filteredstatebefore = filteredstate; + //DEBUG("%d\r\n", t.read_ms()); } } + +float SpectrumUpdate(FftAnalyzer &analyzer, + const Array<float> &sn, const Array<float> &db) +{ + analyzer.Execute(sn, db); + return (db[SLOT_750HZ] - 20) * 2; +} + +// translate cw code to ascii +void docode() +{ + //PRINTF("decording<%s>", code); + if (code[0] == '.'){ // . + if (code[1] == '.'){ // .. + if (code[2] == '.'){ // ... + if (code[3] == '.'){ // .... + if (strcmp(code,"...." ) == 0){ printascii('H'); return;} + if (strcmp(code,"....." ) == 0){ printascii('5'); return;} + if (strcmp(code,"....-" ) == 0){ printascii('4'); return;} + } else if (code[3] == '-'){ // ...- + if (code[4] == '.'){ // ...-. + if (strcmp(code,"...-." ) == 0) + { printascii(126); return;} + if (strcmp(code,"...-.-" ) == 0) + { printascii(62); return;} + if (strcmp(code,"...-..-") == 0) + { printascii(36); return;} + } else if (code[4] == '-'){ // ...-- + if (strcmp(code,"...--" ) == 0) + { printascii('3'); return;} + } else { + if (strcmp(code,"...-" ) == 0) + { printascii('V'); return;} + } + } else { // ... + if (strcmp(code,"..." ) == 0){ printascii('S'); return;} + } + } else if (code[2] == '-'){ // ..- + if (strcmp(code,"..-" ) == 0){ printascii('U'); return;} + if (strcmp(code,"..-." ) == 0){ printascii('F'); return;} + if (strcmp(code,"..---" ) == 0){ printascii('2'); return;} + if (strcmp(code,"..--.." ) == 0){ printascii(63); return;} + } else { // .. + if (strcmp(code,".." ) == 0){ printascii('I'); return;} + } + } else if (code[1] == '-'){ // .- + if (code[2] == '.'){ // .-. + if (code[3] == '.'){ // .-.. + if (strcmp(code,".-.." ) == 0){ printascii('L'); return;} + if (strcmp(code,".-..." ) == 0){ printascii(95); return;} + } else if (code[3] == '-'){ // .-.- + if (strcmp(code,".-.-" ) == 0){ printascii(3); return;} + if (strcmp(code,".-.-." ) == 0){ printascii(60); return;} + if (strcmp(code,".-.-.-" ) == 0){ printascii(46); return;} + } else { // .-. + if (strcmp(code,".-." ) == 0){ printascii('R'); return;} + } + } else if (code[2] == '-'){ // .-- + if (code[3] == '.'){ // .--. + if (strcmp(code,".--." ) == 0){ printascii('P'); return;} + if (strcmp(code,".--.-" ) == 0){ printascii('-'); return;} + if (strcmp(code,".--.-." ) == 0){ printascii(64); return;} + } else if (code[3] == '-'){ // .--- + if (strcmp(code,".---" ) == 0){ printascii('J'); return;} + if (strcmp(code,".----" ) == 0){ printascii('1'); return;} + } else { // .-- + if (strcmp(code,".--" ) == 0){ printascii('W'); return;} + } + } else { // .- + if (strcmp(code,".-") == 0){ printascii('A'); return;} + } + } else { // . + if (strcmp(code,".") == 0){ printascii('E'); return;} + } + } else if (code[0] == '-'){ // - + if (code[1] == '.'){ // -. + if (code[2] == '.'){ // -.. + if (code[3] == '.'){ // -... + if (strcmp(code,"-..." ) == 0){ printascii('B'); return;} + if (strcmp(code,"-...." ) == 0){ printascii('6'); return;} + if (strcmp(code,"-....-" ) == 0){ printascii('-'); return;} + } else if (code[3] == '-'){ // -..- + if (strcmp(code,"-..-" ) == 0){ printascii('X'); return;} + if (strcmp(code,"-..-." ) == 0){ printascii(47); return;} + } else { + if (strcmp(code,"-.." ) == 0){ printascii('D'); return;} + } + } else if (code[2] == '-'){ // -.- + if (code[3] == '.'){ // -.-. + if (strcmp(code,"-.-." ) == 0){ printascii('C'); return;} + if (strcmp(code,"-.-.--" ) == 0){ printascii(33); return;} + } else if (code[3] == '-'){ // -.-- + if (strcmp(code,"-.--" ) == 0){ printascii('Y'); return;} + if (strcmp(code,"-.--." ) == 0){ printascii(40); return;} + if (strcmp(code,"-.--.-" ) == 0){ printascii(41); return;} + } else { // -.- + if (strcmp(code,"-.-" ) == 0){ printascii('K'); return;} + } + } else { // -. + if (strcmp(code,"-.") == 0){ printascii('N'); return;} + } + } else if (code[1] == '-'){ // - + if (code[2] == '.'){ // --. + if (strcmp(code,"--." ) == 0){ printascii('G'); return;} + if (strcmp(code,"--.." ) == 0){ printascii('Z'); return;} + if (strcmp(code,"--.-" ) == 0){ printascii('Q'); return;} + if (strcmp(code,"--..." ) == 0){ printascii('7'); return;} + if (strcmp(code,"--..--" ) == 0){ printascii(44); return;} + } else if (code[2] == '-'){ // --- + if (code[3] == '.'){ // ---. + if (strcmp(code,"---.." ) == 0){ printascii('8'); return;} + if (strcmp(code,"---." ) == 0){ printascii(4); return;} + if (strcmp(code,"---..." ) == 0){ printascii(58); return;} + } else if (code[3] == '-'){ // ---- + if (strcmp(code,"----." ) == 0){ printascii('9'); return;} + if (strcmp(code,"-----" ) == 0){ printascii('0'); return;} + } else { // --- + if (strcmp(code,"---" ) == 0){ printascii('O'); return;} + } + } else { // -- + if (strcmp(code,"--") == 0){ printascii('M'); return;} + } + } else { // - + if (strcmp(code,"-") == 0){ printascii('T'); return;} + } + } +} + +void printascii(char c) +{ + uint8_t i,j; + + out_code = 1; + PRINTF("%c", c); + if (num_last_line == ONE_LINE){ + for (j = 0; j < LINES; j++){ // scroll one line + for (i =0; i < ONE_LINE; i++){ + msg_lcd[j][i] = msg_lcd[j+1][i]; + } + } + for (i =0; i < ONE_LINE; i++){ // Clear last line + msg_lcd[3][i] = ' '; + } + num_last_line = 0; + for (i =0; i < 4; i++){ + lcd.locate(0, i); + lcd.printf("%s", &msg_lcd[i][0]); + } + } + if (!(num_last_line == 0 && c == ' ')){ + msg_lcd[3][num_last_line++] = c; + lcd.locate(0, 3); + lcd.printf("%s", &msg_lcd[3][0]); + } + out_code = 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os.lib Sun Feb 05 08:02:54 2017 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os/#269f58d75b752a4e67a6a2d8c5c698635ffd6752
--- a/mbed.bld Tue Jan 31 12:52:35 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/mbed_official/code/mbed/builds/ad3be0349dc5 \ No newline at end of file