Curing transmitter instabilities with the”High Performance TRX” for 14MHz

I have used a simple dipole for 14MHz temporarily. This antenna was not much as quiet as the Deltaloop but much simpler to install and fix, compared to the loop that has been my standard antenna for 14MHz for years. The noise in the receiver when using the dipole was beyond words.

Thus I changed the dipole for a quad loop again the last weekend. When connecting the transceiver I found that in spite of good SWR (1:1.2) the transmitter was self-oscillating. With the spectrum analyzer I could recognize that there were oscillations in the medium wave range as well as around 14 MHz. This made me examining the transmitter more closely.

After estimated a dozen of checks and failed attempts I changed to improve the performance I decided to alter the input transformer of the final stage. This item,  which by origin had a winding ratio of 4 to 2+2, then was changed by a transformer having 3 to 3+3. This even deteriorated the situation.

Next I concluded that the second winding might have too high impedance. So I went to a 4 to 1+1 transformer (pig nose core BN43-202).

This finally cured the problem to a 100% and gave a very stable transmitter. Output power increased to 28 watts when fully modulated. This might be the direct outcome of better impedance matching.

Here is the current transmitter circuit with all the improvements made so far:

DK7IH - High performance Transceiver - Transmitter section
DK7IH – High performance Transceiver – Transmitter section (Full size image)

73 de Peter and “Thanks for watching!” 😉

Advertisements

Reviewing and improving the semi-automatic antenna tuner

Foreword

When I built the semi automatic tuner two years ago I did not take into account some possible shortcomings the device could suffer from. The first of these I noticed when I exceeded power levels of about more or less than 50 watts. In some cases there was rf incoupling leading the microcontroller to fail so that the relay setting was invalid for the given combination of frequency and antenna. The next point was that the algorithm to set the capacitor was far from being optimized. And, as I found out, the maximum inductance I had inlcuded was far too high. On the other hand the lowest indcutance was to big to ensure very fine tuning. So this was revised, too by stepping the inductors more carefully.

The consequence then was a complete reconstruction of the tuner trying to avoid the problems from rf stray energy being coupled into the microcontroller and improving the software and hardware.

Abstract

Thsi article describes a microcontroller driven semi-automatic antenna tuner capable of handling power levels up to 150 watts. The device is a low pass filter tuner manually tuned by setting the optimized L/C combination by hand and then storing the values into the EEPROM of the mictrocontroller to recall them later (seperately for each band from 80 to 10 meters including WARC bands). The tuner ist designed to couple long wire antennas (i. e. longer than half a wavelength) in the frequency range from about 3 MHz to 30 MHz. The antennas can be balanced or non-balanced.

The device uses 7 coils wound on iron powder toroids and a variable capacitor controlled by a motor with a reduction drive and a a device that detects the current turning angle of the rotator.

Also integrated you will find a measurement section to give the current standing wave ratio and put out this on the display.

General layout

The tuner consists of two main parts:

  • The microcontroller unit
  • The RF unit containing the tuning coils and the variable capacitor.

Let’s see the schematic first:

DK7IH semi automatic antenna tuner V2 (schematic)
DK7IH semi automatic antenna tuner V2 (Schematic FULL SIZE)

Circuit description

Starting on the left side, you see the microcontroller unit equipped with an 8-bit AVR microcontroller (ATMega16 or similar). The user interface is very simple and made of 6 push buttons. These are connected to GND via switchable individual resistors leading to the ADC3 input of the cntroller. The pull up resistor for ADC3 is activated thus forming a voltage divider and thus an individual ADC value for each push button to be recognized by the software. This is done because it saves control lines and controller ports to a wide extent.

The LCD is a two line 16 characters LCD.

Output ports are connected to ULN2003 driver ICs. These ICs contain a driver capable to handle up to 30V DC including a clamp diode so this IC can drive mtors and relays directly. There are capacitors of 0.1uF connected to the port lines to minimize rf coupling effects.

The RF board is made of 7 coils wound on T68-2 toroids with the inductances given in the schematic:

  • L1: 0.1uH: 4 turns,
  • L2: 0.25uH: 7 turns,
  • L3: 0.5uH: 9 turns,
  • L4: 1uH: 13 turns,
  • L5: 2uH: 19 turns,
  • L6: 4uH: 26 turns,
  • L7: 8uH: 37 turns.

Wire gauge is 0.4mm. The inductors are shortened by a 12V relay each if neccessary. So you can (by binary calculation) set any value from 0.1 uH to close to 16uH.

An output transformer is used to give a balanced out for e. g. doublet antenns. It is 10 turns bifilar on a 2.5 cm toroid ferrite core of No. 43 material. If you use a non-balanced antenna you can leave out this transformer.

The capacitor in my construction is a 200pF max. butterfly capacitor with air as dielectric.  The advantage of a butterfly type is that it needs only 90° angle to turn it from minimum to maximum capacity. The motor (a 5V dc version) is connected via a 240:1 gear drive by TAMIYA. The motor is pulse driven so it can be directly connected to 12 Volts with running danger to damage it.

The drive has two outlets providing one axle at each side of the drive. To one of the axles I connected the capacitor, the other one connects to a potentiometer to report the current swing angle to the microcontroller. This allows precise feedback of the capacitor’s current position which is essential for setting it to the desired value. The value of this variable resistor does not really matter since it is only a simple voltage divider. Anything between 1k and 10k should fit. Make sure that you use a piece that is easy to turn to minimize friction. To connect the axles I used PVC tubing with an inside diameter of 3 mm.

Also included is a measurement section to give the user a current reading of VSWR. The coupler can be anything you should regard as proper. I used a strip power coupler from an old CB radio. But other systems should also work.

To compensate losses when tuning low frequencies I added a DC amplifier based on an operational dual system amplifier (LM358). There is no means to reduce sensitivity. This is done by regulating the input power of the driving transmitter. The software will give you a readout for FWD and REF power in the range from 0 to 999. Tune to maxmimun FWD and minimum REF energy and everything will be alright! 😉

Practical aspects

To minimize RF couping into the microcontroller I seperated the control board from the RF board by putting it on a seperate veroboard with an aluminium shielding underneath:

DK7IH semi automatic antenna tuner V2 (inside view)
DK7IH semi automatic antenna tuner V2 (inside view)

The RF board is mounted to the bottom of the case, here with dismantled controller board. The controller board is sited on top of the package.

DK7IH semi automatic antenna tuner V2 (inside view)
DK7IH semi automatic antenna tuner V2 (inside view)

On the right side there is the variable butterfly capacitor, on the board, centered you can see the motor plus the reduction drive. On the left side of this there is a small potentiometer that forms the turning angele detector. To connect this to the ADC of the controller it is highly recommended to use shielded cable!

To come to an end, here is the deveice positioned under the roof window of my shack directly connected to the ladder line:

DK7IH semi automatic antenna tuner V
DK7IH semi automatic antenna tuner V”

Thanks for reading and enjoy your radio! 73 de Peter (DK7IH)

The software

