QRP SSB handheld transceiver for 14 MHz (20 Meter)

On my radiotransmitter-blog I’ve postet an article about my latest project: A compact handheld QRP transceiver for SSB with self-containing battery pack for portable use:

QRP SSB handheld transceiver by Peter Rachow (DK7IH) (C) 2015

QRP SSB handheld transceiver by Peter Rachow (DK7IH) (C) 2015

Read more…

Switching sidebands with the NE612 (Peter Rachow, DK7IH)

In my recent project, the mini QRP SSB transceiver for 20 Meters (14 MHz) I encountered another unexpected problem: accurate sideband switching with the NE 612 as SSB generator can be difficult. Very difficult.

First my circuit looked like this as pointed out in the schematic:

Sideband switching the NE612 (classical version)

Sideband switching the NE612 (classical version)

Two crystals are used, one slightly higher than the passband of your ssb filter, one about 1.5 kcs lower.

When switching I found that the oscillator was not operating correctly and the frequency after the switch was put to the other position was some kcs off the crystal frequency. That time the switch was mounted in the front panel and the leads to the circuit were made of flexible cable with a length of about 8 cm. I speculated that this might come from unwanted capacities or inductances caused by the leads.

To avoid these unwanted influence I experimented with diode and transistor switches. No improvement could be found. Then I mounted a small relay instead the semiconductor switches close to the NE612. Again, no improvement. When analyzing the circuit I found out, that in case I remove the second crystal the remaining one operated perfectly. Oha!

So, I deduced that the internal oscillator was oscillating with two crystals in parallel. A lot of resultless experiments to have both crystals in the circuit but minimizing the influences followed. No cure was in sight.

Later I finally made the decision to use only one crystal. Due to the fact that I wanted to be able to operate on both sidesbands (don’t ask for a reason why! ;-)) I made up my mind to use only one crystal and to pull it to the desired frequency. So it ended up simply with one 9-MHz-crystal, a variable capacitor, a coil and the sideband switch:

Sideband switching the NE612 (successful version)

Sideband switching the NE612 (successful version)

Needless to say that this worked from the scratch. Coil data is simple: 12 turns on a TOKO coil carrier adjustable with ferrite core. The switch is again put into the front panel, no unwanted influences are observable.

Bye for now and 73!

Peter Rachow (DK7IH)

A mini SSB QRP transceiver for 14 MHz (20 meter band) by Peter Rachow (DK7IH) – Pictures

Here are some pictures of my recent project, a very small SSB QRP transceiver (schematics can be found here) that covers the 20 meter band. First let’s have a look to the front panel:

A mini 20-m 14-Mhz SSB Transceiver by Peter Rachow (DK7IH) - Front view

A mini 20-m 14-Mhz SSB Transceiver by Peter Rachow (DK7IH) – Front view

And here we go for an inside view:

A mini 20-m 14-Mhz SSB Transceiver by Peter Rachow (DK7IH) - Inside view

A mini 20-m 14-Mhz SSB Transceiver by Peter Rachow (DK7IH) – Inside view

Starting on the left you can see the AD 9835 DDS chip on the very compact breakout board by artekit.

The breakout board is mounted on a 2 x 8 pin socket row to have the possibility to change the IC ver quickly in case of damage (I set all ICs into sockets without any exception). Above the DDS there is the ATMega 8 micro. Right from the rf-shield made of brass you can see the 9-MHz local oscillator with the ssb modulator and product detector IC NE 612.

For more information on board layout and part distribution have a cursory glance on this commented picture:

A mini 20-m 14-Mhz SSB Transceiver by Peter Rachow (DK7IH) - Inside view with board layout

A mini 20-m 14-Mhz SSB Transceiver by Peter Rachow (DK7IH) – Inside view with board layout

By the way: Had some nice contacts today with stations from all over Europe with 5 watts out. The rig is really fun! 🙂

73 de Peter (DK7IH)

Ooops, I did it again: An ultra-compact QRP SSB monoband transceiver for 14 MHz (20 meter band)

Deutsche Version des Artikels

After having finished my last ssb transceiver project I was to a certain degree dissatisfied with the mechanical size of the rig. Even though it performed very well and I did some nice DX with it (including cracking a pile up for a Jordanian station) I wanted to find out, if I could shrink the mechanical dimensions of the device to another significant degree. A pocket-size transceiver with somewhat around 5 watts PEP output was the goal that I wanted to achieve.

First I searched the web for attractive circuitry. I quickly came across the „Kajman Transceiver“ made by SQ7JHM, OM Jurka (Link to schematic). At the first glance the circuit seemed extraordinary simple. But the problem was: The device has been designed for operation on the 80-meter-band. So some extensions and improvements had to be made to make it perform well on 20.

