Saturday 4 March 2017

BASIC Tech Group - MyNews 28 - AD9850 CW Beacon

Here are the details of a CW Beacon I made, based on the AD9850 Arduino shield. Code below, insert your own message in the code and upload. Can easily be modified to read in the message from your keyboard and send it. PSK31 version underway, watch this space

IMG 0806

Code

// CWTX Beacon
// V1.1 4-3-17
// Thanks to F0GOJ for some of the code
// AD9850
// W_CLK 8
// FQ_UD 9
// DATA 10
// RESET 11
// LCD I2C bus (16x2)
// SDA = A4
// SCL = A5

// ADS9850, LCD and Rotary Encoder libraries
#include "ADS9850.h"
#include "LiquidCrystal_I2C.h"

// AD9850 pins
#define W_CLK 8
#define FQ_UD 9
#define DATA 10
#define RESET 11

// xtal calibration
#define CALIBRATE 124999500

// chose address of 0x27 or 0x3F for LCD
#define LCDADDR 0x27
//#define LCDADDR 0x3F
#define LCDCOLS 16
#define LCDROWS 2


// morse varicode index 0-58 is SP to Z
// [code in a byte][7-n bits to send, MSB first]
// e.g. 192 = 1100 0000, top 4 bits 7-4 = --.. or Z
// 0 = dot, 1 = dash
static int morseVaricode[2][59] = {
  { 0, 212, 72, 0, 144, 0, 128, 120, 176, 180,
    0, 80, 204, 132, 84, 144, 248, 120, 56, 24,
    8, 0, 128, 192, 224, 240, 224, 168, 0, 136,
    0, 48, 104, 64, 128, 160, 128, 0, 32, 192,
    0, 0, 112, 160, 64, 192, 128, 224, 96, 208,
    64, 0, 128, 32, 16, 96, 144, 176, 192
  },
  { 7, 6, 5, 0, 4, 0, 4, 6, 5, 6,
    0, 5, 6, 6, 6, 5, 5, 5, 5, 5,
    5, 5, 5, 5, 5, 5, 6, 6, 0, 5,
    0, 6, 6, 2, 4, 4, 3, 1, 4, 3,
    4, 2, 4, 3, 4, 2, 2, 3, 4, 4,
    3, 3, 1, 3, 4, 3, 4, 4, 4
  }
};

// beacon message to send (u.c.)
char msg[] = "YOUR MESSAGE GOES HERE";

// freq is fHz + cHz, 7030000
long fHz = 7030000;                             // frequency Hz
long cHz = 0;                                 // sub freuency cHz

//speed WPM
int wpm = 10;

// ads (analog-output digital synthesiser) object
ADS9850 ads;

// lcd object
LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS);

void setup() {

  // init LCD
  lcd.begin();
  
  //init AD9850
  ads.begin(W_CLK, FQ_UD, DATA, RESET);         // initialise synthesiser, pins

  // calibrate to xtal actual frequency
  ads.calibrate(CALIBRATE);

  dispMsg(0, 0, "cwTX");
  dispFreq(5, 0, fHz+cHz/100, 2); // display FREQ xxxxxx.xx kHz col 5 row 0
  dispMsg(0, 1, msg); // out msg
}

void loop() {
  cwTx(fHz, cHz, msg, wpm);                     // send CW message

  delay(5000);                                  //repeat 5sec
}

// send CW on freqHz+freqChz, message, WPM
void cwTx(long freqHz, long freqChz, char *stringCw, int cwWpm) {
  byte nbBits, bitVal;                          // nobits to send 7-nbBits
  int d;                                        // varicode data

  // calculate dot time
  int dotTime = 1200 / cwWpm;                   // Duration of 1 dot

  // get 1st char
  int c = *stringCw++;                          // read char

  //send chars in CW
  while (c != '\0') {
    c = toupper(c);                             // u.c.just in case
    
    if (c == ' ') {                             // catch ASCII SP
      c = c - ' ';                              // convert c-32 to index 0 - 58
      ads.down();
      delay(dotTime * 7);
    }
    else if (c > ' ' && c < ']') {
      c = c - ' ';                              // convert c-32 to index 0 - 58
      d = morseVaricode[0][c];                  // get CW varicode data
      nbBits = morseVaricode[1][c];             // get CW varicode length
      if (nbBits != 0) {                        // if not invalid morse
                                                // characters # % < >
        for (int b = 7; b > 7 - nbBits; b--) {  // Send CW character
                                                // (0 for dot, 1 for dash) MSB first
          bitVal = bitRead(d, b);               // look up varicode bit
          ads.setFreq(freqHz, freqChz, 0);      // transmit for
          delay(dotTime + 2 * dotTime * bitVal);// dot length or a dash length
                                                // dash = 3 times the dot
          ads.down();                           // synth off for
          delay(dotTime);                       // 1 dot space between dots|dashes
        }
      }
      ads.down();                               // synth off 3 dots
      delay(dotTime * 3);                       // between characters in a word
    }
    c = *stringCw++;                            // next character in string
  }
  ads.down();                                   // No more transmission
}

// display freq at c)ol, r)ow, f (cHz), to d decimal places (kHz)
void dispFreq(uint8_t c, uint8_t r, uint64_t f, uint8_t d) {
  lcd.setCursor(c, r);
  lcd.print((float)f / 1000, d); // convert to float & kHz
  lcd.print("kHz ");
}

// display msg *m at c)ol, r)ow
void dispMsg(uint8_t c, uint8_t r, char *m)
{
  lcd.setCursor(c, r);
  lcd.print(m);
}


No comments: