Sunday, November 03, 2019

USB temperature measurement with LM35 and Arduino

Just needed a way to output temperate measurement from an LM35 on the serial or USB port.

Nothing fancy here, some code on the Arduino to read an analog input from the sensor and output it on the USB, the usb connection on the Arduino will also take care of powering the circuit.

The output temperature range will be a limited due to max power supply (5v) and of the gain stage (5x) to "increase" resolution of the Arduino ADC and reduce uncertain on the ADC conversion. In practice temperature range will be around 0 to 70 C positive.

Finished, boxed product, just one cable to the sensor and the Arduino inside:



Code running and pooling data to the desktop:

Inside:


Circuit:



Opamp gain stage (5x) for the LM35:


 There's a second opamp in the LM358 that could be used for a second sensor.

Input (10mv per *C, so that is 20.9 *C) and output after opamp:








5.018 gain in practice (1049mv/209mv) and 5.1 in theory. I used a 8.2k and 2K resistors so the gain will be 4.1 + 1

I also created some code to read the values on the desktop using python:

Could be handy for OSD display/overlay on video but mostly will be used for automation measurement.
You can use also any terminal program reading /dev/ttyUSB0 (or other device where the Arduino/circuit is connected):


 By adding the gain stage the fluctuation on the reading is mostly reduced (as image above), much less as when the LM35 output is directly connected to the ADC, could  see around 1 *C or more variance in the initial testing.

[Arduino code]:

 // read temperature from an LM35 sensor
// there is external opapmp with 5x gain to compensate Arduino ADC resolution.
// CT2GQV 2019
// based on code for the LM35 sensor read and adapted to external opapmp
// if no amp on the signal from LM35 then remove lines:   temp_val1 = temp_val1/5;


int lm35_1 = A1;  
int lm35_2 = A2;


void setup() {
  Serial.begin(9600);
}

void loop() {
  int temp_adc_val1;
  int temp_adc_val2;
  float temp_val1;
  float temp_val2;
  temp_adc_val1 = analogRead(lm35_1);    // read sensor 1

// debug
//Serial.print("ADC:"); Serial.print(temp_adc_val1);

  temp_adc_val2 = analogRead(lm35_2);  // read sensor 2
 
  temp_val1 = (temp_adc_val1 * 4.88);    /* Convert adc value to equivalent voltage */
  temp_val1 = temp_val1/5; // we scale the voltage by 5 times with external opamp
  temp_val1 = (temp_val1/10);    /* LM35 gives output of 10mv/°C */


// For second sensor on A2 uncoment the next 4 lines line
//  temp_val2 = (temp_adc_val2 * 4.88);    /* Convert adc value to equivalent voltage */
//  temp_val2 = temp_val2/5;  // scaling by 5 since the opamp will amplify 5x
//  temp_val2 = (temp_val2/10);    /* LM35 gives output of 10mv/°C */
// Serial.print("T2:"); Serial.println(temp_val2);

  Serial.print(temp_val1); Serial.println(" *C");
  delay(1000);
}


[Python code for screen display]:

#!/usr/bin/python
from serial import *
from Tkinter import *
# adaptation from here:
# http://robotic-controls.com/learn/python-guis/tkinter-serial

serialPort = "/dev/ttyUSB0"
baudRate = 9600
ser = Serial(serialPort , baudRate, timeout=0, writeTimeout=0) #ensure non-blocking

#make a TkInter Window
root = Tk()
root.wm_title("- Temperature -")

label = Label(root,text="waiting data...", fg="light green", bg ="dark green", font = "Helvetica 18 bold italic")
label.pack()

serBuffer = ""

def readSerial():
    while True:
        c = ser.read() # attempt to read a character from Serial
       
        #was anything read?
        if len(c) == 0:
            break
       
        # get the buffer from outside of this function
        global serBuffer
       
        # check if character is a delimeter
        if c == '\r':
            c = '' # don't want returns. chuck it
           
        if c == '\n':
            serBuffer += "\n" # add the newline to the buffer

            label.config(text=serBuffer)           

            #add the line to the TOP of the log
#            log.insert('0.0', serBuffer)
            serBuffer = "" # empty the buffer
        else:
            serBuffer += c # add to the buffer
   
    root.after(10, readSerial) # check serial again soon

# after initializing serial, an arduino may need a bit of time to reset
root.after(100, readSerial)

button = Button(root, text=' EXIT ', width=35, command=root.destroy)
button.pack()

