Wednesday, 23 September 2015

Concept Session 4 - ENC LCD

The 4th Concept session covers the prototyping of a VFO with Rotary Encoder tuning and LCD frequency display.

Concept S4 ENC LCD 007

This rotary encoder has 20 steps for each rotation, at each step the signal outputs change as shown, changes depend on the direction the encoder is turned. A library "Rotate.h" sorts out the changes and reports the result.

Concept S4 ENC LCD 008

This is the wiring diagram. The first sketch used is called My_VFO_ROTARY, this displays the VFO frequency on the Monitor as you turn the Encoder. It changes in fixed 100Hz steps - very simple.

// My_VFO_ROTARY controls the freq by rotary encoder, freq display on monitor
// button changes band
// Si5351 I2C bus
// SDA = A4
// SCL = A5
// LCD I2C bus
// SDA = A4
// SCL = A5
// rotary encoder pins
// DT = 2
// CLK = 3
// SW = 4

// I2C, Si5351, LCD and rotary Encoder libraries
#include "Wire.h"
#include "si5351.h"
#include "Rotary.h"

// tuning freq STEPS (cHz), 100Hz
#define STEPS 10000

// rotary Encoder pins 2 & 3 (DT & CLK), band change pin 4 (SW)
#define DT 2
#define CLK 3
#define SW 4

// dds object
Si5351 dds;

// rotary Encoder object
Rotary rot = Rotary(DT, CLK);

// start frequencies (cHz), band names
uint32_t freqStart[3] = {
  710000000, 1014000000, 1410000000
};

// band, freq (cHz)
byte band = 0;
uint32_t freq = freqStart[band];

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

  // init dds si5351 module, "0" = default 25MHz XTAL
  dds.init(SI5351_CRYSTAL_LOAD_8PF, 0);

  // set 8mA output drive
  dds.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);

  // enable VFO output CLK0, disable CLK1 & 2
  dds.output_enable(SI5351_CLK0, 1);
  dds.output_enable(SI5351_CLK1, 0);
  dds.output_enable(SI5351_CLK2, 0);

  // encoder, button, RX, TX, band and XMIT pins
  pinMode(DT, INPUT_PULLUP);
  pinMode(CLK, INPUT_PULLUP);
  pinMode(SW, INPUT_PULLUP);

  freqOut(freq); // output freq
  dispFreq(freq); // display freq
}

void loop() {
  // tune?
  if (tune()) {
    freqOut(freq);
    dispFreq(freq);
  }

  // band?
  if (button()) {
    freq = freqStart[band];
    freqOut(freq);
    dispFreq(freq);
  }
}

// tune?
bool tune() {
  unsigned char dir; // tuning direction CW/CCW

  // turned?
  dir = rot.process(); // read encoder
  if (dir != DIR_NONE) { // turned?
    if (dir == DIR_CW) freq += STEPS; // increment freq +/- STEPS
    if (dir == DIR_CCW) freq -= STEPS;
    return true;
  }
  return false;
}

// band?
bool button() {
  if (digitalRead(SW) == LOW) { // button pressed?
    while (!digitalRead(SW)); // wait for release
    if (band == 2) band = 0; // loop
    else band++;
    return true;
  }
  return false;
}

// frequency (in cHz) for VFO, on CLK0
void freqOut(uint32_t f) {
  dds.set_freq(f, 0ULL, SI5351_CLK0); // converted to cHz
}

// display freq in cHz
void dispFreq(uint32_t f) {
  Serial.print("My VFO = ");
  Serial.print((float)f / 100000, 1); // convert to float for print function
  Serial.println(" kHz");
}


