Monday, 7 November 2016

BASIC Tech Group - MyNews 3 - RF Meter

Here's the RFMETER. Input impedance is 50R, input attenuator of 20dB, max input power 2W. Two line display of dBm, Watts & Volts

Screen Shot 2016 11 07 at 17 53 10

Input is to Arduino Uno pin A0, AREF analog reference is connected to 3.3V.

Code

// RF-Meter,
// input 50R/2W via a pi 20dB attenuator 82R - 240R - 68R
// displays dBm, Watts, Volts. Autoscaling

#include 
#include 

#define LCDADDR 0x3F
#define LCDCOLS 16
#define LCDROWS 2

// Analog input pin
#define DCIN A0
#define AREF 3.3

// intercept (dBm), slope (mw/dB), input impedance, attenuator (dB).
#define INTERCEPT 84.0
#define SLOPE 25.0
#define IMP 50
#define ATTN -20

LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS);

void setup() {
  lcd.begin();
  lcd.backlight();

  // 3.3V connected to AREF
  analogReference(EXTERNAL);

  lcd.clear();
  lcd.setCursor(4, 0);
  lcd.print("RF METER");
}

void loop() {
  float mV, dBm, mW, V;
  
  // calculations for MV input, dBM, mW, and Volts
  mV = 1000.0 * (float)analogRead(DCIN) * (AREF / 1023);
  dBm = (mV / SLOPE) - INTERCEPT;
  dBm -= ATTN;
  mW = pow(10, (dBm / 10));
  V = sqrt((mW / 1000) * IMP);

  // dBm
  lcd.setCursor(0, 1);
  lcd.print(dBm, 0);
  lcd.print("dBm ");

  // Watts
  if (mW < 1.0) {
    lcd.print(mW * 1000, 0);
    lcd.print("uW ");
  }
  else if (mW < 1000.0) {
    lcd.print(mW, 0);
    lcd.print("mW ");
  }
  else {
    lcd.print(mW / 1000, 1);
    lcd.print("W ");
  }

  // Volts
  if (V < 1.0) {
    lcd.print(V * 1000.0, 0);
    lcd.print("mV  ");
  }
  else {
    lcd.print(V, 1);
    lcd.print("V  ");
  }

  delay(500);
}

float dbmMw(float dbm)
{
  return pow(10, (dbm / 10));
}

Saturday, 29 October 2016

BASIC Tech Group - MyNews 2 - Freq Meter

This project has been abandoned as the accuracy is too low

Natively the Arduino UNO can use its timers to count up to around 6MHz. This can be extended up to a more useful 60MHz by using a divide by ten pre-scaler, for example the CD74HC4017 chip.

Here's the schematic for a FREQ_BASIC shield, it uses a 2 line by 16 column I2C Serial LCD display:

Screen Shot 2016 10 29 at 18 07 27

Code

// FREQ-Basic, v2, Input Pin 5

#include 
#include 
#include 

// this LCD has an address of 3F, some others use 27. 16 columns, 2 rows
#define LCDADDR 0x3F
#define LCDCOLS 16
#define LCDROWS 2

// lcd object
LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS);

// count result, and Arduino crystal correction
unsigned long count;
float freq;
float corr = 0.99852;

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.clear();

  FreqCount.begin(1000);
}

void loop() {
  if (FreqCount.available()) {
    count = FreqCount.read();
    
    lcd.setCursor(3, 0);
    lcd.print("Frequency");
    freq = (float)count * corr / 100000; //
    lcd.setCursor(3, 1);
    lcd.print(freq, 3);
    lcd.print("MHz     ");
  }
}

On test with Arduino Si5351 DDS VFO on the left

IMG 0391

Accuracy is better than +/-500Hz, so not so good for accurate readings or frequency calibration, But OK for a general purpose indicator.

Thursday, 6 October 2016

BASIC Tech Group - MyNews 1 - Concept & Basic

VFO-Basic and DCRX-Basic

Last year we made a DDS in the "Concept" program, this provides us with an Arduino shield for frequency synthesis from 100kHz to 250MHz, SDR IQ outputs and a real time clock.

Screen Shot 2016 10 06 at 10 34 07

New BASIC project

The list of possible boards in the project is:

1. VFO - A 40m Basic VFO along the lines of that needed by the Amateur Radio Intermediate course. Introducing a Colpitts serial tuned oscillator with vari-cap tuning and an output buffer stage.

Screen Shot 2016 10 28 at 11 42 24

Eagle files can be downloaded here Schematic, Board.

Screen Shot 2016 10 28 at 11 42 40

2. DCRX - A 40m Basic Direct Conversion Receiver for CW and SSB, based on the world's simplest circuit using the SA612 mixer and LM386 audio amplifier.

Screen Shot 2016 10 06 at 10 24 21

Screen Shot 2016 10 06 at 10 24 46

Eagle files can be downloaded here Schematic, Board

Combined together the VFO and DCRX it makes a simple receiver for 40m, with manual or Arduino software tuning.

Here are the input filter LTSpice simulations:

Screen Shot 2016 11 13 at 21 02 12

Screen Shot 2016 11 13 at 21 02 18

Combined with the DDS frequency synthesiser board of the previous CONCEPT project, instead of using the VFO, the receiver can be tuned to an accurate frequency in the 7MHz band.

Here is the DDS & DCRX in operation, with WSPR signals being received on 40m, with the RX output fed to a Startech ADC running at 16bit/44.1kHz and fed to the WSPR program running on my iMac.

Screen Shot 2016 11 15 at 15 46 51

Screen Shot 2016 11 15 at 15 47 56

IMG 0460

IMG 0461

3. Future projects which are just ideas today and would be developed by members include:

- RFMETER - An RF measurement meter, measuring -80 to +10dBm. Update see later posting for completed design.

- BRIDGE - An Antenna Analyser, basically a 50 ohm bridge that shows the antenna impedance and SWR. RF input from the VFO or DDS

- QRP_RIG - a complete SDR based QRP TX RX

- WSPR PA - a 2W PA for 40, 30, 20m for a WSPR beacon.

- BPF - a switchable 40, 30 20m BPF board that can be used with the RFMETER and QRP_RIG

... and as many other ideas that members have. As an aside have a look at this web site by PY2OHH for a combine measurement system, similar to a combination of our boards stacked on our Arduino UNO. Could give some inspiration.

Thursday, 18 August 2016

BBC Micro:bit calls CQ CQ...

There is a new module available for the BBC micro:bit in the MicroPython programming language. This is a speech generating module.

The results are crude, unless you very carefully adjust the message content and speech settings. But it works out of the box.

Here is a short program to call CQ for myself, M6KWH.

Code

# Call CQ M6KWH
from microbit import *
import speech

# init pin0 to 0 to define a level and stop "hum"
pin0.write_digital(0)

message = "C Q! C Q! C Q!   M 6 K W H! calling C Q!"
while True:
    # flash arrow W
    display.show(Image.ARROW_W)
    sleep(500)
    display.clear()
    sleep(500)
    
    # if A pressed, say greetings
    if button_a.was_pressed():
        speech.say(message, speed=80)
        sleep(1000)

Wednesday, 17 August 2016

433MHz control of room lighting

The Energenie sockets that are very low cost on Amazon, are controlled by a push button hand-held controller. It outputs codes over a 433.92MHz RF signal, which the sockets receive and respond to.

Each socket has a different code, one for ON and one for OFF.

RX & TX

There are some very low cost 433.92MHz transmitters and receivers on the market (below £2 the pair!). Using the receiver and some Arduino software the codes for your personal sockets can be read from the hand-held controller. Once you know these, a second Arduino program can be used to send these code out using the transmitter, and this will control the sockets.

The software for all this is in a library called "RCSwitch.h" downloadable here. The examples given with this library show how to use it.

Screen Shot 2016 08 17 at 10 41 11

These are the Energenie sockets and their controller. Each socket has to initialised to match a code from the controller, but when this is done the sockets can be controlled from the Arduino and connected transmitter.

Screen Shot 2016 08 17 at 10 51 12