root.mainloop()
# end code

--
Have a nice week!

Sunday, October 27, 2019

Si5351 GPS disciplined oscillator with NEO7M module

This marks my 500th post in the blog. Not bad, considering most of the posts are projects, that is a lot of soldering.

Carrying on, I had been experimenting with GPS disciplined oscillators, most using a control loop for a 10Mhz crystal oscillator using 10Khz output from a GPS module PPS. I was not happy with results so decided to go on a different approach.
The NEO7M gps module can output multiple frequencies, the problem is how clean the output is, eventually figure out that a 24Mhz output is enough clean to drive the Si5352 module XO input, this module according to specs can take a crystal of 25 or 27, I tried using external 24Mhz as reference and worked brilliant.


The simplified schematic:


There's also an LED to Arduino pin 10 to indicate satellite lock

Since there are multiple outputs on the Si5351 I used another output (CLK0) for a 1Mhz out besides the 10Mhz one (CLK1).

I didn't used an LCD display on my project to keep consumption as low as possible.

 The 10Mhz output and the GPS antenna input are on the back:
All powered by a 9V battery for portable use.

Inside view:


You need to remove the inboard oscillator crystal from the Si5351 module and connect XA pin to the 24Mhz source from the GPS module.


From datasheet


XB is not used.


The lib's for the Si5351, when programing/compiling the code, need to reflect the new 24Mhz clock input.

Library file:
 Si5351/si5351.h

Change from 25Mhz to 24 as bellow:
 #define SI5351_XTAL_FREQ                                                24000000

The 1Mhz output from the Si5351 is not filtered so plenty of harmonics so it can use as marker.




The final 10Mhz output: is filtered trough a low pass filter to clear some noise and this is the result:



Checking the accuracy of my frequency counter (since I know the GPS is correct):

It's counting 10000000.3 Hz so 0.3 Hz off, for a counter with 20 Year of age  (or so) is not bad.



The code:
It basically programs the u-blox 7m to out a 24Mhz signal on PPS output.
It display all those steps on i2c LCD if connected and just for monitoring
lock LED indication is on when enough satelites are in sync, never the less from the boot it starts output the 24Mhz that might not be stable enough before lock/satelites avaiable but still usable.

// programing of the u-blox 7m module from Arduino for timepulse TP-5
// hex was taken from u-center software configuration view
//
//
// plus, flashing LED connected to pin 10 indicates when enough sat's in view
// u-blox module to connect o 3 and 4 for using soft serial of Arduino
// CT2GQV 2019 mixing multiple libs and examples.

#include
#include
#include "si5351.h"
Si5351 si5351; // i2c 0x60
#include                           
#include  
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7);

const char UBLOX_INIT[] PROGMEM = {   
 
// the actual programing string, uncoment for the one needed. 10Mhz, 2.5Mhz, 24Mhz or 2Mhz
// any frequency not integer divide of 48Mhz will have some jitter since module reference is 48. Best use is for 24 or 2 Mhz

/*
 // CFG-TP5 1Hz / 10Mhz sync
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x96,
  0x98, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x08, 0x00, 0x00, 0x7E, 0xA8,
*/

/*
  // CFG-TP5 1Hz / 10Mhz no sync 50ms cable delay
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x96, 0x98, 0x00,
  0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0xA8, 0x08,
*/
/*
  // CFG-TP5 1Hz / 24 Mhz no sync 0ms cable delay
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6E, 0x01,
  0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6D, 0x8D,
*/

 // CFG-TP5 24MHz / 24 Mhz - allways outputing 24Mhz either in sync with GPS or not. LED on D10 will indicate GPS lock.
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6E, 0x01, 0x00, 0x36,
  0x6E, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x11, 0xD8,

/*
  // CFG-TP5 1Hz / 2.5Mhz no sync 50ms cable delay
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA0, 0x25, 0x26, 0x00,
  0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0xE5, 0x21,
*/

/*
  // CFG-TP5 1Hz / 2 Mhz no sync 50ms cable delay
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x84, 0x1E, 0x00,
  0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x1C, 0x1E,
*/

/* 
  // UBX-CFG-TP5
  0xB5, 0x62, // header
  0x06, 0x31, // time pulse get/set
  0x20,  // lenght 32
  0x00, // tpIdx time pulse selection = 0 = timepulse, 1 = timepulse2  (U1 Char)
  0x00,  // reserved0 U1
  0x01, 0x00, // reserved1 U2
  0x00, 0x32, // antCableDelay ns
  0x00, 0x00, // rf group delay I2
  0x00, 0x90, 0xD0, 0x03, // freqPeriod
  0x00, 0x40, 0x42, 0x0F, // freqPeriodLoc
  0x00, 0xF0, 0x49, 0x02, // pulselenRatio
  0x00, 0x60, 0xAE, 0x0A, // pulselenRatio
  0x00, 0x00, 0x00, 0x00, // userConfigDelay ns
  0x00, 0x77, 0x00, 0x00, // flags - page 135 u-blox 7 Receiver Description Including Protocol Specification V14.pdf
  0x00, 0x48, 0x65,
*/ 

};