(Apology for having some comments in German. I have been using this code for centuries! 😉

/*****************************************************************/
/*              Antennatuner with ATMega 16 V2                   */
/*  ************************************************************ */
/*  Microcontroller:  ATMEL AVR ATmega16, 8 MHz                  */
/*                                                               */
/*  Compiler:         GCC (GNU AVR C-Compiler)                   */
/*  Author:           Peter Rachow DK7IH                         */
/*  Last cahnge:      2018-07-27                                 */
/*****************************************************************/

/*    PORTS */
// O U T P U T 
// LCD 
// RS      = PD2
// E       = PD3
// D4...D7 = PD4..PD7

//Coil relays: PC0...PC6
//Motor drive on/off: PD1
//Motor direction relay: PD0
//Extra capacitor 200pF: PC7 (not yet!)

//I N P U T
//ADC0: SWR-Meter 0
//ADC1: SWR-Meter 1
//ADC2:
//ADC3: Keys
//ADC4: Potentiometer for Capacitor position

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/eeprom.h>
#include <util/delay.h>

int main(void);

#define LCD_INST 0x00
#define LCD_DATA 0x01

#define MAXCAP 220
#define CAPDELAY 10
#define MAXBANDS 7

void lcd_write(char, unsigned char);
void set_rs(char);
void set_e(char);
void lcd_init(void);
void lcd_cls(void);
void lcd_line_cls(int);
void lcd_putchar(int, int, unsigned char);
void lcd_putstring(int, int, char*);
int lcd_putnumber(int, int, long, int);
void lcd_display_test(void);

//BAND DISPLAY & MISC
void show_band(int);
void show_meter(int, int, int);
void define_chars(void);

//Coils & Cpas
void set_coils(int);
void set_cap(int);
void rotate_cap(int);
int get_cap(void);

//ADC
int get_adc(int);
int get_keys(void);

//Delay
void wait_ms(int);

//String
int int2str(long, int, char *, int);
int stringlen(char *);


long runsecs = 0;

/**************************************/
/* Funktionen und Prozeduren fuer LCD */
/**************************************/
// LCD 
// RS      = PD2
// E       = PD3
// D4...D7 = PD4..PD7

/* Ein Byte (Befehl bzw. Zeichen) zum Display senden */
void lcd_write(char lcdmode, unsigned char value)
{
    int x = 16, t1;
	
    set_e(0); 

    if(!lcdmode)
	{
        set_rs(0);    //RS=0 => INST
	}	
    else
	{
        set_rs(1);    // RS=1 => DATA
	}	

    wait_ms(4);
	
    //Hi nibble
    set_e(1);
	for(t1 = 0; t1 < 4; t1++)
	{
	    if(value & x)
	    {
	       PORTD |= x;
	    }
        else	
	    {
           PORTD &= ~(x);
	    }  
		
		x <<= 1;
	}	
	set_e(0);
	
	x = 16;

	// Lo nibble
	set_e(1);
	for(t1 = 0; t1 < 4; t1++)
	{
	    if((value & 0x0F) * 16 & x)
	    {
	       PORTD |= x;
	    }
        else	
	    {
           PORTD &= ~(x);
	    }  
		
		x <<= 1;
	}
    set_e(0);

}

//RS
void set_rs(char status) //PD2  
{
    if(status)
	{
        PORTD |= 4;
	}	
    else
	{
	    PORTD &= ~(4);
	}	
}

//E
void set_e(char status)  //PD3
{
    if(status)
	{
        PORTD |= 8;
	}	
    else
	{
	    PORTD &= ~(8);
	}	
}

/* Ein Zeichen (Char) zum Display senden, dieses in */
/* Zeile row und Spalte col positionieren           */
void lcd_putchar(int row, int col, unsigned char ch)
{
    lcd_write(LCD_INST, col + 128 + row * 0x40);
    lcd_write(LCD_DATA, ch);
}


/* Eine Zeichenkette direkt in das LCD schreiben */
/* Parameter: Startposition, Zeile und Pointer   */
void lcd_putstring(int row, int col, char *s)
{
    unsigned char t1;

    for(t1 = col; *(s); t1++)
	{
        lcd_putchar(row, t1, *(s++));
	}	
}


/* Display loeschen */
void lcd_cls(void)
{
    lcd_write(LCD_INST, 1);
}


/* LCD-Display initialisieren */
void lcd_init(void)
{
    /* Grundeinstellungen: 2 Zeilen, 5x7 Matrix, 4 Bit */
    lcd_write(LCD_INST, 40);
    lcd_write(LCD_INST, 40);
    lcd_write(LCD_INST, 40);

    //MAtrix 5*7
    lcd_write(LCD_INST, 8);

    /* Display on, Cursor off, Blink off */
    lcd_write(LCD_INST, 12);

    /* Entrymode !cursoincrease + !displayshifted */
    lcd_write(LCD_INST, 4);
	
	//4-Bit-Mode
    lcd_write(LCD_INST, 2);	
	
	lcd_cls();
}


//Write number with given amount on digits to LCD
int lcd_putnumber(int col, int row, long num, int dec)
{
    char *numstr = malloc(32);
    int l = 0;
    if(numstr != NULL)
    {
        int2str(num, dec, numstr, 16);
        lcd_putstring(col, row, numstr);
        l = stringlen(numstr);
        free(numstr);
        return l;
      
    } 
    return 0;
}


void lcd_line_cls(int ln)
{
    int t1;
	
	for(t1 = 0; t1 < 15; t1++)
	{
	    lcd_putchar(ln, t1, 32);
	}
}	
/*****************************************/
//           STRING FUNCTIONS
/*****************************************/
//INT 2 ASC
int int2str(long num, int dec, char *buf, int buflen)
{
    int i, c, xp = 0, neg = 0;
    long n, dd = 1E09;

    if(!num)
	{
	    *buf++ = '0';
		*buf = 0;
		return 1;
	}	
		
    if(num < 0)
    {
     	neg = 1;
	    n = num * -1;
    }
    else
    {
	    n = num;
    }

    //Fill buffer with \0
    for(i = 0; i < 12; i++)
    {
	    *(buf + i) = 0;
    }

    c = 9; //Max. number of displayable digits
    while(dd)
    {
	    i = n / dd;
	    n = n - i * dd;
	
	    *(buf + 9 - c + xp) = i + 48;
	    dd /= 10;
	    if(c == dec && dec)
	    {
	        *(buf + 9 - c + ++xp) = '.';
	    }
	    c--;
    }

    //Search for 1st char different from '0'
    i = 0;
    while(*(buf + i) == 48)
    {
	    *(buf + i++) = 32;
    }

    //Add minus-sign if neccessary
    if(neg)
    {
	    *(buf + --i) = '-';
    }

    //Eleminate leading spaces
    c = 0;
    while(*(buf + i))
    {
	    *(buf + c++) = *(buf + i++);
    }
    *(buf + c) = 0;
	
	return c;
}

//STRLEN
int stringlen(char *s)
{
   int t1 = 0;

   while(*(s + t1++));

   return (t1 - 1);
}


//BAND DISPLAY
void show_band(int b)
{

    char *band_str[] = {"80m", "40m", "30m", "20m", "17m", "15m", "12m", "10m"};
    lcd_putstring(0, 13, band_str[b]);
}

//Meter (max. value = 25)
void show_meter(int value, int value_old, int pos)
{
	#define MAXBLOCKS 4
    int v1, v2, v3, i1;
	
    //Clear meter (5 chars) if new value > old value
    if(value < value_old)
    {
        for(i1 = 0; i1 < MAXBLOCKS; i1++)
        {
	        lcd_putchar(1, i1 + pos * 6, 32);
        }
	}
			
	v1 = (int) value / MAXBLOCKS; //Full blocks, 5 cols each
    v2 = value - v1 * MAXBLOCKS;  //Rest
	if(v1 > MAXBLOCKS)
	{
		v1 = MAXBLOCKS;
	}
	
	if(value >= value_old)
	{
	    v3 = (int) value_old / MAXBLOCKS; //Full blocks, 5 cols each, already drawn
	}
	else
	{  
		v3 = 0;
	}	    
	
	//Full blocks	
	for(i1 = v3; i1 < v1; i1++)
	{
	    lcd_putchar(1, i1 + pos * 6, 4); 
	}
	
	//Rest
	if(i1 < MAXBLOCKS)
	{
		if(v2)
	    {
	        lcd_putchar(1, i1 + pos * 6, v2 - 1);
	    }
        else
        {
            lcd_putchar(1, i1 + pos * 6, ' ');
        }
	}
}

//PROGRAM CUNSTOM CHARS FOR S-SMETER
void define_chars(void)
{
    int i1;
	unsigned char adr = 64;
						  
	unsigned char b1[] = {0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, //S-Meter blocks 
	                      0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
						  0x00, 0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x00, 0x00,
						  0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, 0x00,
						  0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
						  	0x0,0x0,0x4,0xe,0x4,0x0,0x0, 0, //+
						  	0x4,0xe,0x4,0x0,0x4,0xe,0x4,0, //++
						  0x00, 0x01, 0x02, 0x12, 0x0A, 0x04, 0x00, 0x00  //Tick
						  
						  };					  
	//Dummy operation!
	lcd_write(LCD_INST, 0);
	lcd_write(LCD_DATA, 0);

    //Load data into CGRAM
	for(i1 = 0; i1 < 64; i1++)  
	{
	    lcd_write(LCD_INST, adr++);
		lcd_write(LCD_DATA, b1[i1]);
	}
}		


/////////////////////////////////////
//
// C O I L S & C A P S
//
/////////////////////////////////////
void set_coils(int pattern)
{
    int unsigned t1, x = 1, p = pattern;
    
    //Inductance in uH  * 100
    int i0[] = {10, 25, 50, 100, 200, 400, 800}, i1 = 0;
    
    //lcd_putstring(0, 10, "    ");
    //lcd_putnumber(0, 10, p, -1, -1, 'l', 0);
    
    for(t1 = 0; t1 < 7; t1++)
    {
		if(p & x)
        {
            PORTC &= ~(x);      
            i1 += i0[t1];
        }
        else
        {    
            PORTC |= x;
        }
        x <<= 1;
     }       
     lcd_putstring(0, 0, "       ");
     lcd_putstring(0, lcd_putnumber(0, 0, i1, 2), "uH");
}

void set_cap(int cap)
{
               
    if(cap < 0 ||cap > MAXCAP)
    {
		return;
	}
	
	lcd_putstring(0, lcd_putnumber(0, 7, cap, -1) + 7, "pF");
	wait_ms(500);
	/*	
    lcd_putnumber(0, 0, get_adc(4), -1, -1, 'l', 0);
    lcd_putnumber(0, 8, cap, -1, -1, 'l', 0);
    lcd_putnumber(1, 0, (int) adc0, -1, -1, 'l', 0);	
    */       
    
    while(get_cap() > cap)
    {
		rotate_cap(0);
		lcd_putstring(0, 7, "      ");
        lcd_putstring(0, lcd_putnumber(0, 7, get_cap(), -1) + 7, "pF");
        if(get_keys() == 5 || get_keys() == 6) //Quit if band QSY key is pressed
        {
			return;
		}	
    }
    
    while(get_cap() < cap)
    {
		rotate_cap(1);
		lcd_putstring(0, 7, "      ");
        lcd_putstring(0, lcd_putnumber(0, 7, get_cap(), -1) + 7, "pF");
        if(get_keys() == 5 || get_keys() == 6) //Quit if band QSY key is pressed
        {
			return;
		}	
    }
        
    

}

//Measure real cap val from sensor
int get_cap(void)
{
	double val = (double) (get_adc(4) - 384) * MAXCAP / 256;
	
	return (int) val;
}
	
void rotate_cap(int direction)
{
	if(direction)
	{
		PORTD &= ~(1); //RelayOFF      
	}
	else
	{
	    PORTD |= 1;   //Relay ON	
	}	
	
	PORTD |= 2;   //Motor ON
	wait_ms(CAPDELAY);
	PORTD &= ~(2);  //Motor OFF      
	wait_ms(CAPDELAY);
}	


ISR(TIMER1_OVF_vect)   	   // Timer1 Überlauf
{ 
    runsecs++;
    TCNT1 = 57724;	  
} 

//***************************************************
//                      ADC
//***************************************************

int get_adc(int adcmode)
{
    int adc_val = 0;
	
	
	ADMUX = (ADMUX &~(0x1F)) | (adcmode & 0x1F);     // Kanal adcmode aktivieren PA0=TUNE
    wait_ms(3);
	
    ADCSRA |= (1<<ADSC);
	wait_ms(3);
	
	adc_val = ADCL;
    adc_val += ADCH * 256;   
	
	while(ADCSRA & (1<<ADSC));
	
	return adc_val;
}	

//Read keys via ADC0
int get_keys(void)
{

    int key_value[] = {18, 22, 29, 43, 74, 132};  
       	
    int t1;
    int adcval = get_adc(3);
        
    //TEST display of ADC value 
    /*
    lcd_cls();
    lcd_putnumber(0, 0, get_adc(3), -1, -1, 'l', 0);
    return 0;    	
    */
    
    for(t1 = 0; t1 < 6; t1++)
    {
        if(adcval > key_value[t1] - 2 && adcval < key_value[t1] + 2)
        {
			 return t1 + 1;     
        }
    }
    
    return 0;
}

/***************************************************/
/* Wartezeit in Millisekunden bei fck = 8.000 MHz  */
/***************************************************/
void wait_ms(int ms)
{
  int t1, t2;

  for(t1 = 0; t1 < ms; t1++)
    for(t2 = 0; t2 < 137 * 8; t2++)
      asm volatile ("nop" ::);
}

int main()
{
	int t1;
	int key;     //Keystroke
	int adc_val; //Value of ADC
    int i = 65;  //L
    int band = 0;
    int l1 = 0, c1 = 0;
    
    //Standard values for DK7IH antenna
    //L=      - (128), 8uH(64), 4uH(32), 2uH(16), 1uH(8), 0.5uH(4), 0.25uH(2), 0.125uH(1)
    int std_l [] = {65, 33, 12, 8, 6, 4, 3, 2, 1};
    int std_c [] = {172, 41, 75, 110, 88, 55, 33, 17};
    
    //Meter data
    int s0, s1;
    int s0_old = -1, s1_old = -1;
    int s0off, s1off;
    int loopcnt0 = 0;;
        
    int ok = 0;
    long runsecs2 = 0;
	
	/* Set ports */
    /* OUTPUT */
    DDRB = 0x1F; //Relays 1.55 of cap switching
    DDRC = 0x7F; //Relays for coils             
    DDRD = 0xFF; //LCD data on PD4...PD7
                 //LCD RS:PD2, E:PD3
                 //PD0, PD1: Relay 6 and 7 of cap switches
    
    PORTA = 0x08; //Pullup resistor for keys' input   
    
    //Display
    lcd_init();
	wait_ms(500);
	lcd_cls();
	lcd_putstring(0, 0, " DK7IH Antenna");				
	lcd_putstring(1, 0, " Tuner Ver. 2.0");				
	wait_ms(500);
	lcd_cls();
			
	//Watchdog abschalten
	WDTCR = 0;
	WDTCR = 0;
    	
	//ADC initialisieren
    ADMUX = (1<<REFS0);     // Referenz = AVCC
    ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADEN); //Frequenzvorteiler 64 u. //ADC einschalten
	ADCSRA |= (1<<ADSC); //Eine Wandlung vornehmen
	while (ADCSRA & (1<<ADSC)); //Eine Wandlung abwarten
    adc_val = ADCL;
    adc_val += ADCH * 256;   //Wert auslesen
	adc_val = 0;
	
	//Timer 1
	TCCR1A = 0;                      // normal mode, keine PWM Ausgänge
    TCCR1B = (1<<CS12) + (1<<CS10) ;   // start Timer mit Systemtakt, Prescaler = /1024
	                                    //Auslösung des Overflow alle Sekunde sec.
    TIMSK = (1<<TOIE1);   // overflow aktivieren.
	TCNT1 = 57724;        //Startwert für Sekundentakt

    //Define custom chars for meter
    //define_chars();

    //Load standard data if eeprom cell empty
    for(t1 = 0; t1 < 8; t1++)
    {
		if(eeprom_read_byte((uint8_t*)(t1 * 2)) == 255)
		{ 
			eeprom_write_byte((uint8_t*)(t1 * 2), std_l[t1]);
			eeprom_write_byte((uint8_t*)(t1 * 2 + 1), std_c[t1]);
		}
	}		
				
		
    //Get recent data           		
   	band = eeprom_read_byte((uint8_t*)32);
   	if(band < 0 || band > MAXBANDS)
	{
	    band = 3;
	}
	show_band(band);
	
	l1 = eeprom_read_byte((uint8_t*)(band * 2));
	if(l1 >= 0 && l1 < 128)
	{
		set_coils(l1);
	}
	else
	{
		set_coils(65);
		lcd_line_cls(1);
		lcd_putstring(0, 0, " -x-uH");
		wait_ms(1000);
	}
	c1 = eeprom_read_byte((uint8_t*)(band * 2) + 1);	
	if(c1 >= 0 && c1 < MAXCAP)
	{
		set_cap(c1);
	}
	else
	{
		set_cap(110);
		lcd_line_cls(1);
		lcd_putstring(0, 0, " -x-pF");
		wait_ms(1000);
	}	
    sei();

    show_band(band);
    
    //Calculate 0-offset of swr meter
    s0off = get_adc(0);
    s1off = get_adc(1);
    
    for(;;) 
	{
		key = get_keys();
		if(i > 0 && key == 2)
		{
			i--;
		    set_coils(i);
		    wait_ms(50);
		}    
		
		if(i < 127 && key == 1)
		{
			i++;
		    set_coils(i);
		    wait_ms(50);
		}    
				
		while(get_cap() > 0 && key == 4) //C(-)
		{
			rotate_cap(0);
		    lcd_putstring(0, 7, "      ");
            lcd_putstring(0, lcd_putnumber(0, 7, get_cap(), -1) + 7, "pF");     
            wait_ms(100);
            key = get_keys();
		}    
		
		while(get_cap() < MAXCAP && key == 3) //C(+)
		{
			rotate_cap(1);
		    lcd_putstring(0, 7, "      ");
            lcd_putstring(0, lcd_putnumber(0, 7, get_cap(), -1) + 7, "pF");     
            wait_ms(100);
            key = get_keys();
		}    

        if(band > 0 && key == 6)         //Band (-)
        {
			band--;
		
			while(!eeprom_is_ready());
		    eeprom_write_byte((uint8_t*)32, band);
										
			lcd_putstring(1, 0, "Recalling.");
				
			l1 = eeprom_read_byte((uint8_t*)(band * 2));
			c1 = eeprom_read_byte((uint8_t*)(band * 2 + 1));

	        if(l1 >= 0 && l1 < 128)
	        {
		        set_coils(l1);
		        i = l1;
	        }
	        else
	        {
		        set_coils(65);
		        lcd_putstring(0, 0, " -x-uH");
		    }    
									
														
			if(c1 >= 0 && c1 <= MAXCAP)
			{
			    set_cap(c1);
			}	
			else
			{
				lcd_putstring(0, 7, "-x-pF");
			}	
				
			show_band(band);
			lcd_putstring(1, 0, "             ");
			while(get_keys());
		}
		
        
        if(key == 5) //Band (+)
		{
		    show_band(band);
			lcd_line_cls(1);
			
		    runsecs2 = runsecs;
			ok = 0;
			lcd_putstring(1, 0, "Waiting....");
			while(get_keys() == 5 && !ok)
			{
			    
			    lcd_putnumber(1, 10, 3 - (runsecs - runsecs2), -1);
				if(runsecs - runsecs2 > 2)
				{
				    ok = 1;
				}	
			}	
			
			if(runsecs > runsecs2 + 1) //Key has been pressed for longer than a second, new values for current band to be set
			{                          //Also store values in EEPROM 
			    while(!eeprom_is_ready());
				eeprom_write_byte((uint8_t*)(band * 2), i); 
				
			    while(!eeprom_is_ready());
				eeprom_write_byte((uint8_t*)(band * 2 + 1), get_cap());
				
				while(!eeprom_is_ready());
				eeprom_write_byte((uint8_t*)32, band);
								
	            lcd_line_cls(1);
				lcd_putstring(1, 0, "Stored.");				
				wait_ms(1000);
				lcd_line_cls(1);
			}
            else	
			{
			    if(band < MAXBANDS) //Change band 1 up
				{
				    band++;
				}
                				
				while(!eeprom_is_ready());
				eeprom_write_byte((uint8_t*)32, band);
				
				show_band(band);
				
				lcd_putstring(1, 0, "Recalling.");
				
			    l1 = eeprom_read_byte((uint8_t*)(band * 2));
				c1 = eeprom_read_byte((uint8_t*)(band * 2 + 1));
								
	            if(l1 >= 0 && l1 < 128)
	            {
		            set_coils(l1);
		            i = l1;
	            }
	            else
	            {
		            set_coils(65);
		            lcd_putstring(0, 0, " -x-uH");
		            wait_ms(1000);
		        }    
									
														
			    if(c1 >= 0 && c1 <= MAXCAP)
			    {
			        set_cap(c1);
			    }	
			    else
			    {
				     lcd_putstring(0, 7, "-x-pF");
			    }	
			    lcd_putstring(1, 0, "             ");
			}	
		}
		
		//Meter check
        if(loopcnt0++ > 10)
        { 
            
            s0 = get_adc(0) - s0off;
            s1 = get_adc(1) - s1off;
            
            if(s0 != s0_old)
            {
				if(s0 > 999)
				{
					s0 = 999;
				}	
				lcd_putstring(1, 0, "FWD:    "); 
				lcd_putnumber(1, 4, s0, -1);
				s0_old = s0;
			}
			
			if(s1 != s1_old)
            {
				if(s1 > 999)
				{
					s1 = 999;
				}
				lcd_putstring(1, 8, "REF:     "); 
				lcd_putnumber(1, 12, s1, -1);
				s1_old = s1;
			}	
            
            loopcnt0 = 0;
        }    
        
	}
	return 0;
}


 

The semi-automatic antenna tuner – Version 1b

This article is outdated! Please read about the new version of the antenna tuner here!


People frequently reading my blog know that I love to improve the things presented here. This is revision one of my semi-automatic antenna tuner for QRP. I found that the reading of the SWR value on the LCD is a little bit uncomfortable. So I decided to use an “old-style” analogue meter. This one has been pulled from a home stereo amplifier.

Semi-automatic antenna tuner V2 (C) DK7IH
Semi-automatic antenna tuner V2 (C) DK7IH

The problem with the installed directional coupler is that the amount of energy and so the induced voltage is a reverse function of coupled frequency. Thus an operational amplifier has been added to amplify the DC voltage from the directional coupler. A 50k stereo potentiometer regulates negative feedback an so reduces the op’s gain.

Semi-automatic antenna tuner V2 (C) DK7IH
Semi-automatic antenna tuner V2 (C) DK7IH

Thanks for watching! 73 de Peter

A semi-automatic antenna tuner for QRP use

This article is outdated! Please read about the new version of the antenna tuner here!


After I had finished my 5 band multibander for QRP SSB operation I had 2 choices becoming QRV on the hf bands – either to build up something like an antenna farm (which would have caused severe problems with my familiy 😉 ) or to build a multi band antenna capable of being used on all short wave ham bands. In order to survive the next months with more or less stable health I have decided to take the latter alternative.