Next we add the LCD display, this connects via an I2C bus connection (note some displays seem to have address 0x0x27 others 0x3F, if one doesn't work try the other).

Concept S4 ENC LCD 014

Wire up your LCD

Concept S4 ENC LCD 016

Concept S4 ENC LCD 019

This is the code for tuning with the encoder

// My_VFO_ROTARY_LCD controls the freq by rotary encoder, freq display on LCD
// button changes band
// Si5351 I2C bus
// SDA = A4
// SCL = A5
// LCD I2C bus
// SDA = A4
// SCL = A5
// rotary encoder pins
// DT = 2
// CLK = 3
// SW = 4

// I2C, Si5351, LCD and rotary Encoder libraries
#include "Wire.h"
#include "si5351.h"
#include "Rotary.h"
#include "LiquidCrystal_I2C.h"

// tuning freq STEPS (cHz), 100Hz
#define STEPS 10000

// rotary Encoder pins 2 & 3 (DT & CLK), band change pin 4 (SW)
#define DT 2
#define CLK 3
#define SW 4

// dds object
Si5351 dds;

// rotary Encoder object
Rotary rot = Rotary(DT, CLK);

// lcd object
LiquidCrystal_I2C lcd(0x27, 16, 2);

// start frequencies (cHz), band names
uint32_t freqStart[3] = {
  710000000, 1014000000, 1410000000};

// band, freq (cHz)
byte band = 0;
uint32_t freq = freqStart[band];

void setup() {
        
  // init LCD & backlight on
  lcd.init();
  lcd.backlight();
  
  // init dds si5351 module, "0" = default 25MHz XTAL
  dds.init(SI5351_CRYSTAL_LOAD_8PF, 0);

  // set 8mA output drive
  dds.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);

  // enable VFO output CLK0, disable CLK1 & 2
  dds.output_enable(SI5351_CLK0, 1);
  dds.output_enable(SI5351_CLK1, 0);
  dds.output_enable(SI5351_CLK2, 0);

  // encoder, button, RX, TX, band and XMIT pins
  pinMode(DT, INPUT_PULLUP);
  pinMode(CLK, INPUT_PULLUP);
  pinMode(SW, INPUT_PULLUP);
  
  freqOut(freq); // output freq
  dispFreq(freq); // display freq
}

void loop() {
  // tune?
  if (tune()) {
    freqOut(freq);
    dispFreq(freq);
  }
  
  // band?
  if (button()) {
    freq = freqStart[band];
    freqOut(freq);
    dispFreq(freq);
  }
}

// tune?
bool tune() {
  unsigned char dir; // tuning direction CW/CCW

  // turned?
  dir = rot.process(); // read encoder
  if (dir != DIR_NONE) { // turned?
    if (dir == DIR_CW) freq += STEPS; // increment freq +/- STEPS
    if (dir == DIR_CCW) freq -= STEPS;
    return true;
  }
  return false;
}

// band?
bool button() {
  if (digitalRead(SW) == LOW) { // button pressed?
    while (!digitalRead(SW)); // wait for release
    if (band == 2) band = 0; // loop
    else band++;
    return true;
  }
  return false;
}

// frequency (in cHz) for VFO, on CLK0
void freqOut(uint32_t f) {
    dds.set_freq(f, 0ULL, SI5351_CLK0); // converted to cHz
}

// display freq in cHz
void dispFreq(uint32_t f) {
  lcd.setCursor(0, 0);
  lcd.print("VFO                 ");
  lcd.setCursor(4, 0);
  lcd.print((float)f / 100000, 1); // convert to float for print function
  lcd.setCursor(13, 0);
  lcd.print("kHz");
}


In a future session we will be building a VFO PCB shield. Some tools are needed for this

Concept S4 ENC LCD 026

1 comment:

NgoprekDiRumahYT said...

Hi Gany, my name is rudik, a ham fellow from Indonesia.

It's been long time i done sucessful replica some of the Si5351A related projects in your blog, and now i am in return to remake it again.
Kindly please provide us the correct Si5351A library used in all your Si5351a related program in this blog, this is simple but really head scratching problems for many who get break up when compiling the sketch.