The receiver is on the right and the transmitter to the left. Each has three connections (the OUTput of the receiver is on two connected pins). The receiver is connected to +5V, pin 2 (interrupt 0) and GND when you run the code reading sketch (see RCSwitch Examples). The transmitter is connected to +5V, Arduino pin 10 and GND. The sketch below allows you to type 1/2, 3/4, 5/6 into the Arduino Serial Monitor window and to switch ON or OFF three of the sockets (the code could easily be extended to cover the four sockets, and the ability to switch ON/OFF all the sockets at once. The codes below are for the sockets I bought, you will have to read and substitute your own codes.

Code to read remote codes

// RX_find_code_1
// detects remote RF signals and IDs LOW, HIGH and length
// start program, then push a button on the remote
// reset to re-run the program

// LED pin, RX input pin
 #define LEDPIN 13
 #define RXPIN A0

 //Create an array to store the data
 const int dataSize = 500;
 byte storedData[dataSize];

 // upper and lower thresholds
 const unsigned int upperThreshold = 100;
 const unsigned int lowerThreshold = 80;
 
// maximum length of the signal, length of signal
 int maxSignalLength = 255;
 int dataCounter = 0;

 // start time, end time, read time
 unsigned long startTime = 0;
 unsigned long endTime = 0;
 unsigned long signalDuration = 0;
 
 void setup(){
  Serial.begin(9600);
  pinMode(LEDPIN, OUTPUT);
  
  /* The following code will only run ONCE --------------
  ---Press the reset button on the Arduino to run again-- */
  
  //Wait here until a LOW signal is received
  while(analogRead(RXPIN) < 1) {
      startTime = micros();  //Update start time with every cycle.
  }
  digitalWrite(LEDPIN, HIGH);  //Turn LED ON
  
  //Read and store the rest of the signal into the storedData array
  for(int i = 0; i < dataSize; i = i+2) {
    
    //Identify the length of the LOW signal---------------LOW
    dataCounter = 0; //reset the counter
    while(analogRead(RXPIN) > upperThreshold && dataCounter < maxSignalLength) {
      dataCounter++;
    }
    storedData[i] = dataCounter;
    
    //Identify the length of the HIGH signal---------------HIGH
    dataCounter = 0;//reset the counter
    while(analogRead(RXPIN) < lowerThreshold && dataCounter < maxSignalLength){
      dataCounter++;
    }
    storedData[i+1] = dataCounter;
    
    /* Any readings between the two threshold values will be ignored.
     *
     * The LOW or HIGH signal length must be less than the variable "maxSignalLength"
     * otherwise it will be truncated.
     *
     * All of the HIGH signals and LOW signals combined must not exceed the variable "dataSize"
     * otherwise it will be truncated.
     *
     * The maximum number of signals is 1700 (memory limit)
     * If you try to extend this variable to a higher number than 1700
     * then the Arduino will freeze up and sketch will not work.*/
  }


  //Record the end time of the read period.
  endTime = micros();
  signalDuration = endTime - startTime;

  //Turn LED OFF
  digitalWrite(LEDPIN, LOW);
  
  //Send report to the Serial Monitor
  Serial.println("=====================");
  Serial.print("Read duration: ");
  Serial.print(signalDuration);
  Serial.println(" us");
  Serial.println("=====================");
  Serial.println("LOW, HIGH");
  delay(20);
  for(int i = 0; i < dataSize; i = i+2) {
    Serial.print(storedData[i]);
    Serial.print(", ");
    Serial.println(storedData[i+1]);
    delay(20);
  }
 }

 void loop(){
   //Do nothing here, press reset to re-run the program
 }
Code to transmit the codes

/*
 Example for my own codes, yours may be different
*/
 
#include 
 
// constructor for mySwitch object
RCSwitch mySwitch = RCSwitch();

byte inByte = 0;

void setup() {
 
 Serial.begin(9600);
 
 // Transmitter is connected to Arduino Pin 10
 mySwitch.enableTransmit(10);
 
// Optional set pulse length.
 // mySwitch.setPulseLength(320);
 
 // Optional set protocol (default is 1, will work for most outlets)
 // mySwitch.setProtocol(2);
 
 // Optional set number of transmission repetitions.
  mySwitch.setRepeatTransmit(4);
 
 Serial.println("Ready"); // Ready to receive commands
}
 
void loop() {
 /* Switch using decimal code */
 if(Serial.available() > 0) { // A byte is ready to receive
   inByte = Serial.read();

   if(inByte == '1') { // byte is '1'
     mySwitch.send(14237327, 24);
     Serial.println("1 ON");
   }
   else if(inByte == '2') { // byte is '2'
     mySwitch.send(14237326, 24);
     Serial.println("1 OFF");
   }
   else if(inByte == '3') { // byte is '3'
     mySwitch.send(14237319, 24);
     Serial.println("2 ON");
   }
   else if(inByte == '4') { // byte is '4'
     mySwitch.send(14237318, 24);
     Serial.println("2 OFF");
   }
   else if(inByte == '5') { // byte is '5'
     mySwitch.send(14237323, 24);
     Serial.println("3 ON");
   }
   else if(inByte == '6') { // byte is '6'
     mySwitch.send(14237322, 24);
     Serial.println("3 OFF");
   }
 }
}
My future target is to add a speech recognition board from Audeme to the Arduino UNO and control my lighting by voice!

Thursday, 11 August 2016

Morse Code Trainer

One thing about morse code is you need repetitive training. No better way to learn and improve your reception. So here's a thing - a MicroPython program running on the BBC micro:bbit that generates random morse letters and sounds for you to train by.

IMG 0146

The connections are simple, pin'0' and GND go to an active piezo buzzer.

Code

The code is self explanatory, for those that know Python. It was written in the "Mu" code editor which has been specifically written to support the micro:bit on all platforms.

from microbit import *
import random

# 'constants' for delays all derived from dot length
dotlength = 250
dashlength = dotlength * 3
interelement = dotlength
interletter = dotlength * 2

# images for displaying dots and dashes

dot_img = Image('00000:00000:00900:00000:00000:')
dash_img = Image('00000:00000:09990:00000:00000:')

letter = ("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")

# Dictionary
morse = {
    "A":".-",
    "B":"-...",
    "C":"-.-.",
    "D":"-..",
    "E":".",
    "F":"..-.",
    "G":"--.",
    "H":"....",
    "I":"..",
    "J":".---",
    "K":"-.-",
    "L":".-..",
    "M":"--",
    "N":"-.",
    "O":"---",
    "P":".--.",
    "Q":"--.-",
    "R":".-.",
    "S":"...",
    "T":"-",
    "U":"..-",
    "V":"...-",
    "W":".--",
    "X":"-..-",
    "Y":"-.--",
    "Z":"--.."
}

# function to convert string to pattern of dots and spaces
def EncodeMorse(message):
    m = message.upper()
    enc = ""
    for c in m:
        enc = enc + morse.get(c," ")
        if morse.get(c," ") != " ":
            enc = enc + " "
    return enc
    
# function to flash out a Morse pattern on the matrix
def FlashMorse(pattern):
   for c in pattern:
       if c == ".":
           display.show(dot_img)
           pin0.write_digital(1)
           sleep(dotlength)
           display.clear()
           pin0.write_digital(0)
           sleep(interelement)
       elif c=="-":
           display.show(dash_img)
           pin0.write_digital(1)
           sleep(dashlength)
           display.clear()
           pin0.write_digital(0)
           sleep(interelement)
       elif c==" ":
           sleep(interletter)
   return

# helper function to encode and flash in one go
def MorseCode(message):
    m = EncodeMorse(message)
    print(m)
    FlashMorse(m)
    return

while True:
    message = random.choice(letter)
    MorseCode(message)
    sleep(2000)


    
    

Tuesday, 9 August 2016

Micro:bit Traffic Lights

A simple, but fun, application of the BBC Micro:bit is to build a set of pedestrian traffic lights. You push the button, the lights cycle to red, it goes pip-pip-pip then the lights cycle back to green.

IMG 0143

Pin 0 goes to the active piezo buzzer, pins 13, 14, 15 are the G, Y, R LEDs and the "cross" switch is on pin 16. The LEDs have series 330R resistors (the current must be limited to less than 5mA for the micro:bit), and the switch has a pull up resistor of 10k to 3V.

Code

# Traffic lights
# pins 330R-LED-GND: 13 green, 14 yellow, 15 red, 16 switch(10k pull-up, active LOW)

# import the micropython library
from microbit import *

# set period of pin 0 pwm output
pin0.set_analog_period(400)
pin0.write_analog(0)

while True:
    # green on
    pin13.write_digital(1)
    display.show("G")
    
    # wait for switch
    if pin16.read_digital() != 1:
        
        # green off, yellow on
        pin13.write_digital(0)
        pin14.write_digital(1)
        display.show("Y")
        sleep(2000)
        
        # yellow off, red on, pip-pip-pip
        pin14.write_digital(0)
        pin15.write_digital(1)
        display.show("R")
        pin0.write_analog(200)
        sleep(8000)
        
        # yellow on, red remains on, pip off
        pin14.write_digital(1)
        display.show("Y")
        pin0.write_analog(0)
        sleep(2000)
        
        # red & yellow off
        pin14.write_digital(0)
        pin15.write_digital(0)

# loop
Press the button to cross the road