Since 08.08.2014 Counts only, if "DNT = disabled".
Your IP is 54.242.75.224 ec2-54-242-75-224.compute-1.
Info
เราจะทำแบบวิศวกรผู้ยิ่งใหญ่
19. March 2024
Your valuable opinion :
March 2024 Tea Time :-)
Si570.php 42580 Bytes 31-05-2023 10:28:02
The Si-570 (SiLabs) • Micromod RF Synthesizer
A 19.9 - 199.999 MHz (CMOS) I2C programmeable XO : ไมโครมด
The Si570 on the Shield, CMOS version (only pin 4, CLK+, in use)
✈ Motivation • Circuit Description
This integrated circuit is widespread and does it's
job in various DIY Applications. Still on the search for "the perfect oscillator" we decided to give this
candidate a try - and see by ourselves, what this device is capeable of. In order to have a universal circuit, we also
packed a lowpass, a 0-50 dB attenuator, a connection for an lcd as well as for a rotary encoder on the Arduino/Genuino (UNO) shaped board.
The sketch does not care if the "new" frequency is within this ±3500 ppm range. We used the NOKIA 5110 display
in order to see how it works. Don't forget to solder the bridge on the adapter board. The contrast may be set in software or by
the potentiometer on the shield. We used the one from Adafruit. But not
the library they offer. If you have the file font.h in the same directory as the arduino sketch, it will show up as another
tab in your development environment.
✈ Si570 - What's inside ?
SiLabs says : "The Si570 XO/Si571 VCXO utilizes Silicon Laboratories’ advanced DSPLL®
circuitry to provide a low-jitter clock at any frequency." - Great one mayst think, but the Si570 comes in several variants.
And all have a different "low-jitter" value. At this time, only the cmos version was available.
✈ Si570 - The Spectrum
The Spectrum of the Si-570 looks very nice. This is - of course - due to the large divider at the output. Our device obviously
outputs 100 MHz (initial settings).
✈ This calibration thing
The vco is locked to an internal crystal oscillator with a nominal frequency of 114.285 MHz and a maximum error of ±2000 ppm.
This is ±0.002 * 114.285 = ±228.570 kHz. A calibration process therefore measures the output frequency while reading
all divider values (Reg 07 - 12) and calculates the "real" crystal frequency. Our Arduino/Genuino sketch reads those values
and displays them on startup. You mayst note those values and feed them into the javascript below. The "real" crystal frequency
is then calculated and shown for future use in the sketch. This is particularly appropriate when you do it after the warm-up sequence.
✈ Arduino Sketch - The Code
Double click on code to select ...
/* //////////////////////////////////////////////////////////////////
ARDUINO/Genuino (UNO) Si570 Evaluation Board - "Micromod Synthesizer"
https://www.changpuak.ch/electronics/Si570.php
Software Version 2.0, USES TIMER INTERRUPT
29.09.2016 by JOËL STEINEMANN AND ALEXANDER FRANK
HELPFUL WEBSITES/LINKS:
http://playground.arduino.cc/Main/PinChangeInterrupt
http://gammon.com.au/interrupts
https://www.youtube.com/watch?v=cwsCxUhHbQM
http://hastebin.com/cufoxazoxo.coffee
Si570 PROGRAMMING HELP:
http://cbjohn.com/aa0zz/PPLL/Article.pdf
DATA SHEETS:
https://www.silabs.com/Support%20Documents/TechnicalDocs/si570.pdf
https://cdn.macom.com/datasheets/MAAD-007086.pdf
////////////////////////////////////////////////////////////////// */
// LCD PINS (NOKIA5110)
#define RST 13
#define CE 12
#define DC 9
#define DIN 11
#define CLK 10
char string[8];
#include <EEPROM.h>
#include <Wire.h>
#include <stdlib.h>
#include "font.h";
#include "TimerOne.h"
// /////////////////////////////////////////////////////////////
// CONSTANTS FOR THE Si570
const int Si570ADDRESS = 0x55 ;
const float MaxFreq = 199.999 ;
const float MinFreq = 19.999 ;
const float Crystal = 114.285046732392 ;
const float MaxVCO = 5670.0 ;
const float MinVCO = 4850.0 ;
float Frequency = 99.999 ;
// ARRAYS FOR THE LOOKUP TABLE
float VCO_Freq[7] = {125,140,155,170,202,236};
unsigned int HSDIV[7] = {11,5,9,4,7,4};
unsigned int HS[13] = {0,0,0,0,0,1,0,3,0,5,0,7};
unsigned int N1[7] = {4,8,4,8,4,6};
unsigned int Block ;
// VARIABLES FOR PROGRAMMING THE Si570
float RFREQ;
unsigned int RF_DIVIDER_INTEGER ;
long RF_DIVIDER_FRACTIONAL ;
unsigned int HS_DIVIDER;
unsigned int N_DIVIDER;
float FR;
// Si570 REGISTER VARIABLES
byte SiR7,SiR8,SiR9,SiR10,SiR11,SiR12;
byte R7,R8,R9,R10,R11,R12;
// /////////////////////////////////////////////////////////////
//VARIABLES AND PIN DEFINITION FOR THE ATTENUATOR
const float LevelMin = -35 ;
const float LevelMax = 15 ;
int Level = 15 ;
const int ATT32 = 2;
const int ATT16 = 3;
const int ATT08 = 4;
const int ATT04 = 5;
const int ATT02 = 6;
const int ATT01 = 7;
// /////////////////////////////////////////////////////////////
unsigned int CursorPosition = 2;
unsigned int CursorOFFtime = 0;
unsigned int AuxKnobEval = 0x00;
float EncoderValue;
boolean EncoderState;
unsigned long currentmillis;
unsigned long LcdMillis;
unsigned long lastchange;
boolean laststate = true;
boolean LcdState = true;
int x=12,y=2;
boolean Frequency_Level = true;
float Max, Min, Addition = 1,maxNr,minNr;
// /////////////////////////////////////////////////////////////
// INTERRUPT VARIABLES
volatile unsigned int RotaryEncoderStatus = 0;
volatile unsigned int RotaryEncoderStatusOld = 0;
volatile unsigned int RotaryEncoderActivity = 1 ;
// /////////////////////////////////////////////////////////////
// serial data input
char inputcmd[100];
int cmdindex=0;
// /////////////////////////////////////////////////////////////
void LcdWriteString(char *characters)
{
while(*characters) LcdWriteCharacter(*characters++);
}
void LcdWriteData(byte data)
{
digitalWrite(DC, HIGH);
digitalWrite(CE, LOW);
shiftOut(DIN, CLK, MSBFIRST, data);
digitalWrite(CE, HIGH);
}
void LcdWriteCmd(byte cmd)
{
digitalWrite(DC, LOW);
digitalWrite(CE, LOW);
shiftOut(DIN, CLK, MSBFIRST, cmd);
digitalWrite(CE, HIGH);
}
void LcdWriteCharacter(byte character)
{
for(int i=0; i<5; i++) LcdWriteData(ASCII[character - 0x20][i]);
LcdWriteData(0x00); // 1 pixel distance
}
void LcdDisplay(byte data)
{
byte UpperNibble = (data & 0xF0) >> 4 ;
byte LowerNibble = data & 0x0F ;
if (UpperNibble < 0x0A) LcdWriteCharacter(UpperNibble + 0x30);
if (UpperNibble >= 0x0A) LcdWriteCharacter(UpperNibble + 0x41 - 0x0A);
if (LowerNibble < 0x0A) LcdWriteCharacter(LowerNibble + 0x30);
if (LowerNibble >= 0x0A) LcdWriteCharacter(LowerNibble + 0x41 - 0x0A);
}
void LcdClearScreen()
{
for (int i=0; i<504; i++) LcdWriteData(0x00) ;
}
void LcdGoToXY(int x, int y)
{
LcdWriteCmd(0x80 | x); // COL
LcdWriteCmd(0x40 | y); // ROW
}
void LcdBlink(int x, int y)
{
if(RotaryEncoderActivity == 0x00) // Encoder pressed or rotated
{
if(millis() - LcdMillis >= 1000)
{
LcdMillis = millis();
if(LcdState)
{
LcdState = !LcdState;
LcdGoToXY(x,y);
LcdWriteString(" ");
}
else
{
if(Frequency_Level) UpDateFreqLCD();
else UpDateLevelLCD();
LcdState = !LcdState;
}
}
}
}
void UpDateFreqLCD() {
LcdGoToXY(0,0);
LcdWriteString("FREQUENCY");
LcdGoToXY(0,2);
// 3 integers + 1 decimal point + 3 fractionals = 7 characters
LcdWriteString(dtostrf(Frequency,7,3,string));
LcdWriteString(" MHz ");
}
void UpDateLevelLCD() {
LcdGoToXY(0,4);
LcdWriteString("LEVEL ");
if (Level > 0) LcdWriteString("+");
if ((Level <= 0)&& (Level > -10)) LcdWriteString(" ");
// 1 sign + 2 integers + 0 decimal point + 0 fractionals = 1+2 characters
LcdWriteString(dtostrf(Level,2,0,string));
LcdWriteString(" dBm ");
}
void UpDateCursorPosition()
{
// CHANGE THE CURSORPOSITION
if (Frequency_Level)// CHECK WHERE IT STANDS NOW(FREQUENCY OR LEVEL)
{
CursorPosition = CursorPosition + 1; // INCREASE CURSORPOSITION
if ( CursorPosition > 5 ) CursorPosition = 0 ;
}
else CursorPosition = 2;
switch(CursorPosition)
{
case 0:
Addition = 100.0; // SET TENS OF MAGNITUDE(10^2)
x = 0; y = 2; // COORDINATES FOR THE BLINKING FUNCTION
break;
case 1:
Addition = 10.0;
x = 6; y = 2; //
break;
case 2:
Addition = 1;
if(Frequency_Level){x = 12; y = 2;}
else{x = 47; y = 4;}
break;
case 3:
Addition = 0.1;
x = 24; y = 2;
break;
case 4:
Addition = 0.01;
x = 30; y = 2;
break;
case 5:
Addition = 0.001;
x = 36; y = 2;
break;
}
}
void UpdateEncoder()
{
/*
¦ A ¦ B ¦
-----------------
¦ 0 ¦ 0 ¦
-----------------
¦¦ ¦ 0 ¦ 1 ¦ -1
¦¦ ----------------- /\
\/ ¦ 1 ¦ 1 ¦ ¦¦
+1 ----------------- ¦¦
¦ 1 ¦ 0 ¦
-----------------
¦ 0 ¦ 0 ¦
-----------------
WHEN AB IS HIGH AND BY THE NEXT ROTATION B GOES HIGH,
THEN THE ENCODER TURNED LEFT.
IF B GOES LOW, THEN IT TURNED RIGTH.
EXACTLY THE OPPOSITE IS TRUE, WHEN AB IS LOW.
*/
//DETECT THE ROTATION OF THE ENCODER AND SET SOME CONSTANTS
switch(RotaryEncoderStatusOld)
{
// AB WERE LOW
case 4:
if ((RotaryEncoderStatus & B0000010) == 0x00)
EncoderValue = EncoderValue + Addition;
else EncoderValue = EncoderValue - Addition;
// STOPS COUNTING IF THE VALUE IS > MAX OR < MIN
if (EncoderValue > Max) EncoderValue = maxNr;
if (EncoderValue < Min) EncoderValue = minNr;
break;
// AB WERE HIGH
case 14:
if ((RotaryEncoderStatus & B0000010) == 0x00)
EncoderValue = EncoderValue - Addition;
else EncoderValue = EncoderValue + Addition;
// STOPS COUNTING IF THE VALUE IS > MAX OR < MIN
if (EncoderValue > Max) EncoderValue = maxNr;
if (EncoderValue < Min) EncoderValue = minNr;
break;
}
if (Frequency_Level)
{
Frequency = EncoderValue;
maxNr = Frequency;
minNr = Frequency;
}
else {Level = EncoderValue; maxNr = Level; minNr = Level; }
}
//SWITCH BETWEEN FREQUENCY AND LEVEL VALUE
void SwitchFreqLevel()
{
// CHECK WHERE IT STANDS NOW
Frequency_Level = !Frequency_Level;
if (Frequency_Level)
{
//SET THE CONSTANTS FOR THE FREQUENCY
EncoderValue = Frequency;
Max = MaxFreq;
Min = MinFreq;
Addition = 1.0;
CursorPosition = 1;
UpDateCursorPosition();
UpDateLevelLCD();
}
else
{
//SET THE CONSTANTS FOR THE ATTENTUATOR LEVEL
EncoderValue = Level;
Max = LevelMax;
Min = LevelMin;
Addition = 1.0;
UpDateCursorPosition();
UpDateFreqLCD();
}
}
// CHECK ROTARY ENCODER (A1...A3)
void CheckRotaryEncoder()
{
RotaryEncoderStatusOld = RotaryEncoderStatus ;
RotaryEncoderStatus = PINC & B00001110 ;
// PORT MANIPULATION FOR FAST READ
RotaryEncoderActivity = RotaryEncoderActivity | (
RotaryEncoderStatus ^ RotaryEncoderStatusOld) ;
}
void Si570SetFrequency(float Freq)
{
// VCO_MIN = 4850 MHz, VCO_MAX = 5670 MHz
/*
HSDIV ¦ N1 ¦ DIVIDER ¦ VCO_MIN ¦ VCO_MAX ¦
------------------------------------------------------
4 ¦ 6 ¦ 24 ¦ 202.08 ¦ 236.25 ¦
------------------------------------------------------
7 ¦ 4 ¦ 28 ¦ 173.21 ¦ 202.50 ¦
------------------------------------------------------
4 ¦ 8 ¦ 32 ¦ 151.56 ¦ 172.18 ¦
------------------------------------------------------
9 ¦ 4 ¦ 36 ¦ 134.72 ¦ 157.50 ¦
------------------------------------------------------
5 ¦ 8 ¦ 40 ¦ 121.25 ¦ 141.75 ¦
------------------------------------------------------
11 ¦ 4 ¦ 44 ¦ 110.23 ¦ 128.87 ¦
------------------------------------------------------ // :1
4 ¦ 12 ¦ 48 ¦ 101.04 ¦ 118.12 ¦
------------------------------------------------------
7 ¦ 8 ¦ 56 ¦ 86.61 ¦ 101.25 ¦
------------------------------------------------------
4 ¦ 16 ¦ 64 ¦ 75.78 ¦ 88.59 ¦
------------------------------------------------------
9 ¦ 8 ¦ 72 ¦ 67.36 ¦ 78.75 ¦
------------------------------------------------------
5 ¦ 16 ¦ 80 ¦ 60.63 ¦ 70.875 ¦
------------------------------------------------------
11 ¦ 8 ¦ 88 ¦ 55.11 ¦ 64.43 ¦
------------------------------------------------------ // :2
4 ¦ 24 ¦ 96 ¦ 50.52 ¦ 59.06 ¦
------------------------------------------------------
7 ¦ 16 ¦ 112 ¦ 43.30 ¦ 50.625 ¦
------------------------------------------------------
4 ¦ 32 ¦ 128 ¦ 37.89 ¦ 44.29 ¦
------------------------------------------------------
9 ¦ 16 ¦ 144 ¦ 33.68 ¦ 39.375 ¦
------------------------------------------------------
5 ¦ 32 ¦ 160 ¦ 30.31 ¦ 35.43 ¦
------------------------------------------------------
11 ¦ 16 ¦ 176 ¦ 27.56 ¦ 32.21 ¦
------------------------------------------------------ // :4
4 ¦ 48 ¦ 192 ¦ 25.26 ¦ 29.53 ¦
------------------------------------------------------
7 ¦ 32 ¦ 224 ¦ 21.65 ¦ 25.31 ¦
------------------------------------------------------
4 ¦ 64 ¦ 256 ¦ 18.95 ¦ 22.14 ¦
------------------------------------------------------
9 ¦ 32 ¦ 288 ¦ 16.84 ¦ 19.68 ¦
------------------------------------------------------
5 ¦ 64 ¦ 320 ¦ 15.16 ¦ 17.71 ¦
------------------------------------------------------
11 ¦ 32 ¦ 352 ¦ 13.78 ¦ 16.10 ¦
------------------------------------------------------ // :8
4 ¦ 96 ¦ 384 ¦ 12.63 ¦ 14.76 ¦
------------------------------------------------------
7 ¦ 64 ¦ 448 ¦ 10.83 ¦ 12.65 ¦
------------------------------------------------------
4 ¦ 128 ¦ 512 ¦ 9.47 ¦ 11.07 ¦
------------------------------------------------------
9 ¦ 64 ¦ 576 ¦ 8.42 ¦ 9.84 ¦
------------------------------------------------------
5 ¦ 128 ¦ 640 ¦ 7.58 ¦ 8.85 ¦
------------------------------------------------------
11 ¦ 64 ¦ 704 ¦ 6.89 ¦ 8.05 ¦
------------------------------------------------------ // :16
THE VALUES IN THE TABLE ABOVE REPEAT ITSELF(236.25/2=118.12,
236.25/4=59.06 AND SO ON). THEREFOR WE JUST SAVED THE FIRST
SIX HSDIV, N1 AND VCO_MAX VALUES IN AN ARRAY. FIRST, SET THE
BLOCK(DIVIDER) AND THEN WE CAN CALCULATE HS_DIV AND N1 BY
DIVIDING THE SAVED VALUES IN THE ARRAY BY THE BLOCK.
*/
int i=-1;
Block = 1;
if(Freq <= 115.0)Block = 2;
if(Freq <= 58.0)Block = 4;
if(Freq <= 28.0)Block = 8;
if(Freq <= 14.0)Block = 16;
do
{
i++;
HS_DIVIDER = HSDIV[i];
N_DIVIDER = ((N1[i]*Block));
}while((VCO_Freq[i]/Block/Freq) <= 1.0);
// BASIC FORMULA: Fout = (Fxtal * RFREQ) / (HS_DIV * N1),
WHERE (Fxtal * RFREQ) MUST BE BETWEEN 4.85 AND 5.67 GHz
RFREQ = Freq* HS_DIVIDER * N_DIVIDER / Crystal;
// SPLIT RFREQ IN INTEGER(10BIT) AND FRACTIONAL(28BIT) PART
RF_DIVIDER_INTEGER = int(RFREQ);
RF_DIVIDER_FRACTIONAL = long(pow(2,28)*(RFREQ-RF_DIVIDER_INTEGER));
// CALCULATE N1, DATA SHEET :
// The value for the N1 register can be calculated by taking the divider
// ratio minus one. For example, to divide by 10,write 0001001 (9 decimal)
// to the N1 registers.
N_DIVIDER = N_DIVIDER - 1;
Si570CommandToByte();
Si570sendData();
}
void Si570CommandToByte()
{
/*
¦ 7 ¦ 6 ¦ 5 ¦ 4 ¦ 3 ¦ 2 ¦ 1 ¦ 0 ¦
-----------------------------------------------------------------------
SiR7 ¦ HS_DIV_INDEX[2:0] ¦ (N1-1)[6:2]
-----------------------------------------------------------------------
SiR8 ¦ (N1-1)[1:0] ¦ RFREQ(INTEGER)[37:32]
-----------------------------------------------------------------------
SiR9 ¦ RFREQ(INTEGER)[31:28] ¦ RFREQ(FRACTIONAL)[27:24]
-----------------------------------------------------------------------
SiR10 ¦ RFREQ(FRACTIONAL)[23:16]
-----------------------------------------------------------------------
SiR11 ¦ RFREQ(FRACTIONAL)[15:8]
-----------------------------------------------------------------------
SiR12 ¦ RFREQ(FRACTIONAL)[7:0]
-----------------------------------------------------------------------
SiReg ¦RST_REG¦ NEW ¦ FREEZ ¦ ¦ ¦ ¦ ¦RECALL ¦
137 ¦ ¦ Freq ¦ M ¦ ¦ ¦ ¦ ¦ ¦
-----------------------------------------------------------------------
SiReg ¦ ¦ ¦ ¦ FREEZ ¦ ¦ ¦ ¦ ¦
137 ¦ ¦ ¦ ¦ DCO ¦ ¦ ¦ ¦ ¦
-----------------------------------------------------------------------
*/
// SET BYTES AS SEEN ABOVE
SiR7 = (HS[HS_DIVIDER]<<5) + (N_DIVIDER>>2);
SiR8 = (N_DIVIDER<<6) + (RF_DIVIDER_INTEGER>>4);
SiR9 = (RF_DIVIDER_INTEGER<<4) + (RF_DIVIDER_FRACTIONAL>>24);
SiR10 = (RF_DIVIDER_FRACTIONAL>>16);
SiR11 = (RF_DIVIDER_FRACTIONAL>>8);
SiR12 = (RF_DIVIDER_FRACTIONAL);
}
void Si570sendData()
{
Wire.beginTransmission(Si570ADDRESS);
Wire.write(137); // WRITE THE BYTE ADRESS (REGISTER 137)
Wire.write(0x10); // 0x10, FREEZ DCO
Wire.endTransmission();
Wire.beginTransmission(Si570ADDRESS);
Wire.write(7); // WRITE THE BYTE ADRESS (REGISTER 7)
Wire.write(SiR7); // WRITE THE REGISTER 7-12
Wire.write(SiR8);
Wire.write(SiR9);
Wire.write(SiR10);
Wire.write(SiR11);
Wire.write(SiR12);
Wire.endTransmission();
Wire.beginTransmission(Si570ADDRESS);
Wire.write(137); // WRITE THE BYTE ADRESS (REGISTER 137)
Wire.write(0x00); // 0x00, UNFREEZ DCO
Wire.endTransmission();
Wire.beginTransmission(Si570ADDRESS);
Wire.write(135); // WRITE THE BYTE ADRESS (REGISTER 135)
Wire.write(0x40); //0x40, INFORM THE Si570 THAT THERE IS A NEW FREQUENCY
Wire.endTransmission();
}
void Si570readData()
{
Wire.beginTransmission(Si570ADDRESS);
Wire.write(0x07); // WRITE THE BYTE ADRESS (REGISTER 7)
Wire.endTransmission();
Wire.requestFrom(Si570ADDRESS,6);
R7 = Wire.read(); // 0x07
R8 = Wire.read(); // 0x08
R9 = Wire.read(); // 0x09
R10 = Wire.read(); // 0x0A
R11 = Wire.read(); // 0x0B
R12 = Wire.read(); // 0x0C
}
void SetAttentuator(byte b)
{
/*
ATTENTUATION ¦ C32 ¦ C16 ¦ C8 ¦ C4 ¦ C2 ¦ C1 ¦
---------------------------------------------------------------
LOSS,REFERENCE¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦
---------------------------------------------------------------
1 dB ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 1 ¦
---------------------------------------------------------------
2 dB ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 1 ¦ 0 ¦
---------------------------------------------------------------
4 dB ¦ 0 ¦ 0 ¦ 0 ¦ 1 ¦ 0 ¦ 0 ¦
---------------------------------------------------------------
8 dB ¦ 0 ¦ 0 ¦ 1 ¦ 0 ¦ 0 ¦ 0 ¦
---------------------------------------------------------------
16 dB ¦ 0 ¦ 1 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦
---------------------------------------------------------------
32 dB ¦ 1 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦
---------------------------------------------------------------
50 dB ¦ 1 ¦ 1 ¦ 0 ¦ 0 ¦ 1 ¦ 0 ¦
---------------------------------------------------------------
*/
// CHECK IF WE ARE IN THE LEVEL MENU
if(!Frequency_Level)
{
// CHANGE ATTENTUATER LEVEL FROM (-35 -> +15) TO (0 -> +50)
b = ((-b)+15);
// REVERSE THE BYTE AND SET ATTENTUATOR(PORT MANIPULATION)
PORTD=((b*0x0802LU&0x22110LU)|(b*0x8020LU&0x88440LU))*0x10101LU>>16;
// Do not change pin 0 and 1(TX,RX)
}
}
void SaveValues()
{
// CHECK FOR CHANGE OF ROTARY ENCODER
if ( RotaryEncoderActivity > 0x00 )
{
lastchange = millis();
laststate = true;
}
// CHECK IF LAST CHANGE OF ROTARY ENCODER > 20 SECONDS
if(((millis()-lastchange)>20000)&& laststate)
{
// SAVE THE VALUES IN THE EEPROM
if( EEPROM.get(0,FR) != Frequency )EEPROM.put(0,Frequency);
if( EEPROM.get(10,FR) != Level )EEPROM.put(10,Level);
laststate = false;
}
}
/*
void SerialProgramming()
{
char ch;
long int temp;
while (Serial.available())
{
ch=(char)Serial.read();
if (((ch >= '0') && (ch <= '9')) || ((ch >= 'A') && (ch <= 'Z')))
inputcmd[cmdindex++]=ch;
if (ch == '\n')
{ // parse command if its a newline
inputcmd[cmdindex]=0; // terminate the string
if ((temp=atol(inputcmd)) > 0)
{
if ((temp<MaxFreq)&&(temp>MinFreq))
Si570SetFrequency(temp);
}
cmdindex=0; // reset command line
}
}
}
*/
void setup() {
// LCD NOKIA 5110
pinMode(RST, OUTPUT);
pinMode(CE, OUTPUT);
pinMode(DC, OUTPUT);
pinMode(DIN, OUTPUT);
pinMode(CLK, OUTPUT);
digitalWrite(RST, LOW);
digitalWrite(RST, HIGH);
LcdWriteCmd(0x21); // LCD extended commands
LcdWriteCmd(0xB8); // set LCD Vop (contrast)
LcdWriteCmd(0x04); // set temp coefficent
LcdWriteCmd(0x14); // LCD bias mode 1:40
LcdWriteCmd(0x20); // LCD basic commands
LcdWriteCmd(0x0C); // LCD normal video
LcdClearScreen();
// Startup display
LcdGoToXY(0,0); LcdWriteString("MICROMOD UNO");
LcdGoToXY(0,2); LcdWriteString("SOFTWARE V1.1");
LcdGoToXY(0,3); LcdWriteString("HARDWARE V1.0");
LcdGoToXY(0,4); LcdWriteString("29.09.2016");
delay(5000);
// CHIP USED : SiLabs 570 CAC000121G
// C: 3.3V CMOS
// A: 50ppm TempStability
// C: 10-160 MHz
// We need to refer to register 07 - 12
Wire.begin(); // join i2c bus (address optional for master)
Si570readData(); // Read the Register
LcdClearScreen();
LcdGoToXY(0,0); LcdWriteString("REG. 07 : 0x"); LcdDisplay(R7);
LcdGoToXY(0,1); LcdWriteString("REG. 08 : 0x"); LcdDisplay(R8);
LcdGoToXY(0,2); LcdWriteString("REG. 09 : 0x"); LcdDisplay(R9);
LcdGoToXY(0,3); LcdWriteString("REG. 10 : 0x"); LcdDisplay(R10);
LcdGoToXY(0,4); LcdWriteString("REG. 11 : 0x"); LcdDisplay(R11);
LcdGoToXY(0,5); LcdWriteString("REG. 12 : 0x"); LcdDisplay(R12);
delay(10000);
LcdClearScreen();
// ATENUATOR, SET ATTENUATOR TO MAX
pinMode(ATT32, OUTPUT); digitalWrite(ATT32, LOW);
pinMode(ATT16, OUTPUT); digitalWrite(ATT16, LOW);
pinMode(ATT08, OUTPUT); digitalWrite(ATT08, LOW);
pinMode(ATT04, OUTPUT); digitalWrite(ATT04, LOW);
pinMode(ATT02, OUTPUT); digitalWrite(ATT02, LOW);
pinMode(ATT01, OUTPUT); digitalWrite(ATT01, LOW);
// THE ROTARY ENCODER: A1, A2, A3
pinMode(A1, INPUT); digitalWrite(A1,HIGH); // PULLUP
pinMode(A2, INPUT); digitalWrite(A2,HIGH);
pinMode(A3, INPUT); digitalWrite(A3,HIGH);
// ENABLE INTERRUPT FOR PIN ...
Timer1.initialize(1000); // EVERY 1 ms
Timer1.attachInterrupt(CheckRotaryEncoder);
RotaryEncoderStatus = PINC ;
RotaryEncoderStatusOld = RotaryEncoderStatus ;
RotaryEncoderActivity = 0x00;
// Read EEPROM
if(EEPROM.read(15) != 0) // Clear all by the first upload
{
for (int i = 0 ; i < EEPROM.length() ; i++)
{
EEPROM.write(i, 0);
}
EEPROM.put(0,Frequency);
EEPROM.put(10,Level);
}
else
{
EEPROM.get(0,Frequency);
EEPROM.get(10,Level);
}
Max = MaxFreq;
Min = MinFreq;
EncoderValue = Frequency;
Addition = 0;
// Set to saved values
Si570SetFrequency(Frequency);
SetAttentuator(Level);
UpDateFreqLCD();
UpDateLevelLCD();
Serial.begin(9600);
}
void loop()
{
// EVALUATE KNOB PRESSED, BIT 3, TOGGLE
if (RotaryEncoderActivity == 0x04)
{
// FALLING EDGE ONLY
if (( RotaryEncoderStatus & B00000100 ) == 0x00)
{
currentmillis = millis();
EncoderState = true;
}
}
// CHECK IF THE KNOB WAS PRESSED AND HOLDED FOR longER
// THAN 1.5 SECONDS.(PRESS AND HOLD)
if ((( RotaryEncoderStatus & B00000100 ) == 0x00)&&(millis()
- currentmillis >= 1500)&&EncoderState)// FALLING EDGE ONLY
{
// CHANGE BETWEEN FREQUENCY AND ATTENTUATOR LEVEL
SwitchFreqLevel();
EncoderState = false;
}
//CHECK IF THE KNOB WAS PRESSED longER THAN 0.1 SECONDS.(SINGLE PRESS)
if ((( RotaryEncoderStatus & B00000100 ) != 0x00)&&(millis()
- currentmillis >= 0.1)&&EncoderState)// RISING EDGE ONLY
{
UpDateCursorPosition();
EncoderState = false;
}
// CHECK FOR CHANGE OF ROTARY ENCODER
if ( RotaryEncoderActivity > 0x00 )
{
// EVALUATE KNOB NOT PRESSED
if (( RotaryEncoderStatus & B00000100 ) != 0x00)
{
UpdateEncoder();
UpDateFreqLCD();
UpDateLevelLCD();
Si570SetFrequency(Frequency);
SetAttentuator(Level);
}
}
SaveValues();
LcdBlink(x,y);
RotaryEncoderActivity = 0 ;
if(Addition == 0)Addition = 1;
//SerialProgramming();
delay(1);
}
// /////////////////////////////////////////////////////////////
// END OF FILE.
// /////////////////////////////////////////////////////////////
✈ Downloads
✈ The Rotary Encoder
The Rotary Encoder is connected at A1,A2 and A3. We used pull-up resistors of 2.2 kΩ in connection
with 47 nF capacitors for debouncing. From the waveforms below, we see that setting the timer interrupt to 1 ms should be far more
than necessary to detect the slopes. Pressing the knob will move the "cursor" to the next (right) digit. Pressing it even
longer and you can change the power level. The actual digit will blink.
✈ The Attenuator
We used an MAAD-007086-000100 (RF Attenuator 50dB ±0.5dB 0 ~ 2GHz 50 Ohm 24-SOIC ) here, because of it's DIY-Formfactor.
(everything else seems to use TQFP or similiar cases). This luxury of easy soldering and easy "programming" has it's price.
Check it out, we got it from Digi-Key for a bargain price of €49.-
In order to have a student proof, lab suiteable device, we addded a
measurement amplifier and a case.
The name "Micromod" was chosen to underline it's usefulness (despite it's small size) and to pay respect to one of the greatest
engineers of our time.
✈ Share your thoughts
The webmaster does not read these comments regularely. Urgent questions should be send via email.
Ads or links to completely uncorrelated things will be removed.
Your Browser says that you allow tracking. Mayst we suggest that you check that DNT thing ?