Browsing my good old antenna handbook by Rothammel I came across an untuned multiband dipole. This is known sometimes as a “doublet antenna“. It’s a simple dipole, fed by an open wire feed line which has to be matched to the transmitter for each band of operation. The length of one branch of this antenna is about a quarter wavelength of the lowest operating frequency which makes it a half-wave dipole for in my case 80 meters. On the internet I found lots of users of this antenna speaking positively about its performance, so I decided to give it a try. Antenna construction is very simple and the doublet antenna does not spoil the optical impression of your ground property seroiusly.

But one major shortcoming of this antenna should not be ignored: The “doublet” antenna can not be operated directly from coax line, it has to be matched for each band seperately to the desired frequency with its specific impedance to come as close as possible to the 50 ohm of the transceiver. Open wire feed line must be used because there is always a high VSWR on the feedline due to the fact that the dipole is not tuned to the operating frequency. But as losses are low in double wire line even if SWR is high, this is not a problem. Be sure that more than 95% of your transmit power will reach the antenna.

Due to the fact that my antenna installation requires only 5 to 6 meters of feedline from my roof window to the antenna’s feed point, I first built a ladder line from flexible cable and homemade acrylic spacers. But this tended to be a little bit service-unfriendly. Always whenI tried to pull back the antenna for modifications, the line (the spacers to say more detailed)  got entangled in the roofing-tiles. So I bought commercial 450-Ohm Wireman line that does not show this problem.:

Double Zepp (Doublet) antenna - Multiband with tuner and 450 Ohms feed line
Double Zepp (Doublet) antenna – Multiband with tuner and 450 Ohms feed line

After having installed antenna and feedline, I first I built a simple L-match tuner for test purposes. If this antenna had not worked with me I would not have lost much time and money. But no need to worry. After having set up the antenna and the tuner I was quite satisfied. Performance was beyond my expectations. But with using this setup more often, I found out that retuning after having QSYed was not that nice. I had written down the settings for capacitor und inductance on a piece of paper so that they could be recalled relatively quickly. But it was not overwhelming conveniant. Thus my idea was: If you have the settings for each band on a paper table, why not putting them into a microcontroller and let the micro do the tuning?

The basic concept of the tuner

The tuner is an L-Match tuner that can match high Z antennas. Long antennas tend to have higher impedances than usually the 50 ohm transceiver’s output. Integrated into the tuner is also an SWR measurement circuit (directional coupler from old CB radio) so that an external SWR meter is not neccessary. The tuner is tuned manually. After matching has been achieved, the values for L and C are stored by pressing a button and can later be recalled by bandswitch. Retuning is easy. Just press buttons for L+, L-, C+ or C-, retune and store the modified settings. After that: Have fun in a QSO!

Coils

