1)Bootloaderにより起動されるので、アプリケーション立上りに約6秒かかる。
2)アプリケーションで使える領域が、約6kB。(B00tloader2kB占有のため)
3)DijisparkのP1(LED点灯回路)が、周辺ポートレベルを吊り上げる為、ポートが正常動作しない。
解決策
1)Bootloaderなしとし、ArduinoIDEで開発する為のAttiny85環境整備を行った。2)DijisparkのP1回路に繋がっている抵抗(102)を外した。
VFO仕様
1)周波数の自動メモリー保存2)Auto STEP(10Hz,100Hz,1kHz,10kHz)のロータリー式での切替
3)RIT機能
4)BFO
5)S-Meter
6)モノバンド
7)帯域外への送信保護
8)自動モード切替
回路図
スケッチ
スイッチ入力は、アナログ信号をラダー回路によってレベル判断を行っている。アナログ信号のPB5は、リセットを兼ねているのでしきい値を設けている。スイッチ入力の判断は、マクロにして見通しを良くした。機械式エンコーダの場合、加速・定常域・減速が安定しておらず、かつ、連続回転の為のノブ持ち返しがある。その為、速度判定2s、ノブ持ち返し保持時間6sに設定している。(エンコーダの種類、回し方などで動作が大きく変わる)
スケッチは、ダウンロードサイトのAttiny85フォルダからダウンロードできる。
///////////////////////////////////////////////////////////////////////////////////
// si5351a VFO Atiny85
//
// 2020/3/12
// JA2GQP
///////////////////////////////////////////////////////////////////////////////////
//---------- Library include --------------------------------
#include "src/si5351a21.h"
#include <Rotary.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
//---------- Define value -----------------------------------
#define SW1 (val < 682) && ( val >= 472) // SW1
#define SW2 (val < 767) && ( val >= 642) // SW2
#define SW3 (val < 818) && ( val >= 727) // SW3
#define SW_TX SW1
#define SW_RIT SW2
#define ENC_A PB1
#define ENC_B PB3
Rotary r=Rotary(ENC_A,ENC_B);
LiquidCrystal_I2C lcd(0x27, 16, 2);
////////////////////////////////
// EEPROM Memory Address
////////////////////////////////
const byte Eep_Init = 0x00; // Eep Init(1byte*1)
const byte Eep_Band = 0x01; // Band(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[4] = {
// DEF LOW(cw) MID(ssb) HI
7050000 ,7000000 ,7045000 ,7200000
};
//---- data offset -----
const byte DEF_F = 0;
const byte LOW_F = 1;
const byte MID_F = 2;
const byte HI_F = 3;
//---- Bfo data -----
const unsigned long IF_FREQ = 10700000L;
const unsigned long CW = 10700600L;
const unsigned long LSB = 10701500L;
const unsigned long USB = 10698500L;
////////////////////////////////
// etc
////////////////////////////////
const byte Int_End = 73; // Initial end code
const int LW_RIT = -5000; // RIT Lower Limit
const int HI_RIT = 5000; // RIT Upper Limit
byte bar5[8]={B00000, // s-meter barcode data
B11011,
B11011,
B11011,
B11011,
B11011,
B11011,
B00000};
byte bar1[8]={B10000,
B11000,
B11100,
B11110,
B11110,
B11100,
B11000,
B10000};
unsigned long previousMillis;
//---------- Variable setting -------------------------------
unsigned long Vfo_Dat;
unsigned long Vfo_Datb = 0;
unsigned long Bfo_Dat;
unsigned long Bfo_Datb = 0;
unsigned long Enc_Step = 10;
int Rit_Dat; // RIT Data
int Rit_Datb = 0; // old
long Lng_Wk; // Long Work
int Int_Wk; // Int Work
char Lcd_Dat[12] = " "; // Lcd Display Buffer
byte Flg_Tx = 0; // TX Flag
byte Flg_Mode = 0; // Mode Flag
byte Flg_Over = 0;
byte Flg_Rit = 0; // RIT Flag
byte Flg_Rdisp = 0; // RIT Display Flag
byte Flg_Disp = 0; // Display Flag
long Enc_Delay = 0; // Encorder Delay(ms)
long Time_Passd; // Time Pass(ms)
byte Flg_eepWT = 0; // EEP Write Flag
long Enc_Velocityb;
long Enc_Velocity; // Encorder velocity(ms)
//---------- Initialization Program ----------------------
void setup() {
unsigned int val;
pinMode(ENC_A,INPUT_PULLUP); // PB3
pinMode(ENC_B,INPUT_PULLUP); // PB4
lcd.begin();
lcd.backlight();
lcd.createChar(0, bar5);
lcd.createChar(1, bar1);
GIMSK |= (1 << PCIE); // Enable pin change interrupt
PCMSK |= (1 << PCINT1) | (1 << PCINT3);
sei(); // INT Enable
if(EEPROM.read(Eep_Init) != Int_End){
delay(10);
eep_init();
}
eep_rdata();
band_check();
mode_disp();
}
//---------- Main program ---------------------------------
void loop() {
unsigned int val;
val = analogRead(A0);
delay(1);
if(SW_TX) // SW_TX
Flg_Tx = 1;
else
Flg_Tx = 0;
Fnc_TRdsp(); // T/R Display
//////////////////////////
// RX
//////////////////////////
if(Flg_Tx == 0){ // RX
display_smeter(analogRead(A2)); // s-meter Display
Fnc_Stp();
si5351a_enable(0x00);
val = analogRead(A0);
delay(1);
if(SW_RIT) // SW_RIT
Fnc_Rit(); // RIT Flag set
if(((Vfo_Dat != Vfo_Datb) && (Flg_Rit == 0)) || (Flg_Disp == 1)){
si5351aSetFrequency(Vfo_Dat + IF_FREQ);
band_check();
mode_disp();
Fnc_Fdsp(Vfo_Dat);
Vfo_Datb = Vfo_Dat;
Flg_Disp = 0;
}
if(((Rit_Dat != Rit_Datb) && (Flg_Rit == 1)) || (Flg_Rdisp == 1)){
si5351aSetFrequency(Vfo_Dat + IF_FREQ + Rit_Dat);
rit_disp(Rit_Dat);
Rit_Datb = Rit_Dat;
Flg_Rdisp = 0;
}
si5351aSetFrequency2(Bfo_Dat); // Bfo data out
}
//////////////////////////
// TX
//////////////////////////
else{
mode_disp();
if(Flg_Over == 0){
si5351a_enable(0x00);
si5351aSetFrequency(Vfo_Dat + IF_FREQ);
}
else{ // Frequency over
si5351a_enable(0x07);
}
if(Flg_Rit == 1)
Flg_Rdisp = 1;
else
Flg_Disp = 1;
}
//////////////////////////
// Save to EEPROM
//////////////////////////
if(Flg_eepWT == 1){ // EEPROM auto Write
if(Time_Passd+2000 < millis()){
eep_wdata();
Flg_eepWT = 0;
}
}
}
//---------- Function Rit ---------
void Fnc_Rit(){
unsigned int val;
if(Flg_Rit == 0){
Rit_Dat = 0;
Flg_Rit = 1;
lcd.setCursor(11,0);
lcd.print("+0 ");
}
else{
mode_disp();
si5351aSetFrequency(Vfo_Dat + IF_FREQ);
Flg_Rit = 0;
}
do{
val = analogRead(A0);
delay(1);
}
while(SW_RIT);
}
//---------- RIT Display ---------------------------------------------
void rit_disp(int rit_data) {
unsigned int ri,rit;
lcd.setCursor(11,0);
if (rit_data >= 0){
lcd.print("+ ");
lcd.setCursor(12,0);
lcd.print(rit_data,DEC);
}
else{
lcd.print(" ");
lcd.setCursor(11,0);
lcd.print(rit_data,DEC);
}
}
//---------- Mode display ----------------------------------------------
void mode_disp() {
lcd.setCursor(11,0);
if((Flg_Tx == 1) && (Flg_Over == 1))
lcd.print(" Over"); // frequency over
else if (Flg_Mode == 0)
lcd.print(" CW"); // CW
else if(Flg_Mode == 1)
lcd.print(" LSB"); // LSB
else if(Flg_Mode == 2)
lcd.print(" USB"); // USB
}
//---------- LCD Bar Display PROC. ------------------------
void display_smeter(int strength){
// range is 0 to 1024 of adc
//meter run from position 3 to 14 (12 )
int scale = (strength*15)/1024;
lcd.setCursor(0, 1);
lcd.print("S");
int smeter=(scale*11)/15;
if(smeter<10)
lcd.print(smeter);
else
lcd.print("9");
lcd.print(">");
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= 1000) {
previousMillis = currentMillis;
//clear all after a small interval
lcd.setCursor(3, 1);
lcd.print(" ");
lcd.noCursor();
}
// write it and show for 500 milli sec
for (int i = 3; i<scale; i++){
lcd.setCursor(i, 1);
lcd.write(byte(0));
if(smeter>9)
lcd.print("+");
}
}
//---------- Encorder procedure(INT) ----------------------
ISR(PCINT0_vect) {
unsigned char result = r.process();
if(Flg_Tx == 0){
if(result) {
Enc_Velocity = millis() - Enc_Velocityb;
if(result == DIR_CW){
Lng_Wk = Vfo_Dat + Enc_Step;
Int_Wk = Rit_Dat + Enc_Step;
}
else{
Lng_Wk = Vfo_Dat - Enc_Step;
Int_Wk = Rit_Dat - Enc_Step;
}
if(Flg_Rit == 1)
Rit_Dat = Int_Wk;
else{
Vfo_Dat = Lng_Wk;
Rit_Dat = 0;
}
Rit_Dat = constrain(Rit_Dat,LW_RIT,HI_RIT); // RIT range check
Flg_eepWT = 1;
Time_Passd = Enc_Velocityb =millis();
}
}
}
//---------- Function Send/receive Display ------
void Fnc_TRdsp(){
lcd.setCursor(0,0);
if(Flg_Tx == 1)
lcd.print("T");
else
lcd.print("R");
}
//---------- Function Frequency Display ---------
void Fnc_Fdsp(long f_disp){
Fnc_Dot_Edit(Lcd_Dat,f_disp);
lcd.setCursor(1,0);
lcd.print(" ");
lcd.setCursor(1,0);
lcd.print(Lcd_Dat);
}
//---------- Function String Dot Edit --------
char *Fnc_Dot_Edit(char *str,long n){
int i = 0; // Write the number
char *p = str;
unsigned long u = abs(n);
do{
*p++ = "0123456789"[u % 10];
u = u / 10;
i++;
if((0 != u) && (0 == (i % 3)))
*p++ = '.';
}
while( 0 != u )
;
if ( n < 0 )
*p++ = '-';
*p = '\0';
Fnc_Revr( str );
return str;
}
//---------- Function String Reverse ---------------------------------
void Fnc_Revr(char *str){
int i,n;
char c;
n=strlen(str);
for(i = 0;i < n / 2;i++){
c=str[i];
str[i]=str[n - i - 1];
str[n - i - 1]=c;
}
}
//---------- 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;
}
//---------- EEPROM Dat Read -----------------------------------------
void eep_rdata(){
Vfo_Dat = eep_read4(Eep_Freq);
}
//---------- EEPROM Dat Write ----------------------------------------
void eep_wdata(){
eep_write4(Vfo_Dat,Eep_Freq);
}
//---------- EEPROM Initialization ------------------------------------
void eep_init(){
int i;
for (i=0;i<64;i++) // 0 clear(128byte)
EEPROM.write(i, 0);
eep_write4(FRQ_TBL[DEF_F],Eep_Freq);
EEPROM.write(Eep_Init,Int_End); // Init end set(73)
}
//---------- Function Encorder STEP ----------------------------------
void Fnc_Stp(){
if(Time_Passd+2000 < millis()){
Enc_Step = 10;
}
else{
if(Enc_Delay+6000 < millis()){
if(Enc_Velocity < 100) // chenge STEP?
Enc_Step = Enc_Step * 10;
if(Enc_Step > 10000) // 10kHz over?
Enc_Step = 10; // STEP = 10Hz
Enc_Delay = millis();
}
}
}
//---------- band chek -----------------------------------------------
void band_check(){
if((Vfo_Dat >= FRQ_TBL[LOW_F]) && (Vfo_Dat <= FRQ_TBL[MID_F])){
Flg_Mode = 0; // CW(0=CW, 1=LSB, 2=USB)
Bfo_Dat = CW;
Flg_Over = 0;
}
else if((Vfo_Dat >= FRQ_TBL[MID_F]) && (Vfo_Dat <= FRQ_TBL[HI_F])){
if(Vfo_Dat >= 10000000){ // greate than 10MHz
Flg_Mode = 2; // USB(0=CW, 1=LSB, 2=USB)
Bfo_Dat = USB;
}
else{
Flg_Mode = 1; // LSB(0=CW, 1=LSB, 2=USB)
Bfo_Dat = LSB;
}
Flg_Over = 0;
}
else{
Flg_Over = 1;
if(Vfo_Dat >= 10000000){ // greate than 10MHz
Flg_Mode = 2; // USB(0=CW, 1=LSB, 2=USB)
Bfo_Dat = USB;
}
else{
Flg_Mode = 1; // LSB(0=CW, 1=LSB, 2=USB)
Bfo_Dat = LSB;
}
}
}