First, the original recveiver seemed to be a problem. The layout is very simple. Above all, there is no rf preamp. This might be OK for the high noise levels on 80 and the relatively high field strength that signals have got there. But for 14 MHz this performed, as I had expected, very poorly as I could easily find out when breadboarding the receiver strip and having it run with a simple VFO. And, in addition, the receiver did not lack only sensitivity, the noise figure was also very poor.

So there were two possibilities to cure this problem: add an rf preamp to the receivers’s front end (to improve noise figure) and maybe add an if amp stage between the two NE612-mixers to improve overall gain.

After having put a dual-gate mosfet rf preamp stage to the receiver it suddenly opened up its ears. Performence now was great compared to that before the modification had been made. With a simple dipole I could listen to VKs ans ZLs in the morning and to state side (even West Coast) in the evening. Being very satisfied with the outcome of this simple measure and strictly sticking to simplicity of cicuitry and limited space I went away from adding an if amplifier. Maybe I’ll give it a try later.

The transmitter had also been modified after a short intensive thinking. I re-constructed my proven 3 stage design with single-ended preamp and driver and two 2SC1306s in push-pull mode as the final. That should deliver 5 watts easily. And, not to drive your tension too high, it finally did.

As Collpits, Hartley and Co. VFO-times are over, I took another AD9835 DDS chip out of my shelf, grabbed into the microcontroller box and an AT Mega 8 microcontroller found its way into the circuit. To have the TTSOP-16-package of the AD9835 on a veroboard I bought a very compact breakout-board for the AD 9835 made by artekit in Italy. Very neat, very compact, very nice. And cheap.

So, enough the talking, here’s the hard stuff, folks! The circuit (not yet finished, but OK as a preview):

A 20 Meter / 14 MHz monoband compact QRP SSB transceiver by Peter Rachow (DK7IH)

A 20 Meter / 14 MHz monoband compact QRP SSB transceiver by Peter Rachow (DK7IH)

The crucial thing is the arrangement of the 2 NE612-mixers involving 2 relays close to them and the 9-MHz-SSB-filter. The relays reverse the signal way between receiving and transmitting. For this purpose I used small print relays made by Finder company.

That’s all so far, the next days I will put in some photos of this neat little 20-Meter-Band-SSB-Transceiver to give more details to the interested reader.

73 the Peter (DK7IH)

Peter Rachow, DK7IH: A 14 MHz (20 meter) SSB transceiver

Today I’d like to present my new homemade 14-MHZ-SSB-Transceiver to my fellow radio amateurs. Some basic information should be given first before details and circuits are to be discussed:
Frequency range: 14,000 kHz to 14,350 kHz
Transmit power: 15 to 20 Watts max.
Mode: SSB only.

The main units of this transceiver are:

  • SSB-Generator: LM358 operational amplifier as microfone amplifier and MC1496 Gilbert-cell mixer for signal production.
  • TX-Mixer: MC1496
  • Transmitter consisting of 4 stages: 1 preamplifier, 1 predriver, 1 driver, 1 final (push-pull), all equipped with bipolar transistors
  • Receiver: single conversion, interfrequency 9.785 MHz, 1 rf preamplifier (dual gate MOSFET) followd by  mixer (dual gate MOSFET), SSB-filter, if-pre and if-main-amplifier (MC1350), product detector (CA3028A), audio preamp, audio final amp (LM 386)
  • Frequency generation: DDS with ATMega32 driving an AD 9835
  • S-Meter and AGC-circuitry: ATMega8 driving led-chain for S and RF presentation an r2r-network with op for generating agc voltage.

Block diagram:

SSB Transceiver for 14 Mhz (20mtr) by Peter Rachow (DK7IH) - Block diagram

SSB Transceiver for 14 Mhz (20mtr) by Peter Rachow (DK7IH) – Block diagram

Front view:

SSB Transceiver for 14 Mhz (20mtr) by Peter Rachow (DK7IH) - Front view

SSB Transceiver for 14 Mhz (20mtr) by Peter Rachow (DK7IH) – Front view (OK, it’s not 100% QRP… 😉 )

Interior view:

SSB Transceiver for 14 Mhz (20mtr) by Peter Rachow (DK7IH) - Interior view

SSB Transceiver for 14 Mhz (20mtr) by Peter Rachow (DK7IH) – Interior view

To be continued…

(C) 2014 by Peter Rachow, DK7IH

Variabler Frequenzoszillator mit DDS AD9835 (Peter Rachow 2014)

