Tuesday 7 March 2017

BASIC Tech Group - MyNews 29 - AD9850 PSK31 Beacon

Following up from the last project, the CW Beacon - I have re-written the code to use a set of Varicode for PSK31 symbols and to switch the frequency output by phase (0 or 180deg).

IMG 0807

Screen Shot 2017 03 10 at 11 03 16Screen Shot 2017 03 10 at 11 01 33

Reception on Mac cocoaModem software

This is the Arduino code.

Code

// BCN_PSK Beacon for PSK31
// V2 7-3-17
// thanks to F0GOJ for principles of the code
// AD9850
// W_CLK 8
// FQ_UD 9
// DATA 10
// RESET 11
// LCD I2C bus (16x2)
// SDA = A4
// SCL = A5

// ADS9850 and LCD I2C libraries
#include "ADS9850.h"
#include "LiquidCrystal_I2C.h"

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

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

// init freqs
#define STARTHZ 7070000
#define STARTCHZ 0

#define BAUD 32

// psk varicode and index of length
int pskVaricode[2][128] = {
  { 683, 731, 749, 887, 747, 863, 751, 765, 767, 239,
    29, 879, 733, 31, 885, 939, 759, 757, 941, 943,
    859, 875, 877, 855, 891, 893, 951, 853, 861, 955,
    763, 895, 1, 511, 351, 501, 475, 725, 699, 383,
    251, 247, 367, 479, 117, 53, 87, 431, 183, 189,
    237, 255, 375, 347, 363, 429, 427, 439, 245, 445,
    493, 85, 471, 687, 701, 125, 235, 173, 181, 119,
    219, 253, 341, 127, 509, 381, 215, 187, 221, 171,
    213, 477, 175, 111, 109, 343, 437, 349, 373, 379,
    685, 503, 495, 507, 703, 365, 735, 11, 95, 47,
    45, 3, 61, 91, 43, 13, 491, 191, 27, 59, 15, 7, 63,
    447, 21, 23, 5, 55, 123, 107, 223, 93, 469, 695,
    443, 693, 727, 949
  },
  { 10, 10, 10, 10, 10, 10, 10, 10, 10,
    8, 5, 10, 10, 5, 10, 10, 10, 10, 10,
    10, 10, 10, 10, 10, 10, 10, 10, 10,
    10, 10, 10, 10, 1, 9, 9, 9, 9, 10, 10,
    9, 8, 8, 9, 9, 7, 6, 7, 9, 8, 8, 8, 8,
    9, 9, 9, 9, 9, 9, 8, 9, 9, 7, 9, 10,
    10, 7, 8, 8, 8, 7, 8, 8, 9, 7, 9, 9,
    8, 8, 8, 8, 8, 9, 8, 7, 7, 9, 9, 9, 9,
    9, 10, 9, 9, 9, 10, 9, 10, 4, 7, 6, 6,
    2, 6, 7, 6, 4, 9, 8, 5, 6, 4, 3, 6, 9,
    5, 5, 3, 6, 7, 7, 8, 7, 9, 10, 9, 10, 10, 10
  }
};

// beacon message to send
char msg[] = "Beacon de M0IFA...";

// freq in Hz and cHz
long freqHz = STARTHZ;                              // frequency Hz
long freqChz = STARTCHZ;                            // sub freuency cHz

// repeat time (ms)
long repeat = 2000;

// 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

  dispMsg(0, 0, "BCNPSK");
  dispFreq(7, 0, freqHz + freqChz / 100, 2); // display FREQ xxxxxx.xx kHz col 5 row 0
  dispMsg(0, 1, msg); // out msg
}

void loop() {
  // send message at frequency
  sendMsg(freqHz, freqChz, msg);



  delay(repeat); // repeat
}

// send message
void sendMsg(long fHz, long fChz, char m[]) {
  int c, vCode, bits;
  uint8_t phase;

  phase = 0x00;
  // Idle is zeroes so only phase inversion
  for (int n = 0; n < BAUD; n++) {
    phase = phase ^ 0x10;                // XOR toggle  b4 1 0000 <-> 0 0000
    ads.setFreq(fHz, fChz, phase);
    delay((961 + BAUD) / BAUD);          // fix baud rate
  }

  c = 0;
  while (m[c] != '\0') {
    vCode = pskVaricode[0][m[c]];         // Get PSK varicode
    bits = pskVaricode[1][m[c]];          // Get PSK varicode length

    vCode <<= 2;                          // add 00 on lsb for char space
    bits += 1;                            // msb to 0

    //send char in psk
    for (int n = bits; n >= 0; n--) {   // msb 1st, bits to 0
      if (bitRead(vCode, n) == 0)       // 0 | 1 ?
        phase = phase ^ 0x10;           // XOR toggle b4 1 0000 <-> 0 0000
      ads.setFreq(fHz, fChz, phase);    // transmit
      delay((961 + BAUD) / BAUD);       // set speed
    }
    c++;
  }

  phase = 0x00;
  // Idle is zeroes so only phase inversion
  for (int n = 0; n < BAUD; n++) {
    phase = phase ^ 0x10;                // XOR toggle  b4 1 0000 <-> 0 0000
    ads.setFreq(fHz, fChz, phase);
    delay((961 + BAUD) / BAUD);          // fix baud rate
  }
  
  // end of message
  ads.down();
}

// 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: