ATtiny1614機能チェックを目的に、oled mono band VFOを作った。デジタル入力、アナログ入力、I2C、割込み、EEPROM と一通りのチップ機能が確認できた。VFOとしても満足できる仕様だと自負してる。
///////////////////////////////////////////////////////////////////////
// si5351a oled(128x32) ATtiny1614 VFO program ver.1.0
// Copyright(C)2023.JA2GQP.All rights reserved.
//
// 2023/9/24
// JA2GQP
//--------------------------------------------------------------------
// Function
// 1.STEP(10k,1k,100,10)
// 2.EEPROM memorry save/reload
// 3.Protection Operation At The Time Of Transmission
// 4.S-Meter
// 5.mono band
//////////////////////////////////////////////////////////////////////
#include "src/Rotary.h"
#include "src/si5351a21.h"
#include <Tiny4kOLED.h>
#include "font/Tlcdnums14x24.h"
#include "font/Tlabels.h"
#include "font/Tpixels.h"
#include <EEPROM.h>
////////////////////////////////
// Set Device
////////////////////////////////
Rotary r = Rotary(2, 5);
////////////////////////////////
// EEPROM Memory Address
////////////////////////////////
const byte Eep_Init = 0x00; // Eep Init(1byte*1)
const byte Eep_Band = 0x01; // Band(1byte*1)
const byte Eep_Mode = 0x02; // Mode(1byte*1)
const byte Eep_Freq = 0x10; // Frequency(4byte*8)
const byte Eep_Step = 0x30; // STEP(4byte*8)
////////////////////////////////
// frquency data
////////////////////////////////
const unsigned long FRQ_TBL[3] = {
// DEF LOW HI
7050000 ,7000000 ,7200000
};
//---- data offset -----
const byte DEF_F = 0;
const byte LOW_F = 1;
const byte HI_F = 2;
////////////////////////////////
// I/O Port
////////////////////////////////
const byte SW_RIT = 4; // RIT SW
const byte SW_STEP = 1; // STEP SW
const byte SW_MODE = 3; // MODE SW
const byte SW_TX = 0; // TX/RX
const byte AD_SM = 10; // S-meter AD
//---- IF Frequency & Bfo data -----
const unsigned long IF_FREQ = 10700000L;
const unsigned long BFO_TBL[3] = {
// CW LSB USB
10700600,10701500,10698500
};
const byte CW = 0; // CW
const byte LSB = 1; // LSB
const byte USB = 2; // USB
////////////////////////////////
// etc
////////////////////////////////
const byte Int_End = 49; // Initial end code
const int LW_RIT = -5000; // RIT Lower Limit
const int HI_RIT = 5000; // RIT Upper Limit
////////////////////////////////
// Memory Assign
////////////////////////////////
unsigned long Vfo_Dat; // VFO Data
unsigned long Enc_Step; // STEP
int Rit_Dat; // RIT Data
char Enc_Dir = 0; // -1 DIR_CCW, 0 DIR_NONE, 1 DIR_CCW
unsigned int Val_Smeter = 0;
unsigned int Val_Smeterb = 1;
unsigned int Time_Passd;
byte Flg_eepWT = 0; // EEP Write Flag
byte Byt_Mode = LSB;
byte Flg_Over;
byte Flg_Tx = 0;
byte Flg_Rit = 0; // RIT Flag
//---------- setup ----------------------------------------------------
void setup() {
pinMode(SW_STEP, INPUT_PULLUP);
pinMode(SW_TX, INPUT_PULLUP);
pinMode(SW_RIT, INPUT_PULLUP);
pinMode(SW_MODE, INPUT_PULLUP);
attachInterrupt(2,rotary_encoder,CHANGE);
attachInterrupt(5,rotary_encoder,CHANGE);
oled.begin();
oled.clear();
oled.on();
if(EEPROM.read(Eep_Init) != Int_End){
delay(10);
eep_init();
}
else{
if(digitalRead(SW_STEP) == LOW){
delay(10);
eep_init();
fover_disp();
while (digitalRead(SW_STEP) == LOW);
}
}
eep_rdata();
step_disp(Enc_Step);
}
//---------- main(Loop) -----------------------------------------------
void loop() {
//---------- receive
if(digitalRead(SW_TX) == HIGH){
Flg_Tx = 0;
si5351a_enable(0x00); // si5351 output enable
//---------- RIT proc
if(Flg_Rit == 1){
Rit_Dat += Enc_Dir * Enc_Step;
Enc_Dir = 0;
Rit_Dat = constrain(Rit_Dat,LW_RIT,HI_RIT);
si5351aSetFrequency(Vfo_Dat + IF_FREQ + Rit_Dat);
rit_disp(Rit_Dat);
}
//---------- normal proc
else{
Vfo_Dat += Enc_Dir * Enc_Step;
Enc_Dir = 0;
band_check(); // range check
si5351aSetFrequency(Vfo_Dat + IF_FREQ);
freq_disp(Vfo_Dat); // frequency display
}
//---------- STEP SW check
if (digitalRead(SW_STEP) == LOW) {
enc_step();
step_disp(Enc_Step);
while (digitalRead(SW_STEP) == LOW);
}
//---------- MODE SW check
if (digitalRead(SW_MODE) == LOW) {
mode_set();
mode_disp(Flg_Tx,Byt_Mode);
while (digitalRead(SW_MODE) == LOW);
}
//---------- RIT SW check
if (digitalRead(SW_RIT) == LOW){
if(Flg_Rit == 0)
Flg_Rit = 1;
else{
Flg_Rit = 0;
Rit_Dat = 0;
}
while (digitalRead(SW_RIT) == LOW);
}
}
//---------- trancemit
else{
Flg_Tx = 1;
if(Flg_Over == 1){ // frequency limit over?
fover_disp();
si5351a_enable(0x05); // VFO and BFO off
}
else
freq_disp(Vfo_Dat); // frequency display
si5351aSetFrequency(Vfo_Dat + IF_FREQ);
}
//---------- common
mode_disp(Flg_Tx,Byt_Mode);
si5351aSetFrequency2(BFO_TBL[Byt_Mode]); // Bfo data out
//---------- s-meter
Val_Smeter = analogRead(AD_SM);
if ((abs(Val_Smeter - Val_Smeterb)) > 3){ // if needed draw S-meter
sm_disp();
Val_Smeterb = Val_Smeter;
}
//---------- Save to EEPROM
if(Flg_eepWT == 1){
if(Time_Passd+2000 < millis()){ // EEPROM auto write(2sec)
eep_wdata();
Flg_eepWT = 0;
}
}
}
//---------- mode set -----------------------------------------------
void mode_set() {
if (Byt_Mode == 2)
Byt_Mode = 0;
else
Byt_Mode++;
}
//---------- band chek -----------------------------------------------
void band_check(){
if((Vfo_Dat >= FRQ_TBL[LOW_F])
&& (Vfo_Dat <= FRQ_TBL[HI_F]))
Flg_Over = 0;
else
Flg_Over = 1;
}
//---------- EEPROM Initialization ------------------------------------
void eep_init(){
int i;
for (i=0;i<64;i++) // 0 clear(64byte)
EEPROM.write(i, 0);
eep_write4(FRQ_TBL[DEF_F],Eep_Freq);
eep_write4(1000,Eep_Step);
EEPROM.write(Eep_Mode,LSB); // mode LSB
EEPROM.write(Eep_Init,Int_End); // Init end set(73)
}
//---------- EEPROM Dat Read -----------------------------------------
void eep_rdata(){
Vfo_Dat = eep_read4(Eep_Freq);
Enc_Step = eep_read4(Eep_Step);
Byt_Mode = EEPROM.read(Eep_Mode);
}
//---------- EEPROM Dat Write ----------------------------------------
void eep_wdata(){
eep_write4(Vfo_Dat,Eep_Freq);
eep_write4(Enc_Step,Eep_Step);
EEPROM.write(Eep_Mode,Byt_Mode); // mode LSB
}
//---------- Write EEPROM 4byte --------------------------------------
void eep_write4(long value,int address){
address += 3;
for(int i = 0;i < 4;i++){
byte toSave = value & 0xFF;
if(EEPROM.read(address) != toSave){
EEPROM.write(address,toSave);
}
value = value >> 8;
address--;
}
}
//---------- Read EEPROM 4byte ---------------------------------------
long eep_read4(int address){
long value = 0;
for(int i = 0;i < 4;i++){
value = value | EEPROM.read(address);
if( i < 3){
value = value << 8;
address++;
}
}
return value;
}
//---------- Encorede STEP -------------------------------------------
void enc_step() {
if (Enc_Step == 10000)
Enc_Step = 10; // 1000 Hz, round to XX.XXX.000
else
Enc_Step = Enc_Step * 10;
}
//---------- Rotaly Encorder -----------------------------------------
void rotary_encoder() { // rotary encoder events
uint8_t result = r.process();
if(Flg_Tx == 0){
if (result) {
if (result == DIR_CW)
Enc_Dir = 1;
else
Enc_Dir = -1;
}
}
Flg_eepWT = 1;
Time_Passd = millis();
}
//---------- S-Meter Display -----------------------------------------
void sm_disp() {
uint8_t a = 0;
uint8_t m = 0;
a = (Val_Smeter + 3) / 113; // 1024 / 9 characters for S = 1,3,5,7,8,9,
// +10,+20,+30
oled.setFont(&Tpixels);
oled.setCursor(25, 3);
for (m = 0; m < a; m++)
if (m < 6)
oled.print('7'); // '5' - hollow rectangle, 6px
else
oled.print('8'); // '6' - filled rectangle, 6px
for (m = a; m < 9; m++)
oled.print('.'); // '.' 1px
}
//---------- STEP Display --------------------------------------------
void step_disp(unsigned long stp) {
oled.setCursor(109, 3);
oled.setFont(&Tlabels);
if (stp == 10)
oled.print("5"); // 10
else if(stp == 100)
oled.print("7"); // 100
else if(stp == 1000)
oled.print("8"); // 1k
else
oled.print("9"); // 10k
}
//---------- Mode display ----------------------------------------------
void mode_disp(byte flg,byte mod) {
oled.setCursor(2, 3);
oled.setFont(&Tlabels);
if(flg == 1)
oled.print("1"); // "1" is "TX" in labels.h
else{
if(mod == 0)
oled.print("2"); // "2" is "CW" in labels.h
else if(mod == 1)
oled.print("3"); // "3" is "LSB"
else if(mod == 2)
oled.print("4"); // "4" is "USB"
}
}
//---------- Frequency renge over --------------------------------------
void fover_disp() {
oled.setFont(&Tlcdnums14x24);
oled.setCursor(1, 0);
oled.print("--.---.--");
}
//---------- RIT Display ---------------------------------------------
void rit_disp(int rit_data) {
unsigned int ri,rit;
oled.setFont(&Tlcdnums14x24);
oled.setCursor(1, 0);
oled.print("::::");
if (rit_data < 0)
oled.print('-');
else
oled.print('+');
rit = abs(rit_data);
ri = rit / 1000;
oled.print(ri);
oled.print('.');
ri = (rit % 1000) / 10;
if (ri < 10)
oled.print('0');
oled.print(ri);
}
//---------- Frequency Display ---------------------------------------
void freq_disp(uint32_t sf_rx) {
uint16_t fr;
oled.setFont(&Tlcdnums14x24);
oled.setCursor(1, 0);
fr = sf_rx / 1000000;
if (fr < 10)
oled.print(':'); // ':' is changed to ' '
oled.print(fr);
oled.print('.');
fr = (sf_rx % 1000000) / 1000;
if (fr < 100)
oled.print('0');
if (fr < 10)
oled.print('0');
oled.print(fr);
oled.print('.');
fr = (sf_rx % 1000) / 10;
if (fr < 10)
oled.print('0');
oled.print(fr);
}