Étiquette : G0UPL

Nouveaux kits récepteurs SDR par Hans G0UPL

Récepteur SDR I/Q QRP Labs G0UPLHans vient d’annoncer deux nouveaux kits originaux dans la lignée de ses célèbres balises QRSS ou WSPR Ultimate qui ont fait retrouver à des milliers de radioamateurs le goût de la construction de kits.

Le premier est un kit récepteur SDR de type I/Q (détection QSD) qui peut servir à la réception des signaux faibles WSPR ou QRSS, mais pas seulement. Il est proposé à 25 USD avec un module filtre de bande aux choix entre 160m et 10m.

Module démodulateur polyphase QRP Labs G0UPLLe deuxième est un module optionnel de démodulateur polyphase pour le récepteur. Il permet de se passer d’une carte son stéréo pour la démodulation des signaux I/Q et produit un signal BLU en sortie.

Comme toujours les kits produits par Hans sont un excellent compromis prix / qualité et surtout proposent des solutions techniques originales. Ils sont ouverts à l’expérimentation et laissent la place pour la personnalisation.

Sproutie : La balise QRSS HiFer de Dave AA7EE

AA7EE carte ATTiny programmateur pour Arduino (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2015/11/AA7EE_programmer_ATTiny NULL.jpg)Il y a quelques temps, Dave AA7EE m’a contacté pour avoir ma version corrigée du code la balise QRSS de G0UPL/G0XAR (http://xv4y NULL.radioclub NULL.asia/2012/01/11/programmer-un-micro-controleur-atmel-attiny-avec-un-arduino/). Il l’a utilisé pour modifier sa propre balise et la placer sur la bande dite HiFer 13553-13567 KHz  autorisée aux USA sans licence. Lisez sur son blog le détail de son projet. Personellement moi j’adore la construction soignée de son programmateur de micro-contrôleur ATTiny.

Nouveautés chez QRP-Labs (G0UPL)

Synthetiseur Si5351 à OCXO QRP Labs G0UPL (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2014/09/Synthetiseur_OCXO_G0UPL NULL.jpg)L’annonce de ces nouveautés datent d’en fait il y a près d’une semaine mais je n’ai pas eu le temps d’en parler. Hans G0UPL va ajouter quelques produits à sa boutique dans les jours qui viennent.

  • Tout d’abord un boîtier en aluminium anodisé noir, pré-découpé pour le kit complet balise Ultimate III (http://www NULL.qrp-labs NULL.com/index NULL.php?route=product/product&product_id=77), avec la place pour toutes les options (filtre de bande, GPS…). Le prix de 20$ (plus port de 10$) est très correct.
  • Un module enfichable pour Arduino Uno qui reprend toutes les fonctionnalités du kit Ultimate III mais sans LCD et boutons (que vous pouvez ajouter vous-même). Cela permettra à ceux qui le veulent de développer eux-même leur logiciel de balise ou de générateur de fréquence en bénéficiant d’une plateforme matérielle performante et à prix raisonnable.
  • Prototype Synthetiseur OCXO G0UPL (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2014/09/Proto_Synthetiseur_OCXO_G0UPL NULL.jpg)Le plus important, c’est un kit synthétiseur de fréquence avec Si5351A et référence 10MHz à OCXO (http://www NULL.hanssummers NULL.com/ocxosynth NULL.html). Le but de ce kit est de remplacer avantageusement les modules chinois avec AD9850. Ceux-ci sont devenus impossibles à approvisionner et présentaient des limites en terme de performance et d’utilisation. Le nouveau kit devrait couvrir de 8 KHz à 160 MHz avec une stabilité de l’ordre de 0,1ppm à chaud, ce qui est excellent!

Le dernier kit est vraiment intéressant et pourra prendre la place dans les kits QRSS Ultimate III existant après une mise à jour du firmware. Avec le module Arduino, cela ouvre la possibilité de construire des générateurs de fréquence très stable jusque 160 MHz.

Un quatrième projet et quant à lui retardé, c’est celui d’un récepteur QRSS comme compagnon au kit balise. Hans cherchait une solution technique innovante mais ses tentatives autour de la démodulation méthode Weaver se sont avérées décevante.

Nouveau site QRP Labs par G0UPL

Kist balise QRP Labs Ultimate 3 (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2014/05/G0UPL_Utlimate3 NULL.jpg)Hans de G0UPL vient de lancer un nouveau site pour son activité de kits radio QRP (http://qrp-labs NULL.com/). Cette activité prenait de plus en plus de place sur son site personnel et il était judicieux de la rendre indépendante.

En pratique rien de nouveau avec les mêmes kits à succès pour réaliser vos balises QRSS ou WSPR synchronisées par GPS. La présentation est plus claire et la boutique optimisée.

Ma pomme dans CQ Magazine de Décembre – Kits balise WSPR

Sommaire CQ Décembre 2013 (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2013/11/2013_12_cq_toc NULL.jpg)Le numéro “Spéciale technique” de décembre de CQ Magazine (http://www NULL.cq-amateur-radio NULL.com/) contiendra un article que j’ai écrit à propos des micro-contrôleurs MSP430 et du LaunchPad de Texas Instruments. En fait j’ai proposé cet article il y a plus d’un an mais ils ne trouvaient pas la place adéquate dans leurs colonnes.

Pour continuer sur ma lancée, je leur ai aussi proposé un article détaillant comment fabriquer sa propre balise WSPR ou QRSS avec un DDS AD9850 et un LaunchPad MSP430. C’est en fait la balise que je proposais en kit (http://xv4y NULL.radioclub NULL.asia/2013/03/21/la-balise-wspr-de-g4jvf/) dont je vais publier les schémas et code source. En principe l’article est accepté pour une publication au premier semestre 2014, j’attends leurs demandes de corrections.

Il y a quelques jours Hans G0UPL a lancé son kit Ultimate QRSS beacon 3 (U3) (http://hanssummers NULL.com/ultimate3 NULL.html)qui a maintenant atteint un bon niveau de fonctionnalité et surtout de stabilité (les premières versions ont essuyées pas mal de bogues). Il propose en option les kits module GPS et platine de filtre de bande à commutation par relais. C’est aujourd’hui l’offre la plus intéressante car il en produit des volumes de plusieurs centaines d’exemplaires. Son seul inconvénient c’est que Hans refuse d’en ouvrir le code source et qu’il est donc impossible de faire vos propres adaptations…

Au passage je suis content de voir que mon travail a porté ses fruits et que Hans a intégré dans son codes des idées issues du mien comme la mise en veille du DDS par le bit W34 et le mode WSPR-15 (pour les VLF). Je suis sûr que le côté “reprogrammable” de mes kits l’a aussi poussé à diffuser les binaires de ses firmwares en ligne pour que les utilisateurs puissent faire les mises à jour, ce qu’il ne voulait pas faire au début.

Balise QRSS synchrone avec le LaunchPad/MSP430

Modifications de la balise QRSS QRP Labs pour WSPR - XV4Y (http://xv4y NULL.radioclub NULL.asia/2012/10/18/balise-wspr-autonome-avec-msp430-le-code-source/kit-wspr-mod-balise/)

[GTranslate]

Voici le code que j’ai écrit et qui permet de modifier l‘émetteur original de QRP Labs (http://xv4y NULL.radioclub NULL.asia/2010/08/16/kit-balise-qrss/) pour en faire une balise transmettant régulièrement toutes les minutes paires. Cela est nécessaire si vous voulez que votre transmission soit “superposable” dans les captures du grabber. En effet, de plus en plus d’OM effectuent des compositages de captures sur une base de 10 minutes. En effectuant un traitement de moyenne ou d’interpolation on peut ainsi faire sortir du bruit un signal qui n’était pas visible autrement. Ce traitement est similaire à celui fait en astronomie planétaire avec Lynkeos (http://lynkeos NULL.sourceforge NULL.net/french/index NULL.html) par exemple.

Un kit préparé avec votre indicatif permettant de modifier le circuit de la balise pour fonctionne avec ce programme (ou la version WSPR) est disponible dans la boutique (http://xv4y NULL.radioclub NULL.asia/boutique/?slug=product_info NULL.php&cPath=22&products_id=30).

Ce programme se compile avec Energia (http://energia NULL.nu/) pour un LaunchPad avec MSP430G2553. Il nécessite ma librairie sRTC (http://xv4y NULL.radioclub NULL.asia/2012/12/19/bibliotheque-rtc-pour-energia-version-1-02/).

/* QRSS beacon with 10 minutes frame for MSP430G2553
 * Code for Energia 008

 * By Yannick DEVOS - XV4Y - May-October 2012
    http://xv4y.radioclub.asia/

    Copyright 2012 Yannick DEVOS under GPL 3.0 license
    Any commercial use or inclusion in a kit is subject to author approval

====
 * Ouput on 2 bits PinA and PinB
 * PTT_key output allows to turn on/off the TX PA while sending
 * Mirror on LED1 and LED2 du LaunchPad for testing
 * Output to Serial for testing
 * Using an R-2R ladder it makes the G0UPL/G0XAR beacon frequency shift

====
Revision history :
v1.00    2012-10-26
         First release
v1.01    2012-12-01
         Cleaning and commenting
v1.02    2012-12-19
         Changes to support version 1.02 of RTC library
         Correction for better time accuracy with Serial output enabled

====
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You can download a copy of the GNU General Public License at <http://www.gnu.org/licenses/>
*/

// Here under don't touch anything unless you know what you do

#include <legacymsp430.h>
#include <sRTC.h> // Library for RTC clock with MSP430

// Alphabet binary coding by G0UPL
// 0 = dot, 1 = dash
const int _A	=	0b11111001;
const int _B	=	0b11101000;
const int _C	=	0b11101010;
const int _D	=	0b11110100;
const int _E	=	0b11111100;
const int _F	=	0b11100010;
const int _G	=	0b11110110;
const int _H	=	0b11100000;
const int _I	=	0b11111000;
const int _J	=	0b11100111;
const int _K	=	0b11110101;
const int _L	=	0b11100100;
const int _M	=	0b11111011;
const int _N	=	0b11111010;
const int _O	=	0b11110111;
const int _P	=	0b11100110;
const int _Q	=	0b11101101;
const int _R	=	0b11110010;
const int _S	=	0b11110000;
const int _T	=	0b11111101;
const int _U	=	0b11110001;
const int _V	=	0b11100001;
const int _W	=	0b11110011;
const int _X	=	0b11101001;
const int _Y	=	0b11101011;
const int _Z	=	0b11101100;
const int _SPC	=       0b11101111;
const int _0	=	0b11011111;
const int _1	=	0b11001111;
const int _2	=	0b11000111;
const int _3	=	0b11000011;
const int _4	=	0b11000001;
const int _5	=	0b11000000;
const int _6	=	0b11010000;
const int _7	=	0b11011000;
const int _8	=	0b11011100;
const int _9	=	0b11011110;
const int _BRK	 =      0b11010010;
const int _WAIT  =	0b10000000;

byte begin_sec;
int begin_chunk;

// Déclaration et initilisation des variables
byte msgIndex = 1;
byte inc_bit = 8;
byte character = _SPC;
boolean start = false;

byte key = 0;
byte etat = 0;

// *** PARAMETERS
// Here modify to your taste or needs

#define PTT_key 8
#define wsprPinA 10
#define wsprPinB 9
#define LEDPinA 14
#define LEDPinB 2
#define StartBtn 5

const int msg[] = {5, _X, _V, _4, _Y, _WAIT};  // Format, is lenght in decimal and then the character constants including the _WAIT for the end of the sequence

int vitesse = 6;    // Number of seconds per dot (QRSS6 = 6)

// Be carefull, this is only for debugging.
// If you enable this in production, the clock will drift to much (5 seconds in 10 minutes)
#define SERIAL_OUT_INFO

// This is in case you use a MSP430 that does not have Hardwart UART. TimerSerial works great but bring a lot of clock drift. Replace each "Serial" object call in the code by mySerial.
/*
#ifdef SERIAL_OUT_INFO
#include <TimerSerial.h> 
TimerSerial mySerial;
#endif
*/

// *** END OF PARAMETERS

#ifdef SERIAL_OUT_INFO
#endif
RealTimeClock myClock;

//******************************************************************
// Defining pins mode
// Encoding the WSPR sequence

void setup() {
  pinMode(PTT_key, OUTPUT);
  pinMode(wsprPinA, OUTPUT);
  pinMode(wsprPinB, OUTPUT);
  pinMode(LEDPinA, OUTPUT);
  pinMode(LEDPinB, OUTPUT);
  pinMode(StartBtn, INPUT_PULLUP);

  myClock.begin();

  #ifdef SERIAL_OUT_INFO
  Serial.begin(9600);
  Serial.println("\n* MSP430 QRSS beacon"); 
  #endif

  digitalWrite( PTT_key, LOW );
  digitalWrite( wsprPinA, LOW );
  digitalWrite( wsprPinB, LOW );

  digitalWrite( LEDPinA, HIGH );
  digitalWrite( LEDPinB, HIGH );

  #ifdef SERIAL_OUT_INFO
  Serial.println("* Wait clock is set. Sending test sequence.");
  #endif
  begin_chunk = myClock.RTC_chunk;
  begin_sec = myClock.RTC_sec;
  while(digitalRead(StartBtn)) {
    // This is for blinking LED fast
    if ((myClock.RTC_chunk-(begin_chunk+15))%60==0)
      digitalWrite( LEDPinA, HIGH );
    if ((myClock.RTC_chunk-(begin_chunk+30))%60==0)
      digitalWrite( LEDPinB, HIGH );
    if ((myClock.RTC_chunk-(begin_chunk+45))%60==0)
      digitalWrite( LEDPinA, LOW );
    if ((myClock.RTC_chunk-(begin_chunk+60))%60==0)
      digitalWrite( LEDPinB, LOW );

    // We also send a test sequence to help calibrate the transmitter
    if ((myClock.RTC_chunk-(begin_chunk+0))%240==0) 
      send_test(begin_sec);

   };
  //randomSeed(myClock.RTC_chunk);
  myClock.Set_Time(0,0,0);
};

//******************************************************************
// Here starts the actual sequence sending

void loop() {
  #ifdef SERIAL_OUT_INFO
  Serial.print("Time:");
  Serial.print(myClock.RTC_min, DEC);
  Serial.print(":");
  Serial.print(myClock.RTC_sec, DEC);
  Serial.print(".");
  Serial.println(myClock.RTC_chunk, DEC);
  #endif

  digitalWrite( PTT_key, LOW );

  digitalWrite( wsprPinB, LOW );
  digitalWrite( LEDPinB, LOW );

  digitalWrite( wsprPinA, LOW );
  digitalWrite( LEDPinA, LOW );

  begin_chunk = myClock.RTC_chunk;

  #ifdef SERIAL_OUT_INFO
  Serial.println("* Waiting 1st sec of every 2 mins.");
  #endif

  while (!(myClock.RTC_sec==1 && (myClock.RTC_min%2)==0)) {  // We start each first second of even minutes
    if ((myClock.RTC_chunk-(begin_chunk+10))%20==0) digitalWrite( LEDPinA, HIGH );
    if ((myClock.RTC_chunk-(begin_chunk+20))%20==0) digitalWrite( LEDPinA, LOW );
  };

  #ifdef SERIAL_OUT_INFO
  Serial.println("\n* Sequence begin");
  #endif
  digitalWrite( PTT_key, HIGH );
  send_sequence();
  #ifdef SERIAL_OUT_INFO
  Serial.println("\n* End");
  #endif
};

//******************************************************************
// Function to send the test sequence
void send_test(char begin_sec) {
    if ((myClock.RTC_sec-(begin_sec+0))%30==0) {
      digitalWrite( PTT_key, LOW );
      digitalWrite( wsprPinA, LOW );
      digitalWrite( wsprPinB, LOW );
      #ifdef SERIAL_OUT_INFO
      Serial.println("* TX Low, Send 00 *");
      #endif
    }

    if ((myClock.RTC_sec-(begin_sec+6))%30==0) {
      digitalWrite( PTT_key, HIGH );
      digitalWrite( wsprPinA, LOW );
      digitalWrite( wsprPinB, LOW );
      #ifdef SERIAL_OUT_INFO
      Serial.println("* TX High, Send 00 *");
      #endif
    }

    if ((myClock.RTC_sec-(begin_sec+12))%30==0) {
      digitalWrite( PTT_key, HIGH );
      digitalWrite( wsprPinA, HIGH );
      digitalWrite( wsprPinB, LOW );
      #ifdef SERIAL_OUT_INFO
      Serial.println("* TX High, Send 01 *");
      #endif
    }

    if ((myClock.RTC_sec-(begin_sec+18))%30==0) {
      digitalWrite( PTT_key, HIGH );
      digitalWrite( wsprPinA, LOW );
      digitalWrite( wsprPinB, HIGH );
      #ifdef SERIAL_OUT_INFO
      Serial.println("* TX High, Send 10 *");
      #endif
    }

    if ((myClock.RTC_sec-(begin_sec+24))%30==0) {
      digitalWrite( PTT_key, HIGH );
      digitalWrite( wsprPinA, HIGH );
      digitalWrite( wsprPinB, HIGH );
      #ifdef SERIAL_OUT_INFO
      Serial.println("* TX High, Send 11 *");
      #endif
    }

};

//******************************************************************
// Function to send the sequence
void send_sequence() {

  while (character != _WAIT) {
    msgIndex = 1;

    while (msgIndex < msg[0]+1) {
      // We read each character in the array
      character = msg[msgIndex];

      inc_bit = 8;

      // Special characters
      if (character == _SPC) {  // For inter-words spacing, we need 5 dots, since we already have 1+2, we need 2 more
         begin_sec = myClock.RTC_sec;
         #ifdef SERIAL_OUT_INFO
         Serial.println("\n* Inter word Space *");
         #endif
         while ( ((60+myClock.RTC_sec-begin_sec)%60)<(2*vitesse) ) {
            delay(0);
         };
         inc_bit = 0;
      };
      if (character == _WAIT) {  // For WAIT or end of sequence, we just skip sending
         #ifdef SERIAL_OUT_INFO
         Serial.println("\n* Enf of sequence *");
         #endif
         inc_bit = 0;
      };

      while (inc_bit) {

        // We read each bit of the character
        etat = bitRead(character,inc_bit-1);

        if (start) {
          if (etat) {
            key=3; // If the bit is 1 then it is a dash
            #ifdef SERIAL_OUT_INFO
            Serial.print("-");
            #endif
          } else {
            key=1; // If the bit is 0 then it is a dot
            #ifdef SERIAL_OUT_INFO
            Serial.print(".");
            #endif
          }

          while (key) {

            digitalWrite( wsprPinB, HIGH );
            digitalWrite( LEDPinB, HIGH );
            digitalWrite( wsprPinA, HIGH );
            digitalWrite( LEDPinA, HIGH );

            // We wait 1 second x VITESSE parameter
            begin_sec = myClock.RTC_sec;
            while ( ((60+myClock.RTC_sec-begin_sec)%60)<(1*vitesse) ) {
              delay(0);
            };

            key--;
          }

          digitalWrite( wsprPinB, LOW );
          digitalWrite( LEDPinB, LOW );
          digitalWrite( wsprPinA, LOW );
          digitalWrite( LEDPinA, LOW );
            // We wait 1 second x VITESSE parameter
          begin_sec = myClock.RTC_sec;
          while ( ((60+myClock.RTC_sec-begin_sec)%60)<(1*vitesse) ) {
            delay(0);
          };
        }

        if (!etat && !start) start=true;

        inc_bit--;

      }
      // We add one space between each characteur (lenght is 3 dots, including the one in the here above loop)
      begin_sec = myClock.RTC_sec;
      #ifdef SERIAL_OUT_INFO
      Serial.print(" ");
      #endif
      while ( ((60+myClock.RTC_sec-begin_sec)%60)<(2*vitesse) ) {
        delay(0);
      };

      start = false;
      msgIndex++;
    };
   };
   character = _SPC;
};

//******************************************************************
// Interruption for the RTC clock
interrupt(TIMER1_A0_VECTOR) Tic_Tac(void) {
  myClock.Inc_chunk();		      // Update chunks
};

Balise WSPR autonome avec MSP430 – le code source

[GTranslate]

Un kit pour ce circuit de générateur de balise WSPR sera bientôt disponible (http://xv4y NULL.radioclub NULL.asia/boutique/?slug=product_info NULL.php&products_id=30).

Ca m’a pris plus de temps que prévu pour publier le code source de mon générateur WSPR à MSP430 pour la balise QRSS de QRP Labs. Le programme “en production” est stable et fonctionne plusieurs jours d’affilée sans problèmes avec de bons reports (spots) sur WSPR. Le problème vient d’un bogue dans le mode debugging justement, les sorties sur port série sensées aidées à la mise au point ne fonctionne pas bien. Ce bogue résulte à la fois d’un problème de l’IDE Energia (au niveau du compilateur certainement) et d’une utilisation trop importante de la SRAM quand je compile le programme en incluant la librairie Serial. Difficile à résoudre, j’ai passé plusieurs jours à essayer d’optimiser les variables et l’utilisation de la RAM mais sans succès. Je vous livre donc le code “tel que” en sachant que le bogue n’est pas gênant en production.

Pour modifier votre balise QRSS en balise autonome WSPR rien de bien compliqué. Il faut construire un petit circuit selon le schéma ci-dessous. En utilisant un LaunchPad les circuits des LED, contacteurs et quartz sont déjà présents. Il faut y ajouter de quoi :

  • alimenter le MSP430G2553 du LaunchPad en 3,3V
  • créer une tension analogique à 4 niveaux grâce à une échelle R-2R à partir des sorties P2.1 et P2.2
  • alimenter en +5V l’étage PA de la balise uniquement quand c’est nécessaire grâce à un transistor BC548 (ou équivalent) connecté sur la sortie P2.0

Schéma générateur balise autonome WSPR à MSP430 (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2012/09/WSPR_balise_schéma NULL.png)

Sur le circuit de la balise par elle-même, rien de compliqué. Les modifications sont résumées sur le schéma suivant et consiste à :

  • Retirer le micro-contrôleur ATTiny8
  • Récupérer le +5V, la masse et le contrôle de la LED “varicap” sur le connecteur DIL8
  • Dessouder la patte +5V du potentiomètre de polarisation (bias) du transistor FET du PA pour la connecter sur le transistor BC548
  • Procéder à un nouvel alignement de la puissance de sortie du PA,
  • Procéder à un nouvel alignement de l’excursion en fréquence (shift) pour qu’elle soit au total de 6Hz
  • Procéder à un nouveau réglage de la fréquence pour être dans la bande WSPR (autour de 10 140 200 Hz sur 30 mètres)

Modifications de la balise QRSS QRP Labs pour WSPR - XV4Y (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2012/10/Kit-WSPR-Mod-balise NULL.jpg)

Pour compiler le code il vous faut bien entendu un LaunchPad avec un MSP430G2253 (http://xv4y NULL.radioclub NULL.asia/2012/04/27/les-micro-controleurs-msp430-de-texas-instruments/). L’environnement de développement Energia correctement installé sur votre micro-ordinateur. La bibliothèque RTC que j’ai développée (http://xv4y NULL.radioclub NULL.asia/2012/05/22/bibliotheque-rtc-pour-le-msp430/) doit aussi être installée dans le répertoire de vos documents Energia. Il vous faut ensuite modifier les paramètre d’indicatif (callsign), de carré Locator et de puissance. Ni la compilation ni le téléchargement ne doivent produire d’erreurs. Une fois le LaunchPad programmé, je vous conseille de placer en position ouverte tous les cavaliers (jumpers) reliant le circuit de programmation-émulation au micro-contrôleur.

L’utilisation du programme par lui même est simple. Vous le mettez sous tension, les deux LEDs rouges et jaunes du LaunchPad vont clignoter alternativement assez rapidement. Le générateur est mode “attente de synchro” et transmet une séquence de test durant au total 30 secondes permettant de vérifier les différentes fréquences symboles et l’extinction du PA.

Ensuite, en utilisant une horloge précise (celle de votre GPS, horloge DCF-77 ou ordinateur synchronisé par NTP), vous appuyez sur le bouton S2 du LaunchPad juste quand l’horloge passe à la seconde zéro d’une minute paire.

Le générateur se met alors en mode “balise” et va transmettre tout de suite une première séquence WSPR. La séquence finie la LED jaune se met à clignoter très rapidement. Si vous appuyez sur le bouton S2 à ce moment, la balise passera à nouveau en émission à la prochaine minute paire. Sinon, elle passera en émission aléatoirement suivant le paramètre que vous avez donné, par défaut le taux est de 20% (tx_rate = 5).

Chez moi, l’horloge reste bonne pendant au moins 72 heures. Après cela elle prend environ une seconde de retard, ce qui suffit à faire que les stations les plus lointaines ne décodent plus la séquence WSPR. La remettre à l’heure ne prend que quelques minutes. L’expérience du GPS montre que sauf à partir dans des solutions complexes et coûteuses (http://www NULL.oe1ifm NULL.at/index NULL.php?option=com_content&view=article&id=49&Itemid=56), atteindre une meilleure stabilité effective reste difficile.

/* WSPR Static Generator for MSP430G2553
 * Code for Energia 008
 
 * By Yannick DEVOS - XV4Y - May-October 2012
    http://xv4y.radioclub.asia/

    Copyright 2012 Yannick DEVOS under GPL 3.0 license
    Any commercial use or inclusion in a kit is subject to author approval
 
 * Based on code by DH3JO Martin Nawrath for WSPR sequence encoding

====
 * Ouput on 2 bits PinA and PinB
 * PTT_key output allows to turn on/off the TX PA while sending
 * Mirror on LED1 and LED2 du LaunchPad for testing
 * Output to Serial for testing
 * Using an R-2R ladder it makes the G0UPL/G0XAR beacon frequency shift

====
Revision history :
v1.00    2012-10-18
         First release

====
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You can download a copy of the GNU General Public License at <http://www.gnu.org/licenses/>
*/

// Here modify to your taste or needs

#define PTT_key 8
#define wsprPinA 10
#define wsprPinB 9
#define LEDPinA 14
#define LEDPinB 2
#define StartBtn 5

const char call[] = "XV4Y ";
const char locator[] = "OK20";
const byte power = 20;
const char tx_rate = 5;

// Be carefull, this is only for debugging.
// If you enable this in production, the clock will drift to much (5 seconds in 10 minutes)
//#define SERIAL_OUT_INFO

// This is in case you use a MSP430 that does not have Hardwart UART. TimerSerial works great but bring a lot of clock drift. Replace each "Serial" object call in the code by mySerial.
/*
#ifdef SERIAL_OUT_INFO
#include <TimerSerial.h> 
TimerSerial mySerial;
#endif
*/

// Here under don't touch anything unless you know what you do

#include <legacymsp430.h>
#include <sRTC.h> // Library for RTC clock with MSP430

const char SyncVec[162] = {
  1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0,0,1,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,1,0,1,0,0,0,0,0,0,1,0,
  1,1,0,0,1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1,0,0,1,0,1,1,0,0,0,1,1,0,1,0,1,0,
  0,0,1,0,0,0,0,0,1,0,0,1,0,0,1,1,1,0,1,1,0,0,1,1,0,1,0,0,0,1,1,1,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,0,
  0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0,0,0
};

boolean force_send = 1;  // The first time the beacon is turned on it will send a sequence
byte symbol, bb, begin_sec;
int begin_chunk;

byte c[11];                // encoded message

byte sym[170];             // symbol table 162
byte symt[170];            // symbol table temp
unsigned long n1;          // encoded callsign
unsigned long m1;          // encodes locator

#ifdef SERIAL_OUT_INFO
#endif
RealTimeClock myClock;

//******************************************************************
// Defining pins mode
// Encoding the WSPR sequence

void setup() {
  pinMode(PTT_key, OUTPUT);
  pinMode(wsprPinA, OUTPUT);
  pinMode(wsprPinB, OUTPUT);
  pinMode(LEDPinA, OUTPUT);
  pinMode(LEDPinB, OUTPUT);
  pinMode(StartBtn, INPUT_PULLUP);

  #ifdef SERIAL_OUT_INFO
  Serial.begin(9600);
  Serial.println("\n* MSP430 WPSR beacon"); 
  #endif

  digitalWrite( PTT_key, LOW );
  digitalWrite( wsprPinA, LOW );
  digitalWrite( wsprPinB, LOW );

  digitalWrite( LEDPinA, HIGH );
  digitalWrite( LEDPinB, HIGH );

  prepare_sequence();

  #ifdef SERIAL_OUT_INFO
  Serial.println("* Wait clock is set. Sending test sequence.");
  #endif
  begin_chunk = myClock.RTC_chunk;
  begin_sec = myClock.RTC_sec;
  while(digitalRead(StartBtn)) {
    // This is for blinking LED fast
    if ((myClock.RTC_chunk-(begin_chunk+15))%60==0)
      digitalWrite( LEDPinA, HIGH );
    if ((myClock.RTC_chunk-(begin_chunk+30))%60==0)
      digitalWrite( LEDPinB, HIGH );
    if ((myClock.RTC_chunk-(begin_chunk+45))%60==0)
      digitalWrite( LEDPinA, LOW );
    if ((myClock.RTC_chunk-(begin_chunk+60))%60==0)
      digitalWrite( LEDPinB, LOW );
    
    // We also send a test sequence to help calibrate the transmitter
    if ((myClock.RTC_chunk-(begin_chunk+0))%240==0) 
      send_test(begin_sec);

   };
  randomSeed(myClock.RTC_chunk);
  myClock.Set_Time(0,0,0);
};

//******************************************************************
// Here starts the actual sequence sending

void loop() {
  #ifdef SERIAL_OUT_INFO
  Serial.print("Time:");
  Serial.print(myClock.RTC_min, DEC);
  Serial.print(":");
  Serial.print(myClock.RTC_sec, DEC);
  Serial.print(".");
  Serial.println(myClock.RTC_chunk, DEC);
  #endif

  digitalWrite( PTT_key, LOW );

  digitalWrite( wsprPinB, LOW );
  digitalWrite( LEDPinB, LOW );

  digitalWrite( wsprPinA, LOW );
  digitalWrite( LEDPinA, LOW );

  begin_chunk = myClock.RTC_chunk;
  
  #ifdef SERIAL_OUT_INFO
  Serial.println("* Waiting 1st sec of even mins.");
  #endif

  while (!(myClock.RTC_sec==1 && (myClock.RTC_min%2)==0)) {  // We start each first second of even minutes
    if ((myClock.RTC_chunk-(begin_chunk+10))%20==0) digitalWrite( LEDPinA, HIGH );
    if ((myClock.RTC_chunk-(begin_chunk+20))%20==0) digitalWrite( LEDPinA, LOW );
    if (!digitalRead(StartBtn)) force_send = 1;  // Pressing the button while in wait mode force the sequence to start next time
  };
  
  if (random(tx_rate+1)==tx_rate || force_send) {  // In order to minimize band occupation, randomly start the transmission depending on tx_rate
    force_send = 0;
    digitalWrite( PTT_key, HIGH );
    send_sequence();
    #ifdef SERIAL_OUT_INFO
    Serial.println("\n* End");
    #endif
  } else {
    // If not, we wait around 1 sec so we don't go through this too early...
    digitalWrite( PTT_key, LOW );
    begin_chunk = myClock.RTC_chunk;
    while ( ((256+myClock.RTC_chunk-begin_chunk)%256)<220 ) {
      delay(0);
    };
  };
};

/* Functions declaration
 * This code by DH3JO
 * KHM 2009 /  Martin Nawrath
 * Kunsthochschule fuer Medien Koeln
 * Academy of Media Arts Cologne
*/


//******************************************************************
// normalize characters 0..9 A..Z Space in order 0..36
char chr_normf(char bc ) {
  char cc=36;
  if (bc >= '0' && bc <= '9') cc=bc-'0';
  if (bc >= 'A' && bc <= 'Z') cc=bc-'A'+10;
  if (bc == ' ' ) cc=36;

  return(cc);
}

//******************************************************************
void encode_call(){
  unsigned long t1;

  // coding of callsign
  n1=chr_normf(call[0]);
  n1=n1*36+chr_normf(call[1]);
  n1=n1*10+chr_normf(call[2]);
  n1=n1*27+chr_normf(call[3])-10;
  n1=n1*27+chr_normf(call[4])-10;
  n1=n1*27+chr_normf(call[5])-10;

  // merge coded callsign into message array c[]
  t1=n1;
  c[0]= t1 >> 20;
//  t1=n1;
  c[1]= t1 >> 12;
//  t1=n1;
  c[2]= t1 >> 4;
//  t1=n1;
  c[3]= t1 << 4;
}

//******************************************************************
void encode_locator(){

  unsigned long t1;
  // coding of locator
  m1=179-10*(chr_normf(locator[0])-10)-chr_normf(locator[2]);
  m1=m1*180+10*(chr_normf(locator[1])-10)+chr_normf(locator[3]);
  m1=m1*128+power+64;

  // merge coded locator and power into message array c[]
  t1=m1;
  c[3]= c[3] + ( 0x0f & t1 >> 18);
//  t1=m1;
  c[4]= t1 >> 10;
//  t1=m1;
  c[5]= t1 >> 2;
//  t1=m1;
  c[6]= t1 << 6;

}
//******************************************************************
// convolutional encoding of message array c[] into a 162 bit stream
void encode_conv(){
  int bc=0;
  int cnt=0;
  int cc;
  unsigned long sh1=0;

  cc=c[0];

  for (int i=0; i < 81;i++) {
    if (i % 8 == 0 ) {
      cc=c[bc];
      bc++;
    }
    if (cc & 0x80) sh1=sh1 | 1;

    symt[cnt++]=parity(sh1 & 0xF2D05351);
    symt[cnt++]=parity(sh1 & 0xE4613C47);

    cc=cc << 1;
    sh1=sh1 << 1;
  }

}

//******************************************************************
byte parity(unsigned long li)
{
  byte po = 0;
  while(li != 0)
  {
    po++;
    li&= (li-1);
  }
  return (po & 1);
}

//******************************************************************
// interleave reorder the 162 data bits and and merge table with the sync vector
void interleave_sync(){
  int ii,ij,b2,bis,ip;
  ip=0;

  for (ii=0;ii<=255;ii++) {
    bis=1;
    ij=0;
    for (b2=0;b2 < 8 ;b2++) {
      if (ii & bis) ij= ij | (0x80 >> b2);
      bis=bis << 1;
    }
    if (ij < 162 ) {
      sym[ij]= SyncVec[ij] +2*symt[ip];
      ip++;
    }
  }
}

// This code by Yannick DEVOS XV4Y 2012

//******************************************************************
// Compute and initialize the sequence
void prepare_sequence() {

  encode_call();
  #ifdef SERIAL_OUT_INFO
  Serial.print("call: ");
  Serial.print(call);
  Serial.print(" ");
  Serial.print(n1,HEX);
  Serial.println(" ");
  #endif

  encode_locator();
  #ifdef SERIAL_OUT_INFO
  Serial.print("locator: ");
  Serial.print(locator);
  Serial.print(" ");
  Serial.print(m1 << 2,HEX);
  Serial.println(" ");
  for (bb=0;bb<=10;bb++){
    Serial.print(c[bb],HEX);
    Serial.print(",");
  }
  Serial.println("");
  #endif

  encode_conv();
  #ifdef SERIAL_OUT_INFO
  Serial.println("");
  for (bb=0;bb<162 ;bb++){
    Serial.print(symt[bb],DEC);
    Serial.print(".");
    if ( (bb+1) %32 == 0) Serial.println("");
  }
  Serial.println("");
  #endif

  interleave_sync();
  #ifdef SERIAL_OUT_INFO
  Serial.println("Channel symbols :");
  for (bb=0;bb<162 ;bb++){
    Serial.print(sym[bb],DEC);
    Serial.print(".");
    if ( (bb+1) %32 == 0) Serial.println("");
  }
  Serial.println("\nEnd of init.");
  #endif

};

//******************************************************************
// Function to send the test sequence
void send_test(char begin_sec) {
    if ((myClock.RTC_sec-(begin_sec+0))%30==0) {
      digitalWrite( PTT_key, LOW );
      digitalWrite( wsprPinA, LOW );
      digitalWrite( wsprPinB, LOW );
      #ifdef SERIAL_OUT_INFO
      Serial.println("* TX Low, Send 00 *");
      #endif
    }

    if ((myClock.RTC_sec-(begin_sec+6))%30==0) {
      digitalWrite( PTT_key, HIGH );
      digitalWrite( wsprPinA, LOW );
      digitalWrite( wsprPinB, LOW );
      #ifdef SERIAL_OUT_INFO
      Serial.println("* TX High, Send 00 *");
      #endif
    }

    if ((myClock.RTC_sec-(begin_sec+12))%30==0) {
      digitalWrite( PTT_key, HIGH );
      digitalWrite( wsprPinA, HIGH );
      digitalWrite( wsprPinB, LOW );
      #ifdef SERIAL_OUT_INFO
      Serial.println("* TX High, Send 01 *");
      #endif
    }

    if ((myClock.RTC_sec-(begin_sec+18))%30==0) {
      digitalWrite( PTT_key, HIGH );
      digitalWrite( wsprPinA, LOW );
      digitalWrite( wsprPinB, HIGH );
      #ifdef SERIAL_OUT_INFO
      Serial.println("* TX High, Send 10 *");
      #endif
    }
    
    if ((myClock.RTC_sec-(begin_sec+24))%30==0) {
      digitalWrite( PTT_key, HIGH );
      digitalWrite( wsprPinA, HIGH );
      digitalWrite( wsprPinB, HIGH );
      #ifdef SERIAL_OUT_INFO
      Serial.println("* TX High, Send 11 *");
      #endif
    }

};

  
//******************************************************************
// Function to send the sequence
void send_sequence() {
  for (bb = 0; bb < 162; bb++) {
    symbol = sym[bb];

    #ifdef SERIAL_OUT_INFO
    Serial.print(" ");
    Serial.print(symbol%10, DEC);
    #endif

    digitalWrite( wsprPinB, (symbol >> 1) );
    digitalWrite( LEDPinB, (symbol >> 1) );

    digitalWrite( wsprPinA, (symbol & 1) );
    digitalWrite( LEDPinA, (symbol & 1) );
    begin_chunk = myClock.RTC_chunk;
    while ( ((256+myClock.RTC_chunk-begin_chunk)%256)<175 ) {
      delay(0);
    };
  };
};


//******************************************************************
// Interruption for the RTC clock
interrupt(TIMER1_A0_VECTOR) Tic_Tac(void) {
  myClock.Inc_chunk();		      // Update chunks
};

Balise WSPR autonome avec MSP430 – suite

Générateur balise autonome WSPR LaunchPad MSP430 (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2012/09/100_3289 NULL.jpg)

[GTranslate]

J’ai retravaillé un peu sur ma balise WSPR autonome (http://xv4y NULL.radioclub NULL.asia/2012/05/11/balise-autonome-wspr-avec-msp430/) construite autour de l’émetteur QRSS de G0UPL/G0XAR (http://www NULL.hanssummers NULL.com/qrsskit NULL.html). D’une part j’ai mis le montage “au propre” sur un circuit imprimé de prototype, d’autre part j’ai implémenté la commande de polarisation du PA ce qui permet de ne pas être en émission constamment et de n’envoyer la séquence WSPR qu’une fois sur quatre de manière aléatoire par exemple.

Le code du générateur lui-même a été optimisé pour générer une séquence de test durant  la phase d’attente de synchronisation de l’horloge. Cela permet de vérifier que les différentes valeurs binaires sont envoyées avec la bonne excursion en fréquence (6Hz au total) et que la fréquence de travail désirée est bien la bonne. La durée de chaque valeur est de 5 secondes, plus longue que durant la séquence WSPR, ce qui facilite les réglages.

Générateur balise autonome WSPR LaunchPad MSP430 deux platines séparées (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2012/09/100_3290 NULL.jpg)Après quelques cafouillages dus à une erreur de câblage, les 3 premières soirées ont été très concluantes. Les reports sur 30 mètres viennent de Thaïlande, des Philippines, du Japon et d’Australie (environ 6000km). Avec les 90mW de la balise de G0UPL c’est tout ce que je peux espérer de mieux surtout à cette saison. En modifiant le circuit du PA j’en ai profité pour remplacer le 2N7000 par un Bs170. Le 2N7000 chauffait anormalement même s’il n’a jamais failli. Avec le Bs170, la dissipation autorisée est plus importante et il ne chauffe plus du tout… Je vais donc essayer d’augmenter la tension d’alimentation de l’´émetteur pour atteindre 9V et les 200mW en émission. J’espère que cela ne posera pas de difficultés pour l’oscillateur et l’étage buffer qui ne seront plus à leur point de fonctionnement optimal, sinon il me faudra charcuter un peu le circuit et ajouter un régulateur supplémentaire.

Reports WSPR 30m 29 septembre 2012 (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2012/10/WSPR_balise_MSP430 NULL.jpg)Il me reste encore quelques petits détails à régler sur le code micro-contrôleur mais je publierai l’ensemble des informations (y compris le schéma) sur une page dédiée d’ici quelques semaines. En attendant n’hésitez pas à me poser des questions si vous en avez.

Nouveau kit QRSS par G0UPL et G0XAR

Schéma G0UPL G0XAR Balise Multimode (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2012/05/G0UPL-G0XAR-Balise-Multimode NULL.jpg)Hans et Stephen viennent d’annoncer un nouveau kit balise multimode QRSS / QRPp (http://www NULL.hanssummers NULL.com/qrsskitmm). La grande nouveauté de ce kit c’est que le micro-contrôleur est maintenant un ATMega168 ce qui permet de faire beaucoup plus beaucoup plus de choses que le très limité ATTiny13 utilisé précédemment.

Les modes supportés seront :

  • QRSS (télégraphie lente par porteuse ON/OFF)
  • FSK/CW (télégraphie lente par modulation de la fréquence
  • DFCW (télégraphie lente par modulation de fréquence mais traits et points chacun sur une fréquence)
  • WSPR (Weak Signal Propagation Reporter par K1JT)
  • Hellschreiber lent (Hellschreiber lent par modulation de fréquence)
  • Hellschreiber (Hellschreiber vitesse normale et demi-vitesse)
  • CW (télégraphie normale)
  • Motifs FSK personnalisables

Autres fonctionnalités

  • Afficheur LCD 24 caractères LCD et interface utilisateur deux boutons
  • Programmable par l’utilisateur (indicatif, message, vitesse, FSK, mode, etc)
  • Paramètres stockés en EEPROM
  • Interface GPS pour verrouiller la fréquence
  • Génération du message WSPR (pas de PC requis)
  • Le locator de la séquence WSPR peut être généré à partir des informations du GPS
  • Taille de la trame QRSS paramètrable pour une réception QRSS de trames superposées (moyenne étalée dans le temps)
  • Balise CW standard à intervales réglables
  • Produit 150mW en sortie HF, sortie audio possible pour piloter un transceiver
  • Puissance supérieure possible par l’ajout d’un transistor supplémentaire au PA ou par l’utilisation d’une tension d’alimentation supérieure

Les commandes seront ouvertes d’ici une à deux semaines et l’expédition des kits devrait débuter dans trois semaines. Le prix prévu est de l’ordre de 15 à 20£, soit environ 23-31$US ou 18-25€.

Un brouillon du manuel de 26 pages peut-être téléchargé pour avoir plus de détails (http://www NULL.hanssummers NULL.com/images/stories/qrsskitmm/instructions1 NULL.pdf).

Balise autonome WSPR avec MSP430

[GTranslate]

Ces derniers jours je me suis amusé un peu à programmer le LaunchPad de TI avec Energia. Le but étant de voir si du code Arduino (AVR ATMega) était facilement portable sur le MSP430.

Capture port série Balise WSPR MSP430 XV4Y (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2012/05/Capture-Balise-WSPR-MSP430 NULL.jpg)La réponse est oui, si le code est propre (pas toujours facile) et s’il n’utilise pas des librairies non encore portée sur Energia (ce qui va diminuer avec le temps). En pratique je suis parti d’un morceau de code de F4GKA/VA2GKA (http://www NULL.itsrainingelephants NULL.com/2012/04/29/wspr-30m-ready/#comments) et d’un autre de DH3JO (http://wsprnet NULL.org/drupal/node/1342) pour faire une balise WSPR autonome. Le code est fonctionnel mais n’a pas encore été testé sur l’air. Cerise sur le gâteau, il est “rétroportable” sur Arduino car il suffit de changer les numéros de broches.

J’ai encore un peu de travail autour de cela, mais pour les curieux voici les résultats de quelques heures de réflexion ce matin. Il me faut maintenant connecter cela sur la balise QRSS du kit de G0UPL / G0XAR et voir comment cela se comporte en particulier du point de vue dérive de la synchronisation dans le temps. Contrairement à mon Arduino Nano le LaunchPad n’est pas équipé d’origine d’un quartz mais j’ai ce qu’il faut sous la main.

Au passage la modification du kit balise QRSS peut se faire comme l’a fait IW1QLH avec une échelle R-2R (http://www NULL.iw1qlh NULL.net/index NULL.php/projects-hardware-mainmenu-66/99-qrp/115-qrss-beacon).

Le fichier pour Energia/Arduino est disponible au téléchargement (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2012/05/WSPR_autonome_XV4Y NULL.txt). Attention, il faudra renommer le fichier en .ino au lieu du .txt (WordPress n’aime pas les .ino)

/* WSPR Static Generator for MSP430G2553
* Code for Energia 005a</code>

* By Yannick DEVOS - XV4Y - May 2012
* Free for HAM Radio usage

* Based on VA2GKA Guenael Jouchet code for sending
* Based on DH3JO Martin Nawrath for WSPR sequence encoding

*
* Internal clock of MSP430 could be not stable enough, try a Crystal
* Start the circuit on the second 0 of an odd minute

* Ouput on 2 bits PinA and PinB
* Mirror on LED1 and LED2 du LaunchPad for testing
* Output to Serial for testing
* Using an R-2R ladder it makes the G0UPL/G0XAR beacon frequency shift
*/

#include// Comment on Arduino, replace mySerial by Serial everywhere

#define wsprPinA 7
#define wsprPinB 6
#define LEDPinA 14
#define LEDPinB 2
#define StartBtn 5

const char SyncVec[162] = {
1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0,0,1,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,1,0,1,0,0,0,0,0,0,1,0,
1,1,0,0,1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1,0,0,1,0,1,1,0,0,0,1,1,0,1,0,1,0,
0,0,1,0,0,0,0,0,1,0,0,1,0,0,1,1,1,0,1,1,0,0,1,1,0,1,0,0,0,1,1,1,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,0,
0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0,0,0
};

const char call[] = "XV4Y ";
const char locator[] = "OK20";
const byte power = 20;

int i;
char symbol;

int ii,bb;

byte c[11]; // encoded message

byte sym[170]; // symbol table 162
byte symt[170]; // symbol table temp
unsigned long n1; // encoded callsign
unsigned long m1; // encodes locator

TimerSerial mySerial; // Comment on Arduino

//******************************************************************
// Defining pins mode
// Encoding the WSPR sequence

void setup() {
mySerial.begin(); // Comment on Arduino
pinMode(wsprPinA, OUTPUT); // Change for Arduino/AVR
pinMode(wsprPinB, OUTPUT); // Change for Arduino/AVR
pinMode(LEDPinA, OUTPUT); // Change for Arduino/AVR
pinMode(LEDPinB, OUTPUT); // Change for Arduino/AVR
pinMode(StartBtn, INPUT_PULLUP); // INPUT for Arduino and put pin to HIGH
// digitalWrite(StartBtn, HIGH); // Don't use this on LaunchPad/MSP430

mySerial.print("\n\n\n*** MSP430 WPSR beacon \n");

encode_call();
mySerial.print("call: ");
mySerial.print(call);
mySerial.print(" ");
mySerial.print(n1,HEX);
mySerial.println(" ");

encode_locator();
mySerial.print("locator: ");
mySerial.print(locator);
mySerial.print(" ");
mySerial.print(m1 &lt;&lt; 2,HEX);
mySerial.println(" ");
for (bb=0;bb mySerial.print(c[bb],HEX);
mySerial.print(",");
}
mySerial.println("");
encode_conv();

mySerial.println("");

for (bb=0;bbmySerial.print(symt[bb],DEC);
mySerial.print(".");
if ( (bb+1) %32 == 0) mySerial.println("");
}
mySerial.println("");

interleave_sync();

mySerial.println("Channel symbols :");
for (bb=0;bb mySerial.print(sym[bb],DEC);
mySerial.print(".");
if ( (bb+1) %32 == 0) mySerial.println("");
}
mySerial.println("");

};

//******************************************************************
// Here starts the actual sequence sending

void loop() {
digitalWrite( wsprPinB, LOW );
digitalWrite( LEDPinB, LOW );

digitalWrite( wsprPinA, LOW );
digitalWrite( LEDPinA, LOW );
mySerial.println("*** Sequence sending delayed.");
mySerial.println("*** Press S2 to start now.");
i = 0;
while (i &lt; 9408) {
delay(1);
if (digitalRead(StartBtn)==LOW) {
i = 20000;
} else {
i++;
};

}

for (i = 0; i &lt; 170; i++) { symbol = sym[i]; mySerial.print(symbol%10, DEC); mySerial.print(" "); digitalWrite( wsprPinB, (symbol &gt;&gt; 1) );
digitalWrite( LEDPinB, (symbol &gt;&gt; 1) );

digitalWrite( wsprPinA, (symbol &amp; 1) );
digitalWrite( LEDPinA, (symbol &amp; 1) );
delay(682.667);
};
mySerial.println("\n *** End of sequence");
};

/* Functions declaration
* This code by DH3JO
* KHM 2009 / Martin Nawrath
* Kunsthochschule fuer Medien Koeln
* Academy of Media Arts Cologne
*/

//******************************************************************
void encode() {
encode_call();
encode_locator();
encode_conv();
interleave_sync();
};
//******************************************************************
// normalize characters 0..9 A..Z Space in order 0..36
char chr_normf(char bc ) {
char cc=36;
if (bc &gt;= '0' &amp;&amp; bc = 'A' &amp;&amp; bc &gt; 20;
t1=n1;
c[1]= t1 &gt;&gt; 12;
t1=n1;
c[2]= t1 &gt;&gt; 4;
t1=n1;
c[3]= t1 &lt;&lt; 4; } //****************************************************************** void encode_locator(){ unsigned long t1; // coding of locator m1=179-10*(chr_normf(locator[0])-10)-chr_normf(locator[2]); m1=m1*180+10*(chr_normf(locator[1])-10)+chr_normf(locator[3]); m1=m1*128+power+64; // merge coded locator and power into message array c[] t1=m1; c[3]= c[3] + ( 0x0f &amp; t1 &gt;&gt; 18);
t1=m1;
c[4]= t1 &gt;&gt; 10;
t1=m1;
c[5]= t1 &gt;&gt; 2;
t1=m1;
c[6]= t1 &lt;&lt; 6;

}
//******************************************************************
// convolutional encoding of message array c[] into a 162 bit stream
void encode_conv(){
int bc=0;
int cnt=0;
int cc;
unsigned long sh1=0;

cc=c[0];

for (int i=0; i &lt; 81;i++) {
if (i % 8 == 0 ) {
cc=c[bc];
bc++;
}
if (cc &amp; 0x80) sh1=sh1 | 1;

symt[cnt++]=parity(sh1 &amp; 0xF2D05351);
symt[cnt++]=parity(sh1 &amp; 0xE4613C47);

cc=cc &lt;&lt; 1;
sh1=sh1 &lt;&lt; 1;
}

}

//******************************************************************
byte parity(unsigned long li)
{
byte po = 0;
while(li != 0)
{
po++;
li&amp;= (li-1);
}
return (po &amp; 1);
}

//******************************************************************
// interleave reorder the 162 data bits and and merge table with the sync vector
void interleave_sync(){
int ii,ij,b2,bis,ip;
ip=0;

for (ii=0;iibis=1;
ij=0;
for (b2=0;b2 &lt; 8 ;b2++) { if (ii &amp; bis) ij= ij | (0x80 &gt;&gt; b2);
bis=bis &lt;&lt; 1;
}
if (ij &lt; 162 ) {
sym[ij]= SyncVec[ij] +2*symt[ip];
ip++;
}
}
}