VFO mit DDS-Baustein AD9832
(C) 2014 Peter Rachow
Die folgende Schaltung zeigt, wie ein AD9835 als Frequenzsynthesebaustein von einem ATMega128 angesteuert wird. Das Projekt ist gedacht als Frequenzaufbereitung für einen Amateurfunktransceiver. Die Schaltung liefert ein hochfrequenzstabiles und extrem genaues Ausgangssignal, welches in diesem Falle variabel zwischen 5 und 5.5 MHz liegt.

Projektüberblick

Die Schaltung besteht aus mehreren Funktionsgruppen:

a) Der Frequenzeinstellung,
b) dem Mikrocontroller ATMega128 mit einem LCD-Textdisplay,
c) dem DDS-Baustein AD9835,
d) einem Ausgangsverstärker.

Einzelheiten

a) Die Frequenzeinstellung ist unkonventionell gelöst. Ziel war es, einen Drehregler zu emulieren, wie er an Transceivern Standard ist. Dazu wäre grundsätzlich ein optischer Drehgeber denkbar gewesen, der über den uC abgefragt wird. Ich habe stattdessen foglenden Weg gewählt:

Ein kleiner Gleichstrommotor, wie er in Modellbahnloks oder anderweitig verwendet wird, wird als Generator betrieben. Die Höhe der Spannung, welche er liefert, hängt ab von der Winkelgeschwindigkeit mit der die Achse in Drehung versetzt wird. Die Polarität der Spannung ist zusätzlich abhängig von der Drehrichtung.

Der als Generator „missbrauchte“ Motor liefert sein Signal an einen OP vom Typ LM358. Wird der Motor nicht bewegt, so erzeugt dieser OP eine konstante Spannung von ungefähr 2,5 V. Wird der Motor gedreht steigt oder fällt die Spannung als Funktion von Winkelgeschwindigkeit und Drehrichtung um einen bestimmten Betrag. Sie pendelt dabei zwischen 0 und 5 Volt und lässt sich so über den ADC des ATMega präzise auswerten. Peter Rachow  Diese Daten steuern die Frequenzeinstellung des Controllers und damit des DDS-Bausteins AD9835.

Achtung: Bürstenlose Motoren eignen sich hierfür nicht!

b) Die Beschaltung des ATMega128 mit dem 2 x 16-Zeilen-Display zeigt keine Besonderheiten, so dass hier keine weiteren Ausführungen vonnöten sind.

c) Der AD9835 wird nur im TSSOP-SMD-Package geliefert. Empfehlenswert ist eine Adapterplatine, wenn man in konventioneller Technik mit bedrahteten Komponenten arbeiten will. Die Leitungen insbesondere nach Masse sind kurz zu halten. Die von Peter Rachow aufgebaute Schaltung besitzt ein Ausgangsfilter (Pi-Schaltung), welches unbedingt erforderlich ist, um eine sinusförmige Ausgangsspannung zu erhalten. Der AD9835 kann theoretisch bis ca. 20 MHz betrieben werden, allerdings ist dann die Signalqualität nicht mehr optimal. Der Chip benötigt als Referenz einen Quarzoszillator. Hier sind max. 50 MHz zulässig.

d) Der Ausgangsverstärker liefert ein Signal von ca. 2VSS. Statt des 2SC1975 (in alten CB-Geräten immer mehrfach enthalten) kann jeder andere NPN-Transistor mit einer fT von > 30 MHz verwendet werden.

Die Schaltung:

VFO mit DDS-Chip AD9835 (C) 2014 Peter Rachow

VFO mit DDS-Chip AD9835 (C) 2014 Peter Rachow

Hier ein Beispielcode für den ATMega128 zur direkten Synthese der Frequenz mit dem AD9835. Es werden eigene SPI-Routinen verwendet. Das genaue Timing steht im Datenblatt.

/*****************************************************************/
/*                 DDS mit ATMega 128 und AD 9835                */
/*  ************************************************************ */
/*  Mikrocontroller:  ATMEL AVR ATmega128, 8 MHz                 */
/*                                                               */
/*  Compiler:         GCC (GNU AVR C-Compiler)                   */
/*  Autor:            Peter Rachow                               */
/*  Letzte Aenderung: 01.09.2014                                 */
/*****************************************************************/

#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>

char *appstr = "AVR DDS V15";

unsigned long runseconds = 0;

/*******************/
//       SPI
/*******************/
//Belegung
//FSYNC: PC2 (4)
//SCLK: PC3 (8)
//SDATA: PC4 (16)

void spi_start(void);
void spi_send_bit(int);
void spi_send_byte(unsigned int);
void spi_send_word(unsigned int);
void spi_stop(void);

void set_frequency(unsigned long);

/***************/
/* LCD-Display */
/***************/
//Daten: PD4..PD7
//E: PC0
//RS: PC1

#define LCD_INST 0x00
#define LCD_DATA 0x01

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


int main(void);

//************
//    SPI
//************
void spi_start(void)
{

    //FSYNC lo
    PORTC &= ~(4); // Bit PC2 löschen
      
}

void spi_send_bit(int sbit)
{
    //Bit setzen oder löschen
    if(sbit)
    {
        PORTC |= 16;  //Bit PC4 setzen
    }
    else
    {
        PORTC &= ~(16);  //Bit PC4 löschen
    }

    //SCLK hi
    PORTC |= 8;  //Bit PC3 setzen
       
    //SCLK lo
    PORTC &= ~(8);  //Bit PC3 löschen
   
}

void spi_send_byte(unsigned int sbyte)
{
    int t1, x = 128;
   
    for(t1 = 0; t1 < 8; t1++)
    {
        spi_send_bit(sbyte & x);   
        x /= 2;
    }   
   
    PORTC |= 16;  //SDATA hi

}
// Peter Rachow 
void spi_send_word(unsigned int sbyte)
{
    unsigned int t1, x = 32768;
   
    for(t1 = 0; t1 < 16; t1++)
    {
        spi_send_bit(sbyte & x);   
        x /= 2;
    }   

    PORTC |= 16; //SDATA hi
}


void spi_stop(void)
{
    //FSYNC hi
    PORTC |= 4; // Bit PC2 setzen
   
}


//***************************************
//           TIMER 2
//***************************************
// Timer 2 Ereignisroutine (autom. Aufruf 1/s)
ISR(TIMER0_OVF_vect)
{
    runseconds++;
    TCNT0 = 0;       // Timerregister auf 0
}

/**************************************/
/* Funktionen und Prozeduren fuer LCD */
/**************************************/
//Anschlussbelegeung am uC:
//LCD-Data: PD4..PD7
//E: PC0
//RS: PC1

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

    if(!lcdmode)
        set_rs(0);    /* RS=0 => Befehl */
    else
        set_rs(1);    /* RS=1 => Zeichen */

    _delay_ms(waitcycles * 2);  

    set_e(1);
    PORTD = value & 0xF0;           /* Hi byte */
    set_e(0);
   
    set_e(1);
    PORTD = (value & 0x0F) * 0x10;  /* Lo byte */
    set_e(0);

}

/* E setzen */
void set_e(char status)  /* PORT PC0 = Pin 6 am LCD */
{
    if(status)
    {
        PORTC |= 1;
    }   
    else
    {
        PORTC &= ~(1);
    }   
}


/* RS setzen */
void set_rs(char status) /* PORT PC1 = Pin 4 am LCD */
{
    if(status)
    {
        PORTC |= 2;
    }   
    else
    {
        PORTC &= ~(2);
    }   
}


/* 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, 1);
    lcd_write(LCD_DATA, ch, 1);
}


/* Eine Zeichenkette direkt in das LCD schreiben */
/* Parameter: Startposition, Zeile und Pointer   */
//Peter Rachow 
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, 5);
}


/* Display loeschen (eine Zeile) */
void lcd_linecls(int displine, int chars)
{
    unsigned char t1;

    for(t1 = 0; t1 <= chars; t1++)
        lcd_putchar(displine, t1, 32);
}


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

    lcd_write(LCD_INST, 2, 5);
    lcd_write(LCD_INST, 8, 5);

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

    lcd_cls();

    /* Entrymode !cursoincrease + !displayshifted */
    lcd_write(LCD_INST, 4, 5);
}


