Sunday, October 07, 2018

Skylab SKM52 - C&Q 84 - GPS module

Had this Skylab SKM52 GPS module for some time, in the past I tested it but nothing special made with it.

 


 Another ref/name for the module is: C&Q 84


Data-sheet here: http://www.skylab.com.cn/uploadfile/Download/201508011706307884.pdf

Original idea was to use the pps output to discipline another oscillator but no need for the moment.

This is the pps out:



Lat/Lon display:

Time display:

Interesting enough I could never see the $GPZDA (date and time) ever coming out of the module (during debug output) as on the spec data-sheet, this display of data is just taken from the normal output string. ZDA string would give the microseconds.... probably not implemented.

The code made will scroll alternately between the the values of position and time.


Connections and module view:



Vcc   - Arduino 3v3 output
RX    - Arduino D4 (softserial)
TX    - Arduino D3 (softserial)
GND - Arduino GND
PPS out: connect to a LED with a resistor. PPS only outputs when there's a stable GPS signal.
 
Pin 10 on Arduino to a 1k resistor then anode of LED, cathode to ground and this will indicate a GPS fix



Code:

////////////////// code here bellow
 // read the SKM52 Skylabe GPS module (C&Q 84) via softserial and dumps lat/lon/time on the Arduino nano USB
//
//
// pin D3 on Arduino to TX and D4 to RX on the GPS module
// power to module from the 3v3 output on arduino.
//
// CT2GQV 20180922

#include
#include
// initialize the library with the numbers of the interface pins
#define I2C_ADDR    0x27
#define BACKLIGHT_PIN     3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7
LiquidCrystal_I2C       lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

#include
#include

unsigned long fix_age;

SoftwareSerial GPS(3,4);
TinyGPS gps;
void gpsdump(TinyGPS &gps);
bool feedgps();
void getGPS();
long lat, lon;
float LAT, LON;

int fix_detected=0; // no fix yet

int year;
byte month, day, hour, minutes, second, hundredths;

//For the dual display
long previousMillis = 0;
long interval = 3000; // 3 seconds
int a = 60;


void setup(){
  pinMode(10, OUTPUT);
  GPS.begin(9600);
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE); // init the backlight
  lcd.setBacklight(1);        // Backlight on

}

void loop(){
  long lat, lon;
  unsigned long fix_age, time, date, speed, course;
  unsigned long chars;
  unsigned short sentences, failed_checksum;

  gps.get_position(&lat, &lon, &fix_age);
  gps.get_datetime(&date, &time, &fix_age);

  getGPS();
 
  // do we have a fix or not
  if (fix_age == TinyGPS::GPS_INVALID_AGE) {
    Serial.println("No fix detected");fix_detected=0;
    digitalWrite(10, HIGH); delay (1); digitalWrite(10, LOW);
  } else if (fix_age > 5000) {
     Serial.println("Warning: possible stale data!");fix_detected=1;
    digitalWrite(10, HIGH); delay (10); digitalWrite(10, LOW);
   }
  else  fix_detected=2; //Serial.println("Data is current.");
  // lcd.setCursor(0,1); lcd.print("fix: "); lcd.print(fix_detected);

  if (fix_detected==0 ||  fix_detected==1) {lcd.setCursor(0,0); lcd.print("WAITING FIX!!");};

// fix_detected=2; // for debug only to see output even without fix

  if (fix_detected==2) { // let's print gps data
    digitalWrite(10, HIGH); // set the green LED to allways on
 
 
   Serial.print("Lat : ");      Serial.print(LAT);
   Serial.print(" :: Lon : ");  Serial.print(LON);
 
   gps.crack_datetime(&year, &month, &day, &hour, &minutes, &second, &hundredths, &fix_age);
   Serial.print("::"); Serial.print(year);
   Serial.print("-"); Serial.print(month);
   Serial.print("-"); Serial.print(day);
 
   Serial.print("T"); Serial.print(hour);
   Serial.print(":"); Serial.print(minutes);
   Serial.print(":"); Serial.print(second);


   // every interval print the lat
   unsigned long currentMillis = millis();
   if (currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;
    lcd.setCursor(0,0); lcd.print("Lat:"); lcd.print(LAT);
    lcd.setCursor(0,1); lcd.print("Lon:"); lcd.print(LON);
    delay(2000);
   }
 
   lcd.setCursor(0,0); lcd.print("                ");
   lcd.setCursor(0,1); lcd.print("                ");
   lcd.setCursor(0,0); lcd.print(year); lcd.print("-"); lcd.print(month); lcd.print("-"); lcd.print(day);
   lcd.setCursor(0,1); lcd.print(hour); lcd.print(":"); lcd.print(minutes); lcd.print(":"); lcd.print(second);
 
   // no NMEA sentences see where it displays the hundreths...
   // probably needs module programing, says on the manual that outputs the $GPZDA date and time...
   // manual http://www.skylab.com.cn/uploadfile/Download/201508011706307884.pdf
   //  Serial.print("."); Serial.print(hundredths);
   Serial.println();
  }; // endif fix detected
 
 
}

