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;
}
}
}
3/28大須懇親会は中止です。
返信削除what rotary library you are using in this sketch. i was trying in your download folder it doesnt work.
返信削除thank you very much for your help
73s de yb1ahy Agus
Hi yb1ahy.
返信削除Please use st7032_vfo.zip in the attiny85 folder of the download site. You have all the files you need.
JA2GQP san.
返信削除i am sorry, i couldnot get your name in your blog
I am almost done. All library i put in arduino\library outside that they cannot be compiled.
one other thing is EEPROM.h, would you mind to indicate which library i can use.
Thank you and appreciate for your help.
73s de YB1AHY. Agus.
To yb1ahy.
返信削除JA2GQP's Download site
https://sites.google.com/site/ja2gqp/
EEPROM.h is a library installed in Arduino IDE.
Hi JA2GQP
返信削除Thank you and I fix the EEPROM.h
But i got this:
Arduino: 1.8.12 (Windows 7), Board: "Digispark (Default - 16.5mhz)"
text section exceeds available space in board
Sketch uses 7788 bytes (129%) of program storage space. Maximum is 6012 bytes.
Global variables use 266 bytes of dynamic memory.
Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it.
Error compiling for board Digispark (Default - 16.5mhz).
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
any advis? Thank you for your time
73s de YB1AHY
To YB1AHY.
返信削除what.
It says that Digi Spark cannot be used. Please read the blog carefully. You can see that it is used as Attin85.
Sorry i missed your written. i ll try..thank you very much.
返信削除Hatzimemasite JA2GQP san.
返信削除Nice project. Would a SSD1306 OLED fit in Attiny85 memory space, or am I asking the impossible.
73 de Konstantinos, SV1ONW
I haven't checked the combination of Attiny85 and oled, but I think the memory capacity is insufficient.
返信削除Mosi mosi.
返信削除Domo arigato, for your very prompt response.
I also thought so.
But if I find some time, I may give it a try.
I like your functionality and your coding a lot.
Konstantinos.
I will check it
返信削除