Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: main.cpp
- Revision:
- 0:166e0710d217
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Fri Jan 27 04:07:01 2017 +0000
@@ -0,0 +1,384 @@
+/*
+ * mbed program / cwdecoder
+ * using the Goertzel Algorithm
+ * tested on Nucleo-F411RE, F446RE, L476RG mbed board
+ *
+ * Modified by Kenji Arai
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * http://mbed.org/users/kenjiArai/
+ *
+ * Started: January 16th, 2017
+ * Revised: January 27th, 2017
+ *
+ * Original program: -> See refernce.txt
+ * http://skovholm.com/cwdecoder
+ * by Hjalmar Skovholm Hansen OZ1JHM
+ *
+ * Reference: -> See refernce.txt
+ * https://courses.cs.washington.edu/courses/cse466/12au/
+ * calendar/Goertzel-EETimes.pdf
+ * by Kevin Banks
+ * http://archive.eetindia.co.in/www.eetindia.co.in/
+ * STATIC/DOWNLOAD/09banks.txt
+ */
+///////////////////////////////////////////////////////////////////////
+// CW Decoder made by Hjalmar Skovholm Hansen OZ1JHM VER 1.01 //
+// Feel free to change, copy or what ever you like but respect //
+// that license is http://www.gnu.org/copyleft/gpl.html //
+// Discuss and give great ideas on //
+// https://groups.yahoo.com/neo/groups/oz1jhm/conversations/messages //
+///////////////////////////////////////////////////////////////////////
+
+// Include --------------------------------------------------------------------
+#include "mbed.h"
+#include "configuration.h"
+#include "TextLCD.h"
+
+// Definition -----------------------------------------------------------------
+// see configuration.h
+
+// Object ---------------------------------------------------------------------
+AnalogIn analog(A0);
+DigitalOut myled(LED1);
+DigitalOut ad_cnv(D5);
+DigitalOut loop_trg(D6);
+DigitalOut buzzer(D7);
+Serial pc(USBTX, USBRX);
+Timer t;
+Ticker event;
+I2C i2c(PB_9, PB_8); // SDA, SCL
+TextLCD_I2C_N lcd(&i2c, ST7036_SA2, TextLCD::LCD16x2, NC, TextLCD::ST7032_3V3);
+
+// RAM ------------------------------------------------------------------------
+double 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;
+
+volatile bool adc_action = false;
+
+uint8_t n = SAMPLE_NUM;
+double coeff;
+double Q1 = 0.0f;
+double Q2 = 0.0f;
+double sine;
+double cosine;
+double sampling_freq = SAMPLE_RATE;
+double target_freq = TARGET_FREQ;
+double testData[SAMPLE_NUM + 10];
+double bw;
+
+// Noise Blanker time which shall be computed so this is initial
+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;
+
+// ROM / Constant data --------------------------------------------------------
+
+// Function prototypes --------------------------------------------------------
+void setup(void);
+void loop(void);
+void docode(void);
+void printascii(char);
+void adc_convert(void);
+
+//------------------------------------------------------------------------------
+// Control Program
+//------------------------------------------------------------------------------
+int main(){
+ setup();
+ double sampling_cycle = 1.0f / sampling_freq;
+ event.attach(&adc_convert, sampling_cycle);
+ t.start(); // start timer
+ // LCD
+ lcd.setContrast(0x1a);
+ lcd.locate(0, 0); // 1st line top
+ // 1234567890123456
+ lcd.printf(" CW Decoder ");
+ lcd.locate(0, 1); // 2nd line top
+ // 1234567890123456
+ lcd.printf(" by JH1PJL");
+ while(true){
+ myled = !myled;
+ loop();
+ }
+}
+
+void setup(){ // Initial setting for goertzel calculation
+ bw = sampling_freq / (double)n;
+ double k = (int16_t) (0.5f + (((double)n * target_freq) / sampling_freq));
+ double omega = (2.0f * PI * k) / (double)n;
+ sine = sin(omega);
+ cosine = cos(omega);
+ coeff = 2.0f * cosine;
+}
+
+// Interruput service routine (triggered by event.attach(..,..)
+void adc_convert(){
+ adc_action = false;
+ //if (adc_action == true){ adc_action = false;}
+}
+
+void loop(){
+ loop_trg = !loop_trg;
+ DEBUG("sample=, %u, ", n);
+ for (int8_t index = 0; index < n; index++){
+ // start sampling
+ ad_cnv = 1;
+ adc_action = true;
+ // wait sampling
+ while (adc_action == true){ ;}
+ ad_cnv = 0;
+ testData[index] = analog.read() * 1024.0f;
+ DEBUG("%f, ", testData[index]);
+ double Q0 = coeff * Q1 - Q2 + testData[index];
+ Q2 = Q1;
+ Q1 = Q0;
+ }
+ // only need the real part
+ double magnitudeSquared = (Q1 * Q1) + (Q2 * Q2) - Q1 * Q2 * coeff;
+ DEBUG(", mag, %f\r\n", magnitudeSquared);
+ magnitude = sqrt(magnitudeSquared);
+ Q2 = 0.0f;
+ Q1 = 0.0f;
+ // magnitude limit automatic
+ if (magnitude > magnitudelimit_low){
+ // moving average filter
+ magnitudelimit =
+ (magnitudelimit +((magnitude - magnitudelimit) / 6.0f));
+ }
+ if (magnitudelimit < magnitudelimit_low){
+ magnitudelimit = magnitudelimit_low;
+ }
+ // check for the magnitude
+ if(magnitude > magnitudelimit * 0.6f){ // 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;
+ }
+ }
+ }
+ // 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;
+ }
+ }
+ if (filteredstate == HIGH){ // we did end a LOW
+ double 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.7f;}
+ if(wpm > 45){ lacktime = 1.9f;}
+ if(wpm > 50){ lacktime = 2.0f;}
+ 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");
+ }
+ }
+ }
+ // 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){
+ myled = HIGH;
+ buzzer = 1;
+ } else {
+ myled = LOW;
+ buzzer = 0;
+ }
+ // the end of main loop clean up
+ realstatebefore = realstate;
+ lasthighduration = highduration;
+ filteredstatebefore = filteredstate;
+}
+
+// translate cw code to ascii
+void docode(){
+ 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(6); 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(45); 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){
+ PUTC(c);
+ lcd.putc(c);
+}