Balise CW à base d’un module DDS AD9850

Quoi de plus sympa que d’avoir une balise CW à base d’une carte arduino et d’un module DDS AD9850?

En plus de ne pas être très onéreux à mettre en place, c’est une bonne initiation aux module DDS que je voulais utiliser pour monter mon propre analyseur d’antenne. Par manque de certaines pièces que je n’ai pas encore, j’ai trouvé sur différents sites la possibilité de faire une balise cw entre 0 et 40 Mhz en QRP avec environ 1mW 😉

En termes de connectique, il faut brancher le DDS comme suivant :

  • Pin 8 (W_CLK) – connecté au pin W_CLK du DDS AD9850
  • Pin 9 (FQ_UD) – connecté au pin FQ_UD du DDS AD9850
  • Pin 10 (DATA) – connecté au pin DATA du DDS AD9850
  • Pin 11 (RESET) – connecté au pin RST du DDS AD9850

Donc assez simple, en termes de code à pousser sur l’arduino, le plus simple que j’ai trouvé étant le suivant :

// Modified and adapted as a qrpp (100µW) CW beacon using arduino uno and AD98550 board
// Hardware wiring and Code to send a sinewave carrier with AD9850 taken from
// http://nr8o.dhlpilotcentral.com/?p=83 Thanks Ron!!
// CW sending code was taken from http://brainwagon.org Thanks Mark!!
// Almost all merit belongs to the above authors. I only did the adapting job and added "+ - = " codes
// I am not a good programmer, but it works!. Feel free to improve and correct bugs.
// If you modify will be nice to send a brief note to Mark and Ron, real fathers of code
// I also will appreciate you send a note with the improved/modified code to ea5ehs[at]gmail.com Niceto Muñoz
// 73 es DX from Niceto (EA5EHS)

// Modificado y adaptado como baliza CW qrpp (100µW), usando "Arduino uno" y una placa con "AD9850"
// El conexionado y el código para generar una señal senoidal con el AD9850 se ha tomado de
// http://nr8o.dhlpilotcentral.com/?p=83 Gracias Ron!!
// El código para generar los caracteres CW se ha tomado de http://brainwagon.org Gracias Mark!!
// Casi todo el mérito pertenece a los autores anteriores. Yo únicamente hice el trabajo de adaptar los dos códigos,
// añadiendo tambien los caracteres cw para "+ - =".
// Yo no soy un buen programador, pero funciona!. El código es totalmente libre para mejorarlo y corregir errores.
// Si lo modificas, estaría bien que enviaras una pequeña nota a Mark y Ron, padres reales del código.
// Tambien me gustaría que me enviaras una copia del código mejorado/modificado a mi correo ea5ehs[arroba]gmail.com
// 73 es Dx Niceto (EA5EHS)

struct t_mtab { char c, pat; } ;

struct t_mtab morsetab[] = {
 {'+', 42}, 
 {'-', 97},
 {'=', 49},
 {'.', 106},
 {',', 115},
 {'?', 76},
 {'/', 41},
 {'A', 6},
 {'B', 17},
 {'C', 21},
 {'D', 9},
 {'E', 2},
 {'F', 20},
 {'G', 11},
 {'H', 16},
 {'I', 4},
 {'J', 30},
 {'K', 13},
 {'L', 18},
 {'M', 7},
 {'N', 5},
 {'O', 15},
 {'P', 22},
 {'Q', 27},
 {'R', 10},
 {'S', 8},
 {'T', 3},
 {'U', 12},
 {'V', 24},
 {'W', 14},
 {'X', 25},
 {'Y', 29},
 {'Z', 19},
 {'1', 62},
 {'2', 60},
 {'3', 56},
 {'4', 48},
 {'5', 32},
 {'6', 33},
 {'7', 35},
 {'8', 39},
 {'9', 47},
 {'0', 63}
} ;
 #define W_CLK 8 // Pin 8 - connect to AD9850 module word load clock pin (CLK)
 #define FQ_UD 9 // Pin 9 - connect to freq update pin (FQ)
 #define DATA 10 // Pin 10 - connect to serial data load pin (DATA)
 #define RESET 11 // Pin 11 - connect to reset pin (RST).
 
 #define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }

 #define FREQUENCY 7001500
 #define FREQUENCY2 0 //putting a second frequency different from 0, you also generate an inverse keying CW signal that can be heard using FM mode :)
 #define N_MORSE (sizeof(morsetab)/sizeof(morsetab[0]))
 #define SPEED (23)
 #define DOTLEN (1200/SPEED)
 #define DASHLEN (3*(1200/SPEED))


void dash()
{
 sendFrequency(FREQUENCY);
 delay(DASHLEN);
 sendFrequency(FREQUENCY2);
 delay(DOTLEN);
}

void dit()
{
 sendFrequency(FREQUENCY);
 delay(DOTLEN);
 sendFrequency(FREQUENCY2);
 delay(DOTLEN);
}


void send(char c)
{
 int i ;
 if (c == ' ') {
 delay(7*DOTLEN) ;
 return ;
 }
 for (i=0; i<N_MORSE; i++) {
 if (morsetab[i].c == c) {
 unsigned char p = morsetab[i].pat ;

 while (p != 1) {
 if (p & 1)
 dash() ;
 else
 dit() ;
 p = p / 2 ;
 }
 delay(2*DOTLEN) ;
 return ;
 }
 }
 /* if we drop off the end, then we send a space */
 Serial.print("?") ;
}

void sendmsg(char *str)
{
 while (*str)
 send(*str++) ;
}
 // transfers a byte, a bit at a time, LSB first to the 9850 via serial DATA line
void tfr_byte(byte data)
{
 for (int i=0; i<8; i++, data>>=1) {
 digitalWrite(DATA, data & 0x01);
 pulseHigh(W_CLK); //after each bit sent, CLK is pulsed high
 }
}

 // frequency calc from datasheet page 8 = <sys clock> * <frequency tuning word>/2^32
void sendFrequency(double frequency) {
 int32_t freq = frequency * 4294967295/125000000; // note 125 MHz clock on 9850
 for (int b=0; b<4; b++, freq>>=8) {
 tfr_byte(freq & 0xFF);
 }
 tfr_byte(0x000); // Final control byte, all 0 for 9850 chip
 pulseHigh(FQ_UD); // Done! Should see output
}

void setup() {
 // configure arduino data pins for output
 pinMode(FQ_UD, OUTPUT);
 pinMode(W_CLK, OUTPUT);
 pinMode(DATA, OUTPUT);
 pinMode(RESET, OUTPUT);
 
 pulseHigh(RESET);
 pulseHigh(W_CLK);
 pulseHigh(FQ_UD); // this pulse enables serial mode - Datasheet page 12 figure 10
}



void loop() {
 sendmsg(" V V V F4WAT/B QRPP BEACON - LOC : JN09JG - 100 MICRO-WATTS E E E E E E E E E E") ;
 delay(50000) ;
}

Dans un future très proche, je vais recoder sur un raspberry pi pour permettre de changer le message à envoyer de façons dynamique.

Merci à NR80, K6HX et EA5EHS pour l’idée et le code

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *