Launching a weather balloon design

Extracting and monitoring the data from the sensors is critical for meteorological organizations. A standalone Weather Data logger is used for logging the temperature, humidity, rainfall, leaf wetness, pressure, sun radiation etc, but, standalone data loggers are restricted to collect data on the ground stations only. To supervise the environmental parameters like temperature, humidity, pressure, wind speed and wind direction in the sky, this logging technique is not feasible. To overcome this problem, it is necessary to change the design strategy.

Presented here is a case study of environmental weather balloon that monitors the atmospheric parameters over the air using the RF module AX5042. Weather balloons are often called Radiosonde or GPSsonde . The aim of this design is to capture the data from a sensor and send it to the receiver located on the ground.

The weather balloon is divided into three blocks. They are UHF transmitter (for RF transmission), sensor unit, and Time synchronization modules (GPS and RTC).

Flying Weather Balloon (Source: WNEP)

First of all, I will go through the block diagram of Radiosonde. Later, we will explore the inner details of hardware and their interfacing.

Block Diagram of RadioSonde (Weather Balloon) (Source: Kumar B)

Working of Weather Balloon

The AX5042 RF chip generates the required transmission frequency. You can also set the transmission time interval for sending the data.

Any microcontroller can be used to interface various external peripherals like GPS, RTC (Real Time Clock) and Sensors.

The data is captured from the sensors and sent to the remote location using RF communication.

To have correct transmission, a Real time clock (RTC) DS3231 with an accuracy of ±1ppm is preferred.

But, how to get the time and date?

A GPS receiver Ublox is put upon to get the date and time from the INSAT satellite installed at space.

Not only the date and time, you can also get the latitude, longitude etc. from the MAX7C GPS module.

The obtained date and time from the GPS unit is loaded into the microcontroller.

Generally, the radiosondes use frequencies in the range of 400 MHz to 600 MHz.


This algorithm describes the basic idea of implementing weather balloon.

  1. Sync the GPS with the satellite.

  2. Get the time from the GPS.

  3. Load this time into RTC (Real time clock).

  4. Lock the frequency using AX5042.

  5. Send and receive the sensor data periodically.

Software Environment (Source: Kumar B)

Getting Started with AX5042

By now, you’re probably wondering, How to know the underlying hardware? Don’t worry.

On semiconductor provides Evaluation kit DVK-BASE-2-GEVK with necessary add on modules.

The AXsem integrated circuits use AX−RadioLAB GUI and AX-MicroLab code generators, AXSDB Debugger, and AXCode: Blocks IDE.

Here I have used AT89C2051 microcontroller for working out the prototype. The microcontroller is communicated with AX5042 using SPI interface.

First of all, the AX5042 has to be loaded with certain frequency. To do that PLL bits has to be programmed.

Hardware and Software Design

I have written the application code in embedded C using keil µVision IDE. The below interface shows the connection between microcontroller, AX5042 and HYT 271 humidity sensor.

The humidity sensor runs on 3.3V pull-up resistors. It is advisable to use 2.2K resistors for better response.

AX5042 and Microcontroller Connection (Source: Kumar B)

AX5042 has to be programmed for producing the required frequency. The microcontroller writes and read the data using SPI interface.

/*This code will generate the RF frequency using AX5042. */#include <REG52.H>#include <at892051.h#include <stdio.h>#define SyDataO              P1_4#define SyDataI              P1_5#define SyClock              P1_6#define SythLE               P1_7LoadPLL (void);DataFrame (void);spi_write (unsigned long spi_addr);init_ax5042 (void);unsigned char spi_read (unsigned int spi_addr);

This function will generate external interrupt has occurred from AX5042. AX5042 acts as slave and the microcontroller as master.

/*********interrupt Function for Ext.Interrupt-0 *********/unsigned char ex0_isr_counter = 0;void ex0_isr (void) interrupt 0{     ex0_isr_counter++;          // Increment the count     LoadPLL ( );     P3_2 = 1;}

The application code starts from here. The serial port is configured at 9600 baud rate for sending the characters to the serial terminal.   

/*******main function *******/void main (void){           unsigned char W;/*Set serial port for 9600 baud at 11.0592 MHz.  Note that we use Timer 1 for the baud rate generator.*/     SCON = 0x50;     TMOD |= 0x20;     TH1   = 0xFA;     TR1   = 1;     RI      = 1;     TI    = 1;     PCON |= 0x80;     IT0 = 1;      // Configure interrupt 0 for falling edge on /INT0 (P3.2)     EX0 = 1;       // Enable EX0 Interrupt     EA = 1;         // Enable Global Interrupt Flag    // Frequency Loading Program      P1=0;      P3=4;      SythLE = 1;      SyClock= 0;      SyDataO= 0;     while (1)     //Infinite loop       {

   The getchar function waits to receive the character from the serial terminal. If the received character matches, function will get executed.

            /*Wait for the pulse to start. */            W = getchar ( );            if (W== 'r')               {                                            printf ("RF");                    init_ax5042 ( );                    LoadPLL ( );               }                          if (W== 'w')               {                       printf ("Wd");                    LoadPLL ( );               }                          if (W==‘t’)               {                         init_ax5042 ();               }       }}

This  function creates delay in seconds.

delay (int n)      /*  Wait for ‘n’ seconds */{    int i;    for (i=0; i< n; i++)     {          ;     }}

To use the configuration registers for 2051, header file is included for AT89C2051 .

/* Header file for AT89C2051 */#ifndef __AT892051_H__#define __AT892051_H__/*------------------------------------------------P1 Bit Registers------------------------------------------------*/sbit P1_4 = 0x94;sbit P1_5 = 0x95;sbit P1_6 = 0x96;sbit P1_7 = 0x97;/*------------------------------------------------P3 Bit Registers (Mnemonics & Ports)------------------------------------------------*/sbit P3_0 = 0xB0;sbit P3_1 = 0xB1;sbit P3_2 = 0xB2;sbit P3_3 = 0xB3;sbit P3_4 = 0xB4;sbit P3_5 = 0xB5;/* P3_6 Hardwired as AOUT */sbit P3_7 = 0xB7;/*------------------------------------------------Interrupt Vectors:Interrupt Address = (Number * 8) + 3------------------------------------------------*/#define IE0_VECTOR  0 /* 0x03 External interrupt 0 */#define IE1_VECTOR  2 /* 0x13 External interrupt 1 */#define SIO_VECTOR  4 /* 0x23 Serial port */#endif

The AX5042 has to be configured to send and receive the data. The AX5042 registers has to be enabled. (Scroll to see full code below.)

/*Header file for AX5042*//*AX 5042 registers which have to be modified or read in course of transmission or reception of data*/ #ifndef __AX5042_H_#define __AX5042_H_#define AX5042_REG_REVISION             0x00#define AX5042_REG_SCRATCH                    0x01#define AX5042_REG_POWERMODE           0x02 #define AX5042_REG_FIFOCTRL             0x04#define AX5042_REG_FIFODATA             0x05 #define   AX5042_REG_IRQMASK            0x06 #define AX5042_REG_PINCFG1               0x0C#define AX5042_REG_PINCFG2               0x0D#define AX5042_REG_PINCFG3               0x0E /*******************************//* AX5042 Static Register Definition*//*******************************/// AX5042 register names#define AX5042_REG_XTALOSC               0x03#define AX5042_REG_IFMODE                0x08#define AX5042_REG_MODULATION            0x10#define AX5042_REG_ENCODING              0x11#define AX5042_REG_FRAMING               0x12#define AX5042_REG_CRCINIT3              0x14#define AX5042_REG_CRCINIT2              0x15#define AX5042_REG_CRCINIT1              0x16#define AX5042_REG_CRCINIT0              0x17#define AX5042_REG_FEC                   0x18#define AX5042_REG_FECSYNC               0x19#define AX5042_REG_FREQ3                 0x20#define AX5042_REG_FREQ2                 0x21#define AX5042_REG_FREQ1                 0x22#define AX5042_REG_FREQ0                 0x23#define AX5042_REG_FSKDEV2               0x25#define AX5042_REG_FSKDEV1               0x26#define AX5042_REG_FSKDEV0               0x27#define AX5042_REG_IFFREQHI              0x28#define AX5042_REG_IFFREQLO              0x29#define AX5042_REG_PLLLOOP               0x2c#define AX5042_REG_PLLRANGING            0x2d#define AX5042_REG_PLLRNGCLK             0x2e#define AX5042_REG_TXPWR                 0x30#define AX5042_REG_TXRATEHI              0x31#define AX5042_REG_TXRATEMID             0x32#define AX5042_REG_TXRATELO              0x33#define AX5042_REG_MODMISC               0x34#define AX5042_REG_ADCMISC               0x38#define AX5042_REG_AGCTARGET             0x39#define AX5042_REG_AGCATTACK             0x3a#define AX5042_REG_AGCDECAY              0x3b#define AX5042_REG_AGCCOUNTER            0x3c#define AX5042_REG_CICDECHI              0x3e#define AX5042_REG_CICDECLO              0x3f#define AX5042_REG_DATARATEHI            0x40#define AX5042_REG_DATARATELO            0x41#define AX5042_REG_TMGGAINHI             0x42#define AX5042_REG_TMGGAINLO             0x43#define AX5042_REG_PHASEGAIN             0x44#define AX5042_REG_FREQGAIN              0x45#define AX5042_REG_FREQGAIN2             0x46#define AX5042_REG_AMPLGAIN              0x47#define AX5042_REG_SPAREOUT              0x60#define AX5042_REG_TESTOBS               0x68#define AX5042_REG_APEOVER               0x70#define AX5042_REG_TMMUX                 0x71#define AX5042_REG_PLLVCOI               0x72#define AX5042_REG_PLLCPEN               0x73#define AX5042_REG_PLLRNGMISC            0x74#define AX5042_REG_AGCMANUAL             0x78#define AX5042_REG_ADCDCLEVEL            0x79#define AX5042_REG_RFMISC                0x7a#define AX5042_REG_TXDRIVER              0x7b#define AX5042_REG_REF                   0x7c#define AX5042_REG_RXMISC                0x7d#define AX5042_idle                      0x00// receive states#define AX5042_RX_preamble               0x01#define AX5042_RX_delimiter_start        0x02#define AX5042_RX_data                   0x03#define AX5042_RX_CRC                    0x04#define AX5042_RX_packet_end             0x05#define AX5042_RX_abort                  0x06 // Transmit States#define AX5042_TX_preamble               0x81#define AX5042_TX_delimiter_start        0x82#define AX5042_TX_data                   0x83#define AX5042_TX_CRC                    0x84#define AX5042_TX_delimiter_stop        0x85#define AX5042_TX_postamble              0x86#define   AX5042_RX                      0x00#define AX5042_TX                        0x01#define DONE                             0x00#define PROCESSING                       0x01#endif /* __AX5042_H_ */ The registers are configured for AX5042. /*This function initialises the AX5042 using SPI interface */ /* to initialise ax5042*/init_ax5042 (void){/*register settings are calculated by the AXEVK software */spi_write (0x0200);             //modeOFFAX5042_REG_POWERMODEspi_write (0x0C10);             // AX5042_REG_PINCFG1spi_write (0x7201);            //PLLARNG=1 AX5042_REG_PLLVCOIspi_write (0x7401);            //PLLARNG AX5042_REG_PLLRNGMISC spi_write (0x0302);           // AX5042_REG_XTALOSCspi_write (0x0800);           // AX5042_REG_IFMODEspi_write (0x1009);           //AX5042_REG_MODULATIONspi_write (0x1104);           // AX5042_REG_ENCODINGspi_write (0x1204);           // AX5042_REG_FRAMINGspi_write (0x14ff);          // AX5042_REG_CRCINIT3spi_write (0x15ff);          // AX5042_REG_CRCINIT2spi_write (0x16ff);          // AX5042_REG_CRCINIT1spi_write (0x17ff);         // AX5042_REG_CRCINIT0spi_write (0x1810);         // AX5042_REG_FECspi_write (0x1962);         // AX5042_REG_FECSYNCspi_write (0x2036);         // AX5042_REG_FREQ3spi_write (0x2145);        // AX5042_REG_FREQ2spi_write (0x227b);        // AX5042_REG_FREQ1spi_write (0x2387);       // AX5042_REG_FREQ0spi_write (0x2c1d);      // AX5042_REG_PLLLOOPspi_write (0x2d08);      // AX5042_REG_PLLRANGINGspi_write (0x2e03);      // AX5042_REG_PLLRNGCLKspi_write (0x3403);      // AX5042_REG_MODMISCspi_write (0x6000);      // AX5042_REG_SPAREOUTspi_write (0x6800);      // AX5042_REG_TESTOBSspi_write (0x7000);      //AX5042_REG_APEOVERspi_write (0x7100);      // AX5042_REG_TMMUXspi_write (0x7204);      // AX5042_REG_PLLVCOIspi_write (0x7301);      // AX5042_REG_PLLCPENspi_write (0x7400);      // AX5042_REG_PLLRNGMISCspi_write (0x7a30);     // AX5042_REG_RFMISCspi_write (0x7c23);            // AX5042_REG_REF spi_write (0x2500);           // AX5042_REG_FSKDEV2spi_write (0x2666);          // AX5042_REG_FSKDEV1spi_write (0x2767);         // AX5042_REG_FSKDEV0spi_write (0x300f);         // AX5042_REG_TXPWRspi_write (0x3101);         // AX5042_REG_TXRATEHIspi_write (0x3299);         // AX5042_REG_TXRATEMIDspi_write (0x339b);        // AX5042_REG_TXRATELOspi_write (0x7b88);        // AX5042_REG_TXDRIVER}

The configured frequency is loaded into the PLL IC.

/*This function will store the PLL values into AX5042*/LoadPLL ( ){ unsigned int SyncDividend;spi_write (0xaaaa);spi_write (0xaaaa);SyncDividend=spi_read (0x10aa);DataFrame ( );}

This function will write the data to AX5042.

         /*Function to write the data to AX5042*/spi_write (unsigned long spi_addr){    unsigned int j;    spi_addr = spi_addr | 0x8000;    SythLE = 0;    delay (3);    for (j=0; j<=15; j++)         {           SyClock= 0;     if((spi_addr & 0x8000) ==0)                    SyDataO=0;     else                   SyDataO=1;            delay(3);                   SyClock=1;            spi_addr = (spi_addr<<1);            delay(3);             }          delay(3);          SythLE = 1;          SyClock= 0;          SyDataO = 0;  }

This function will read the data from AX5042.

/*Function to read the data from AX5042*/unsigned char spi_read (unsigned int spi_addr){    unsigned int d;    unsigned int j;    d= 0x0000;     spi_addr = spi_addr & 0x7fff;        SythLE = 1;     delay(3);     SythLE = 0;     delay(3);     for(j=0; j<=15; j++)     {                     delay(3);              SyClock= 0;               if((spi_addr & 0x8000) ==0)                                   SyDataO=0;               else                                          SyDataO=1;            delay(3);                         SyClock=1;          spi_addr= (spi_addr<<1);                 d=d<<1;          d= d ^ SyDataO;          delay(3);          }          SythLE = 1;          SyClock= 0;          SyDataO = 0;       return d;}

This function constructs the data packet for transmission. The data is taken from the humidity module.

DataFrame ( ){unsigned int Sensordata;SythLE = 0;Sensordata=humidity;SythLE = 1;SyClock= 0;}

After setting the RF frequency, we have to construct the data frame and send to the receiver.

The data may be captured from any sensor. I have used HYT 271 Humidity sensor and read the humidity and temperature using I2C.

As AX5042 acts as transmitter as well as receiver, we can transmit and receive the data using the same module.

But AX5042 is just part of the Weather balloon.

Weather balloons are precise in their timing due to implementation of GPS and real time clock.

In the upcoming article, we will explore on how to use GPS and RTC for the radiosonde application.


[1] Serial Peripheral Interface Bus – Wikipedia

[2] On Semi DVK-BASE-2-GEVK: DVK-2 Base Evaluation Kit

[3] HYT271 Humidity sensor interface using I2C



Kumar B is a device driver developer w orking as an embedded software engineer in Qualcomm having 6+ years of working experience in developing embedded devices on various target boards. His areas of interest include Internet of Things, Artificial Intelligence, Machine Learning and Image processing.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.