int SATLED = 10;  // for showing we have statelites and in sync
int havefix = 0; // to keep track if we have fix for at least 3 seconds
float start_freq = 2000000000;

TinyGPS gps;
// SoftwareSerial ss(4, 3);
SoftwareSerial ss(3, 4);
int sats = 0 ;

void setup()

  lcd.begin(16, 2);                           // LCD set for 16 by 2 display
  lcd.setBacklightPin(3,POSITIVE);            // (BL, BL_POL)
  lcd.setBacklight(HIGH);                     // LCD backlight turned ON
 
  lcd.setCursor(0, 0);                        //
  lcd.print("Booting...");    
  ss.begin(9600);

  pinMode(SATLED, OUTPUT); // to indicate we have enough satelites
  digitalWrite(SATLED, HIGH);
  delay(2000);
  digitalWrite(SATLED, LOW);

   // actual u-blox 7m programing 
   for(int i = 0; i < sizeof(UBLOX_INIT); i++) {                       
    ss.write( pgm_read_byte(UBLOX_INIT+i) );
    delay(5); // simulating a 38400baud pace (or less), otherwise commands are not accepted by the device.
  }
// ends here  
  
  Serial.begin(9600);
  Serial.println("= sent init string to GPS =");
  lcd.setCursor(0, 0); lcd.print("NO DATA   ");
 
   // on the library Si5351/si5351.h chang it to 24Mhz 
   // #define SI5351_XTAL_FREQ                                                25000000
   si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
   si5351.set_freq(10000000, 0, SI5351_CLK1); // 10.000 Mhz for the ext 10Mhz of counter
   si5351.set_freq( 1000000, 0, SI5351_CLK0); //  1.000 Mhz for the marker

}

void loop()
{
  bool newData = false;
  unsigned long chars;
  unsigned short sentences, failed;

  // For one second we parse GPS data and report some key values
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (ss.available())
    {
      char c = ss.read();
      Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }
  }

  if (newData)
  {
    float flat, flon;
    unsigned long age;
    gps.f_get_position(&flat, &flon, &age);
    Serial.print("LAT=");
    Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
    Serial.print(" LON=");
    Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
    Serial.print(" SAT=");
    sats = gps.satellites();
    Serial.println(sats);
    // lcd.setCursor(0, 0); lcd.print("Satelites:");lcd.print(sats);
   
    if (sats >= 3){ // we have sats in view, we should be good
      digitalWrite(SATLED, HIGH); // delay(200);digitalWrite(SATLED, LOW );
      havefix=2;
      havefix++; // increments every time we have fix until 3, if we don't have fix/sats then after 3 cycles it will go zero and we shutt the indicator led.
      if (havefix >= 3)havefix=3; // never goes over 3
      Serial.println(); Serial.print("SAT_HAVE_FIX: "); Serial.println(havefix); 
    };   
  } // end new data
 
  if (havefix >= 1) havefix--; // we had allready 1 fix in the loop
  if (havefix==0) { digitalWrite(SATLED, LOW ); }; // we don't have fix so power off the fix LED 
  Serial.print("MAIN_HAVE_FIX: "); Serial.println(havefix);
 
  gps.stats(&chars, &sentences, &failed);
  if (chars == 0)
    Serial.println("** No characters received from GPS: check wiring **");

}

//=end code==============

I've seen other type of approach for similar problem using just a 1 Hz PPS and then integrating and correcting in software the "error" from one of the clock outputs of the Si5351, this is also a valid approach if your GPS module can only do 1Hz PPS out, like on this ARRL article:
 http://www.arrl.org/files/file/QEX_Next_Issue/2015/Jul-Aug_2015/Marcus.pdf


Have a nice day!



Sunday, July 28, 2019

