Kenji Arai / Mbed OS cwdecoder_Goertzel_on_mbed-os

Dependencies:   TextLCD

Committer:
kenjiArai
Date:
Fri Jan 27 04:07:01 2017 +0000
Revision:
0:166e0710d217
Morse code (CW) decoder program. Original source is made by Hjalmar Skovholm Hansen OZ1JHM. The program uses the Goertzel Algorithm.
;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kenjiArai 0:166e0710d217 1 //---------------------------------------------------------------------------------------------------------------------------------------------------
kenjiArai 0:166e0710d217 2 // http://www.skovholm.com/decoder11.ino
kenjiArai 0:166e0710d217 3 //---------------------------------------------------------------------------------------------------------------------------------------------------
kenjiArai 0:166e0710d217 4
kenjiArai 0:166e0710d217 5 ///////////////////////////////////////////////////////////////////////
kenjiArai 0:166e0710d217 6 // CW Decoder made by Hjalmar Skovholm Hansen OZ1JHM VER 1.01 //
kenjiArai 0:166e0710d217 7 // Feel free to change, copy or what ever you like but respect //
kenjiArai 0:166e0710d217 8 // that license is http://www.gnu.org/copyleft/gpl.html //
kenjiArai 0:166e0710d217 9 // Discuss and give great ideas on //
kenjiArai 0:166e0710d217 10 // https://groups.yahoo.com/neo/groups/oz1jhm/conversations/messages //
kenjiArai 0:166e0710d217 11 ///////////////////////////////////////////////////////////////////////
kenjiArai 0:166e0710d217 12
kenjiArai 0:166e0710d217 13 ///////////////////////////////////////////////////////////////////////////
kenjiArai 0:166e0710d217 14 // Read more here http://en.wikipedia.org/wiki/Goertzel_algorithm //
kenjiArai 0:166e0710d217 15 // if you want to know about FFT the http://www.dspguide.com/pdfbook.htm //
kenjiArai 0:166e0710d217 16 ///////////////////////////////////////////////////////////////////////////
kenjiArai 0:166e0710d217 17
kenjiArai 0:166e0710d217 18 #include <LiquidCrystal.h>
kenjiArai 0:166e0710d217 19
kenjiArai 0:166e0710d217 20 ///////////////////////////////////////////////
kenjiArai 0:166e0710d217 21 // select the pins used on the LCD panel /
kenjiArai 0:166e0710d217 22 ///////////////////////////////////////////////
kenjiArai 0:166e0710d217 23 // LiquidCrystal lcd(RS, E, D4, D5, D6, D7) //
kenjiArai 0:166e0710d217 24 ///////////////////////////////////////////////
kenjiArai 0:166e0710d217 25
kenjiArai 0:166e0710d217 26 LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
kenjiArai 0:166e0710d217 27
kenjiArai 0:166e0710d217 28 const int colums = 20; /// have to be 16 or 20
kenjiArai 0:166e0710d217 29 const int rows = 4; /// have to be 2 or 4
kenjiArai 0:166e0710d217 30
kenjiArai 0:166e0710d217 31 int lcdindex = 0;
kenjiArai 0:166e0710d217 32 int line1[colums];
kenjiArai 0:166e0710d217 33 int line2[colums];
kenjiArai 0:166e0710d217 34
kenjiArai 0:166e0710d217 35 ////////////////////////////////
kenjiArai 0:166e0710d217 36 // Define 8 specials letters //
kenjiArai 0:166e0710d217 37 ////////////////////////////////
kenjiArai 0:166e0710d217 38
kenjiArai 0:166e0710d217 39 byte U_umlaut[8] = {B01010,B00000,B10001,B10001,B10001,B10001,B01110,B00000}; // 'ワ'
kenjiArai 0:166e0710d217 40 byte O_umlaut[8] = {B01010,B00000,B01110,B10001,B10001,B10001,B01110,B00000}; // 'ヨ'
kenjiArai 0:166e0710d217 41 byte A_umlaut[8] = {B01010,B00000,B01110,B10001,B11111,B10001,B10001,B00000}; // 'ト'
kenjiArai 0:166e0710d217 42 byte AE_capital[8] = {B01111,B10100,B10100,B11110,B10100,B10100,B10111,B00000}; // 'ニ'
kenjiArai 0:166e0710d217 43 byte OE_capital[8] = {B00001,B01110,B10011,B10101,B11001,B01110,B10000,B00000}; // 'リ'
kenjiArai 0:166e0710d217 44 byte fullblock[8] = {B11111,B11111,B11111,B11111,B11111,B11111,B11111,B11111};
kenjiArai 0:166e0710d217 45 byte AA_capital[8] = {B00100,B00000,B01110,B10001,B11111,B10001,B10001,B00000}; // 'ナ'
kenjiArai 0:166e0710d217 46 byte emtyblock[8] = {B00000,B00000,B00000,B00000,B00000,B00000,B00000,B00000};
kenjiArai 0:166e0710d217 47
kenjiArai 0:166e0710d217 48 int audioInPin = A1;
kenjiArai 0:166e0710d217 49 int audioOutPin = 10;
kenjiArai 0:166e0710d217 50 int ledPin = 13;
kenjiArai 0:166e0710d217 51
kenjiArai 0:166e0710d217 52 float magnitude ;
kenjiArai 0:166e0710d217 53 int magnitudelimit = 100;
kenjiArai 0:166e0710d217 54 int magnitudelimit_low = 100;
kenjiArai 0:166e0710d217 55 int realstate = LOW;
kenjiArai 0:166e0710d217 56 int realstatebefore = LOW;
kenjiArai 0:166e0710d217 57 int filteredstate = LOW;
kenjiArai 0:166e0710d217 58 int filteredstatebefore = LOW;
kenjiArai 0:166e0710d217 59
kenjiArai 0:166e0710d217 60
kenjiArai 0:166e0710d217 61 ///////////////////////////////////////////////////////////
kenjiArai 0:166e0710d217 62 // The sampling frq will be 8928 on a 16 mhz //
kenjiArai 0:166e0710d217 63 // without any prescaler etc //
kenjiArai 0:166e0710d217 64 // because we need the tone in the center of the bins //
kenjiArai 0:166e0710d217 65 // you can set the tone to 496, 558, 744 or 992 //
kenjiArai 0:166e0710d217 66 // then n the number of samples which give the bandwidth //
kenjiArai 0:166e0710d217 67 // can be (8928 / tone) * 1 or 2 or 3 or 4 etc //
kenjiArai 0:166e0710d217 68 // init is 8928/558 = 16 *4 = 64 samples //
kenjiArai 0:166e0710d217 69 // try to take n = 96 or 128 ;o) //
kenjiArai 0:166e0710d217 70 // 48 will give you a bandwidth around 186 hz //
kenjiArai 0:166e0710d217 71 // 64 will give you a bandwidth around 140 hz //
kenjiArai 0:166e0710d217 72 // 96 will give you a bandwidth around 94 hz //
kenjiArai 0:166e0710d217 73 // 128 will give you a bandwidth around 70 hz //
kenjiArai 0:166e0710d217 74 // BUT remember that high n take a lot of time //
kenjiArai 0:166e0710d217 75 // so you have to find the compromice - i use 48 //
kenjiArai 0:166e0710d217 76 ///////////////////////////////////////////////////////////
kenjiArai 0:166e0710d217 77
kenjiArai 0:166e0710d217 78 float coeff;
kenjiArai 0:166e0710d217 79 float Q1 = 0;
kenjiArai 0:166e0710d217 80 float Q2 = 0;
kenjiArai 0:166e0710d217 81 float sine;
kenjiArai 0:166e0710d217 82 float cosine;
kenjiArai 0:166e0710d217 83 float sampling_freq=8928.0;
kenjiArai 0:166e0710d217 84 float target_freq=558.0; /// adjust for your needs see above
kenjiArai 0:166e0710d217 85 float n=48.0; //// if you change her please change next line also
kenjiArai 0:166e0710d217 86 int testData[48];
kenjiArai 0:166e0710d217 87
kenjiArai 0:166e0710d217 88 //////////////////////////////
kenjiArai 0:166e0710d217 89 // Noise Blanker time which //
kenjiArai 0:166e0710d217 90 // shall be computed so //
kenjiArai 0:166e0710d217 91 // this is initial //
kenjiArai 0:166e0710d217 92 //////////////////////////////
kenjiArai 0:166e0710d217 93 int nbtime = 6; /// ms noise blanker
kenjiArai 0:166e0710d217 94
kenjiArai 0:166e0710d217 95 long starttimehigh;
kenjiArai 0:166e0710d217 96 long highduration;
kenjiArai 0:166e0710d217 97 long lasthighduration;
kenjiArai 0:166e0710d217 98 long hightimesavg;
kenjiArai 0:166e0710d217 99 long lowtimesavg;
kenjiArai 0:166e0710d217 100 long startttimelow;
kenjiArai 0:166e0710d217 101 long lowduration;
kenjiArai 0:166e0710d217 102 long laststarttime = 0;
kenjiArai 0:166e0710d217 103
kenjiArai 0:166e0710d217 104 char code[20];
kenjiArai 0:166e0710d217 105 int stop = LOW;
kenjiArai 0:166e0710d217 106 int wpm;
kenjiArai 0:166e0710d217 107
kenjiArai 0:166e0710d217 108
kenjiArai 0:166e0710d217 109 ////////////////
kenjiArai 0:166e0710d217 110 // init setup //
kenjiArai 0:166e0710d217 111 ////////////////
kenjiArai 0:166e0710d217 112 void setup() {
kenjiArai 0:166e0710d217 113
kenjiArai 0:166e0710d217 114 ////////////////////////////////////
kenjiArai 0:166e0710d217 115 // The basic goertzel calculation //
kenjiArai 0:166e0710d217 116 ////////////////////////////////////
kenjiArai 0:166e0710d217 117 int k;
kenjiArai 0:166e0710d217 118 float omega;
kenjiArai 0:166e0710d217 119 k = (int) (0.5 + ((n * target_freq) / sampling_freq));
kenjiArai 0:166e0710d217 120 omega = (2.0 * PI * k) / n;
kenjiArai 0:166e0710d217 121 sine = sin(omega);
kenjiArai 0:166e0710d217 122 cosine = cos(omega);
kenjiArai 0:166e0710d217 123 coeff = 2.0 * cosine;
kenjiArai 0:166e0710d217 124
kenjiArai 0:166e0710d217 125 ///////////////////////////////
kenjiArai 0:166e0710d217 126 // define special characters //
kenjiArai 0:166e0710d217 127 ///////////////////////////////
kenjiArai 0:166e0710d217 128 lcd.createChar(0, U_umlaut); // German
kenjiArai 0:166e0710d217 129 lcd.createChar(1, O_umlaut); // German, Swedish
kenjiArai 0:166e0710d217 130 lcd.createChar(2, A_umlaut); // German, Swedish
kenjiArai 0:166e0710d217 131 lcd.createChar(3, AE_capital); // Danish, Norwegian
kenjiArai 0:166e0710d217 132 lcd.createChar(4, OE_capital); // Danish, Norwegian
kenjiArai 0:166e0710d217 133 lcd.createChar(5, fullblock);
kenjiArai 0:166e0710d217 134 lcd.createChar(6, AA_capital); // Danish, Norwegian, Swedish
kenjiArai 0:166e0710d217 135 lcd.createChar(7, emtyblock);
kenjiArai 0:166e0710d217 136 lcd.clear();
kenjiArai 0:166e0710d217 137
kenjiArai 0:166e0710d217 138 Serial.begin(115200);
kenjiArai 0:166e0710d217 139 pinMode(ledPin, OUTPUT);
kenjiArai 0:166e0710d217 140 lcd.begin(colums, rows);
kenjiArai 0:166e0710d217 141 for (int index = 0; index < colums; index++){
kenjiArai 0:166e0710d217 142 line1[index] = 32;
kenjiArai 0:166e0710d217 143 line2[index] = 32;
kenjiArai 0:166e0710d217 144 }
kenjiArai 0:166e0710d217 145
kenjiArai 0:166e0710d217 146 }
kenjiArai 0:166e0710d217 147
kenjiArai 0:166e0710d217 148 ///////////////
kenjiArai 0:166e0710d217 149 // main loop //
kenjiArai 0:166e0710d217 150 ///////////////
kenjiArai 0:166e0710d217 151 void loop() {
kenjiArai 0:166e0710d217 152
kenjiArai 0:166e0710d217 153 /////////////////////////////////////
kenjiArai 0:166e0710d217 154 // The basic where we get the tone //
kenjiArai 0:166e0710d217 155 /////////////////////////////////////
kenjiArai 0:166e0710d217 156
kenjiArai 0:166e0710d217 157 for (char index = 0; index < n; index++)
kenjiArai 0:166e0710d217 158 {
kenjiArai 0:166e0710d217 159 testData[index] = analogRead(audioInPin);
kenjiArai 0:166e0710d217 160 }
kenjiArai 0:166e0710d217 161 for (char index = 0; index < n; index++){
kenjiArai 0:166e0710d217 162 float Q0;
kenjiArai 0:166e0710d217 163 Q0 = coeff * Q1 - Q2 + (float) testData[index];
kenjiArai 0:166e0710d217 164 Q2 = Q1;
kenjiArai 0:166e0710d217 165 Q1 = Q0;
kenjiArai 0:166e0710d217 166 }
kenjiArai 0:166e0710d217 167 float magnitudeSquared = (Q1*Q1)+(Q2*Q2)-Q1*Q2*coeff; // we do only need the real part //
kenjiArai 0:166e0710d217 168 magnitude = sqrt(magnitudeSquared);
kenjiArai 0:166e0710d217 169 Q2 = 0;
kenjiArai 0:166e0710d217 170 Q1 = 0;
kenjiArai 0:166e0710d217 171
kenjiArai 0:166e0710d217 172 //Serial.print(magnitude); Serial.println(); //// here you can measure magnitude for setup..
kenjiArai 0:166e0710d217 173
kenjiArai 0:166e0710d217 174 ///////////////////////////////////////////////////////////
kenjiArai 0:166e0710d217 175 // here we will try to set the magnitude limit automatic //
kenjiArai 0:166e0710d217 176 ///////////////////////////////////////////////////////////
kenjiArai 0:166e0710d217 177
kenjiArai 0:166e0710d217 178 if (magnitude > magnitudelimit_low){
kenjiArai 0:166e0710d217 179 magnitudelimit = (magnitudelimit +((magnitude - magnitudelimit)/6)); /// moving average filter
kenjiArai 0:166e0710d217 180 }
kenjiArai 0:166e0710d217 181
kenjiArai 0:166e0710d217 182 if (magnitudelimit < magnitudelimit_low)
kenjiArai 0:166e0710d217 183 magnitudelimit = magnitudelimit_low;
kenjiArai 0:166e0710d217 184
kenjiArai 0:166e0710d217 185 ////////////////////////////////////
kenjiArai 0:166e0710d217 186 // now we check for the magnitude //
kenjiArai 0:166e0710d217 187 ////////////////////////////////////
kenjiArai 0:166e0710d217 188
kenjiArai 0:166e0710d217 189 if(magnitude > magnitudelimit*0.6) // just to have some space up
kenjiArai 0:166e0710d217 190 realstate = HIGH;
kenjiArai 0:166e0710d217 191 else
kenjiArai 0:166e0710d217 192 realstate = LOW;
kenjiArai 0:166e0710d217 193
kenjiArai 0:166e0710d217 194 /////////////////////////////////////////////////////
kenjiArai 0:166e0710d217 195 // here we clean up the state with a noise blanker //
kenjiArai 0:166e0710d217 196 /////////////////////////////////////////////////////
kenjiArai 0:166e0710d217 197
kenjiArai 0:166e0710d217 198 if (realstate != realstatebefore){
kenjiArai 0:166e0710d217 199 laststarttime = millis();
kenjiArai 0:166e0710d217 200 }
kenjiArai 0:166e0710d217 201 if ((millis()-laststarttime)> nbtime){
kenjiArai 0:166e0710d217 202 if (realstate != filteredstate){
kenjiArai 0:166e0710d217 203 filteredstate = realstate;
kenjiArai 0:166e0710d217 204 }
kenjiArai 0:166e0710d217 205 }
kenjiArai 0:166e0710d217 206
kenjiArai 0:166e0710d217 207 ////////////////////////////////////////////////////////////
kenjiArai 0:166e0710d217 208 // Then we do want to have some durations on high and low //
kenjiArai 0:166e0710d217 209 ////////////////////////////////////////////////////////////
kenjiArai 0:166e0710d217 210
kenjiArai 0:166e0710d217 211 if (filteredstate != filteredstatebefore){
kenjiArai 0:166e0710d217 212 if (filteredstate == HIGH){
kenjiArai 0:166e0710d217 213 starttimehigh = millis();
kenjiArai 0:166e0710d217 214 lowduration = (millis() - startttimelow);
kenjiArai 0:166e0710d217 215 }
kenjiArai 0:166e0710d217 216
kenjiArai 0:166e0710d217 217 if (filteredstate == LOW){
kenjiArai 0:166e0710d217 218 startttimelow = millis();
kenjiArai 0:166e0710d217 219 highduration = (millis() - starttimehigh);
kenjiArai 0:166e0710d217 220 if (highduration < (2*hightimesavg) || hightimesavg == 0){
kenjiArai 0:166e0710d217 221 hightimesavg = (highduration+hightimesavg+hightimesavg)/3; // now we know avg dit time ( rolling 3 avg)
kenjiArai 0:166e0710d217 222 }
kenjiArai 0:166e0710d217 223 if (highduration > (5*hightimesavg) ){
kenjiArai 0:166e0710d217 224 hightimesavg = highduration+hightimesavg; // if speed decrease fast ..
kenjiArai 0:166e0710d217 225 }
kenjiArai 0:166e0710d217 226 }
kenjiArai 0:166e0710d217 227 }
kenjiArai 0:166e0710d217 228
kenjiArai 0:166e0710d217 229 ///////////////////////////////////////////////////////////////
kenjiArai 0:166e0710d217 230 // now we will check which kind of baud we have - dit or dah //
kenjiArai 0:166e0710d217 231 // and what kind of pause we do have 1 - 3 or 7 pause //
kenjiArai 0:166e0710d217 232 // we think that hightimeavg = 1 bit //
kenjiArai 0:166e0710d217 233 ///////////////////////////////////////////////////////////////
kenjiArai 0:166e0710d217 234
kenjiArai 0:166e0710d217 235 if (filteredstate != filteredstatebefore){
kenjiArai 0:166e0710d217 236 stop = LOW;
kenjiArai 0:166e0710d217 237 if (filteredstate == LOW){ //// we did end a HIGH
kenjiArai 0:166e0710d217 238 if (highduration < (hightimesavg*2) && highduration > (hightimesavg*0.6)){ /// 0.6 filter out false dits
kenjiArai 0:166e0710d217 239 strcat(code,".");
kenjiArai 0:166e0710d217 240 Serial.print(".");
kenjiArai 0:166e0710d217 241 }
kenjiArai 0:166e0710d217 242 if (highduration > (hightimesavg*2) && highduration < (hightimesavg*6)){
kenjiArai 0:166e0710d217 243 strcat(code,"-");
kenjiArai 0:166e0710d217 244 Serial.print("-");
kenjiArai 0:166e0710d217 245 wpm = (wpm + (1200/((highduration)/3)))/2; //// the most precise we can do ;o)
kenjiArai 0:166e0710d217 246 }
kenjiArai 0:166e0710d217 247 }
kenjiArai 0:166e0710d217 248
kenjiArai 0:166e0710d217 249 if (filteredstate == HIGH){ //// we did end a LOW
kenjiArai 0:166e0710d217 250
kenjiArai 0:166e0710d217 251 float lacktime = 1;
kenjiArai 0:166e0710d217 252 if(wpm > 25)lacktime=1.0; /// when high speeds we have to have a little more pause before new letter or new word
kenjiArai 0:166e0710d217 253 if(wpm > 30)lacktime=1.2;
kenjiArai 0:166e0710d217 254 if(wpm > 35)lacktime=1.5;
kenjiArai 0:166e0710d217 255
kenjiArai 0:166e0710d217 256 if (lowduration > (hightimesavg*(2*lacktime)) && lowduration < hightimesavg*(5*lacktime)){ // letter space
kenjiArai 0:166e0710d217 257 docode();
kenjiArai 0:166e0710d217 258 code[0] = '\0';
kenjiArai 0:166e0710d217 259 Serial.print("/");
kenjiArai 0:166e0710d217 260 }
kenjiArai 0:166e0710d217 261 if (lowduration >= hightimesavg*(5*lacktime)){ // word space
kenjiArai 0:166e0710d217 262 docode();
kenjiArai 0:166e0710d217 263 code[0] = '\0';
kenjiArai 0:166e0710d217 264 printascii(32);
kenjiArai 0:166e0710d217 265 Serial.println();
kenjiArai 0:166e0710d217 266 }
kenjiArai 0:166e0710d217 267 }
kenjiArai 0:166e0710d217 268 }
kenjiArai 0:166e0710d217 269
kenjiArai 0:166e0710d217 270 //////////////////////////////
kenjiArai 0:166e0710d217 271 // write if no more letters //
kenjiArai 0:166e0710d217 272 //////////////////////////////
kenjiArai 0:166e0710d217 273
kenjiArai 0:166e0710d217 274 if ((millis() - startttimelow) > (highduration * 6) && stop == LOW){
kenjiArai 0:166e0710d217 275 docode();
kenjiArai 0:166e0710d217 276 code[0] = '\0';
kenjiArai 0:166e0710d217 277 stop = HIGH;
kenjiArai 0:166e0710d217 278 }
kenjiArai 0:166e0710d217 279
kenjiArai 0:166e0710d217 280 /////////////////////////////////////
kenjiArai 0:166e0710d217 281 // we will turn on and off the LED //
kenjiArai 0:166e0710d217 282 // and the speaker //
kenjiArai 0:166e0710d217 283 /////////////////////////////////////
kenjiArai 0:166e0710d217 284
kenjiArai 0:166e0710d217 285 if(filteredstate == HIGH){
kenjiArai 0:166e0710d217 286 digitalWrite(ledPin, HIGH);
kenjiArai 0:166e0710d217 287 tone(audioOutPin,target_freq);
kenjiArai 0:166e0710d217 288 }
kenjiArai 0:166e0710d217 289 else{
kenjiArai 0:166e0710d217 290 digitalWrite(ledPin, LOW);
kenjiArai 0:166e0710d217 291 noTone(audioOutPin);
kenjiArai 0:166e0710d217 292 }
kenjiArai 0:166e0710d217 293
kenjiArai 0:166e0710d217 294 //////////////////////////////////
kenjiArai 0:166e0710d217 295 // the end of main loop clean up//
kenjiArai 0:166e0710d217 296 /////////////////////////////////
kenjiArai 0:166e0710d217 297 updateinfolinelcd();
kenjiArai 0:166e0710d217 298 realstatebefore = realstate;
kenjiArai 0:166e0710d217 299 lasthighduration = highduration;
kenjiArai 0:166e0710d217 300 filteredstatebefore = filteredstate;
kenjiArai 0:166e0710d217 301 }
kenjiArai 0:166e0710d217 302
kenjiArai 0:166e0710d217 303
kenjiArai 0:166e0710d217 304 ////////////////////////////////
kenjiArai 0:166e0710d217 305 // translate cw code to ascii //
kenjiArai 0:166e0710d217 306 ////////////////////////////////
kenjiArai 0:166e0710d217 307
kenjiArai 0:166e0710d217 308 void docode(){
kenjiArai 0:166e0710d217 309 if (strcmp(code,".-") == 0) printascii(65);
kenjiArai 0:166e0710d217 310 if (strcmp(code,"-...") == 0) printascii(66);
kenjiArai 0:166e0710d217 311 if (strcmp(code,"-.-.") == 0) printascii(67);
kenjiArai 0:166e0710d217 312 if (strcmp(code,"-..") == 0) printascii(68);
kenjiArai 0:166e0710d217 313 if (strcmp(code,".") == 0) printascii(69);
kenjiArai 0:166e0710d217 314 if (strcmp(code,"..-.") == 0) printascii(70);
kenjiArai 0:166e0710d217 315 if (strcmp(code,"--.") == 0) printascii(71);
kenjiArai 0:166e0710d217 316 if (strcmp(code,"....") == 0) printascii(72);
kenjiArai 0:166e0710d217 317 if (strcmp(code,"..") == 0) printascii(73);
kenjiArai 0:166e0710d217 318 if (strcmp(code,".---") == 0) printascii(74);
kenjiArai 0:166e0710d217 319 if (strcmp(code,"-.-") == 0) printascii(75);
kenjiArai 0:166e0710d217 320 if (strcmp(code,".-..") == 0) printascii(76);
kenjiArai 0:166e0710d217 321 if (strcmp(code,"--") == 0) printascii(77);
kenjiArai 0:166e0710d217 322 if (strcmp(code,"-.") == 0) printascii(78);
kenjiArai 0:166e0710d217 323 if (strcmp(code,"---") == 0) printascii(79);
kenjiArai 0:166e0710d217 324 if (strcmp(code,".--.") == 0) printascii(80);
kenjiArai 0:166e0710d217 325 if (strcmp(code,"--.-") == 0) printascii(81);
kenjiArai 0:166e0710d217 326 if (strcmp(code,".-.") == 0) printascii(82);
kenjiArai 0:166e0710d217 327 if (strcmp(code,"...") == 0) printascii(83);
kenjiArai 0:166e0710d217 328 if (strcmp(code,"-") == 0) printascii(84);
kenjiArai 0:166e0710d217 329 if (strcmp(code,"..-") == 0) printascii(85);
kenjiArai 0:166e0710d217 330 if (strcmp(code,"...-") == 0) printascii(86);
kenjiArai 0:166e0710d217 331 if (strcmp(code,".--") == 0) printascii(87);
kenjiArai 0:166e0710d217 332 if (strcmp(code,"-..-") == 0) printascii(88);
kenjiArai 0:166e0710d217 333 if (strcmp(code,"-.--") == 0) printascii(89);
kenjiArai 0:166e0710d217 334 if (strcmp(code,"--..") == 0) printascii(90);
kenjiArai 0:166e0710d217 335
kenjiArai 0:166e0710d217 336 if (strcmp(code,".----") == 0) printascii(49);
kenjiArai 0:166e0710d217 337 if (strcmp(code,"..---") == 0) printascii(50);
kenjiArai 0:166e0710d217 338 if (strcmp(code,"...--") == 0) printascii(51);
kenjiArai 0:166e0710d217 339 if (strcmp(code,"....-") == 0) printascii(52);
kenjiArai 0:166e0710d217 340 if (strcmp(code,".....") == 0) printascii(53);
kenjiArai 0:166e0710d217 341 if (strcmp(code,"-....") == 0) printascii(54);
kenjiArai 0:166e0710d217 342 if (strcmp(code,"--...") == 0) printascii(55);
kenjiArai 0:166e0710d217 343 if (strcmp(code,"---..") == 0) printascii(56);
kenjiArai 0:166e0710d217 344 if (strcmp(code,"----.") == 0) printascii(57);
kenjiArai 0:166e0710d217 345 if (strcmp(code,"-----") == 0) printascii(48);
kenjiArai 0:166e0710d217 346
kenjiArai 0:166e0710d217 347 if (strcmp(code,"..--..") == 0) printascii(63);
kenjiArai 0:166e0710d217 348 if (strcmp(code,".-.-.-") == 0) printascii(46);
kenjiArai 0:166e0710d217 349 if (strcmp(code,"--..--") == 0) printascii(44);
kenjiArai 0:166e0710d217 350 if (strcmp(code,"-.-.--") == 0) printascii(33);
kenjiArai 0:166e0710d217 351 if (strcmp(code,".--.-.") == 0) printascii(64);
kenjiArai 0:166e0710d217 352 if (strcmp(code,"---...") == 0) printascii(58);
kenjiArai 0:166e0710d217 353 if (strcmp(code,"-....-") == 0) printascii(45);
kenjiArai 0:166e0710d217 354 if (strcmp(code,"-..-.") == 0) printascii(47);
kenjiArai 0:166e0710d217 355
kenjiArai 0:166e0710d217 356 if (strcmp(code,"-.--.") == 0) printascii(40);
kenjiArai 0:166e0710d217 357 if (strcmp(code,"-.--.-") == 0) printascii(41);
kenjiArai 0:166e0710d217 358 if (strcmp(code,".-...") == 0) printascii(95);
kenjiArai 0:166e0710d217 359 if (strcmp(code,"...-..-") == 0) printascii(36);
kenjiArai 0:166e0710d217 360 if (strcmp(code,"...-.-") == 0) printascii(62);
kenjiArai 0:166e0710d217 361 if (strcmp(code,".-.-.") == 0) printascii(60);
kenjiArai 0:166e0710d217 362 if (strcmp(code,"...-.") == 0) printascii(126);
kenjiArai 0:166e0710d217 363 //////////////////
kenjiArai 0:166e0710d217 364 // The specials //
kenjiArai 0:166e0710d217 365 //////////////////
kenjiArai 0:166e0710d217 366 if (strcmp(code,".-.-") == 0) printascii(3);
kenjiArai 0:166e0710d217 367 if (strcmp(code,"---.") == 0) printascii(4);
kenjiArai 0:166e0710d217 368 if (strcmp(code,".--.-") == 0) printascii(6);
kenjiArai 0:166e0710d217 369
kenjiArai 0:166e0710d217 370 }
kenjiArai 0:166e0710d217 371
kenjiArai 0:166e0710d217 372 /////////////////////////////////////
kenjiArai 0:166e0710d217 373 // print the ascii code to the lcd //
kenjiArai 0:166e0710d217 374 // one a time so we can generate //
kenjiArai 0:166e0710d217 375 // special letters //
kenjiArai 0:166e0710d217 376 /////////////////////////////////////
kenjiArai 0:166e0710d217 377 void printascii(int asciinumber){
kenjiArai 0:166e0710d217 378
kenjiArai 0:166e0710d217 379 int fail = 0;
kenjiArai 0:166e0710d217 380 if (rows == 4 and colums == 16)fail = -4; /// to fix the library problem with 4*16 display http://forum.arduino.cc/index.php/topic,14604.0.html
kenjiArai 0:166e0710d217 381
kenjiArai 0:166e0710d217 382 if (lcdindex > colums-1){
kenjiArai 0:166e0710d217 383 lcdindex = 0;
kenjiArai 0:166e0710d217 384 if (rows==4){
kenjiArai 0:166e0710d217 385 for (int i = 0; i <= colums-1 ; i++){
kenjiArai 0:166e0710d217 386 lcd.setCursor(i,rows-3);
kenjiArai 0:166e0710d217 387 lcd.write(line2[i]);
kenjiArai 0:166e0710d217 388 line2[i]=line1[i];
kenjiArai 0:166e0710d217 389 }
kenjiArai 0:166e0710d217 390 }
kenjiArai 0:166e0710d217 391 for (int i = 0; i <= colums-1 ; i++){
kenjiArai 0:166e0710d217 392 lcd.setCursor(i+fail,rows-2);
kenjiArai 0:166e0710d217 393 lcd.write(line1[i]);
kenjiArai 0:166e0710d217 394 lcd.setCursor(i+fail,rows-1);
kenjiArai 0:166e0710d217 395 lcd.write(32);
kenjiArai 0:166e0710d217 396 }
kenjiArai 0:166e0710d217 397 }
kenjiArai 0:166e0710d217 398 line1[lcdindex]=asciinumber;
kenjiArai 0:166e0710d217 399 lcd.setCursor(lcdindex+fail,rows-1);
kenjiArai 0:166e0710d217 400 lcd.write(asciinumber);
kenjiArai 0:166e0710d217 401 lcdindex += 1;
kenjiArai 0:166e0710d217 402 }
kenjiArai 0:166e0710d217 403
kenjiArai 0:166e0710d217 404 void updateinfolinelcd(){
kenjiArai 0:166e0710d217 405 /////////////////////////////////////
kenjiArai 0:166e0710d217 406 // here we update the upper line //
kenjiArai 0:166e0710d217 407 // with the speed. //
kenjiArai 0:166e0710d217 408 /////////////////////////////////////
kenjiArai 0:166e0710d217 409
kenjiArai 0:166e0710d217 410 int place;
kenjiArai 0:166e0710d217 411 if (rows == 4){
kenjiArai 0:166e0710d217 412 place = colums/2;}
kenjiArai 0:166e0710d217 413 else{
kenjiArai 0:166e0710d217 414 place = 2;
kenjiArai 0:166e0710d217 415 }
kenjiArai 0:166e0710d217 416 if (wpm<10){
kenjiArai 0:166e0710d217 417 lcd.setCursor((place)-2,0);
kenjiArai 0:166e0710d217 418 lcd.print("0");
kenjiArai 0:166e0710d217 419 lcd.setCursor((place)-1,0);
kenjiArai 0:166e0710d217 420 lcd.print(wpm);
kenjiArai 0:166e0710d217 421 lcd.setCursor((place),0);
kenjiArai 0:166e0710d217 422 lcd.print(" WPM");
kenjiArai 0:166e0710d217 423 }
kenjiArai 0:166e0710d217 424 else{
kenjiArai 0:166e0710d217 425 lcd.setCursor((place)-2,0);
kenjiArai 0:166e0710d217 426 lcd.print(wpm);
kenjiArai 0:166e0710d217 427 lcd.setCursor((place),0);
kenjiArai 0:166e0710d217 428 lcd.print(" WPM ");
kenjiArai 0:166e0710d217 429 }
kenjiArai 0:166e0710d217 430
kenjiArai 0:166e0710d217 431 }
kenjiArai 0:166e0710d217 432
kenjiArai 0:166e0710d217 433 //---------------------------------------------------------------------------------------------------------------------------------------------------
kenjiArai 0:166e0710d217 434 // http://archive.eetindia.co.in/www.eetindia.co.in/STATIC/DOWNLOAD/09banks.txt
kenjiArai 0:166e0710d217 435 //---------------------------------------------------------------------------------------------------------------------------------------------------
kenjiArai 0:166e0710d217 436 // Listing 1 A Goertzel implementation
kenjiArai 0:166e0710d217 437
kenjiArai 0:166e0710d217 438 #include <stdio.h>
kenjiArai 0:166e0710d217 439 #include <math.h>
kenjiArai 0:166e0710d217 440
kenjiArai 0:166e0710d217 441 #define FLOATING float
kenjiArai 0:166e0710d217 442 #define SAMPLE unsigned char
kenjiArai 0:166e0710d217 443
kenjiArai 0:166e0710d217 444 #define SAMPLING_RATE 8000.0 //8kHz
kenjiArai 0:166e0710d217 445 #define TARGET_FREQUENCY 941.0 //941 Hz
kenjiArai 0:166e0710d217 446 #define N 205 //Block size
kenjiArai 0:166e0710d217 447
kenjiArai 0:166e0710d217 448 FLOATING coeff;
kenjiArai 0:166e0710d217 449 FLOATING Q1;
kenjiArai 0:166e0710d217 450 FLOATING Q2;
kenjiArai 0:166e0710d217 451 FLOATING sine;
kenjiArai 0:166e0710d217 452 FLOATING cosine;
kenjiArai 0:166e0710d217 453
kenjiArai 0:166e0710d217 454 SAMPLE testData[N];
kenjiArai 0:166e0710d217 455
kenjiArai 0:166e0710d217 456 /* Call this routine before every "block" (size=N) of samples. */
kenjiArai 0:166e0710d217 457 void ResetGoertzel(void)
kenjiArai 0:166e0710d217 458 {
kenjiArai 0:166e0710d217 459 Q2 = 0;
kenjiArai 0:166e0710d217 460 Q1 = 0;
kenjiArai 0:166e0710d217 461 }
kenjiArai 0:166e0710d217 462
kenjiArai 0:166e0710d217 463 /* Call this once, to precompute the constants. */
kenjiArai 0:166e0710d217 464 void InitGoertzel(void)
kenjiArai 0:166e0710d217 465 {
kenjiArai 0:166e0710d217 466 int k;
kenjiArai 0:166e0710d217 467 FLOATING floatN;
kenjiArai 0:166e0710d217 468 FLOATING omega;
kenjiArai 0:166e0710d217 469
kenjiArai 0:166e0710d217 470 floatN = (FLOATING) N;
kenjiArai 0:166e0710d217 471 k = (int) (0.5 + ((floatN * TARGET_FREQUENCY) / SAMPLING_RATE));
kenjiArai 0:166e0710d217 472 omega = (2.0 * PI * k) / floatN;
kenjiArai 0:166e0710d217 473 sine = sin(omega);
kenjiArai 0:166e0710d217 474 cosine = cos(omega);
kenjiArai 0:166e0710d217 475 coeff = 2.0 * cosine;
kenjiArai 0:166e0710d217 476
kenjiArai 0:166e0710d217 477 printf("For SAMPLING_RATE = %f", SAMPLING_RATE);
kenjiArai 0:166e0710d217 478 printf(" N = %d", N);
kenjiArai 0:166e0710d217 479 printf(" and FREQUENCY = %f,\n", TARGET_FREQUENCY);
kenjiArai 0:166e0710d217 480 printf("k = %d and coeff = %f\n\n", k, coeff);
kenjiArai 0:166e0710d217 481
kenjiArai 0:166e0710d217 482 ResetGoertzel();
kenjiArai 0:166e0710d217 483 }
kenjiArai 0:166e0710d217 484
kenjiArai 0:166e0710d217 485 /* Call this routine for every sample. */
kenjiArai 0:166e0710d217 486 void ProcessSample(SAMPLE sample)
kenjiArai 0:166e0710d217 487 {
kenjiArai 0:166e0710d217 488 FLOATING Q0;
kenjiArai 0:166e0710d217 489 Q0 = coeff * Q1 - Q2 + (FLOATING) sample;
kenjiArai 0:166e0710d217 490 Q2 = Q1;
kenjiArai 0:166e0710d217 491 Q1 = Q0;
kenjiArai 0:166e0710d217 492 }
kenjiArai 0:166e0710d217 493
kenjiArai 0:166e0710d217 494
kenjiArai 0:166e0710d217 495 /* Basic Goertzel */
kenjiArai 0:166e0710d217 496 /* Call this routine after every block to get the complex result. */
kenjiArai 0:166e0710d217 497 void GetRealImag(FLOATING *realPart, FLOATING *imagPart)
kenjiArai 0:166e0710d217 498 {
kenjiArai 0:166e0710d217 499 *realPart = (Q1 - Q2 * cosine);
kenjiArai 0:166e0710d217 500 *imagPart = (Q2 * sine);
kenjiArai 0:166e0710d217 501 }
kenjiArai 0:166e0710d217 502
kenjiArai 0:166e0710d217 503 /* Optimized Goertzel */
kenjiArai 0:166e0710d217 504 /* Call this after every block to get the RELATIVE magnitude squared. */
kenjiArai 0:166e0710d217 505 FLOATING GetMagnitudeSquared(void)
kenjiArai 0:166e0710d217 506 {
kenjiArai 0:166e0710d217 507 FLOATING result;
kenjiArai 0:166e0710d217 508
kenjiArai 0:166e0710d217 509 result = Q1 * Q1 + Q2 * Q2 - Q1 * Q2 * coeff;
kenjiArai 0:166e0710d217 510 return result;
kenjiArai 0:166e0710d217 511 }
kenjiArai 0:166e0710d217 512
kenjiArai 0:166e0710d217 513 /*** End of Goertzel-specific code, the remainder is test code. */
kenjiArai 0:166e0710d217 514
kenjiArai 0:166e0710d217 515 /* Synthesize some test data at a given frequency. */
kenjiArai 0:166e0710d217 516 void Generate(FLOATING frequency)
kenjiArai 0:166e0710d217 517 {
kenjiArai 0:166e0710d217 518 int index;
kenjiArai 0:166e0710d217 519 FLOATING step;
kenjiArai 0:166e0710d217 520
kenjiArai 0:166e0710d217 521 step = frequency * ((2.0 * PI) / SAMPLING_RATE);
kenjiArai 0:166e0710d217 522
kenjiArai 0:166e0710d217 523 /* Generate the test data */
kenjiArai 0:166e0710d217 524 for (index = 0; index < N; index++)
kenjiArai 0:166e0710d217 525 {
kenjiArai 0:166e0710d217 526 testData[index] = (SAMPLE) (100.0 * sin(index * step) + 100.0);
kenjiArai 0:166e0710d217 527 }
kenjiArai 0:166e0710d217 528 }
kenjiArai 0:166e0710d217 529
kenjiArai 0:166e0710d217 530 /* Demo 1 */
kenjiArai 0:166e0710d217 531 void GenerateAndTest(FLOATING frequency)
kenjiArai 0:166e0710d217 532 {
kenjiArai 0:166e0710d217 533 int index;
kenjiArai 0:166e0710d217 534
kenjiArai 0:166e0710d217 535 FLOATING magnitudeSquared;
kenjiArai 0:166e0710d217 536 FLOATING magnitude;
kenjiArai 0:166e0710d217 537 FLOATING real;
kenjiArai 0:166e0710d217 538 FLOATING imag;
kenjiArai 0:166e0710d217 539
kenjiArai 0:166e0710d217 540 printf("For test frequency %f:\n", frequency);
kenjiArai 0:166e0710d217 541 Generate(frequency);
kenjiArai 0:166e0710d217 542
kenjiArai 0:166e0710d217 543 /* Process the samples */
kenjiArai 0:166e0710d217 544 for (index = 0; index < N; index++)
kenjiArai 0:166e0710d217 545 {
kenjiArai 0:166e0710d217 546 ProcessSample(testData[index]);
kenjiArai 0:166e0710d217 547 }
kenjiArai 0:166e0710d217 548
kenjiArai 0:166e0710d217 549 /* Do the "basic Goertzel" processing. */
kenjiArai 0:166e0710d217 550 GetRealImag(&real, &imag);
kenjiArai 0:166e0710d217 551
kenjiArai 0:166e0710d217 552 printf("real = %f imag = %f\n", real, imag);
kenjiArai 0:166e0710d217 553
kenjiArai 0:166e0710d217 554 magnitudeSquared = real*real + imag*imag;
kenjiArai 0:166e0710d217 555 printf("Relative magnitude squared = %f\n", magnitudeSquared);
kenjiArai 0:166e0710d217 556 magnitude = sqrt(magnitudeSquared);
kenjiArai 0:166e0710d217 557 printf("Relative magnitude = %f\n", magnitude);
kenjiArai 0:166e0710d217 558
kenjiArai 0:166e0710d217 559 /* Do the "optimized Goertzel" processing */
kenjiArai 0:166e0710d217 560 magnitudeSquared = GetMagnitudeSquared();
kenjiArai 0:166e0710d217 561 printf("Relative magnitude squared = %f\n", magnitudeSquared);
kenjiArai 0:166e0710d217 562 magnitude = sqrt(magnitudeSquared);
kenjiArai 0:166e0710d217 563 printf("Relative magnitude = %f\n\n", magnitude);
kenjiArai 0:166e0710d217 564
kenjiArai 0:166e0710d217 565 ResetGoertzel();
kenjiArai 0:166e0710d217 566 }
kenjiArai 0:166e0710d217 567
kenjiArai 0:166e0710d217 568 /* Demo 2 */
kenjiArai 0:166e0710d217 569 void GenerateAndTest2(FLOATING frequency)
kenjiArai 0:166e0710d217 570 {
kenjiArai 0:166e0710d217 571 int index;
kenjiArai 0:166e0710d217 572
kenjiArai 0:166e0710d217 573 FLOATING magnitudeSquared;
kenjiArai 0:166e0710d217 574 FLOATING magnitude;
kenjiArai 0:166e0710d217 575 FLOATING real;
kenjiArai 0:166e0710d217 576 FLOATING imag;
kenjiArai 0:166e0710d217 577
kenjiArai 0:166e0710d217 578 printf("Freq=%7.1f ", frequency);
kenjiArai 0:166e0710d217 579 Generate(frequency);
kenjiArai 0:166e0710d217 580
kenjiArai 0:166e0710d217 581 /* Process the samples. */
kenjiArai 0:166e0710d217 582 for (index = 0; index < N; index++)
kenjiArai 0:166e0710d217 583 {
kenjiArai 0:166e0710d217 584 ProcessSample(testData[index]);
kenjiArai 0:166e0710d217 585 }
kenjiArai 0:166e0710d217 586
kenjiArai 0:166e0710d217 587 /* Do the "standard Goertzel" processing. */
kenjiArai 0:166e0710d217 588 GetRealImag(&real, &imag);
kenjiArai 0:166e0710d217 589
kenjiArai 0:166e0710d217 590 magnitudeSquared = real*real + imag*imag;
kenjiArai 0:166e0710d217 591 printf("rel mag^2=%16.5f ", magnitudeSquared);
kenjiArai 0:166e0710d217 592 magnitude = sqrt(magnitudeSquared);
kenjiArai 0:166e0710d217 593 printf("rel mag=%12.5f\n", magnitude);
kenjiArai 0:166e0710d217 594
kenjiArai 0:166e0710d217 595 ResetGoertzel();
kenjiArai 0:166e0710d217 596 }
kenjiArai 0:166e0710d217 597
kenjiArai 0:166e0710d217 598 int main(void)
kenjiArai 0:166e0710d217 599 {
kenjiArai 0:166e0710d217 600 FLOATING freq;
kenjiArai 0:166e0710d217 601
kenjiArai 0:166e0710d217 602 InitGoertzel();
kenjiArai 0:166e0710d217 603
kenjiArai 0:166e0710d217 604 /* Demo 1 */
kenjiArai 0:166e0710d217 605 GenerateAndTest(TARGET_FREQUENCY - 250);
kenjiArai 0:166e0710d217 606 GenerateAndTest(TARGET_FREQUENCY);
kenjiArai 0:166e0710d217 607 GenerateAndTest(TARGET_FREQUENCY + 250);
kenjiArai 0:166e0710d217 608
kenjiArai 0:166e0710d217 609 /* Demo 2 */
kenjiArai 0:166e0710d217 610 for (freq = TARGET_FREQUENCY - 300; freq <= TARGET_FREQUENCY + 300; freq += 15)
kenjiArai 0:166e0710d217 611 {
kenjiArai 0:166e0710d217 612 GenerateAndTest2(freq);
kenjiArai 0:166e0710d217 613 }
kenjiArai 0:166e0710d217 614
kenjiArai 0:166e0710d217 615 return 0;
kenjiArai 0:166e0710d217 616 }
kenjiArai 0:166e0710d217 617
kenjiArai 0:166e0710d217 618 //---------------------------------------------------------------------------------------------------------------------------------------------------
kenjiArai 0:166e0710d217 619 // End of reference source code
kenjiArai 0:166e0710d217 620 //---------------------------------------------------------------------------------------------------------------------------------------------------