From Hamsterworks Wiki!

Jump to: navigation, search

This FPGA project was completed in Feb 2016.

One of the 'wacky' project ideas I had was to make a Morse code transmitter.

It is a simple AM transmitter hack, that actually does work.

The idea behind it is quite simple. To generate a 1000kHz carrier, the 100MHz system clock is divided by 100 (flipping a the 'carrier' bit every 50 cycles).

To generate the tone, the system clock is divided by 227,272 (flipping the 'tone' bit every 113,636 cycles)

The amplitude modulation scheme is pretty basic too. When not transmitting the tone two of the PMOD pins has the carrier. When the button is pressed the either one or three of the PMOD pins are then have the carrier, which should either increase or decrease the power transmitted by 50%.


The antenna

For very short range testing I use three 150mm solid core wires, in PMOD JC pins 1, 2, and 3. The effective range for my radio receiver is about 30 cm.

File:Morse antenna short.png

This is pretty poor, but given that the wavelength of 1 MHz signal is 300m, and we are using wires that are a 1/2000th of the wavelength this is expected.

With longer wires the range increases quite a bit.

File:Morse antenna long.png

RF Signal quality

The quality of the signal is very poor - as the output is not a nice clean sine wave, along with the 1 MHz signal there all the odd harmonics (e.g 3 MHz, 5MHz, 7 MHz, ...) and even though they have less power than the primary signal, due to their shorter wavelength they most likely will be more readily transmitted by the antenna. If you have a short wave radio you might be able to listen to them too. With my shortwave radio I am able to receive a clear signal on 29 MHz!

Source files


set_property -dict { PACKAGE_PIN E3    IOSTANDARD LVCMOS33 } [get_ports { clk }];
create_clock -add -name sys_clk_pin -period 10.0 [get_ports {clk}];

set_property -dict { PACKAGE_PIN D9    IOSTANDARD LVCMOS33 } [get_ports { btn0 }];
set_property -dict { PACKAGE_PIN H5    IOSTANDARD LVCMOS33 } [get_ports { led0 }]; 

set_property -dict { PACKAGE_PIN U12   IOSTANDARD LVCMOS33 } [get_ports { to_antenna[0] }];
set_property -dict { PACKAGE_PIN V12   IOSTANDARD LVCMOS33 } [get_ports { to_antenna[1] }];
set_property -dict { PACKAGE_PIN V10   IOSTANDARD LVCMOS33 } [get_ports { to_antenna[2] }];
set_property -dict { PACKAGE_PIN V11   IOSTANDARD LVCMOS33 } [get_ports { to_antenna[3] }]; 


library IEEE;

entity morse is
    Port ( clk        : in  STD_LOGIC;
           btn0       : in  STD_LOGIC;
           led0       : out STD_LOGIC;
           to_antenna : out STD_LOGIC_VECTOR (3 downto 0));
end morse;

architecture Behavioral of morse is
    signal carrier_counter : unsigned( 9 downto 0) := to_unsigned(0,10);
    signal tone_counter    : unsigned(16 downto 0) := to_unsigned(0,17);
    signal carrier         : std_logic := '0';
    signal tone            : std_logic := '0';

        if rising_edge(clK) then
           led0 <= btn0;
           -- Do we output the 50% level, or the modulated levels? 
           if btn0 = '0' then
                to_antenna <= carrier & '0' & carrier & '0';
                if tone = '1' then
                    to_antenna <= carrier & carrier & carrier & '0';
                    to_antenna <= '0' & carrier & '0' & '0';
                end if;
           end if;
           -- Update the counters for the carrier and modulation tone
           if carrier_counter = (100_000_000/2_000_000)-1 then
                carrier_counter <= to_unsigned(0, carrier_counter'length);
                carrier <= not carrier;
                carrier_counter <= carrier_counter + 1;
           end if;

           if tone_counter = 100_000_000/880-1 then
                tone_counter <= to_unsigned(0,tone_counter'length);
                tone <= not tone;
                tone_counter <= tone_counter + 1;
           end if;
        end if;
    end process;

end Behavioral;

Personal tools