void getGPS(){
  bool newdata = false;
  unsigned long start = millis();
  // Every 1 seconds we print an update
  while (millis() - start < 1000)
  {
    if (feedgps ()){
      newdata = true;
    }
  }
  if (newdata)
  {
    gpsdump(gps);
  }
}

bool feedgps(){
  while (GPS.available())
  {
    if (gps.encode(GPS.read()))
      return true;
  }
  return 0;
}

void gpsdump(TinyGPS &gps)
{
  gps.get_position(&lat, &lon);
  LAT = lat;
  LON = lon;
  {
    feedgps(); // If we don't feed the gps during this long routine, we may drop characters and get checksum errors
  }
}



//////////// Have a nice week!



Saturday, September 15, 2018

New AD8307 power meter

Having done previously two power meter's based on the AD8307, with analog display and with computer interface, decided to build one other unit more self contained and with a ref calibrator included.

Here's the outcome:






The circuit is a simple one:

Taken from here.The AD8307 output is connected to an Arduino analog input and computation is done in software, with output to the LCD and usb line.

Build process here:

 The slug repellent tape is excellent for RF blindage, only need's to have something bellow to give some more rigidity.
It brings the AD8307 noise level to -76dBm.

Board assembly:


The calibrator was based on the one here.

It's not spot on according to the Marconi and R&S but does an approximate job in case the input needs to be validated.

Bellow validating the 0 dBm output of the Marconi power meter:


1.5db down the reference is not bad (possible accounting 0.5 for the cable and plugs thenselfs).

20 dB attenuation of the 0 dBm signal:

..still of by at least 2.1 db down. The attenuator used was measured at 19.7db.


If I need more precision will use the other meter's I have:


For quick check in circuits with risk of blowing something it will be better to use the homemade one, the price different between an AD8307 and the other sensors is in the 20 fold at least.



The other power meter meter's I built before was this one:



from the post here.
The digital voltmeter, on top of the unit, does not display dBm instead the output of the opamp after the AD8307. So the compute dBm needs a table.

And the one inside this VNA




From this post.

The Arduino code used on the new AD8307 power meter is this one:

---
// AD8307 with LCD and serial output
// main code example from here: https://nebula.wsimg.com/62b67d433d922306a59c74c2c4fb0ece?AccessKeyId=DAA432FA80C5DABC0234&disposition=0&alloworigin=1
// some changes made by CT2GQV - 2018
// version 20180915

#include
#include
// initialize the library with the numbers of the interface pins
#define I2C_ADDR    0x3F
#define BACKLIGHT_PIN     3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7
LiquidCrystal_I2C       lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

//pwr sensor stuff
const int sensorpin = A0;

// serial print the voltage at the Arduino A0 / from http://forum.arduino.cc/index.php/topic,44216.0.html#13
void printDouble( double val, byte precision){
 // prints val with number of decimal places determine by precision
 // precision is a number from 0 to 6 indicating the desired decimial places
 // example: printDouble( 3.1415, 2); // prints 3.14 (two decimal places)

 Serial.print (int(val));  //prints the int part
 if( precision > 0) {
   Serial.print("."); // print the decimal point
   unsigned long frac;
   unsigned long mult = 1;
   byte padding = precision -1;
   while(precision--)
      mult *=10;
    
   if(val >= 0)
     frac = (val - int(val)) * mult;
   else
     frac = (int(val)- val ) * mult;
   unsigned long frac1 = frac;
   while( frac1 /= 10 )
     padding--;
   while(  padding--)
     Serial.print("0");
   Serial.print(frac,DEC) ;
 }
}


