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.
main.cpp
- Committer:
- kenjiArai
- Date:
- 2017-01-27
- Revision:
- 0:166e0710d217
File content as of revision 0:166e0710d217:
/*
* 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);
}