Programing TP5 (time pulse) on the Ublox NEO-7M via Arduino

I needed to program the time pulse (TP-5) output on a Ublox NEO-7M GPS module, that is strait forward with the U-center software (connect serial and power betwen PC and GPS module), only problem is that software only runs on Windows and I'm more a Linux user.

The module can also be programed via the Arduino or any device with a serial port as long as you know the u-blox programing specification/protocol.
For the correct command to be sent you can either read the u-blox programing/documentation manual and calculate/generate the string plus the crc or you deploy U-center software on Windows, take the hex output for your needed output and program that on Arduino.

I started to read the specs and try to recreate the command but half way trough it just decided to boot a Windows and deploy U-center and then get the needed outputs, example here:

The two Hex lines are is in the bottom right.

Most of the details on how to accomplish this here were taken from a nice tutorial from "iforce2d" channel at:

 https://www.youtube.com/watch?v=ylxwOg2pXrc

Have a go there, it's very well explained from someone who really knows what is doing.... not my case :)

The output of some of the frequencies tested with the module directly at the "PPS" output pin (not the internal blinking LED).

 2Mhz
 2.5Mhz, all the ones that are not integer division of 48Mhz appear with some jitter.
 24Mhz is not the most square, also due to probes.
The module used is one like the above.
Vcc is 5v, txd and rxd to Arduino softserial 3,4 and PPS is the output.

In the code are 2Mhz, 2.5Mhz, 10Mhz and 24Mhz output examples, all with 1Hz timepulse if not enough satelites to provide a precise frequency are avaiable.
If other frequencies are needed I suggest installing U-center and then generate the needed Hex code and insert it on the code bellow.

The code also includes one output for I2C LCD, serial and LED to indicate status, it can be removed, if you just need to program the module. I added it as part of some experiemtes, don't expect to be perfect was mostly for troubleshooting some GPS modules I have.

Arduino code bellow:
/////////////////////
// programing of the u-blox 7m module from Arduino for timepulse TP-5
// hex was taken from u-center software configuration view
//
//
// plus, flashing LED connected to pin 10 indicates when enough sat's in view
// u-blox module to connect o 3 and 4 for using soft serial of Arduino
// CT2GQV 2019 mixing multiple libs and examples.

#include
#include
#include                           
#include  
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7);

const char UBLOX_INIT[] PROGMEM = { 
 
// the actual programing string, uncoment for the one needed. 10Mhz, 2.5Mhz, 24Mhz or 2Mhz
// any frequency not integer divide of 48Mhz will have some jitter since module reference is 48. Best use is for 24 or 2 Mhz

/*
 // CFG-TP5 1Hz / 10Mhz sync
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x96,
  0x98, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x08, 0x00, 0x00, 0x7E, 0xA8,
*/

/*
  // CFG-TP5 1Hz / 10Mhz no sync 50ms cable delay
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x96, 0x98, 0x00,
  0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0xA8, 0x08,
*/

/*
  // CFG-TP5 1Hz / 24 Mhz no sync 0ms cable delay
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6E, 0x01,
  0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6D, 0x8D,
*/

/*
  // CFG-TP5 1Hz / 2.5Mhz no sync 50ms cable delay
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA0, 0x25, 0x26, 0x00,
  0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0xE5, 0x21,
*/

  // CFG-TP5 1Hz / 2 Mhz no sync 50ms cable delay
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x84, 0x1E, 0x00,
  0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x1C, 0x1E,


/* 
  // UBX-CFG-TP5 parameters (not fully complete)
  0xB5, 0x62, // header
  0x06, 0x31, // time pulse get/set
  0x20,  // lenght 32
  0x00, // tpIdx time pulse selection = 0 = timepulse, 1 = timepulse2  (U1 Char)
  0x00,  // reserved0 U1
  0x01, 0x00, // reserved1 U2
  0x00, 0x32, // antCableDelay ns
  0x00, 0x00, // rf group delay I2
  0x00, 0x90, 0xD0, 0x03, // freqPeriod
  0x00, 0x40, 0x42, 0x0F, // freqPeriodLoc
  0x00, 0xF0, 0x49, 0x02, // pulselenRatio
  0x00, 0x60, 0xAE, 0x0A, // pulselenRatio
  0x00, 0x00, 0x00, 0x00, // userConfigDelay ns
  0x00, 0x77, 0x00, 0x00, // flags - page 135 u-blox 7 Receiver Description Including Protocol Specification V14.pdf
  0x00, 0x48, 0x65,
*/ 

};

int SATLED = 10;  // for showing we have satelites

TinyGPS gps;
// SoftwareSerial ss(4, 3);
SoftwareSerial ss(3, 4);
int sats = 0 ;

void setup()

  lcd.begin(16, 2);                           // LCD set for 16 by 2 display
  lcd.setBacklightPin(3,POSITIVE);            // (BL, BL_POL)
  lcd.setBacklight(HIGH);                     // LCD backlight turned ON
 
  lcd.setCursor(0, 0);                        //
  lcd.print("Booting...");    
  ss.begin(9600);

  pinMode(SATLED, OUTPUT); // to indicate we have enough satelites
  digitalWrite(SATLED, HIGH);
  delay(2000);
  digitalWrite(SATLED, LOW);

// actual u-blox 7m programing 
   for(int i = 0; i < sizeof(UBLOX_INIT); i++) {                       
    ss.write( pgm_read_byte(UBLOX_INIT+i) );
    delay(5); // simulating a 38400baud pace (or less), otherwise commands are not accepted by the device.
  }
// ends here  
  
  Serial.begin(9600);
  Serial.println("= sent init string to GPS =");
  lcd.setCursor(0, 0); lcd.print("NO DATA   ");
}

void loop()
{
  bool newData = false;
  unsigned long chars;
  unsigned short sentences, failed;

  // For one second we parse GPS data and report some key values
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (ss.available())
    {
      char c = ss.read();
      Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }
  }

  if (newData)
  {
    float flat, flon;
    unsigned long age;
    gps.f_get_position(&flat, &flon, &age);
    Serial.print("LAT=");
    Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
    Serial.print(" LON=");
    Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
    Serial.print(" SAT=");
    Serial.print(gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites());
    sats = gps.satellites();
    lcd.setCursor(0, 0); lcd.print("Satelites:");lcd.print(sats);
    if (sats >= 3){digitalWrite(SATLED, HIGH); delay(20);digitalWrite(SATLED, LOW );};
    //if (sats < 3 ){digitalWrite(SATLED, LOW );};
    Serial.print(" PREC=");
    Serial.print(gps.hdop() == TinyGPS::GPS_INVALID_HDOP ? 0 : gps.hdop());
  }
 
  gps.stats(&chars, &sentences, &failed);
 if (chars == 0)
    Serial.println("** No characters received from GPS: check wiring **");
}


////////////////////
..code ended.

Have a nice week!

Sunday, June 23, 2019

Simple 10Ghz frequency counter #2

After previous post on the simple 10Ghz frequency counter # 1, here's another option that will be cheaper than buying a full featured 10 Ghz range frequency counter. Again, different functionalities, this way shown it's just to provide an alternative since Ghz range frequency counters are normally very expensive.
This method involves using an old wave-meter.
Now a days you can find some wave-meters ate reasonable prices, in the range of less than 60Eur like this one from HP that I got recently:


It covers roughly 8 to 12Ghz, it's an HP X532B. Diferent models have different ranges, I wanted 10Ghz so this is the appropriate one.
The wave-meter by it self is not enough to measure a frequency, you will need waveguide transition from coax and a waveguide detector. You can build these two components quit echeaply and they will still work, not lab grade but enough for amateur use.


Bellow the ones I build using copper pcb, not an optimal material but will do:
The waveguide detector part:

Most critical measurement is the distance from the diode to the reflection plate on the back (opposite to the front facing side), what I did was measure 1/4 wave from the end and then adjusted the backplate to biggest signal.

View from the back still not covered:
For the flange mount and bolts placement I just used the template of the wave-meter it self but dimensions are pretty much standard.

For the coax to waveguide transition, same method:

 Signal entrance view:




The antenna can be DC connected to ground or open, I preferred the open option in case I need to provide dc over coax.
Basically I used the pin of the sma connector plus a bit of wire to make the correct wavelength
Again, this is not a calibrated devices but on the overall usage it does not make a difference, as long as we can place a signal at the entrance of the wave meter and detect it on the output we are good to measure frequencies.
The only possible downside is if the waveguide transition block loads the circuit we are trying to measure shifting it's frequency, anyhow the actual frequency after load will be measured. 


I used a Russian D405B microwave mixer as detector since was a cheaper alternative (around 1Eur each plus shipping) to 1N23C and 1N21 that are commonly used in this type of application. The diode arrives in lead sealed container, nice touch, no microwaves will "touch" the diode until is unwrapped.



Bellow a test of the diode with a microamp meter


 At this point if you want to see if your diode works, just cook something on the microwave and while it's running place the diode near the door, should see some deflection on a microamp-meter, you can also use a DMM on milivolt scale.



Dimensions are only critical if you need max optimization.

Now on to measurement:
Keep in mind that this method is not as simple as connecting cable to a regular frequency counter and check the result, you need to observe the output value of the detector and look for very small dips on the output, you need to go really slow in order to find it since it's very sharp and small, it's good if you know the ballpark frequency, otherwise it can be very boring rotating the wavemeter knob back and forth until found since the know is quite de-multiplied.

Same values I measure:

 The dip value above
 The frequency on the dial
and the "normal" value at the signal output.

Bellow the test setup:
 I used my home-brew signal generator for testing and validation

Another view from the top knob:




I build recently a millivoltmeter where I added a blinking led if measured value had over 10% change in the average result so I could rotate the knob faster and just look a the led blink to find the dip. That made my life easier when checking for the dip.

It's the led marked "VAR" in the image bellow

 I will post in the future more information on this millivoltmeter.

Meanwhile, have a nice day.











 

Thursday, June 13, 2019

Simple 10Ghz frequency counter #1

After previous post on the 10Ghz generator we need to measure it.

The following method is probably the cheapest you could find for 10 Ghz measure, still not dirty cheap but considering the price of a real counter on a much lower magnitude order.

This is nothing more than an LNB for satellite TV feeding a UHF frequency counter module.

Circuit:

You inject 12V onto the LNB, DC block it and feed the counter input.

The LNB:

The counter:

...mine is a VFD display module placed in a box with additional crystal testing circuit you have also LED versions (search for PLJ-8LED-H RF Signal Frequency Counter).

To calculate your signal input frequency just sum 9.75Ghz

Keep in mind that this will give you an approx frequency since on most of the LNB's the 9.75 Ghz LO is far from precise. The ones with PLL are a bit more stable.
Anyhow it will let you know if you are in the ball part.


The oscillator feeding the signal was the one from previous post placed in front of the LNB with a piece of wire as antenna:


Total cost will be around 10Eur for the counter plus 15Eur for the LNB and additional components, compare that even for a second hand HP or EIP... ok compare just the price...


Have fun




Monday, June 10, 2019

Simple 10Ghz oscillator with FVC99 hybrid VCO

I wanted to test 10Ghz band, more like a challenge than for any practical application, so started some experiments.

One of the first builds was an oscillator, it's a simple module out of the shelf with just a companion pot for tunning.

The module is an FVC99 hybrid VCO and more data available here:
It's major advantage is price, something less than 10Eur. Cheaper that any other sort of VCO (except probably the cheap motion detector modules that I will show in the future).

Mine is covering 9.5GHz to 10.326 Ghz


I am lucky to have a Ghz capable frequency counter, in a future post will show how to measure in some other ways (cheaper).

Without any care on the output connection it measured -15dBm to -4 on the full frequency range.

Schematic:
So nothing more than power to the module and a pot doing resitive divider connected to the tune terminal of the same module (VT). It's 5V on the picture but I used a 6V regulator.

Keep in mind that i mistakenly connect the 78X regulator on opposite direction.. in case you follow the wiring on the picture....still thinking how I manage to do that the first time...guess i'm getting old.

 ...frequency calibration is more in the "around here" mark than any precision device. Enough for playing around.

These electrical installation boxes/housings are perfect for this type of assembly. just add a piece of pcb.

Have a nice day!






Sunday, June 09, 2019

AC panel voltmeter convertion to DC

Well, this is the first post of 2019.




Since the start of the blog the idea was always to document some of my projects and also as a means that others can be motivated to build something.
This would e a win win situation, the more people building the more need for components so the more shops would keep open since lately the tendency is for hobby electronics to decline. Also I would keep information on my project that could be handy when I have to fix them since I'm not good on taking notes.

Said that, here's a small conversion of a 250V AC panel voltmeter to 25V DC.
The schematic is nothing more than a series diode (using one of the existing from the original PCB) with a resistor and a variable trimmer in series with moving coil meter. The original schematic (for AC) is seen on the background.
Calibration was just using a 9V battery and setting the trimer to read 9V, (90V AC on the original scale). Not critical here since I just wanted a means of checking if one of my DC power supplies was outputting the selected voltage.









Have a great one!