/* Eine n-stellige Zahl direkt in das LCD schreiben */
/* Parameter: Startposition und Zeile; Zahl,        */
/* darzustellende Ziffern, Position des Dezimalpunktes, (l)links- oder (r)echtsbuendig */
int lcd_putnumber(int row, int col, long num, int digits, int dec, char orientation, char showplussign)
{
    char cl = col, minusflag = 0;
    unsigned char cdigit[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, digitcnt = 0;
    long t1, t2, n = num, r, x = 1;

    if(num < 0)
    {
        minusflag = 1;
        n *= -1;
    }

    /* Stellenzahl automatisch bestimmen */
    if(digits == -1)
    {
        for(t1 = 1; t1 < 10 && (n / x); t1++)
            x *= 10;
        digits = t1 - 1;
    }

    if(!digits)
        digits = 1;

    for(t1 = digits - 1; t1 >= 0; t1--)
    {
        x = 1;
        for(t2 = 0; t2 < t1; t2++)
            x *= 10;
        r = n / x;
        cdigit[digitcnt++] = r + 48;

        if(t1 == dec)
            cdigit[digitcnt++] = 46;
        n -= r * x;
    }

    digitcnt--;
    t1 = 0;

    /* Ausgabe */
    switch(orientation)
    {
      case 'l': 
        cl = col;
        if(minusflag)
        {
            lcd_putchar(row, cl++, '-');
            digitcnt++;
        }     
        else
        {
            if(showplussign)
            {
                lcd_putchar(row, cl++, '+');
                digitcnt++;
            }
        }   
           

        while(cl <= col + digitcnt)                       /* Linksbuendig */
            lcd_putchar(row, cl++, cdigit[t1++]);

        break;

      case 'r': 
        t1 = digitcnt;                              /* Rechtsbuendig */
        for(cl = col; t1 >= 0; cl--)             
            lcd_putchar(row, cl, cdigit[t1--]);
        if(minusflag)   
            lcd_putchar(row, --cl, '-');
    }

    if(dec == -1)
        return digits;
    else
        return digits + 1;   
}

void set_frequency(unsigned long freq)
{

    double fxtal = 50000;  //fQuarz in Khz
    double fword1;
    unsigned long hiword, loword;
    unsigned char hmsb, lmsb, hlsb, llsb;

    fword1 = freq / fxtal * 0xFFFFFFFF;

    //Aufspalten der 32 Bit in 2 * 16 Bit   
    hiword = (unsigned long) fword1 / 65536;
    loword = (unsigned long) fword1 - hiword * 65536;

    //Aufspalten der 1. 16 Bit in 2 * 8 Bit
    hmsb = hiword / 256;
    lmsb = hiword - hmsb * 256;
   
    //Aufspalten der 2. 16 Bit in 2 * 8 Bit
    hlsb = loword / 256;
    llsb = loword - hlsb * 256;
   
    //Initialisierung, AD9835 in Sleepmode setzen
    spi_start();
    spi_send_word(0xF800);
    spi_stop();
       
    //Senden der 4 * 16 Bit
    spi_start();
    spi_send_word(0x33 * 0x100 + hmsb);
    spi_stop();
       
    spi_start();
    spi_send_word(0x22 * 0x100 + lmsb);
    spi_stop();
       
    spi_start();
    spi_send_word(0x31 * 0x100 + hlsb);
    spi_stop();
       
    spi_start();
    spi_send_word(0x20 * 0x100 + llsb);
    spi_stop();
       
    //Sequenzende AD9835 aus Sleepmode wecken
    spi_start();
    spi_send_word(0xC000);
    spi_stop();
}


int main()
{
    unsigned long runseconds_old = 0;
    unsigned int freq = 5000;
   
    /* Ports einrichten */
    /* OUTPUT */
    DDRC = 0xFF; //LCD (RS und E) an PC0, PC1 / SPI PC2, PC3, PC4
    DDRD = 0xF0; //LCD (Daten) an PD4...PD7
       
    //JTAG abschalten
    MCUCSR |= (1<<JTD);
    MCUCSR |= (1<<JTD);
   
    // Timer 0 fuer Sekundenzaehlung initialisieren, wird getaktet vom 32.768 kHz-Uhrenqurz
    TIMSK &=~((1<<TOIE0)|(1<<OCIE0));     //TC0 Interrupt unterbinden
    ASSR |= (1<<AS0);           //Timer/Counter0 im Asynchronmodus mit Uhrenquarz. 
    TCNT0 = 0x00;
    TCCR0 = 0x05;                //Abgeleitet von f.xtal (CLK / 128) Taktrate
                                 //für f=1/s definieren
    while(ASSR&0x07);            //Warten bis REgister Update durchlaufen hat
    TIMSK |= (1<<TOIE0);        //8-bit Timer/Counter0 Overflow Interrupt einschalten

    sei();
   
    usart_init(51); //9600 Bd    8N1
   
    lcd_init();
    _delay_ms(50);
    lcd_putstring(0, 0, appstr);
   
    runseconds_old = runseconds;
    
    for(;;)
    {
        if(runseconds >= runseconds_old + 3)
        {       
            set_frequency(freq);
            lcd_putnumber(0, 0, freq, -1, -1, 'l', 0);
            lcd_putstring(0, 4, " kHz OK.");
            freq += 100;
            if(freq > 5500)
            {
                freq = 5000;
            }   
            runseconds_old = runseconds;
        }   
    }
   
   
    return 0;
}