There are 6 coils in the tuner, switched (shortened) by 6 relays. The inductances are doubled (more or less) from one coil to the successor, so that in combination nearly each inductance between 0.5 uH and 39 uH can be switched. It turned out that this concept works fine. The single inductances are:

20uH, 10 uH, 5 uH, 2.5 uH, 1 uh, 0.5 uH

Coil data: Each coil except the smallest one is wound on a T80-2 Amidon toroid. Use 0.3 mm diameter copper enameled wire. The winding data:

  • L1 (20uH):  60T.
  • L2 (10uH): 43T.
  • L3 (5uH):  30T.
  • L4 (2.5uH): 21T.
  • L5 (1uH):  13T.
  • L6 (0.5uH, wound on T50-2 core): 10T.

Output transformer

Another coil must be wound because the antenna has an unbalanced circuit inside (1 coil, 1 cap). The feed line on the other hand is balanced, so this has to be kept in mind. To convert the unbalanced output of the tuner circuit to the balanced feeder line, I use a 1:4 balun at the output of the coil chain (T1 in circuit diagram). Wind 12 turns bifilar of 0.8 mm twisted (about 3 twists per cm) enameled copper wire to a FT114-43 Amidon core using this pattern.

Hint: On the picture below there is a balun transformer that I previously had installed. It was a Guanella balun but it did not perform satisfyingly. Tuning could not easily be achieved on 10 and 15 meters.

