CW Decoder (Morse code decoder) 1st release version. mbed = 131 revision (Not latest) is used. Only run on DISCO-F746NG mbed board.

Dependencies:   BSP_DISCO_F746NG F746_GUI F746_SAI_IO LCD_DISCO_F746NG TS_DISCO_F746NG UIT_FFT_Real mbed

Base on F746_Spectrogram program created by 不韋 呂-san.
/users/MikamiUitOpen/code/F746_Spectrogram/
Thanks 不韋 呂-san to use fundamental parts such as FFT, SAI, GUI and other useful subroutines.
You do NOT need any modification for mbed hardware and NO additional circuits.
The mbed board read CW tone from your receiver speaker via MEMES microphone (on board) and show it on the screen.

Committer:
kenjiArai
Date:
Sun Feb 05 07:49:54 2017 +0000
Revision:
0:e608fc311e4e
CW Decoder (Morse code decoder) 1st release version. mbed = 131 revision (Not latest) is used. Only run on DISCO-F746NG mbed board.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kenjiArai 0:e608fc311e4e 1 /*
kenjiArai 0:e608fc311e4e 2 * mbed program / cwdecoder using the FFT Algorithm
kenjiArai 0:e608fc311e4e 3 * tested on DISCO-F746G mbed board
kenjiArai 0:e608fc311e4e 4 *
kenjiArai 0:e608fc311e4e 5 * Modified by Kenji Arai
kenjiArai 0:e608fc311e4e 6 * http://www.page.sannet.ne.jp/kenjia/index.html
kenjiArai 0:e608fc311e4e 7 * http://mbed.org/users/kenjiArai/
kenjiArai 0:e608fc311e4e 8 *
kenjiArai 0:e608fc311e4e 9 * Started: January 28th, 2017
kenjiArai 0:e608fc311e4e 10 * Revised: Feburary 5th, 2017
kenjiArai 0:e608fc311e4e 11 *
kenjiArai 0:e608fc311e4e 12 * Reference program:
kenjiArai 0:e608fc311e4e 13 * 1) 2016/10/02, Copyright (c) 2016 MIKAMI, Naoki
kenjiArai 0:e608fc311e4e 14 * https://developer.mbed.org/users/MikamiUitOpen/code/F746_Spectrogram/
kenjiArai 0:e608fc311e4e 15 * 2) http://skovholm.com/cwdecoder
kenjiArai 0:e608fc311e4e 16 * by Hjalmar Skovholm Hansen OZ1JHM
kenjiArai 0:e608fc311e4e 17 */
kenjiArai 0:e608fc311e4e 18
kenjiArai 0:e608fc311e4e 19 // Include --------------------------------------------------------------------
kenjiArai 0:e608fc311e4e 20 #include "mbed.h"
kenjiArai 0:e608fc311e4e 21 #include "SAI_InOut.hpp"
kenjiArai 0:e608fc311e4e 22 #include "F746_GUI.hpp"
kenjiArai 0:e608fc311e4e 23 #include "Matrix.hpp"
kenjiArai 0:e608fc311e4e 24 #include "NumericLabel.hpp"
kenjiArai 0:e608fc311e4e 25 #include "FFT_Analysis.hpp"
kenjiArai 0:e608fc311e4e 26 #include "MethodCollection.hpp"
kenjiArai 0:e608fc311e4e 27
kenjiArai 0:e608fc311e4e 28 #warning "If you would like to run this program, you need modify mbed revision."
kenjiArai 0:e608fc311e4e 29 #warning "Please set mbed revision 131 (dated on Dec. 15, 2016)"
kenjiArai 0:e608fc311e4e 30
kenjiArai 0:e608fc311e4e 31 // Definition -----------------------------------------------------------------
kenjiArai 0:e608fc311e4e 32 //#define METHOD_COLLECTION_HPP // MethodCollection.hpp will NOT use
kenjiArai 0:e608fc311e4e 33
kenjiArai 0:e608fc311e4e 34 #define HIGH 1
kenjiArai 0:e608fc311e4e 35 #define LOW 0
kenjiArai 0:e608fc311e4e 36 #define MILLIS() t.read_ms()
kenjiArai 0:e608fc311e4e 37
kenjiArai 0:e608fc311e4e 38 #define ONE_LINE 34
kenjiArai 0:e608fc311e4e 39 #define LINES 11
kenjiArai 0:e608fc311e4e 40 #define WORK_LINE LINES
kenjiArai 0:e608fc311e4e 41 #define TOTAL_CHAR (ONE_LINE * LINES)
kenjiArai 0:e608fc311e4e 42
kenjiArai 0:e608fc311e4e 43 #define USE_COM
kenjiArai 0:e608fc311e4e 44 //#define USE_DEBUG
kenjiArai 0:e608fc311e4e 45
kenjiArai 0:e608fc311e4e 46 #ifdef USE_COM
kenjiArai 0:e608fc311e4e 47 #define BAUD(x) pc.baud(x)
kenjiArai 0:e608fc311e4e 48 #define GETC(x) pc.getc(x)
kenjiArai 0:e608fc311e4e 49 #define PUTC(x) pc.putc(x)
kenjiArai 0:e608fc311e4e 50 #define PRINTF(...) pc.printf(__VA_ARGS__)
kenjiArai 0:e608fc311e4e 51 #define READABLE(x) pc.readable(x)
kenjiArai 0:e608fc311e4e 52 #else
kenjiArai 0:e608fc311e4e 53 #define BAUD(x) {;}
kenjiArai 0:e608fc311e4e 54 #define GETC(x) {;}
kenjiArai 0:e608fc311e4e 55 #define PUTC(x) {;}
kenjiArai 0:e608fc311e4e 56 #define PRINTF(...) {;}
kenjiArai 0:e608fc311e4e 57 #define READABLE(x) {;}
kenjiArai 0:e608fc311e4e 58 #endif
kenjiArai 0:e608fc311e4e 59
kenjiArai 0:e608fc311e4e 60 #ifdef USE_DEBUG
kenjiArai 0:e608fc311e4e 61 #define DEBUG(...) pc.printf(__VA_ARGS__)
kenjiArai 0:e608fc311e4e 62 #else
kenjiArai 0:e608fc311e4e 63 #define DEBUG(...) {;}
kenjiArai 0:e608fc311e4e 64 #endif
kenjiArai 0:e608fc311e4e 65
kenjiArai 0:e608fc311e4e 66 using namespace Mikami;
kenjiArai 0:e608fc311e4e 67
kenjiArai 0:e608fc311e4e 68 // ROM / Constant data --------------------------------------------------------
kenjiArai 0:e608fc311e4e 69 const int FS = I2S_AUDIOFREQ_32K;
kenjiArai 0:e608fc311e4e 70 const int N_FFT = 512;
kenjiArai 0:e608fc311e4e 71 #define SLOT_750HZ 12 // 32KHz /512 * 12 = 750Hz
kenjiArai 0:e608fc311e4e 72
kenjiArai 0:e608fc311e4e 73 char *const open_msg[] = {
kenjiArai 0:e608fc311e4e 74 "Center freq.: 750 Hz",
kenjiArai 0:e608fc311e4e 75 "Sampling freq. 32 kHz",
kenjiArai 0:e608fc311e4e 76 "FFT / # of points: 512",
kenjiArai 0:e608fc311e4e 77 "Two modes ",
kenjiArai 0:e608fc311e4e 78 "(1) CW / MORSE Decoder",
kenjiArai 0:e608fc311e4e 79 "(2) Show Spectram"
kenjiArai 0:e608fc311e4e 80 };
kenjiArai 0:e608fc311e4e 81
kenjiArai 0:e608fc311e4e 82 // RAM ------------------------------------------------------------------------
kenjiArai 0:e608fc311e4e 83 float magnitude ;
kenjiArai 0:e608fc311e4e 84 int16_t magnitudelimit = 100;
kenjiArai 0:e608fc311e4e 85 int16_t magnitudelimit_low = 100;
kenjiArai 0:e608fc311e4e 86 int16_t realstate = LOW;
kenjiArai 0:e608fc311e4e 87 int16_t realstatebefore = LOW;
kenjiArai 0:e608fc311e4e 88 int16_t filteredstate = LOW;
kenjiArai 0:e608fc311e4e 89 int16_t filteredstatebefore = LOW;
kenjiArai 0:e608fc311e4e 90 int16_t nbtime = 2; // ms noise blanker
kenjiArai 0:e608fc311e4e 91 int32_t starttimehigh;
kenjiArai 0:e608fc311e4e 92 int32_t highduration;
kenjiArai 0:e608fc311e4e 93 int32_t lasthighduration;
kenjiArai 0:e608fc311e4e 94 int32_t hightimesavg;
kenjiArai 0:e608fc311e4e 95 int32_t lowtimesavg;
kenjiArai 0:e608fc311e4e 96 int32_t startttimelow;
kenjiArai 0:e608fc311e4e 97 int32_t lowduration;
kenjiArai 0:e608fc311e4e 98 int32_t laststarttime = 0;
kenjiArai 0:e608fc311e4e 99 char code[32];
kenjiArai 0:e608fc311e4e 100 int16_t stop = LOW;
kenjiArai 0:e608fc311e4e 101 int16_t wpm;
kenjiArai 0:e608fc311e4e 102 uint32_t cycle = 0;
kenjiArai 0:e608fc311e4e 103 uint8_t msg_lcd[LINES + 1][48];
kenjiArai 0:e608fc311e4e 104 uint8_t num_last_line = 0;
kenjiArai 0:e608fc311e4e 105 Array<float> sn(N_FFT+1);
kenjiArai 0:e608fc311e4e 106 Array<float> db(N_FFT/2+1);
kenjiArai 0:e608fc311e4e 107 LCD_DISCO_F746NG *lcd = GuiBase::GetLcdPtr();
kenjiArai 0:e608fc311e4e 108
kenjiArai 0:e608fc311e4e 109 // Object ---------------------------------------------------------------------
kenjiArai 0:e608fc311e4e 110 Timer t;
kenjiArai 0:e608fc311e4e 111 DigitalOut myled(LED1);
kenjiArai 0:e608fc311e4e 112 DigitalOut data_in(D5);
kenjiArai 0:e608fc311e4e 113 DigitalOut loop_trg(D6);
kenjiArai 0:e608fc311e4e 114 DigitalOut out_code(D7);
kenjiArai 0:e608fc311e4e 115 Serial pc(USBTX, USBRX);
kenjiArai 0:e608fc311e4e 116 SaiIO mySai(SaiIO::INPUT, N_FFT+1, FS, INPUT_DEVICE_DIGITAL_MICROPHONE_2);
kenjiArai 0:e608fc311e4e 117 FftAnalyzer fftAnalyzer(N_FFT+1, N_FFT);
kenjiArai 0:e608fc311e4e 118
kenjiArai 0:e608fc311e4e 119 // Function prototypes --------------------------------------------------------
kenjiArai 0:e608fc311e4e 120 void setup(void);
kenjiArai 0:e608fc311e4e 121 void loop(void);
kenjiArai 0:e608fc311e4e 122 void docode(void);
kenjiArai 0:e608fc311e4e 123 void printascii(char);
kenjiArai 0:e608fc311e4e 124 void adc_convert(void);
kenjiArai 0:e608fc311e4e 125 float SpectrumUpdate(FftAnalyzer &analyzer,
kenjiArai 0:e608fc311e4e 126 const Array<float> &sn, const Array<float> &db);
kenjiArai 0:e608fc311e4e 127 void cw_decoder(void);
kenjiArai 0:e608fc311e4e 128 void spectrogram(void);
kenjiArai 0:e608fc311e4e 129 uint8_t mode_slect(void);
kenjiArai 0:e608fc311e4e 130 void spectrum(void);
kenjiArai 0:e608fc311e4e 131 //------------------------------------------------------------------------------
kenjiArai 0:e608fc311e4e 132 // Control Program
kenjiArai 0:e608fc311e4e 133 //------------------------------------------------------------------------------
kenjiArai 0:e608fc311e4e 134 int main()
kenjiArai 0:e608fc311e4e 135 {
kenjiArai 0:e608fc311e4e 136 while (true){
kenjiArai 0:e608fc311e4e 137 lcd->Clear(GuiBase::ENUM_BACK);
kenjiArai 0:e608fc311e4e 138 uint8_t n = mode_slect();
kenjiArai 0:e608fc311e4e 139 switch (n){
kenjiArai 0:e608fc311e4e 140 case 0:
kenjiArai 0:e608fc311e4e 141 cw_decoder();
kenjiArai 0:e608fc311e4e 142 break;
kenjiArai 0:e608fc311e4e 143 case 1:
kenjiArai 0:e608fc311e4e 144 spectrum();
kenjiArai 0:e608fc311e4e 145 break;
kenjiArai 0:e608fc311e4e 146 default:
kenjiArai 0:e608fc311e4e 147 break;
kenjiArai 0:e608fc311e4e 148 }
kenjiArai 0:e608fc311e4e 149 }
kenjiArai 0:e608fc311e4e 150 }
kenjiArai 0:e608fc311e4e 151
kenjiArai 0:e608fc311e4e 152 uint8_t mode_slect()
kenjiArai 0:e608fc311e4e 153 {
kenjiArai 0:e608fc311e4e 154 Label obj0(240, 2, "Operationg Mode",
kenjiArai 0:e608fc311e4e 155 Label::CENTER, Font24, LCD_COLOR_LIGHTGREEN);
kenjiArai 0:e608fc311e4e 156 Label obj1(40, 30, open_msg[0], Label::LEFT, Font20);
kenjiArai 0:e608fc311e4e 157 Label obj2(40, 50, open_msg[1], Label::LEFT, Font20);
kenjiArai 0:e608fc311e4e 158 Label obj3(40, 70, open_msg[2], Label::LEFT, Font20);
kenjiArai 0:e608fc311e4e 159 Label obj4(40, 100, open_msg[3], Label::LEFT, Font20, LCD_COLOR_LIGHTGREEN);
kenjiArai 0:e608fc311e4e 160 Label obj5(70, 120, open_msg[4], Label::LEFT, Font20, LCD_COLOR_LIGHTGREEN);
kenjiArai 0:e608fc311e4e 161 Label obj6(70, 140, open_msg[5], Label::LEFT, Font20, LCD_COLOR_LIGHTGREEN);
kenjiArai 0:e608fc311e4e 162 Button button0( 50, 200, 180, 50, "CW/MORSE", Font24);
kenjiArai 0:e608fc311e4e 163 Button button1(260, 200, 180, 50, "SPECTRAM", Font24);
kenjiArai 0:e608fc311e4e 164 while (true){
kenjiArai 0:e608fc311e4e 165 if (button0.Touched()){ return 0UL;}
kenjiArai 0:e608fc311e4e 166 if (button1.Touched()){ return 1UL;}
kenjiArai 0:e608fc311e4e 167 wait(0.02f);
kenjiArai 0:e608fc311e4e 168 }
kenjiArai 0:e608fc311e4e 169 }
kenjiArai 0:e608fc311e4e 170
kenjiArai 0:e608fc311e4e 171 void spectrogram()
kenjiArai 0:e608fc311e4e 172 {
kenjiArai 0:e608fc311e4e 173 lcd->Clear(GuiBase::ENUM_BACK);
kenjiArai 0:e608fc311e4e 174 PRINTF("\r\nFFT Spectroram\r\n");
kenjiArai 0:e608fc311e4e 175 Button button10(380, 240, 80, 30, "MENUE", Font16);
kenjiArai 0:e608fc311e4e 176 spectrum();
kenjiArai 0:e608fc311e4e 177 if (button10.Touched()){ return;}
kenjiArai 0:e608fc311e4e 178 }
kenjiArai 0:e608fc311e4e 179
kenjiArai 0:e608fc311e4e 180 void cw_decoder()
kenjiArai 0:e608fc311e4e 181 {
kenjiArai 0:e608fc311e4e 182 lcd->Clear(GuiBase::ENUM_BACK);
kenjiArai 0:e608fc311e4e 183 PRINTF("\r\nCW Decoder(FFT) by JH1PJL\r\n");
kenjiArai 0:e608fc311e4e 184 Label myLabel1(120, 250, "CW Decoder(FFT) by JH1PJL",
kenjiArai 0:e608fc311e4e 185 Label::CENTER, Font16);
kenjiArai 0:e608fc311e4e 186 Button button20(380, 240, 80, 30, "MENUE", Font16);
kenjiArai 0:e608fc311e4e 187 printf("Sys=%u\r\n", SystemCoreClock);
kenjiArai 0:e608fc311e4e 188 lcd->SetTextColor(LCD_COLOR_GREEN);
kenjiArai 0:e608fc311e4e 189 lcd->SetFont(&Font20);
kenjiArai 0:e608fc311e4e 190 mySai.RecordIn();
kenjiArai 0:e608fc311e4e 191 t.start();
kenjiArai 0:e608fc311e4e 192 while (true){
kenjiArai 0:e608fc311e4e 193 loop_trg = !loop_trg;
kenjiArai 0:e608fc311e4e 194 data_in = 1;
kenjiArai 0:e608fc311e4e 195 while (mySai.IsCaptured() == false){;}
kenjiArai 0:e608fc311e4e 196 for (int n=0; n<mySai.GetLength(); n++){
kenjiArai 0:e608fc311e4e 197 int16_t xL, xR;
kenjiArai 0:e608fc311e4e 198 mySai.Input(xL, xR);
kenjiArai 0:e608fc311e4e 199 sn[n] = (float)xL;
kenjiArai 0:e608fc311e4e 200 }
kenjiArai 0:e608fc311e4e 201 data_in = 0;
kenjiArai 0:e608fc311e4e 202 //magnitude = SpectrumUpdate(spectra, fftAnalyzer, sn, db);
kenjiArai 0:e608fc311e4e 203 magnitude = SpectrumUpdate(fftAnalyzer, sn, db);
kenjiArai 0:e608fc311e4e 204 //printf("%f\r\n", magnitude);
kenjiArai 0:e608fc311e4e 205 if (magnitude > magnitudelimit_low){ // magnitude limit automatic
kenjiArai 0:e608fc311e4e 206 magnitudelimit = // moving average filter
kenjiArai 0:e608fc311e4e 207 (magnitudelimit +((magnitude - magnitudelimit) / 6.0f));
kenjiArai 0:e608fc311e4e 208 }
kenjiArai 0:e608fc311e4e 209 if (magnitudelimit < magnitudelimit_low){
kenjiArai 0:e608fc311e4e 210 magnitudelimit = magnitudelimit_low;
kenjiArai 0:e608fc311e4e 211 }
kenjiArai 0:e608fc311e4e 212 // check for the magnitude
kenjiArai 0:e608fc311e4e 213 if(magnitude > magnitudelimit * 0.9f){ // just to have some space up
kenjiArai 0:e608fc311e4e 214 realstate = HIGH;
kenjiArai 0:e608fc311e4e 215 } else {
kenjiArai 0:e608fc311e4e 216 realstate = LOW;
kenjiArai 0:e608fc311e4e 217 }
kenjiArai 0:e608fc311e4e 218 // clean up the state with a noise blanker
kenjiArai 0:e608fc311e4e 219 if (realstate != realstatebefore){
kenjiArai 0:e608fc311e4e 220 laststarttime = MILLIS();
kenjiArai 0:e608fc311e4e 221 }
kenjiArai 0:e608fc311e4e 222 if ((MILLIS()-laststarttime)> nbtime){
kenjiArai 0:e608fc311e4e 223 if (realstate != filteredstate){
kenjiArai 0:e608fc311e4e 224 filteredstate = realstate;
kenjiArai 0:e608fc311e4e 225 }
kenjiArai 0:e608fc311e4e 226 }
kenjiArai 0:e608fc311e4e 227 // durations on high and low
kenjiArai 0:e608fc311e4e 228 if (filteredstate != filteredstatebefore){
kenjiArai 0:e608fc311e4e 229 if (filteredstate == HIGH){
kenjiArai 0:e608fc311e4e 230 starttimehigh = MILLIS();
kenjiArai 0:e608fc311e4e 231 lowduration = (MILLIS() - startttimelow);
kenjiArai 0:e608fc311e4e 232 }
kenjiArai 0:e608fc311e4e 233 if (filteredstate == LOW){
kenjiArai 0:e608fc311e4e 234 startttimelow = MILLIS();
kenjiArai 0:e608fc311e4e 235 highduration = (MILLIS() - starttimehigh);
kenjiArai 0:e608fc311e4e 236 if (highduration < (2.0f *hightimesavg) || hightimesavg == 0.0f){
kenjiArai 0:e608fc311e4e 237 // now we know avg dit time ( rolling 3 avg)
kenjiArai 0:e608fc311e4e 238 hightimesavg = (highduration+hightimesavg+hightimesavg) / 3.0f;
kenjiArai 0:e608fc311e4e 239 }
kenjiArai 0:e608fc311e4e 240 if (highduration > (5.0f * hightimesavg) ){
kenjiArai 0:e608fc311e4e 241 // if speed decrease fast ..
kenjiArai 0:e608fc311e4e 242 hightimesavg = highduration+hightimesavg;
kenjiArai 0:e608fc311e4e 243 }
kenjiArai 0:e608fc311e4e 244 }
kenjiArai 0:e608fc311e4e 245 }
kenjiArai 0:e608fc311e4e 246 // now we will check which kind of baud we have - dit or dah
kenjiArai 0:e608fc311e4e 247 // and what kind of pause we do have 1 - 3 or 7 pause
kenjiArai 0:e608fc311e4e 248 // we think that hightimeavg = 1 bit
kenjiArai 0:e608fc311e4e 249 if (filteredstate != filteredstatebefore){
kenjiArai 0:e608fc311e4e 250 stop = LOW;
kenjiArai 0:e608fc311e4e 251 if (filteredstate == LOW){ //// we did end a HIGH
kenjiArai 0:e608fc311e4e 252 // 0.6 filter out false dits
kenjiArai 0:e608fc311e4e 253 if (highduration < (hightimesavg * 2.0f)
kenjiArai 0:e608fc311e4e 254 && highduration > (hightimesavg * 0.6f)){
kenjiArai 0:e608fc311e4e 255 strcat(code,".");
kenjiArai 0:e608fc311e4e 256 DEBUG(".");
kenjiArai 0:e608fc311e4e 257 }
kenjiArai 0:e608fc311e4e 258 if (highduration > (hightimesavg*2)
kenjiArai 0:e608fc311e4e 259 && highduration < (hightimesavg * 6.0f)){
kenjiArai 0:e608fc311e4e 260 strcat(code,"-");
kenjiArai 0:e608fc311e4e 261 DEBUG("-");
kenjiArai 0:e608fc311e4e 262 wpm = (wpm + (1200/((highduration)/3)))/2;
kenjiArai 0:e608fc311e4e 263 }
kenjiArai 0:e608fc311e4e 264 }
kenjiArai 0:e608fc311e4e 265 if (filteredstate == HIGH){ // we did end a LOW
kenjiArai 0:e608fc311e4e 266 float lacktime = 1;
kenjiArai 0:e608fc311e4e 267 // when high speeds we have to have a little more pause
kenjiArai 0:e608fc311e4e 268 // before new letter or new word
kenjiArai 0:e608fc311e4e 269 if(wpm > 25){ lacktime = 1.0f;}
kenjiArai 0:e608fc311e4e 270 if(wpm > 30){ lacktime = 1.2f;}
kenjiArai 0:e608fc311e4e 271 if(wpm > 35){ lacktime = 1.5f;}
kenjiArai 0:e608fc311e4e 272 if(wpm > 40){ lacktime = 1.7f;}
kenjiArai 0:e608fc311e4e 273 if(wpm > 45){ lacktime = 1.9f;}
kenjiArai 0:e608fc311e4e 274 if(wpm > 50){ lacktime = 2.0f;}
kenjiArai 0:e608fc311e4e 275 if (lowduration > (hightimesavg*(2.0f * lacktime))
kenjiArai 0:e608fc311e4e 276 && lowduration < hightimesavg*(5.0f * lacktime)){
kenjiArai 0:e608fc311e4e 277 docode();
kenjiArai 0:e608fc311e4e 278 code[0] = '\0';
kenjiArai 0:e608fc311e4e 279 DEBUG("/");
kenjiArai 0:e608fc311e4e 280 }
kenjiArai 0:e608fc311e4e 281 if (lowduration >= hightimesavg*(5.0f * lacktime)){ // word space
kenjiArai 0:e608fc311e4e 282 docode();
kenjiArai 0:e608fc311e4e 283 code[0] = '\0';
kenjiArai 0:e608fc311e4e 284 printascii(' ');
kenjiArai 0:e608fc311e4e 285 DEBUG("\r\n");
kenjiArai 0:e608fc311e4e 286 }
kenjiArai 0:e608fc311e4e 287 }
kenjiArai 0:e608fc311e4e 288 }
kenjiArai 0:e608fc311e4e 289 // write if no more letters
kenjiArai 0:e608fc311e4e 290 if ((MILLIS() - startttimelow) > (highduration * 6.0f) && stop == LOW){
kenjiArai 0:e608fc311e4e 291 docode();
kenjiArai 0:e608fc311e4e 292 code[0] = '\0';
kenjiArai 0:e608fc311e4e 293 stop = HIGH;
kenjiArai 0:e608fc311e4e 294 }
kenjiArai 0:e608fc311e4e 295 // we will turn on and off the LED
kenjiArai 0:e608fc311e4e 296 // and the speaker
kenjiArai 0:e608fc311e4e 297 if(filteredstate == HIGH){
kenjiArai 0:e608fc311e4e 298 myled = HIGH;
kenjiArai 0:e608fc311e4e 299 } else {
kenjiArai 0:e608fc311e4e 300 myled = LOW;
kenjiArai 0:e608fc311e4e 301 }
kenjiArai 0:e608fc311e4e 302 // the end of main loop clean up
kenjiArai 0:e608fc311e4e 303 realstatebefore = realstate;
kenjiArai 0:e608fc311e4e 304 lasthighduration = highduration;
kenjiArai 0:e608fc311e4e 305 filteredstatebefore = filteredstate;
kenjiArai 0:e608fc311e4e 306 DEBUG("%d\r\n", t.read_ms());
kenjiArai 0:e608fc311e4e 307 // return to menue or continue
kenjiArai 0:e608fc311e4e 308 if (button20.Touched()){ return;}
kenjiArai 0:e608fc311e4e 309 }
kenjiArai 0:e608fc311e4e 310 }
kenjiArai 0:e608fc311e4e 311
kenjiArai 0:e608fc311e4e 312 float SpectrumUpdate(FftAnalyzer &analyzer,
kenjiArai 0:e608fc311e4e 313 const Array<float> &sn, const Array<float> &db)
kenjiArai 0:e608fc311e4e 314 {
kenjiArai 0:e608fc311e4e 315 analyzer.Execute(sn, db);
kenjiArai 0:e608fc311e4e 316 return (db[SLOT_750HZ] - 20) * 2;
kenjiArai 0:e608fc311e4e 317 }
kenjiArai 0:e608fc311e4e 318
kenjiArai 0:e608fc311e4e 319 // translate cw code to ascii
kenjiArai 0:e608fc311e4e 320 void docode()
kenjiArai 0:e608fc311e4e 321 {
kenjiArai 0:e608fc311e4e 322 //PRINTF("decording<%s>", code);
kenjiArai 0:e608fc311e4e 323 if (code[0] == '.'){ // .
kenjiArai 0:e608fc311e4e 324 if (code[1] == '.'){ // ..
kenjiArai 0:e608fc311e4e 325 if (code[2] == '.'){ // ...
kenjiArai 0:e608fc311e4e 326 if (code[3] == '.'){ // ....
kenjiArai 0:e608fc311e4e 327 if (strcmp(code,"...." ) == 0){ printascii('H'); return;}
kenjiArai 0:e608fc311e4e 328 if (strcmp(code,"....." ) == 0){ printascii('5'); return;}
kenjiArai 0:e608fc311e4e 329 if (strcmp(code,"....-" ) == 0){ printascii('4'); return;}
kenjiArai 0:e608fc311e4e 330 } else if (code[3] == '-'){ // ...-
kenjiArai 0:e608fc311e4e 331 if (code[4] == '.'){ // ...-.
kenjiArai 0:e608fc311e4e 332 if (strcmp(code,"...-." ) == 0)
kenjiArai 0:e608fc311e4e 333 { printascii(126); return;}
kenjiArai 0:e608fc311e4e 334 if (strcmp(code,"...-.-" ) == 0)
kenjiArai 0:e608fc311e4e 335 { printascii(62); return;}
kenjiArai 0:e608fc311e4e 336 if (strcmp(code,"...-..-") == 0)
kenjiArai 0:e608fc311e4e 337 { printascii(36); return;}
kenjiArai 0:e608fc311e4e 338 } else if (code[4] == '-'){ // ...--
kenjiArai 0:e608fc311e4e 339 if (strcmp(code,"...--" ) == 0)
kenjiArai 0:e608fc311e4e 340 { printascii('3'); return;}
kenjiArai 0:e608fc311e4e 341 } else {
kenjiArai 0:e608fc311e4e 342 if (strcmp(code,"...-" ) == 0)
kenjiArai 0:e608fc311e4e 343 { printascii('V'); return;}
kenjiArai 0:e608fc311e4e 344 }
kenjiArai 0:e608fc311e4e 345 } else { // ...
kenjiArai 0:e608fc311e4e 346 if (strcmp(code,"..." ) == 0){ printascii('S'); return;}
kenjiArai 0:e608fc311e4e 347 }
kenjiArai 0:e608fc311e4e 348 } else if (code[2] == '-'){ // ..-
kenjiArai 0:e608fc311e4e 349 if (strcmp(code,"..-" ) == 0){ printascii('U'); return;}
kenjiArai 0:e608fc311e4e 350 if (strcmp(code,"..-." ) == 0){ printascii('F'); return;}
kenjiArai 0:e608fc311e4e 351 if (strcmp(code,"..---" ) == 0){ printascii('2'); return;}
kenjiArai 0:e608fc311e4e 352 if (strcmp(code,"..--.." ) == 0){ printascii(63); return;}
kenjiArai 0:e608fc311e4e 353 } else { // ..
kenjiArai 0:e608fc311e4e 354 if (strcmp(code,".." ) == 0){ printascii('I'); return;}
kenjiArai 0:e608fc311e4e 355 }
kenjiArai 0:e608fc311e4e 356 } else if (code[1] == '-'){ // .-
kenjiArai 0:e608fc311e4e 357 if (code[2] == '.'){ // .-.
kenjiArai 0:e608fc311e4e 358 if (code[3] == '.'){ // .-..
kenjiArai 0:e608fc311e4e 359 if (strcmp(code,".-.." ) == 0){ printascii('L'); return;}
kenjiArai 0:e608fc311e4e 360 if (strcmp(code,".-..." ) == 0){ printascii(95); return;}
kenjiArai 0:e608fc311e4e 361 } else if (code[3] == '-'){ // .-.-
kenjiArai 0:e608fc311e4e 362 if (strcmp(code,".-.-" ) == 0){ printascii(3); return;}
kenjiArai 0:e608fc311e4e 363 if (strcmp(code,".-.-." ) == 0){ printascii(60); return;}
kenjiArai 0:e608fc311e4e 364 if (strcmp(code,".-.-.-" ) == 0){ printascii(46); return;}
kenjiArai 0:e608fc311e4e 365 } else { // .-.
kenjiArai 0:e608fc311e4e 366 if (strcmp(code,".-." ) == 0){ printascii('R'); return;}
kenjiArai 0:e608fc311e4e 367 }
kenjiArai 0:e608fc311e4e 368 } else if (code[2] == '-'){ // .--
kenjiArai 0:e608fc311e4e 369 if (code[3] == '.'){ // .--.
kenjiArai 0:e608fc311e4e 370 if (strcmp(code,".--." ) == 0){ printascii('P'); return;}
kenjiArai 0:e608fc311e4e 371 if (strcmp(code,".--.-" ) == 0){ printascii('-'); return;}
kenjiArai 0:e608fc311e4e 372 if (strcmp(code,".--.-." ) == 0){ printascii(64); return;}
kenjiArai 0:e608fc311e4e 373 } else if (code[3] == '-'){ // .---
kenjiArai 0:e608fc311e4e 374 if (strcmp(code,".---" ) == 0){ printascii('J'); return;}
kenjiArai 0:e608fc311e4e 375 if (strcmp(code,".----" ) == 0){ printascii('1'); return;}
kenjiArai 0:e608fc311e4e 376 } else { // .--
kenjiArai 0:e608fc311e4e 377 if (strcmp(code,".--" ) == 0){ printascii('W'); return;}
kenjiArai 0:e608fc311e4e 378 }
kenjiArai 0:e608fc311e4e 379 } else { // .-
kenjiArai 0:e608fc311e4e 380 if (strcmp(code,".-") == 0){ printascii('A'); return;}
kenjiArai 0:e608fc311e4e 381 }
kenjiArai 0:e608fc311e4e 382 } else { // .
kenjiArai 0:e608fc311e4e 383 if (strcmp(code,".") == 0){ printascii('E'); return;}
kenjiArai 0:e608fc311e4e 384 }
kenjiArai 0:e608fc311e4e 385 } else if (code[0] == '-'){ // -
kenjiArai 0:e608fc311e4e 386 if (code[1] == '.'){ // -.
kenjiArai 0:e608fc311e4e 387 if (code[2] == '.'){ // -..
kenjiArai 0:e608fc311e4e 388 if (code[3] == '.'){ // -...
kenjiArai 0:e608fc311e4e 389 if (strcmp(code,"-..." ) == 0){ printascii('B'); return;}
kenjiArai 0:e608fc311e4e 390 if (strcmp(code,"-...." ) == 0){ printascii('6'); return;}
kenjiArai 0:e608fc311e4e 391 if (strcmp(code,"-....-" ) == 0){ printascii('-'); return;}
kenjiArai 0:e608fc311e4e 392 } else if (code[3] == '-'){ // -..-
kenjiArai 0:e608fc311e4e 393 if (strcmp(code,"-..-" ) == 0){ printascii('X'); return;}
kenjiArai 0:e608fc311e4e 394 if (strcmp(code,"-..-." ) == 0){ printascii(47); return;}
kenjiArai 0:e608fc311e4e 395 } else {
kenjiArai 0:e608fc311e4e 396 if (strcmp(code,"-.." ) == 0){ printascii('D'); return;}
kenjiArai 0:e608fc311e4e 397 }
kenjiArai 0:e608fc311e4e 398 } else if (code[2] == '-'){ // -.-
kenjiArai 0:e608fc311e4e 399 if (code[3] == '.'){ // -.-.
kenjiArai 0:e608fc311e4e 400 if (strcmp(code,"-.-." ) == 0){ printascii('C'); return;}
kenjiArai 0:e608fc311e4e 401 if (strcmp(code,"-.-.--" ) == 0){ printascii(33); return;}
kenjiArai 0:e608fc311e4e 402 } else if (code[3] == '-'){ // -.--
kenjiArai 0:e608fc311e4e 403 if (strcmp(code,"-.--" ) == 0){ printascii('Y'); return;}
kenjiArai 0:e608fc311e4e 404 if (strcmp(code,"-.--." ) == 0){ printascii(40); return;}
kenjiArai 0:e608fc311e4e 405 if (strcmp(code,"-.--.-" ) == 0){ printascii(41); return;}
kenjiArai 0:e608fc311e4e 406 } else { // -.-
kenjiArai 0:e608fc311e4e 407 if (strcmp(code,"-.-" ) == 0){ printascii('K'); return;}
kenjiArai 0:e608fc311e4e 408 }
kenjiArai 0:e608fc311e4e 409 } else { // -.
kenjiArai 0:e608fc311e4e 410 if (strcmp(code,"-.") == 0){ printascii('N'); return;}
kenjiArai 0:e608fc311e4e 411 }
kenjiArai 0:e608fc311e4e 412 } else if (code[1] == '-'){ // -
kenjiArai 0:e608fc311e4e 413 if (code[2] == '.'){ // --.
kenjiArai 0:e608fc311e4e 414 if (strcmp(code,"--." ) == 0){ printascii('G'); return;}
kenjiArai 0:e608fc311e4e 415 if (strcmp(code,"--.." ) == 0){ printascii('Z'); return;}
kenjiArai 0:e608fc311e4e 416 if (strcmp(code,"--.-" ) == 0){ printascii('Q'); return;}
kenjiArai 0:e608fc311e4e 417 if (strcmp(code,"--..." ) == 0){ printascii('7'); return;}
kenjiArai 0:e608fc311e4e 418 if (strcmp(code,"--..--" ) == 0){ printascii(44); return;}
kenjiArai 0:e608fc311e4e 419 } else if (code[2] == '-'){ // ---
kenjiArai 0:e608fc311e4e 420 if (code[3] == '.'){ // ---.
kenjiArai 0:e608fc311e4e 421 if (strcmp(code,"---.." ) == 0){ printascii('8'); return;}
kenjiArai 0:e608fc311e4e 422 if (strcmp(code,"---." ) == 0){ printascii(4); return;}
kenjiArai 0:e608fc311e4e 423 if (strcmp(code,"---..." ) == 0){ printascii(58); return;}
kenjiArai 0:e608fc311e4e 424 } else if (code[3] == '-'){ // ----
kenjiArai 0:e608fc311e4e 425 if (strcmp(code,"----." ) == 0){ printascii('9'); return;}
kenjiArai 0:e608fc311e4e 426 if (strcmp(code,"-----" ) == 0){ printascii('0'); return;}
kenjiArai 0:e608fc311e4e 427 } else { // ---
kenjiArai 0:e608fc311e4e 428 if (strcmp(code,"---" ) == 0){ printascii('O'); return;}
kenjiArai 0:e608fc311e4e 429 }
kenjiArai 0:e608fc311e4e 430 } else { // --
kenjiArai 0:e608fc311e4e 431 if (strcmp(code,"--") == 0){ printascii('M'); return;}
kenjiArai 0:e608fc311e4e 432 }
kenjiArai 0:e608fc311e4e 433 } else { // -
kenjiArai 0:e608fc311e4e 434 if (strcmp(code,"-") == 0){ printascii('T'); return;}
kenjiArai 0:e608fc311e4e 435 }
kenjiArai 0:e608fc311e4e 436 }
kenjiArai 0:e608fc311e4e 437 }
kenjiArai 0:e608fc311e4e 438
kenjiArai 0:e608fc311e4e 439 void printascii(char c)
kenjiArai 0:e608fc311e4e 440 {
kenjiArai 0:e608fc311e4e 441 uint8_t i,j;
kenjiArai 0:e608fc311e4e 442
kenjiArai 0:e608fc311e4e 443 out_code = 1;
kenjiArai 0:e608fc311e4e 444 PRINTF("%c", c);
kenjiArai 0:e608fc311e4e 445 msg_lcd[WORK_LINE][num_last_line++] = c;
kenjiArai 0:e608fc311e4e 446 if (num_last_line == ONE_LINE){
kenjiArai 0:e608fc311e4e 447 for (j = 0; j < LINES; j++){ // scroll one line
kenjiArai 0:e608fc311e4e 448 for (i =0; i < ONE_LINE; i++){
kenjiArai 0:e608fc311e4e 449 msg_lcd[j][i] = msg_lcd[j+1][i];
kenjiArai 0:e608fc311e4e 450 }
kenjiArai 0:e608fc311e4e 451 }
kenjiArai 0:e608fc311e4e 452 for (i =0; i < ONE_LINE; i++){ // Clear last line
kenjiArai 0:e608fc311e4e 453 msg_lcd[WORK_LINE][i] = ' ';
kenjiArai 0:e608fc311e4e 454 }
kenjiArai 0:e608fc311e4e 455 num_last_line = 0;
kenjiArai 0:e608fc311e4e 456 for (i =0; i < (WORK_LINE + 1); i++){
kenjiArai 0:e608fc311e4e 457 lcd->DisplayStringAtLine( i, &msg_lcd[i][0]);
kenjiArai 0:e608fc311e4e 458 }
kenjiArai 0:e608fc311e4e 459 } else {
kenjiArai 0:e608fc311e4e 460 lcd->DisplayStringAtLine(WORK_LINE, &msg_lcd[WORK_LINE][0]);
kenjiArai 0:e608fc311e4e 461 }
kenjiArai 0:e608fc311e4e 462 out_code = 0;
kenjiArai 0:e608fc311e4e 463 }
kenjiArai 0:e608fc311e4e 464
kenjiArai 0:e608fc311e4e 465 //------------------------------------------------
kenjiArai 0:e608fc311e4e 466 // リアルタイム・スペクトログラム
kenjiArai 0:e608fc311e4e 467 // 入力: MEMS マイク
kenjiArai 0:e608fc311e4e 468 //
kenjiArai 0:e608fc311e4e 469 // 2016/10/02, Copyright (c) 2016 MIKAMI, Naoki
kenjiArai 0:e608fc311e4e 470 // modified by JH1PJL
kenjiArai 0:e608fc311e4e 471 //------------------------------------------------
kenjiArai 0:e608fc311e4e 472 void spectrum()
kenjiArai 0:e608fc311e4e 473 {
kenjiArai 0:e608fc311e4e 474 const int FS = I2S_AUDIOFREQ_16K; // 標本化周波数: 16 kHz
kenjiArai 0:e608fc311e4e 475 const int N_FFT = 512; // FFT の点数
kenjiArai 0:e608fc311e4e 476 const float FRAME = (N_FFT/(float)FS)*1000.0f; // 1 フレームに対応する時間(単位:ms)
kenjiArai 0:e608fc311e4e 477
kenjiArai 0:e608fc311e4e 478 const int X0 = 40; // 表示領域の x 座標の原点
kenjiArai 0:e608fc311e4e 479 const int Y0 = 200; // 表示領域の y 座標の原点
kenjiArai 0:e608fc311e4e 480 const int H0 = 160; // 表示する際の周波数軸の長さ(5 kHz に対応)
kenjiArai 0:e608fc311e4e 481 const uint16_t PX_1KHZ = H0/5; // 1 kHz に対応するピクセル数
kenjiArai 0:e608fc311e4e 482 const int W0 = 360; // 横方向の全体の表示の幅(単位:ピクセル)
kenjiArai 0:e608fc311e4e 483 const int H_BAR = 2; // 表示する際の 1 フレームに対応する横方向のピクセル数
kenjiArai 0:e608fc311e4e 484 const int SIZE_X = W0/H_BAR;
kenjiArai 0:e608fc311e4e 485 const uint16_t MS100 = 100*H_BAR/FRAME; // 100 ms に対応するピクセル数
kenjiArai 0:e608fc311e4e 486 const uint32_t AXIS_COLOR = LCD_COLOR_WHITE;//0xFFCCFFFF;
kenjiArai 0:e608fc311e4e 487
kenjiArai 0:e608fc311e4e 488 Matrix<uint32_t> spectra(SIZE_X, H0+1, GuiBase::ENUM_BACK);
kenjiArai 0:e608fc311e4e 489
kenjiArai 0:e608fc311e4e 490 SaiIO mySai(SaiIO::INPUT, N_FFT+1, FS,
kenjiArai 0:e608fc311e4e 491 INPUT_DEVICE_DIGITAL_MICROPHONE_2);
kenjiArai 0:e608fc311e4e 492
kenjiArai 0:e608fc311e4e 493 LCD_DISCO_F746NG *lcd = GuiBase::GetLcdPtr(); // LCD 表示器のオブジェクト
kenjiArai 0:e608fc311e4e 494 lcd->Clear(GuiBase::ENUM_BACK);
kenjiArai 0:e608fc311e4e 495 Label myLabel1(240, 2, "Real-time spectrogram", Label::CENTER, Font16);
kenjiArai 0:e608fc311e4e 496
kenjiArai 0:e608fc311e4e 497 // ButtonGroup の設定
kenjiArai 0:e608fc311e4e 498 const uint16_t B_W = 50;
kenjiArai 0:e608fc311e4e 499 const uint16_t B_Y = 242;
kenjiArai 0:e608fc311e4e 500 const uint16_t B_H = 30;
kenjiArai 0:e608fc311e4e 501 const string RUN_STOP[3] = {"MENUE","RUN", "STOP"};
kenjiArai 0:e608fc311e4e 502 ButtonGroup runStop(285, B_Y, B_W, B_H, 3, RUN_STOP, 0, 0, 3, 1);
kenjiArai 0:e608fc311e4e 503
kenjiArai 0:e608fc311e4e 504 Button clear(430, B_Y, B_W, B_H, "CLEAR");
kenjiArai 0:e608fc311e4e 505 clear.Inactivate();
kenjiArai 0:e608fc311e4e 506 // ButtonGroup の設定(ここまで)
kenjiArai 0:e608fc311e4e 507
kenjiArai 0:e608fc311e4e 508 // 座標軸
kenjiArai 0:e608fc311e4e 509 DrawAxis(X0, Y0, W0, H0, AXIS_COLOR, MS100, PX_1KHZ, lcd);
kenjiArai 0:e608fc311e4e 510
kenjiArai 0:e608fc311e4e 511 Array<float> sn(N_FFT+1);
kenjiArai 0:e608fc311e4e 512 Array<float> db(N_FFT/2+1);
kenjiArai 0:e608fc311e4e 513
kenjiArai 0:e608fc311e4e 514 // 色と dB の関係の表示
kenjiArai 0:e608fc311e4e 515 ColorDb(Y0, AXIS_COLOR, lcd);
kenjiArai 0:e608fc311e4e 516
kenjiArai 0:e608fc311e4e 517 FftAnalyzer fftAnalyzer(N_FFT+1, N_FFT);
kenjiArai 0:e608fc311e4e 518
kenjiArai 0:e608fc311e4e 519 // ループ内で使う変数の初期化
kenjiArai 0:e608fc311e4e 520 int stop = 1; // 0: run, 1: stop
kenjiArai 0:e608fc311e4e 521
kenjiArai 0:e608fc311e4e 522 while(!runStop.GetTouchedNumber(stop)) {}
kenjiArai 0:e608fc311e4e 523 // データ読み込み開始
kenjiArai 0:e608fc311e4e 524 mySai.RecordIn();
kenjiArai 0:e608fc311e4e 525
kenjiArai 0:e608fc311e4e 526 while (true)
kenjiArai 0:e608fc311e4e 527 {
kenjiArai 0:e608fc311e4e 528 runStop.GetTouchedNumber(stop);
kenjiArai 0:e608fc311e4e 529
kenjiArai 0:e608fc311e4e 530 if (stop == 0){
kenjiArai 0:e608fc311e4e 531 NVIC_SystemReset();
kenjiArai 0:e608fc311e4e 532 }
kenjiArai 0:e608fc311e4e 533 else if (stop == 1)
kenjiArai 0:e608fc311e4e 534 {
kenjiArai 0:e608fc311e4e 535 clear.Inactivate();
kenjiArai 0:e608fc311e4e 536 if (mySai.IsCaptured())
kenjiArai 0:e608fc311e4e 537 {
kenjiArai 0:e608fc311e4e 538 // 1フレーム分の信号の入力
kenjiArai 0:e608fc311e4e 539 for (int n=0; n<mySai.GetLength(); n++)
kenjiArai 0:e608fc311e4e 540 {
kenjiArai 0:e608fc311e4e 541 int16_t xL, xR;
kenjiArai 0:e608fc311e4e 542 mySai.Input(xL, xR);
kenjiArai 0:e608fc311e4e 543 sn[n] = (float)xL;
kenjiArai 0:e608fc311e4e 544 }
kenjiArai 0:e608fc311e4e 545 //mySai.ResetCaptured();
kenjiArai 0:e608fc311e4e 546
kenjiArai 0:e608fc311e4e 547 // スペクトルの更新
kenjiArai 0:e608fc311e4e 548 SpectrumUpdate(spectra, fftAnalyzer, sn, db);
kenjiArai 0:e608fc311e4e 549 // スペクトルの表示
kenjiArai 0:e608fc311e4e 550 DisplaySpectrum(spectra, X0, Y0, H_BAR, lcd);
kenjiArai 0:e608fc311e4e 551 }
kenjiArai 0:e608fc311e4e 552 }
kenjiArai 0:e608fc311e4e 553 else if (stop == 2)
kenjiArai 0:e608fc311e4e 554 {
kenjiArai 0:e608fc311e4e 555 if (!clear.IsActive()) clear.Activate();
kenjiArai 0:e608fc311e4e 556 if (clear.Touched())
kenjiArai 0:e608fc311e4e 557 {
kenjiArai 0:e608fc311e4e 558 spectra.Fill(GuiBase::ENUM_BACK); // スペクトルの表示をクリア
kenjiArai 0:e608fc311e4e 559 DisplaySpectrum(spectra, X0, Y0, H_BAR, lcd);
kenjiArai 0:e608fc311e4e 560 clear.Draw();
kenjiArai 0:e608fc311e4e 561 }
kenjiArai 0:e608fc311e4e 562 }
kenjiArai 0:e608fc311e4e 563 }
kenjiArai 0:e608fc311e4e 564 }