void setup() {
 Serial.begin(57600); // should be enough
// set up the number of columns and rows on the LCD
lcd.begin(16, 2);
lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE); // init the backlight
lcd.setBacklight(1);        // Backlight on
 analogReference(DEFAULT);
}

void loop() {
 // power in
 int sensorval = analogRead(sensorpin);

 // might need to read or match agains analog ref.
 //float voltage = (sensorval/1024.0) * 5.0;
 float voltage = (sensorval/1023.0) * 5.0;
 
 float pwr = ((voltage-0.269) * 40)-77;
 float volts = ((voltage-0.269) * 40);
 float pwrW = pow(10,((pwr-30)/10));
 float vts = sqrt(pwrW * 50);
 float ptp = vts * 2.828;
delay(200);
 lcd.setCursor(0,0);
 lcd.print("Pwr ");
 lcd.print(pwr, 1);
 lcd.print("dBm   ");

// Serial.print(sensorval); Serial.print(" DAC   ");
printDouble(voltage,3); Serial.print(" Vdc   ");
Serial.print(pwr); Serial.println(" dBm");

 lcd.setCursor(0,1);
if (vts > 0.9)
 {
  lcd.print("rms  ");
  lcd.print(vts, 2); lcd.print("V  ");
  float ptp = vts * 2.828;
  //lcd.print(" p2p ");
  //lcd.print(ptp, 2);
 }
 if (vts < 1 and vts > 0.001)
 {
 vts = vts * 1000;
 lcd.print("rms  ");
 lcd.print (vts, 2);  lcd.print("mV  ");
 float ptp = vts * 2.828;
 //lcd.print(" p2p ");
 //lcd.print(ptp, 2);
 }
 if (vts < .001)
 {
 vts = vts * 1000000;
 lcd.print("rms  ");
 lcd.print(vts, 2); lcd.print("uV  ");
 float ptp = vts * 2.828;
 //lcd.print(" p2p ");
 //lcd.print(ptp, 2);
 }
}


---

That's it, have a great day!


Sunday, August 26, 2018

New RF frequency generator for the shack


Nothing build here, next time!

Before going on holidays I had the idea to get an rf frequency generator of good quality to be used as a reference when testing circuits.
Previous I built one based on an Si5750, also used at times an AD9850 or a quick crystal circuit but nothing permanent and referenced.
Searching online, I found probably one of the cheapest 1Gz frequency generator available  that an ham near my QTH was selling. The looks are not perfect, it had in the past a not so caring previous owner but gives a precision frequency output. Now developed a fault in the output circuit which I suspect probably due to calibration data missing, so I hope. Still it outputs a constant signal but still need to measure to confirm specs.

Here it is:


The knob is not the original one and the bezel around the power button is not in good shape, parts that I probably replace one of this days:

Knob: 0078.1192.00
Spout:0396.0897.00


The fault that it has is error 4 and according to page 11 of SMY Service Manual

Error message "Err. 4"
Level control does not work correctly:

- Level overrange
- AM overrange
- Overrange with AM EXT DC
- 'Level-Preset' calibration faulty

I just hope it was not me making any wrong setting (did it once when selected external reference and was error'ing since nothing connected), in any case will check output and run the calibration details to see if it goes away....

For reference the routine and troubleshooting areas are

Service manual
6.3.3.1 Level Error
A5 Output Unit OPUY01/02
A12 Power Module option SMY-B40
A6 Attenuator ATT01

Page 18 - Level-preset calibration is special function 45.

And some more pictures. By the way the frequency is bang on, only the level, still not measured, looks a bit low when an S9 is generated and connected to an uncalibrated radio in any case.






Have a nice week!








Thursday, June 14, 2018

Park Air Electronics Model 2100 DIP switch settings

Just got an email from a radio enthusiast living in the "small" island East of this one (I'm currently in Ireland just for reference). He was asking for the dip switch settings of the Park Air Electronics 2100 airband receiver since he has a model with similar programing.
I will share here all info I have since I'm pretty sure it will also be useful for me in the future (case I loose the papers).

Inside the receiver you can see the DIP switches for VFO programing:



The documentation I have and that helped me programing it and making a Arduino based controller for it:

Page 1:

Page 2:

Page 3:


..unfortunately the frequency excursion/programing without retuning of the VFO coil is too short (2Mhz) and made the external controller project useless as I documented here. If you follow the blog, I then used the code to control an Si5351 + airband receiver kit here.

Have a nice day Terry!



Wednesday, June 13, 2018

Back to the future - Arduino DCF77 transmitter

Here's the proof:

..that's December first, 2072!


On a serious note, needed to test a DCF77 receiver box that was (and still is) giving some problems to get reception since there was no other way of testing with a "real" strong signal why not making a transmitter for it.

Luckily that's pretty simple and someone already had done it here.

I first tested if was transmitting with my VLF receiver:



...it was

And then with my watch:

which includes a DCF77 receiver to keep time...it updated but antenna wire needs to be close by.
   
The schematic is strait forward, 1K resistor from pin 3 to ground with antenna wire in the middle.



The Arduino code you can get it here. There's also details include on how it works. Keep in mind that you need an Arduino with a quartz crystal for clock, most likely a ceramic will not work.

I just hard-coded the start time but you can change by serial port:


Still the DCF77 receiver box that I wanted to work, doesn't.... that will be another post (and no it's not the antenna wire you see disconnected in the picture)



Have a nice day!

Sunday, June 03, 2018

Teensy 3.6 + Si5351 connection and code

Just another example for the Teensy 3.6 board. This one with the Si5351 clock generator breakout from Adafruit.

Schematic:




There is no need to supply external power if the board (+5V on Vin) is being used with USB, that's enough for the Teensy and Si5351 boards.


Resulting wave:


Code:
//------------------------
/*
  Outputs 1.1 Mhz on CLK2 output of the Adafrui Si5351 board connected to Teensy 3.6
  Just for demo.
  CT2GQV 2018
 */

#include
#include

#define Si_5351_crystal 25000000 // Adafruit breakout board
#define Si_5351_clock  SI5351_CLK2

Si5351 si5351;
long calibration_constant = -8000;

// Pin 13 has an LED connected on most Arduino boards.
// Pin 11 has the LED on Teensy 2.0
// Pin 6  has the LED on Teensy++ 2.0
// Pin 13 has the LED on Teensy 3.0
// give it a name:
int led = 13;

void setup() {               
  // initialize the digital pin as an output for the LED blink
  pinMode(led, OUTPUT);    

si5351.init(SI5351_CRYSTAL_LOAD_10PF, Si_5351_crystal, calibration_constant);
si5351.set_freq(110000000,Si_5351_clock); // 1.1Mhz

 
}

void loop() {
  // just blinks the led while power lasts
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

//------------------------


And that's it,

Have a great week!

Sunday, May 27, 2018

Teensy 3.6 + 2.8" TFT LCD Display SPI Serial 240*320 ILI9341 connection and code

Just doing some experiments with a Teensy 3.6 microcontroller board, a graphical display and some other bits and pieces.
Since it was not easy to find a single source of information with a code example and pin connections, here's a compilation of it:

Schematic:


For testing porpoises the supply is not needed as long as USB power cable is connected to the board.

Bellow the code to run:

/////////////////////////////////
/*
  Just place some text on the ILI9341 display using a Teensy 3.6
  CT2GQV 2018
*/

#include
#include
#include "font_Arial.h"
#include

#define BACKLIGHT_PIN   3
#define TFT_DC          20
#define TFT_CS          21
#define TFT_RST         255  // 255 = unused. connect to 3.3V
#define TFT_MOSI        7
#define TFT_SCLK        14
#define TFT_MISO        12

ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);


// Pin 13 has an LED connected on most Arduino boards.
// Pin 11 has the LED on Teensy 2.0
// Pin 6  has the LED on Teensy++ 2.0
// Pin 13 has the LED on Teensy 3.0 and 3.6 by the way
int led = 13;

void setup() {               
  // for the built in LED.
  pinMode(led, OUTPUT);    
  // for the backlight
  pinMode(BACKLIGHT_PIN, OUTPUT );
  analogWrite(BACKLIGHT_PIN, 128); // 0 to 255

  tft.begin();
  tft.setRotation( 3 );
  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(10, 1);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_ORANGE);
  tft.setFont(Arial_14);
  tft.print("This side UP");
   tft.setCursor(50, 20);
  tft.setTextSize(2);
  tft.setFont(Arial_10);
  tft.print("Arial 10 font");
 
}

// the loop routine runs over and over again forever:
void loop() {
  // it just blinks the led
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

/////////////////////////////////

Code result:



The display back side (top of the display as on previous picture is the sd card side)



The testing board with backside connections:


 Teensy 3.6 pin assignment diagram.



 Have a nice week!