Capacitor

The tuner uses a motor driven air dielectrical and butterfly shaped capacitor with max. 220 pF capacity. The advantage of a butterfly type is that it needs only 90° to turn it from minimum to maximum capacity. The motor (a 5V dc version) is connected via a 240:1 gear drive by TAMIYA. The drive has two outlets providing one axle at each side of the drive. To one of the axles I connected the capacitor, the other one connects to a potentiometer to report the current swing angle to the microcontroller.This allows precise feedback of the capacitor’s current position which is essential for setting it to the desired value. The value of this variable resistor does not really matter since it is only a simple voltage divider. Anything between 5k and 100k should fit. Make sure that you use a piece that is easy to turn to minimize friction. To connect the axles I used PVC tubing with an inside diameter of 3 mm.

This is the setup:

Semi automatic antenna tuner for QRP (C) 2016 by Peter Rachow (DK7IH)
Semi automatic antenna tuner for QRP (C) 2016 by Peter Rachow (DK7IH)

Circuit

Here’s the schematic of the tuner:

Semi automatic antenna tuner for QRP (C) 2016 by Peter Rachow (DK7IH)
Semi automatic antenna tuner for QRP (C) 2016 by Peter Rachow (DK7IH)

Right at the 50 Ohms input where the transceiver is connected you can see a 120 kOhm resistor. The purpose of this one is to keep static electricity away from your rig. Antennas with open ends (like the “doublet”) can build up high voltages particularly when strong rainfall coincides with heavy winds. The raindrops build up an electrical potential during their way through the clouds. I once have seen sparks of 1 to 2 cm of length in my shack when I brought the feed line wire of the antenna close to a grounded metal cabinet.

First impression of performance

I have been using the tuner for three weeks by now. My antenna has got a total length of 40 meters, height is from 10 to 12 meters above ground. Feed point is approximately centered. The antenna with this tuner allows operation on all the 5 bands of my QRP multibander. Signal reports are usually good. On 20m I receive 5 and 9 reports very often. Transmit power only is 10 watts. On 40m and 80m the same is true. Even 15 meters, usually not so fine on a 40 meter long doublet, works fine. 10 meters has not been tested yet due to band conditions.

Maximum distance so far was to W2YP (East coast NY) with my rig having 10 watts output on 25th February receiving a 57 report.

Enclosure

I used a simple plastic box that is available for eletrical installations. RF leads are on top:

Semi automatic antenna tuner for QRP (C) 2016 by Peter Rachow (DK7IH)
Semi automatic antenna tuner for QRP (C) 2016 by Peter Rachow (DK7IH)

Software

I’m currently doing some improvements concerning software. If you are interested in the software, please drop me a mail: peter.rachow(at)web.de !

Enhancing the tuner

This tuner mainly for matching long wire antennas which have a comparatively high Z in relation to the 50 Ohms of a radio tranceiver. If you also want to match low Z antennas (shorter than 1/4 wavelength), the capacitor must be put to the opposite of the coils:

tuner-for-hi-or-lo-z

If you would like to have the capacitor in place for switching between hi an low Z antennas another relay will do the job. The microntroller has still plenty of usable ports.

Thanks for reading!

Peter (DK7IH)