Archives par mot-clé : balise

Recycler un vieux téléphone Android en balise QRSS ou WSPR avec ZL1BPU

Murray ZL1BPU est un fervent amateur des modes à très basse puissance QRSS depuis de très longues années. Il avait déjà écrit un programme permettant de transmettre depuis son PC des bandes son WAV générée par ChirpPix. Plusieurs versions améliorées sont arrivées pour en accroître la précision et autoriser le stacking (http://www NULL.qsl NULL.net/zl1bpu/SOFT/Tools NULL.htm).

La grande nouveauté du jour est qu’il vient d’écrire le même programme pour smartphone ou tablette Android (http://www NULL.qsl NULL.net/zl1bpu/SOFT/AndroidMEPT NULL.txt). Pas besoin de beaucoup de puissance car aucun calcul n’est fait par le terminal. Le programme est écrit en RFO Basic et devrait donc tourner sur de vieux smartphones Android que vous aviez mis au rebus. Vous générez à l’avance vos messages QRSS ou Hellschreiber et avec la sortie audio de votre téléphone connectée à l’entrée micro d’un transceiver BLU, vous voilà prêts!

Murray donne aussi le schéma d’un circuit de mise à niveau et de commutation émission-réception (PTT) par VOX. Vous pouvez télécharger ChirpPix sur la page suivante (http://www NULL.xs4all NULL.nl/~nl9222/soundcard/chirppix NULL.zip).

VOX PTT ZL1BPU (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2014/11/VOX-PTT-5 NULL.png)

QRSS sur 80 mètres avec ZL2IK

Capture ZL2IK grabber 2014-06-04 80m XV4Y (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2014/06/Argo1140 NULL.jpg)Il y a quelques jours j’ai vu sur la liste QRSS Knights (http://mail NULL.cnts NULL.be/mailman/listinfo/knightsqrss_cnts NULL.be) que Pete ZL2IK et Rick W7RNB faisaient des essais (fructueux) de transmission sur 80 mètres. Je sais par mes expérimentations sur WSPR (http://xv4y NULL.radioclub NULL.asia/2013/12/18/wspr-sur-80-metres/) que la propagation est bonne avec la Nouvelle-Zélande mais je n’avais pas encore eu l’occasion de faire l’essai en QRSS. Comme Pete avait placé son grabber QRSS (http://zl2ik NULL.com/Grabber NULL.html) sur la bande, c’était l’occasion de faire un essai.

Après avoir reprogrammé le micro-contrôleur MSP430 de ma balise (http://xv4y NULL.radioclub NULL.asia/2014/01/28/article-balises-wspr-a-dds-pour-cq-magazine-codes-sources/) pour qu’il transmette un signal QRSS6 avec 5Hz de séparation, dès la tombée de la nuit le succès fut immédiat. Les signaux sont très forts et ont été reçu durant toute la période de pénombre commune entre nos deux stations. Ce soir je vais continuer les essais mais en transmettant aussi sur 40 mètres.

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.

Etude de la propagation : suivi automatisée des balises NCDXF

Jim VE7FO est un grand amateur de concours radio. C’est d’ailleurs pour cette raison qu’il a rejoint l’équipe de testeurs du projet COSTA (dont le nom définitif sera annoncé d’ici peu) car il souhaite avoir des statistiques sur les performances des membres de son équipe.

Réception NCDXF VE7FO 2013-08-19 (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2013/08/NCDXF_VE7FO_S-2013-08-19 NULL.gif)Le pendant de cette étude a posteriori de comment s’est passé le concours, c’est une planification rigoureuse de la stratégie à adopter face à la propagation. Certains OMs (et nombreux sont des pointures dans le domaine des contests) vous disent “Il suffit de rester sur la bande la plus haute ouverte et ne descendre que lorsque le nombre de QSOs diminue trop fortement. Et on ne fait les bandes-basses que lors des couchers et levers de soleil”. C’est vrai dans la plupart des cas et pour les gros concours où il est plus important de courir les points que de chasser les multiplicateurs. Il y a d’autres cas où on a besoin de savoir vers quelle direction sera la meilleure ouverture et c’est là qu’une étude de la propagation est nécessaire.

Les logiciels de modélisation (tel que ceux basés sur le moteur VOACAP comme ce site que j’utilise beaucoup (http://www NULL.voacap NULL.com/)) sont très utiles mais ne donne que des prévisions suivant des modèles statistiques théoriques. Une étude des conditions réelles de propagation est souvent d’une meilleure aide. Personnellement j’utilise WSPR à cet effet, mais Jim préfère lui le logiciel Faros (http://www NULL.dxatlas NULL.com/faros/) qui écoute les balises NCDXF (http://www NULL.ncdxf NULL.org/pages/beacons NULL.html) réparties de par le monde et dresse une carte des conditions de propagation. L’avantage des balises NCDXF c’est qu’utilisant 100W dans une antenne verticale en télégraphie elles sont plus proche de la réalité. Cette carte peut ensuite être téléchargée sur un site web comme celui de Jim VE7FO pour partager avec d’autres OM ses résultats. De nombreux sites similaires existent.

Balise QRP pour le 80 mètres

Schéma émetteur 1,5W 3,5 MHz (http://www NULL.vk2zay NULL.net/article/172)Toujours à la recherche d’un schéma d’amplificateur QRP éprouvé pour des balises QRSS et WSPR (http://xv4y NULL.radioclub NULL.asia/boutique/?slug=product_info NULL.php&products_id=33), je suis tombé sur ce sympathique montage de VK2ZAY (http://www NULL.vk2zay NULL.net/article/172) permettant de sortir 1,5W sous 13,8V sans adaptation d’impédance exotique. Rustique et n’utilisant que des composants simples, il a le mérite de pouvoir être réalisé en une après-midi avec des fonds de tiroirs.

Point intéressant, Alan justifie son choix de 2 transistors 2N7000 en parallèle face à un seul transistor équivalent ou à un IRF510. Les différences de performance minimes et la température de fonctionnement donne rapidement priorité au premier choix sans éliminer les autres qui peuvent s’avérer intéressant suivant les cas. Dès que j’ai le temps je vais essayer de le réaliser mais avec 1 seul Bs170 qui en principe chauffe moins que le 2N7000 et ne l’alimentant que sous 9V pour sortir un peu moins de puissance.

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
};

Bibliothèque RTC pour le MSP430

[GTranslate]

Le micro-contrôleur MSP430G2553 de Texas Instruments livrés avec le LaunchPad dispose de tout le nécessaire pour en faire une horloge temps-réel (RTC). Il suffit de lui connecter un quartz 32KHz et de le programmer convenablement.

TI donne les librairies en assembleur utilisable avec leur environnement de développement. Pour Energia, une nouvelle librairie était nécessaire, je me suis donc attelé à sa conception.

Rien de révolutionnaire, mais ça peut servir à d’autres. C’est sur cette librairie qu’est basée ma balise autonome WSPR que je compte proposer en semi-kit d’ici peu (certainement à mon retour de vacances début juillet). D’origine la dérive en fréquence est de l’ordre du Hertz pour 24 heures (20ppm) ce qui suffit pour une nuit de transmission WSPR, mais peut-être ajustée avec un condensateur variable pour corriger la fréquence du quartz.

Le fichier d’en-têtes (sRTCsec.h) :

/*
 sRTC.h - Library for adding simple RTC capabilities using MSP430 hardware
 By Yannick DEVOS (XV4Y) - 2012

///////////////////////////////// How to use the lib

 * Create an instance of the object

 RealTimeClock myClock;

 * In order to have this RTC library working you should add this code to the end of your main program :

 interrupt(TIMER1_A0_VECTOR) Tic_Tac(void) {
	myClock.Inc_sec();		      // Update secondes
 };

 * Enjoy the clock reading the RTC_sec, RTC_min, RTC_hr variables

 */

// ensure this library description is only included once
#ifndef RTCsec_h
#define RTCsec_h

// library interface description
class RealTimeClockSec
{
	// user-accessible "public" interface
public:
	RealTimeClockSec(void);
	void Set_Time(char hr, char mins, char secs);
    char RTC_sec; // This how you read the time, by reading the vars
    char RTC_min;
    char RTC_hr;
	void Inc_sec(void); // This methode should be invoked by an Interrupt call (see top of the file comment)
	// A few private methods
private:
	void Inc_min(void);
	void Inc_hr(void);
};

#endif

Le code par lui-même (sRTCsec.cpp) :

/*
 sRTC.h - Library for adding simple RTC capabilities using MSP430 hardware
 By Yannick DEVOS (XV4Y) - 2012
 */

// include this library's description file
#include <sRTCsec.h>
#include <legacymsp430.h>

// Constructor /////////////////////////////////////////////////////////////////

RealTimeClockSec::RealTimeClockSec(void)
{
	RTC_sec = 0;
	RTC_min = 0;
	RTC_hr = 0;

	WDTCTL = WDTPW | WDTHOLD; // Kill watch-dog

	BCSCTL1 = DIVA_3;        // Clock = ACLK / 8
	BCSCTL3 |= (LFXT1S_0 | XCAP_3);        // Internal 12.5pF cap for 32KHz crystal

	TA1CCTL0 = CCIE;             //  CCR0 interupt activated
	TA1CCR0 = 4096-1;               // 4096 ticks of 32KHz XTal = 1 second => CCR0 counts N+1
	TA1CTL = TASSEL_1 | ID_3 | MC_1;  // Clock for TIMER 1 = ACLK, By 8 division, up front

};

// Methods /////////////////////////////////////////////////////////////////

void RealTimeClockSec::Inc_sec(void) {
	RTC_sec = RTC_sec + 1;		      // Update seconds
	if (RTC_sec == 60) {
		RTC_sec=0;
		Inc_min();
	};
};

void RealTimeClockSec::Inc_min(void) {
	RTC_min = RTC_min + 1;		      // Update minutes
	if (RTC_min == 60) {
		RTC_min=0;
		Inc_hr();
	};
};

void RealTimeClockSec::Inc_hr(void) {
	RTC_hr = RTC_hr + 1;		      // Update hours
	if (RTC_hr == 24) {
		RTC_hr=0;
	};
};

void RealTimeClockSec::Set_Time(char hrs=0, char mins=0, char secs=0) {
	if ((hrs>=0 && hrs <24) && (mins>=0 && mins<60) && (secs>=0 && secs<60)) {
		RTC_hr = hrs;	// Set time to values given in parameters
		RTC_min = mins;
		RTC_sec = secs;
	};
};

Avec un exemple (testé sous Energia 005a) c’est plus facile à comprendre :

#include &lt;sRTCsec.h&gt;
#include &lt;legacymsp430.h&gt;
#include &lt;TimerSerial.h&gt;

TimerSerial mySerial;
RealTimeClockSec myRTC;

  int ledState = LOW;

void setup() {
  pinMode(2, OUTPUT);

  // This is to close the serial output so you are able to upload a new sketch to the LaunchPad
  pinMode(5, INPUT_PULLUP),
  attachInterrupt(5,fin,LOW);

  mySerial.begin();

};

// The LED1 will blink each exact second and the time will be printed to the serial port
void loop() {
  if ((myRTC.RTC_sec % 2)==0 && ledState== HIGH) {
  ledState = LOW;
  mySerial.print(myRTC.RTC_min, DEC);
  mySerial.print(":");
  mySerial.println(myRTC.RTC_sec, DEC);
  digitalWrite(2, ledState);
  };

  if ((myRTC.RTC_sec % 2)==1 && ledState== LOW) {
  ledState = HIGH;
  mySerial.print(myRTC.RTC_min, DEC);
  mySerial.print(":");
  mySerial.println(myRTC.RTC_sec, DEC);
  digitalWrite(2, ledState);
  };
};

void fin() {
  mySerial.end();
};

interrupt(TIMER1_A0_VECTOR) Tic_Tac(void) {
	myRTC.Inc_sec();		      // Update secondes
};

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++;
}
}
}

8771km avec 100mW

Bon, je ne vais pas vous faire le remake de l’article de l’année dernière alors je vais essayer de faire bref.

QRSS 10s avec 100mW (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2012/01/XV4Y_on_ZL2IK_30m NULL.jpg)Après avoir correctement reprogrammé ma MEPT QRSS (http://xv4y NULL.radioclub NULL.asia/2012/01/11/programmer-un-micro-controleur-atmel-attiny-avec-un-arduino/) pour le 30 mètres, j’ai passé un peu plus de temps que d’habitude à regarder les images collectées par les différents grabbers QRSS (http://digilander NULL.libero NULL.it/i2ndt/grabber/grabber-compendium NULL.htm). J’étais donc très content de voir que mon signal se traçait faiblement certes mais à la bonne fréquence et avec le bon indicatif sur l’ensemble de réception de Peter ZL2IK (http://www NULL.igrin NULL.co NULL.nz/~peter/Grabber NULL.htm).

La trace est faiblarde mais en regardant à 10.140.050, en commençant par la droite, on voit à 13.08 UTC la fin du Y, à 13.05 la fin du 4 et à 13.03 UTC celle du V. Je vais essayer d’améliorer le filtrage de l’alimentation de la balise car je trouve que les traits sont un peu larges…

Programmer un micro-contrôleur Atmel ATtiny avec un Arduino (MAJ)

[GTranslate]

Il y a plus d’un an j’avais monté un kit balise QRSS (MEPT QRSS pour être exact) de G0UPL (http://xv4y NULL.radioclub NULL.asia/2010/08/16/kit-balise-qrss/). Hans livre le micro-contrôleur ATTiny13 du kit programmé à l’avance avec l’indicatif que vous lui demandez, or le mien a changé entretemps!

Arduino utilisé comme ISP pour reprogrammer un ATTiny13

J’avais donc en tête de reprogrammer celui-ci avec le bon indicatif. C’est facilement faisable avec une platine Arduino programmée pour agir en tant qu’ISP (In System Programmer). Une condition cependant, que les Fuse-bits ne soient pas programmés car dans ce cas un programmateur à tension élevée est nécessaire pour tout remettre à zéro. Hans et Steve m’ont confirmé que ce n’était pas le cas pour leur micro-contrôleur.

Je ne vais pas vous faire un guide pas-par-pas ici, plusieurs tutoriaux sont disponibles sur internet et mieux documentés. Je vais plutôt vous dire où trouver les informations. A noter que j’utilise un Macintosh, mais les grandes lignes restent les mêmes.

Liste des ingrédients :

  • La dernière version de l’IDE de l’Arduino (http://arduino NULL.cc/en/Main/Software).
  • Le pack de développement CrossPack pour AVR (http://www NULL.obdev NULL.at/products/crosspack/index NULL.html) qui permettra de compiler le code vers un binaire AVR avec XCode et installera aussi AVRDude permettant de communiquer avec le microcontrôleur de chez Atmel.
  • Un Arduino avec ATMega328, une plaque d’essais, des câbles, des jumpers et un condensateur (à mettre entre la pin RESET et la masse de l’Arduino.
Recette :
  • Lancer l’IDE Arduino, ouvrir le sketch Arduino ISP des exemples, le programmer dans l’Arduino.
  • Créer un projet dans XCode, copier le code du keyer QRSS (http://www NULL.hanssummers NULL.com/images/stories/qrsskeyer/beacon NULL.c) et le compiler.
  • Câbler l’Arduino et l’ATTiny de telle façon à raccorder les masses et +5V des deux circuits ensembles. Connecter les broches 10, 11, 12 et 13 de l’Arduino respectivement aux broches 1 (RST), 5 (MOSI), 6 (MISO),7 (SCK) de l’ATTiny13. (Voir photo un peu plus haut)
  • Ouvrir une fenêtre du terminal (shell) et récupérer l’ancien binaire (voir capture ci-dessous,cliquez pour élargir).Récupération du binaire du précédent programme dans la Flash de l'ATTiny13 avec AVRDude (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2012/01/Download-binaire-ATTiny13-XV4TUJ NULL.jpg)
  • Programmer l’ATTiny avec le fichier .hex généré par XCode (voir capture ci-dessous, cliquez pour élargir).Envoi du binaire du nouveau programme dans la Flash de l'ATTiny13 avec AVRDude (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2012/01/Upload-binaire-ATTiny13-XV4Y NULL.jpg)

Ca marche, ma balise envoie maintenant le bon indicatif (voir plus bas pour la mise à jour). Je n’ai plus qu’à procéder au réalignement périodique de la fréquence car celle-ci bouge un peu (50Hz c’est beaucoup en QRSS) avec les changements de saison et de température moyenne.

Mon but était de reprogrammer un ATTiny13 (http://futurlec NULL.com/Atmel/ATTiny13V NULL.shtml) avec le code source de G0UPL/G0XAR. Celui-ci est dans le langage C spécifique à ce micro-contrôleur, et avec le template AVR de XCode ont produit un binaire (fichier .hex) en code machine pour celui-ci. La flash sur l’ATTiny13 et de 1Ko, le binaire fait 664o.

Si vous disposez d’ATTiny45 ou ATTiny85, (http://futurlec NULL.com/Atmel/ATTiny85 NULL.shtml) ceux-ci ayant plus de mémoire, une autre possibilité existe si vous souhaitez créer vos propres programmes. En effet, le projet Arduino-Tiny (http://code NULL.google NULL.com/p/arduino-tiny/) a pour but de porter le noyau Arduino sur ATTiny. Ceci permet d’utiliser l’environnement de développement (IDE) d’Arduino et son langage plus évolué. Toutes les commandes ne sont pas utilisables car certaines sont propres au micro-contrôleur ATMega (http://futurlec NULL.com/Atmel/ATMEGA328P-AU NULL.shtml) des Arduino. Toutefois, pour un bon nombre de projets simples (balise (http://xv4y NULL.radioclub NULL.asia/2011/07/01/balise-cw-a-base-de-micro-controleur-arduino/), manipulateur électronique (http://xv4y NULL.radioclub NULL.asia/2011/12/09/arduino-manipulateur-cw-de-numero-de-serie-pour-concours/)…) cela permet de réduire de le coût et de simplifier le circuit.

Mise à jour : Contrairement à ce que je pensais au début même si la programmation du micro-contrôleur se passait bien aucune “manipulation” n’était effectuée par la balise, le signal restait fixe mais variait à cause du changement de température…

Je prends contact avec Stephen et Hans qui me donne deux informations. D’abord la fréquence à indiquer dans le Makefile pour la compilation est 9 600 000 Hz, car les ATTiny ont été programmés avec les fuse-bytes indiquant une horloge de 9,6 Mhz et pas de prescaling par le diviseur-par-8. Ensuite un petit bogue réside dans leur code qui ne compile plus sur les nouvelles versions de WinAVR (qui utilise avr-libc comme Crosspack). Après quelques recherches (je ne suis pas très doué en programmation), le code est corrigé et compile maintenant parfaitement. La version mise à jour du code devrait être disponible chez G0UPL, n’hésitez pas à me contacter pour plus de détails.