無線ブログ集
メイン | 簡易ヘッドライン |
リンク 単体表示
jl7gmnのblog (2024/7/3 7:06:06)
現在データベースには 156 件のデータが登録されています。
JR-310プチレストアその3
(2023/3/23 0:56:24)
JR-310の使用している真空管でIF段の6BA6が2つ使われていたので、オークションで2つ落札準備しました。手持ちは古い6BA6なので、ひとまず測定済みでOKというものということで用意しました。6BD6も、6AU6も代用はできるようです。他第一局発のクリスタル発振用の6BL8
(1/2:3局管、
1/2:5極管)複合管は最初、手持ちになかったので、6U8(6U8A)が代替えで使えるという情報で使用していました。これもオークションで注文し、OK品ということで入手しました。他、高周波増幅用の6BZ6も手持ちは古いものなので、これもオークションで4本まとめて出てましたので、落札して準備しています。今日あたり届くと思います。当たりハズレがあるかもしれませが、数あるのでどれか使えればということです。Hi
!
6BZ6:オールバンドRF増幅
6BL8:1/2第一局部発振、1/2第一混合
6CB6:第2混合
6BA6:IF増幅1
6BA6:IF増幅2
6BM8:1/2低周波増幅、1/2電力増幅
今回は6BL8の1/2第一局部発振をArduinoNANOとDDS
ICのSI5351Aのクロックジェネレータモジュールで代用できるかということです。スケッチもおわり、実際のテスト接続を行って見ることにしました。最初はすでにOSC発振器でDDS
ICを想定して7MHzの12.955MHzをバリコンを通してJR-310の第一局発のクリスタル箇所につないで、前もって問題なく動作することは確認済みです。早速、実際のArduinoNANO-DDSの出力での確認です。
かなり線の引き回しが長いですが、DDSの出力(7MHz:12.955MHz)をつなぎました。
結果は、問題なくもとのOSCと全く同様に動作してくれました。波形も矩形波だったので心配でしたが、直接でも問題ないようです。ある程度LPFをつける予定ではいます。高調波でのイメージ受信とかが周波数によっては起きる可能性もありますから。送信で使用する場合はLPFは必須ですね。
昼のコンディションの悪い時ですが、DDS出力OSC接続で、何も問題なく受信できています。
まずは、DDSでの第一局発代替えはOKということです。他のバンドも問題ありませんでした。
つづく?
JR-310プチレストアその2
(2023/3/11 6:03:04)
////////////////////////////////
// Channel Frequency
////////////////////////////////
#define CH1_FRQ 7765000L // EXT:1.8MHz
#define CH2_FRQ 9455000L // 3.5MHz
#define CH3_FRQ 12955000L // 7.0MHz
#define CH4_FRQ 19955000L // 14.0MHz
#define CH5_FRQ 26955000L // 21.0MHz
#define CH6_FRQ 33955000L // 28.0MHz
#define CH7_FRQ 34455000L // 28.5MHz
#define CH8_FRQ 35055000L // 29.1MHz
#define CH9_FRQ 33955000L // 50.0MHz 28.0MHz
#define CH10_FRQ 34455000L // 50.5MHz 28.5MHz
#define CH11_FRQ 20955000L // 15.0MHz WWV JJY
////////////////////////////////
// etc
////////////////////////////////
#define CH1 1 // Channel 1: EXT 1.8MHz
#define CH2 2 // Channel 2: 3.5MHz
#define CH3 3 // Channel 3: 7.0MHz
#define CH4 4 // Channel 4:14.0MHz
#define CH5 5 // Channel 5:21.0MHz
#define CH6 6 // Channel 6:28.0MHz
#define CH7 7 // Channel 7:28.5MHz
#define CH8 8 // Channel 8:29.1MHz
#define CH9 9 // Channel 9:50.0MHz(28.0MHz)
#define CH10 10 // Channel 10:50.5MHz(28.5MHz)
#define CH11 11 // Channel 11:15.0MHz
#define MAX_CHN 11 // Max Channel 4
#define INT_END 73 // Initial end code
//#define IF_FRQ 10700000L // IF Frequency 10.7MHz
//#define IF_FRQ 455000L // IF Frequency 0.455MHz
#define IF_FRQ 0L // IF Frequency 0MHz
#define OLED_ADR 0x3C // OLED Address
//---------- EEPROM Memory Address -----------------------
#define EEP_INT 0x00 // Eep Init(1byte*1)
#define EEP_CHN 0x01 // Channel(1byte*1)
//---------- Memory Assign -------------------
unsigned long Vfo_Dat = 0; // VFO Data
unsigned long Vfo_Datb = 0; // old
unsigned long If_Dat;
unsigned long Frq_Dat; // Frequency Data
byte Byt_Chn = CH1; // Channel SW
byte Flg_Tx = 0; // TX Flag
byte Flg_Txb = 1; // old
unsigned int Val_SM = 0; // S-Meter Data
unsigned int Val_SMb = 0; // old
unsigned long awase = 0; //frequency [Hz]周波数補正 add 2023/march/10
//---------- Initialization Program ---------------
void setup(){
Serial.begin(9600);
si5351.init(SI5351_CRYSTAL_LOAD_8PF,0,0);//crystal 25.000 MHz, correction 0
si5351.drive_strength(SI5351_CLK0,SI5351_DRIVE_4MA);//Drive lebel 4mA set
oled.begin(&Adafruit128x32, OLED_ADR);
pinMode(SW_TX,INPUT_PULLUP); //A2
pinMode(SW_CH,INPUT_PULLUP); //A0
pinMode(SW_160,INPUT_PULLUP); //D12
pinMode(SW_80, INPUT_PULLUP); //D11
pinMode(SW_40, INPUT_PULLUP); //D10
pinMode(SW_20, INPUT_PULLUP); //D9
pinMode(SW_15, INPUT_PULLUP); //D8
pinMode(SW_101,INPUT_PULLUP); //D7
pinMode(SW_102,INPUT_PULLUP); //D6
pinMode(SW_103,INPUT_PULLUP); //D5
pinMode(SW_61, INPUT_PULLUP); //D4
pinMode(SW_62, INPUT_PULLUP); //D3
pinMode(SW_WWV,INPUT_PULLUP); //D2
if(EEPROM.read(EEP_INT) != INT_END){ // Eep initialaz
delay(10);
Eep_Init();
}
Byt_Chn = EEPROM.read(EEP_CHN); // Channel
CH_Set();
Disp_Comm1();
}
//---------- Main program ---------------
void loop() {
if(digitalRead(SW_TX) == HIGH){ // RX ?
if((digitalRead(SW_160) == LOW)){ // CH SW On?
Byt_Chn= CH1;
CH_Set();
}
if((digitalRead(SW_80) == LOW)){
Byt_Chn= CH2;
CH_Set();
}
if((digitalRead(SW_40) == LOW)){
Byt_Chn= CH3;
CH_Set();
}
if((digitalRead(SW_20) == LOW)){
Byt_Chn= CH4;
CH_Set();
}
if((digitalRead(SW_15) == LOW)){
Byt_Chn= CH5;
CH_Set();
}
if((digitalRead(SW_101) == LOW)){
Byt_Chn= CH6;
CH_Set();
}
if((digitalRead(SW_102) == LOW)){
Byt_Chn= CH7;
CH_Set();
}
if((digitalRead(SW_103) == LOW)){
Byt_Chn= CH8;
CH_Set();
}
if((digitalRead(SW_61) == LOW)){
Byt_Chn= CH9;
CH_Set();
}
if((digitalRead(SW_62) == LOW)){
Byt_Chn= CH10;
CH_Set();
}
if((digitalRead(SW_WWV) == LOW)){
Byt_Chn= CH11;
CH_Set();
}
Flg_Tx = 0;
If_Dat = IF_FRQ;
}
else{ // TX
Flg_Tx = 1; // Yes,TX Flag set
If_Dat = 0; // If_Dat 0 set
}
//Vfo_Dat = Frq_Dat + If_Dat;
Vfo_Dat = Frq_Dat + If_Dat + awase;
Serial.print("Frq_Dat = ");
Serial.println( Frq_Dat);
Serial.print("Vfo_Dat = ");
Serial.println( Vfo_Dat);
if(Vfo_Dat != Vfo_Datb){ // Frequency update?
si5351.set_freq(Vfo_Dat * SI5351_FREQ_MULT,SI5351_CLK0);
Vfo_Datb = Vfo_Dat;
}
if(Flg_Tx != Flg_Txb){
Disp_Comm1();
Flg_Txb = Flg_Tx;
}
Val_SM = analogRead(PIN_SM);
if ((abs(Val_SM - Val_SMb)) > 3) { // if needed draw S-meter
Disp_SM();
Val_SMb = Val_SM;
}
}
//---------- Channel Data Set & Display Frequency ---------
void CH_Set(){
oled.setFont(lcdnums14x24);
oled.setCursor(1, 0);
Serial.print("Byt_Chn = ");
Serial.println(Byt_Chn);
switch(Byt_Chn){
case CH11:
Frq_Dat = CH11_FRQ;
awase = 272;
oled.print("11:15.000");
break;
case CH10:
Frq_Dat = CH10_FRQ;
awase = 450;
oled.print("10:50.500");
break;
case CH9:
Frq_Dat = CH9_FRQ;
awase = 445;
oled.print("09:50.000");
break;
case CH8:
Frq_Dat = CH8_FRQ;
awase = 460;
oled.print("08:29.100");
break;
case CH7:
Frq_Dat = CH7_FRQ;
awase = 450;
oled.print("07:28.500");
break;
case CH6:
Frq_Dat = CH6_FRQ;
awase = 445;
oled.print("06:28.000");
break;
case CH5:
Frq_Dat = CH5_FRQ;
awase = 354;
oled.print("05:21.000");
break;
case CH4:
Frq_Dat = CH4_FRQ;
awase = 262;
oled.print("04:14.000");
break;
case CH3:
Frq_Dat = CH3_FRQ;
awase = 169;
oled.print("03:7.000");
break;
case CH2:
Frq_Dat = CH2_FRQ;
awase = 123;
oled.print("02:3.500");
break;
case CH1:
Frq_Dat = CH1_FRQ;
awase = 100;
oled.print("01:1.800");
break;
default:
break;
}
EEPROM.write(EEP_CHN,Byt_Chn);
}
//---------- Display Common1(TX/RX) ---------
void Disp_Comm1(){
oled.setCursor(2, 3);
oled.setFont(labels);
if(Flg_Tx == 1)
oled.print("2"); // "2" is "TX" in labels.h
else
oled.print("1"); // "1" is "RX" in labels.h
}
//---------- CH SW Check ----------------------
void CH_Switch(){
Byt_Chn++;
while(digitalRead(SW_CH) == LOW)
;
if(Byt_Chn > MAX_CHN)
Byt_Chn = CH1;
}
//---------- Display S-Meter -------------------
void Disp_SM() {
uint8_t a = 0;
uint8_t m = 0;
a = (Val_SM + 3) / 113; // 1024 / 9 characters for S = 1,3,5,7,8,9,+10,+20,+30
oled.setFont(pixels);
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
}
//---------- EEProm Initialization -----------------
void Eep_Init(){
EEPROM.write(EEP_INT,INT_END); // Init end set(73)
EEPROM.write(EEP_CHN,CH1); // Init end set(73)
}
JR−310の第一局発のDDS ICでの代用の各バンド毎での周波数の合わせ込み用のスケッチを追加しました。 awase値
で調整します。数ヘルツ程度のズレ補正追い込みが各バンド毎にできるようになります。使うDDS
IC毎に発振周波数は若干異なるのでそれぞれでの合わせ込みは必要です。Hi!
現時点での全スケッチになります。もとの仕様上送受信の切り替えSWポートA2がありますが、局発としては受信のみのモードでSW
”L”での送信時ルーチンは使いません。がスケッチはそのままです。特に問題はありません。前の仕様のCH切り替えのA0のSWのルーチンもしかり、スケッチはそのまま残してありますが、使っていません。Sメータの入力A7もそのまま残してあります。A0,A2,A7はSWとしては使いません。発振周波数設定時、メモリ記録し、電源オン時にレジューム機能するEEPROM機能はとても便利なので、そのまま使わさせてもらっています。
オリジナルのスケッチはJA2GQP OMの6m_ch_VFOになります。
私がJR−310用の局発用として修正または追加したスケッチのルーチンは緑色部になります。
シリアルモニタでの周波数設定値確認用のSerial.print文は残してあります。
■テスト中のブレッドボードArduinoNANOとDDS IC Si5351A
//////////////////////////////////////////////////////////////////////
// si5351a 6m AM VFO program ver.1.0
// Copyright(C)2019.JA2GQP.All rights reserved.
//
// 2019/3/19
// JA2GQP
//////////////////////////////////////////////////////////////////////
// 2023/march/09 for JR-310 1'ST OSC USE SI5315A DDS IC
// MODIFIED BY JL7GMN
//////////////////////////////////////////////////////////////////////
// si5351a 6m AM VFO program ver.1.0
// Copyright(C)2019.JA2GQP.All rights reserved.
//
// 2019/3/19
// JA2GQP
//////////////////////////////////////////////////////////////////////
// 2023/march/09 for JR-310 1'ST OSC USE SI5315A DDS IC
// MODIFIED BY JL7GMN
//////////////////////////////////////////////////////////////////////
#include "src/si5351.h" // https://github.com/etherkit/Si5351Arduino,
v2.1.0
#include "src/SSD1306AsciiAvrI2c.h" // https://github.com/greiman/SSD1306Ascii
#include <EEPROM.h>
//---------- Set I/O Device ---------------------
Si5351 si5351(0x60); // Si5351 I2C address
SSD1306AsciiAvrI2c oled;
//---------- Define Constant Value ----------
#define SW_CH A0 // CH SW
#define SW_TX A2 // TX SW
#define PIN_SM A7 // S-meter voltage input
#define SW_160 12 //D12 EXT:1.8MHz
#define SW_80 11 //D11 3.5MHz
#define SW_40 10 //D10 7.0MHz //#define SW_30 9 //10.0MHz
#define SW_20 9 //D9 14.0MHz //#define SW_17 7 //18.0MHz
#define SW_15 8 //D8 21.0MHz //#define SW_12 5 //24.5MHz
#define SW_101 7 //D7 28.0MHz
#define SW_102 6 //D6 28.5MHz
#define SW_103 5 //D5 29.1MHz
#define SW_61 4 //D4 50.0MHz 28.0MHz
#define SW_62 3 //D3 50.5MHz 28.5MHz
#define SW_WWV 2 //D2 15.0MHz WWV JJY
#include "src/SSD1306AsciiAvrI2c.h" // https://github.com/greiman/SSD1306Ascii
#include <EEPROM.h>
//---------- Set I/O Device ---------------------
Si5351 si5351(0x60); // Si5351 I2C address
SSD1306AsciiAvrI2c oled;
//---------- Define Constant Value ----------
#define SW_CH A0 // CH SW
#define SW_TX A2 // TX SW
#define PIN_SM A7 // S-meter voltage input
#define SW_160 12 //D12 EXT:1.8MHz
#define SW_80 11 //D11 3.5MHz
#define SW_40 10 //D10 7.0MHz //#define SW_30 9 //10.0MHz
#define SW_20 9 //D9 14.0MHz //#define SW_17 7 //18.0MHz
#define SW_15 8 //D8 21.0MHz //#define SW_12 5 //24.5MHz
#define SW_101 7 //D7 28.0MHz
#define SW_102 6 //D6 28.5MHz
#define SW_103 5 //D5 29.1MHz
#define SW_61 4 //D4 50.0MHz 28.0MHz
#define SW_62 3 //D3 50.5MHz 28.5MHz
#define SW_WWV 2 //D2 15.0MHz WWV JJY
////////////////////////////////
// Channel Frequency
////////////////////////////////
#define CH1_FRQ 7765000L // EXT:1.8MHz
#define CH2_FRQ 9455000L // 3.5MHz
#define CH3_FRQ 12955000L // 7.0MHz
#define CH4_FRQ 19955000L // 14.0MHz
#define CH5_FRQ 26955000L // 21.0MHz
#define CH6_FRQ 33955000L // 28.0MHz
#define CH7_FRQ 34455000L // 28.5MHz
#define CH8_FRQ 35055000L // 29.1MHz
#define CH9_FRQ 33955000L // 50.0MHz 28.0MHz
#define CH10_FRQ 34455000L // 50.5MHz 28.5MHz
#define CH11_FRQ 20955000L // 15.0MHz WWV JJY
////////////////////////////////
// etc
////////////////////////////////
#define CH1 1 // Channel 1: EXT 1.8MHz
#define CH2 2 // Channel 2: 3.5MHz
#define CH3 3 // Channel 3: 7.0MHz
#define CH4 4 // Channel 4:14.0MHz
#define CH5 5 // Channel 5:21.0MHz
#define CH6 6 // Channel 6:28.0MHz
#define CH7 7 // Channel 7:28.5MHz
#define CH8 8 // Channel 8:29.1MHz
#define CH9 9 // Channel 9:50.0MHz(28.0MHz)
#define CH10 10 // Channel 10:50.5MHz(28.5MHz)
#define CH11 11 // Channel 11:15.0MHz
#define MAX_CHN 11 // Max Channel 4
#define INT_END 73 // Initial end code
//#define IF_FRQ 10700000L // IF Frequency 10.7MHz
//#define IF_FRQ 455000L // IF Frequency 0.455MHz
#define IF_FRQ 0L // IF Frequency 0MHz
#define OLED_ADR 0x3C // OLED Address
//---------- EEPROM Memory Address -----------------------
#define EEP_INT 0x00 // Eep Init(1byte*1)
#define EEP_CHN 0x01 // Channel(1byte*1)
//---------- Memory Assign -------------------
unsigned long Vfo_Dat = 0; // VFO Data
unsigned long Vfo_Datb = 0; // old
unsigned long If_Dat;
unsigned long Frq_Dat; // Frequency Data
byte Byt_Chn = CH1; // Channel SW
byte Flg_Tx = 0; // TX Flag
byte Flg_Txb = 1; // old
unsigned int Val_SM = 0; // S-Meter Data
unsigned int Val_SMb = 0; // old
unsigned long awase = 0; //frequency [Hz]周波数補正 add 2023/march/10
//---------- Initialization Program ---------------
void setup(){
Serial.begin(9600);
si5351.init(SI5351_CRYSTAL_LOAD_8PF,0,0);//crystal 25.000 MHz, correction 0
si5351.drive_strength(SI5351_CLK0,SI5351_DRIVE_4MA);//Drive lebel 4mA set
oled.begin(&Adafruit128x32, OLED_ADR);
pinMode(SW_TX,INPUT_PULLUP); //A2
pinMode(SW_CH,INPUT_PULLUP); //A0
pinMode(SW_160,INPUT_PULLUP); //D12
pinMode(SW_80, INPUT_PULLUP); //D11
pinMode(SW_40, INPUT_PULLUP); //D10
pinMode(SW_20, INPUT_PULLUP); //D9
pinMode(SW_15, INPUT_PULLUP); //D8
pinMode(SW_101,INPUT_PULLUP); //D7
pinMode(SW_102,INPUT_PULLUP); //D6
pinMode(SW_103,INPUT_PULLUP); //D5
pinMode(SW_61, INPUT_PULLUP); //D4
pinMode(SW_62, INPUT_PULLUP); //D3
pinMode(SW_WWV,INPUT_PULLUP); //D2
if(EEPROM.read(EEP_INT) != INT_END){ // Eep initialaz
delay(10);
Eep_Init();
}
Byt_Chn = EEPROM.read(EEP_CHN); // Channel
CH_Set();
Disp_Comm1();
}
//---------- Main program ---------------
void loop() {
if(digitalRead(SW_TX) == HIGH){ // RX ?
if((digitalRead(SW_160) == LOW)){ // CH SW On?
Byt_Chn= CH1;
CH_Set();
}
if((digitalRead(SW_80) == LOW)){
Byt_Chn= CH2;
CH_Set();
}
if((digitalRead(SW_40) == LOW)){
Byt_Chn= CH3;
CH_Set();
}
if((digitalRead(SW_20) == LOW)){
Byt_Chn= CH4;
CH_Set();
}
if((digitalRead(SW_15) == LOW)){
Byt_Chn= CH5;
CH_Set();
}
if((digitalRead(SW_101) == LOW)){
Byt_Chn= CH6;
CH_Set();
}
if((digitalRead(SW_102) == LOW)){
Byt_Chn= CH7;
CH_Set();
}
if((digitalRead(SW_103) == LOW)){
Byt_Chn= CH8;
CH_Set();
}
if((digitalRead(SW_61) == LOW)){
Byt_Chn= CH9;
CH_Set();
}
if((digitalRead(SW_62) == LOW)){
Byt_Chn= CH10;
CH_Set();
}
if((digitalRead(SW_WWV) == LOW)){
Byt_Chn= CH11;
CH_Set();
}
Flg_Tx = 0;
If_Dat = IF_FRQ;
}
else{ // TX
Flg_Tx = 1; // Yes,TX Flag set
If_Dat = 0; // If_Dat 0 set
}
//Vfo_Dat = Frq_Dat + If_Dat;
Vfo_Dat = Frq_Dat + If_Dat + awase;
Serial.print("Frq_Dat = ");
Serial.println( Frq_Dat);
Serial.print("Vfo_Dat = ");
Serial.println( Vfo_Dat);
if(Vfo_Dat != Vfo_Datb){ // Frequency update?
si5351.set_freq(Vfo_Dat * SI5351_FREQ_MULT,SI5351_CLK0);
Vfo_Datb = Vfo_Dat;
}
if(Flg_Tx != Flg_Txb){
Disp_Comm1();
Flg_Txb = Flg_Tx;
}
Val_SM = analogRead(PIN_SM);
if ((abs(Val_SM - Val_SMb)) > 3) { // if needed draw S-meter
Disp_SM();
Val_SMb = Val_SM;
}
}
//---------- Channel Data Set & Display Frequency ---------
void CH_Set(){
oled.setFont(lcdnums14x24);
oled.setCursor(1, 0);
Serial.print("Byt_Chn = ");
Serial.println(Byt_Chn);
switch(Byt_Chn){
case CH11:
Frq_Dat = CH11_FRQ;
awase = 272;
oled.print("11:15.000");
break;
case CH10:
Frq_Dat = CH10_FRQ;
awase = 450;
oled.print("10:50.500");
break;
case CH9:
Frq_Dat = CH9_FRQ;
awase = 445;
oled.print("09:50.000");
break;
case CH8:
Frq_Dat = CH8_FRQ;
awase = 460;
oled.print("08:29.100");
break;
case CH7:
Frq_Dat = CH7_FRQ;
awase = 450;
oled.print("07:28.500");
break;
case CH6:
Frq_Dat = CH6_FRQ;
awase = 445;
oled.print("06:28.000");
break;
case CH5:
Frq_Dat = CH5_FRQ;
awase = 354;
oled.print("05:21.000");
break;
case CH4:
Frq_Dat = CH4_FRQ;
awase = 262;
oled.print("04:14.000");
break;
case CH3:
Frq_Dat = CH3_FRQ;
awase = 169;
oled.print("03:7.000");
break;
case CH2:
Frq_Dat = CH2_FRQ;
awase = 123;
oled.print("02:3.500");
break;
case CH1:
Frq_Dat = CH1_FRQ;
awase = 100;
oled.print("01:1.800");
break;
default:
break;
}
EEPROM.write(EEP_CHN,Byt_Chn);
}
//---------- Display Common1(TX/RX) ---------
void Disp_Comm1(){
oled.setCursor(2, 3);
oled.setFont(labels);
if(Flg_Tx == 1)
oled.print("2"); // "2" is "TX" in labels.h
else
oled.print("1"); // "1" is "RX" in labels.h
}
//---------- CH SW Check ----------------------
void CH_Switch(){
Byt_Chn++;
while(digitalRead(SW_CH) == LOW)
;
if(Byt_Chn > MAX_CHN)
Byt_Chn = CH1;
}
//---------- Display S-Meter -------------------
void Disp_SM() {
uint8_t a = 0;
uint8_t m = 0;
a = (Val_SM + 3) / 113; // 1024 / 9 characters for S = 1,3,5,7,8,9,+10,+20,+30
oled.setFont(pixels);
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
}
//---------- EEProm Initialization -----------------
void Eep_Init(){
EEPROM.write(EEP_INT,INT_END); // Init end set(73)
EEPROM.write(EEP_CHN,CH1); // Init end set(73)
}
上記で全バンドの局発信号に対応できました。
【JR-310でのバンドSWへの接続方法】
バンド入力ポートのD2からD12はJR−310のクリスタルがついていたロータリーSWに接続します。局発の真空管6BL8のグリッドからロータリーSWコモン端子接続は切り離します。そしてロータリーSWコモンはGNDにつなぎます。D2からD12はプルアップの入力ポートですので、ロータリーSWを回し設定したときにArduinoNANOのバンドの入力ポート(バンド周波数に対応したD2からD12のどれか)が”H”から”L”となり設定バンドの局発周波数が発振設定されます。
DDSの出力波形を見てると完全な正弦波でないので、バッファー兼LPFも必要と思っています。が、一旦、直接現状このままで、JR−310でつないでみてどうかも確認したいと思います。
先週、Ubuntu
18.04LTSが起動しなくなってしまいました。サポート期限が2023年4月までです。なので起動しなくなったついで、このDeskTopPCで対応できるUbuntu20.04LTSを急遽インストールしています。20.04LTSはサポート期限が2025年4月まであるので、2年間は大丈夫です。22.04LTSはサポート期限は2027年4月までですが、PCが対応すれば入れたいところですが、Vistaですので無理があります。Hi!
20.04LTSは問題なく動いてくれます。
20.04LTSをインストールしましたが、18.04LTSで使用していたアプリの再度設定が必要な状態となっています。Arduino
IDEは第一優先で設定し動作させました。WindosXP時代対応のプリンターは現在確認したところメーカーでもLinux用のドライバを用意してくれてあったため、問題なくインストールできました。順次20.04LTSにて18.04LTSで動いていたアプリを動作するように設定をし直さなければなりません。20.04LTSではそのままで18.04LTSのアプリはうごきませんでした。各アプリの階層設定を含め少し手間が掛かりそうです。トラブルでどんどんやることが増えてばかりで、目的のことがやれないでいます。18.04LTSで動いていた便利なアプリは、操作も使い込んでなれていますから、なんとか動かしたいと思います。!
つづく?
JR-310プチレストアその1
(2023/3/9 4:01:55)
以前、使ったことがあるセパレートタイプのJR-310、TX-310の送受信機をオークションで格安で手に入れることができました。真空管は全部ないということでしたが、手持ちに代替えを含めありますので、本来の真空管とは異なりますが、ひとまず確認用ということで、真空管を全部取り付けました。電源は問題なく入ります。ただ、前のオーナーもレストアを少し行っていた形跡がありましたが、動作はしない状態です。回路図を用意し、少しチェックをしてみることにしました。
バンドで高周波の増幅はある程度しているようで、受信周波数はまだわかりませんが、高周波増幅回路での同調時ノイズが聞こえました。実際のアンテナをつないで、7MHzの交信が聞こえるか見てみました。周波数はかなりずれていましたが、強力な局の信号は聞こえました。同調ノイズは調整してないため、アマチュア無線のバンドは聞こえました。が、調整が必要な状態です。周波数が数十キロヘルツずれています。バンドノイズがする周波数帯としない周波数帯がありました。全バンドの第一局初の発振をオシロスコープで見てみました。生きているのは3.5MHzと7MHzだけでした。他のバンドは局発が発振していません。クリスタルがダメになってるようです。また、7MHzの局発の周波数は12.955MHzですが、交換したらしく、別の周波数(12.88417MHz)のクリスタルがついていました。クリスタルの周波数が違っていたため、差し引き約+70KHzほどのズレは局発のクリスタルが原因とわかりました。ネットでもレストア情報を見るとこの機種はやはり局初のクリスタルがダメになっていたという情報がありました。
測定器OSCで局発の周波数12.955MHzを5Vp-pで発振させバリコンを通してミキサにつないで7MHzの周波数とダイアルが一致してるかも含めて受信動作を確認してみました。もとのクリスタルの真空管での発振レベルはかなり電圧がありましたが測定器OSCからの5Vp-pでも3Vp-pでも受信レベルには変化はなく、問題なく受信できています。低出力レベルのOSC出力でも使えそうです。
素直には、クリスタルを注文するのが順当ですが、全部のクリスタルを注文すると金額が万超えです。なので今回はDDS
ICで局発を代用することを考えることにしました。DDS IC
のSi5351Aクロックジェネレータモジュールを使うことにしました。TS-820のDDSで使用実績がありましたのでこれにしました。DDS
ICを今回は小型のArduinoNANOを使うことにしました。JR-310に組み入れるにも小型で適していると思います。参考にした回路はJA2GQP OM局のホームページの6mAM
VFOをもとに行いました。
OMの仕様ではプッシュボタンを押すごとにバンドがインクリメントアップして周波数が変わる仕様です。また、受信器のSメータもついています。今回は局発用の発振のみなのでSメータ入力は使いません。
私は他のI/O端子を検出して周波数を発振するように仕様変更しています。
ArduinoNANOの使用できるI/Oもバンド数分用意できますので、今回のような各バンド局発用にうってつけです。
WARCバンドはありませんが、拡張する方法を考えればできそうです。
今回はWARCバンド拡張は考えないで、もとと同じJR-310のオリジナル周波数仕様にて作成します。
バンド検出用入力は下記のポートを使いました。
D2:15MHz WWV
D3:50.5MHz(28.5MHz)
D4:50.0MHz(28.0MHz)
D5:29.1MHz
D6:28.5MHz
D7:28.0MHz
D8:21.0MHz
D9:14.0MHz
D10:7.0MHz
D11:3.5MHz
D12:EXT (1.8MHz)
上記のI/O端子はプルアップをスケッチ上で指定していますが、電圧が低かったので外付け抵抗で3.3VにPULLUPしています。
IF周波数のヘテロダインも仕様上ありますが、今回はヘテロダインIF機能は不要なので0MHz
です。また、OMの使用したDDS ICユニットとは異なる秋月電子のDDS IC
Si5351Aを使いました。、基本接続は同じです。端子のハンダ付は必要ですが、ユニットとしては8PのICと同じなのでとても扱いやすいです。今現在新しい仕様に合わせてスケッチを検討し、コーディングしています。JR-310のバンドSWをそのまま使うことで考えています。ほぼ問題ないレベルまで手動動作確認できています。作成時の確認で局発の周波数でも、バンド周波数でもOLED128X32で表示させることで、出力と合わせて実験もスムースに行えています。あとは若干の周波数のズレ補正スケッチを追加して行けば、ジャスト周波数の局発になります。
古くて、大きな筐体はかなりの改造でも組み入れることができるので、十分楽しめます。やはり真空管の受信器はぬくもりがあってとてもいいです。
つづく?
愛知タワー風速値表示追加その6
(2023/2/2 3:13:45)
ArduinoNano での1.8inch
TFT液晶表示も問題ないことより、ESP32DevKitCの使用と並行してデコード部の機能だけをArduinoNANOでデコード部回路をブレッドボードで作製しました。そして仮の風速パルス源として実験装置のOSC信号を使ってた風速カウント値を1.8inch
TFT液晶に表示出来ました。色々とOSCの周波数を変えカウントのデコード表示を確認していると気になる事がありました。前回も書きましたが、現状の入力値に対しての表示部との時間関係で周波数が上がった時(風速が早くなった時)に0から順番に表示されず、数値が飛んでしまう現象があります。
対策は原因に合わせて対策を取る必要があります。原因としては風速の値の大小にて表示のゲートタイミングがいつも同じことによるものです。さすれば、風速の値の大小にてゲートタイミング(ディレータイム)を変えればよいということです。具体的には、色々と方法が考えられますが、方法の1つとしてはデコード値の値のある区間毎にて適切なディレータイムを設定する事です。ただし0から127の区間の分け方とディレータイムをどれぐらいに設定するかの各区間での確認が必要です。しかもスケッチは区間設定した分の追加となります。区間を2,3適当に設定し実験してみましたが、少しカット&トライがひつような感じで時間がかかりそうでしたので、もう少し別の方法を考えることにしました。
その方法とは、風速で変わるバイナリーのB0ポートを使い低い周波数の周波数を読み取りして、周波数の範囲を適当に設定しディレータイムを設定する方法です。これをやるには周波数カウンターをArduinoNanoに新たに組み込む必要があります。タイミング的に周波数カウンターをいろいろと実験していましたので、その情報の中の低周波用カウンターをArduino系で実現していた情報にて試してみました。バイナリーのデコード処理だけで現状動作していますので残りの空きポートが使用出来るかの確認です。やはりポートのバッティングがありデコード入力の入れ替えが必要でした。入れ替えを行ない動作確認を行ないました。(低周波カウンターは割り込みを使う方式で、ArduinoNano
で使用できる割り込みPORTはD2かD3の2つのどちらかです。バイナリーの入力のD2がバッティングしていましたので、B0バイナリー入力を(A1)D15
に変更し、D2をカウンターの割り込みで使っています。D2(カウンター入力)とD15(B0バイナリー入力)はつなぐことになります。)
カウンターを使うので周波数区間を分ける必要がありましたが区間3つで表示も問題なく十分な抜けのないカウント動作をさせる事が出来ています。ディレータイムも1箇所の設定で出来るので簡単です。
デコード処理もカウンターも上手く動作し組み入れることが出来ました。低周波数カウンター組込で参照したGitHub情報は下記になります。
ArduinoNano でデコード部に低周波カウンターを組み込んだ回路図を纏めました。
回路図上でのカウンターの追加は、D2ポートの追加とD2ポートバッティングによるB0バイナリー入力ポートをD15ポートへ変更のみです。
仮のパルス源のOSC周波数を色々と変え、ゆらぎの風に見立ててカウント値を確認しましたが、カウントが抜ける様な表示はありませんでした。低周波数カウンターは変化のある風速値を十分検出しカウント表示をしてくれています。
カウンター組込スケッチ追加部とバッティングによる変更スケッチ部です。
【定義部】
//------------------------------------------
#include "HzMeter_asukiaaa.hpp"
//------------------------------------------
#include "HzMeter_asukiaaa.hpp"
//------------------------------------------
#define WIND0 15 //D2 binary
1 (0,1)change D15
//---------------------------------------------------------------
#define PIN_INTERRUPT_HZ_METER 2
#if digitalPinToInterrupt(PIN_INTERRUPT_HZ_METER) < 0
#error needed to assign interrupt pin for PIN_INTERRUPT_HZ_METER
#endif
#define HISTORY_LENGTH 15
HzMeter_asukiaaa::Core hzMeter(HISTORY_LENGTH);
//---------------------------------------------------------------
#define PIN_INTERRUPT_HZ_METER 2
#if digitalPinToInterrupt(PIN_INTERRUPT_HZ_METER) < 0
#error needed to assign interrupt pin for PIN_INTERRUPT_HZ_METER
#endif
#define HISTORY_LENGTH 15
HzMeter_asukiaaa::Core hzMeter(HISTORY_LENGTH);
//---------------------------------------------------------------
int16_t dljikan;
//for frequency counter
int pinLed = 15;//3
int LED_Stat = 1;
unsigned long frq;
//for frequency counter
int pinLed = 15;//3
int LED_Stat = 1;
unsigned long frq;
【setup部】
void setup(void) {
Serial.begin(115200);
//-----------------------------------------------------
hzMeter.begin();
pinMode(PIN_INTERRUPT_HZ_METER, INPUT_PULLUP);
attachInterrupt(
digitalPinToInterrupt(PIN_INTERRUPT_HZ_METER),
[]() { hzMeter.countUp(); }, RISING);
//-----------------------------------------------------
pinMode(pinLed,OUTPUT);
Serial.begin(115200);
//-----------------------------------------------------
hzMeter.begin();
pinMode(PIN_INTERRUPT_HZ_METER, INPUT_PULLUP);
attachInterrupt(
digitalPinToInterrupt(PIN_INTERRUPT_HZ_METER),
[]() { hzMeter.countUp(); }, RISING);
//-----------------------------------------------------
pinMode(pinLed,OUTPUT);
【void loop()部】
void loop() {
//-----------------------------------------------------
hzMeter.onInterval();
auto countInfo = hzMeter.getInfoBundled();
Serial.print(countInfo.calcHzByFirstAndLast());
Serial.print("Hz from ");
Serial.print(countInfo.measuredFrom);
Serial.print(" to ");
Serial.println(countInfo.measuredTill);
if(countInfo.calcHzByFirstAndLast()<= 0.80)
{
dljikan = 1000;
}
else
{
if(countInfo.calcHzByFirstAndLast()<= 1.50)
{
dljikan = 500;
}
}
if(countInfo.calcHzByFirstAndLast()<= 1.80)
{
dljikan = 200;
}
else
{
dljikan = 100;
}
//-----------------------------------------------------
hzMeter.onInterval();
auto countInfo = hzMeter.getInfoBundled();
Serial.print(countInfo.calcHzByFirstAndLast());
Serial.print("Hz from ");
Serial.print(countInfo.measuredFrom);
Serial.print(" to ");
Serial.println(countInfo.measuredTill);
if(countInfo.calcHzByFirstAndLast()<= 0.80)
{
dljikan = 1000;
}
else
{
if(countInfo.calcHzByFirstAndLast()<= 1.50)
{
dljikan = 500;
}
}
if(countInfo.calcHzByFirstAndLast()<= 1.80)
{
dljikan = 200;
}
else
{
dljikan = 100;
}
//-----------------------------------------------------
〜
省略
〜
sprintf(ce,"%3d",windvalue);
tft.fillScreen(ST77XX_BLACK);
tft.setCursor( 50, 50 );
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize( 5 );//10
tft.println(ce);
delay(dljikan);
}
tft.fillScreen(ST77XX_BLACK);
tft.setCursor( 50, 50 );
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize( 5 );//10
tft.println(ce);
delay(dljikan);
}
液晶の表示も縦置きから横置きにし風速値のみ表示する様に余分な表示は消しました。
ひとまず表示だけでのArduinoNANOの試作は完成ということにします。後は実際のカウンターにつないでの最終確認がありますが後にします。
次は、元の軌道に戻り、ESP32DevKitCでのデコード表示にとりかかります。
つづく?
愛知タワー風速値表示追加その5
(2023/1/31 6:19:43)
・シリアルボーレートの変更(9600 → 115200
)
tft.setTextColor(ST7735_YELLOW);
tft.setCursor (30, 95);
//tft.print(windvalue);
//tft.print ("038");
sprintf(ce,"%3d",windvalue);
tft.print(ce);
delay(150);
tft.setTextSize(4);
tft.setCursor(30,95);
tft.setTextColor(ST7735_BLACK);
tft.print(ce);
//tft.print(" ");
delay(10);
}
ArduinoNanoでTFT液晶表示のスケルトンまでできたので、実際に7ビットのポート入力のデコード部をスケッチしました。スケッチはオリジナルのwebスケッチに下記のデコードの部分を付け足しています。
オリジナルからの変更追加箇所です。
・TFT液晶display
の表記とRSTポートの変更D8→D15(D2〜D8)を連続で並べる為の変更)
#define TFT_SCLK 13
#define TFT_MLSI 11
#define TFT_CS 10
#define TFT_DC 9
//#define TFT_RST 8
#define TFT_RST 14
#define TFT_MLSI 11
#define TFT_CS 10
#define TFT_DC 9
//#define TFT_RST 8
#define TFT_RST 14
int16_t windvalue;
char ce[6];
char ce[6];
ポート定義部追加
#define WIND0 2 //D2 binary 1 (0,1)
#define WIND1 3 //D3 binary 2 (0,1)
#define WIND2 4 //D4 binary 4 (0,1)
#define WIND3 5 //D5 binary 8 (0,1)
#define WIND4 6 //D6 binary 16 (0,1)
#define WIND5 7 //D7 binary 32 (0,1)
#define WIND6 8 //D8 binary 64 (0,1)
#define WIND1 3 //D3 binary 2 (0,1)
#define WIND2 4 //D4 binary 4 (0,1)
#define WIND3 5 //D5 binary 8 (0,1)
#define WIND4 6 //D6 binary 16 (0,1)
#define WIND5 7 //D7 binary 32 (0,1)
#define WIND6 8 //D8 binary 64 (0,1)
void setup(void) {
Serial.begin( 115200 );
Serial.begin( 115200 );
pinMode(pinLed,OUTPUT);
/ /Port D2-D8 input setting (0-127)
pinMode(WIND0, INPUT); //D2 Port normally LOW
pinMode(WIND1, INPUT); //D3 Port normally LOW
pinMode(WIND2, INPUT); //D4 Port normally LOW
pinMode(WIND3, INPUT); //D5 Port normally LOW
pinMode(WIND4, INPUT); //D6 Port normally LOW
pinMode(WIND5, INPUT); //D7 Port normally LOW
pinMode(WIND6, INPUT); //D8 Port normally LOW
〜
pinMode(WIND0, INPUT); //D2 Port normally LOW
pinMode(WIND1, INPUT); //D3 Port normally LOW
pinMode(WIND2, INPUT); //D4 Port normally LOW
pinMode(WIND3, INPUT); //D5 Port normally LOW
pinMode(WIND4, INPUT); //D6 Port normally LOW
pinMode(WIND5, INPUT); //D7 Port normally LOW
pinMode(WIND6, INPUT); //D8 Port normally LOW
〜
省略
}
void loop() {
// put your main code here, to
run repeatedly:
if(((((((digitalRead(WIND0)==LOW)
and(digitalRead(WIND1)==LOW)
and(digitalRead(WIND2)==LOW)
and(digitalRead(WIND3)==LOW)
and(digitalRead(WIND4)==LOW)
and(digitalRead(WIND5)==LOW)
and(digitalRead(WIND6)==LOW)))))))
{
windvalue = 0;
}
else
{
if(((((((digitalRead(WIND0)==HIGH)
and(digitalRead(WIND1)==LOW)
and(digitalRead(WIND2)==LOW)
and(digitalRead(WIND3)==LOW)
and(digitalRead(WIND4)==LOW)
and(digitalRead(WIND5)==LOW)
and(digitalRead(WIND6)==LOW)))))))
{
windvalue = 1;
}
}
if(((((((digitalRead(WIND0)==LOW)
and(digitalRead(WIND1)==HIGH)
and(digitalRead(WIND2)==LOW)
and(digitalRead(WIND3)==LOW)
and(digitalRead(WIND4)==LOW)
and(digitalRead(WIND5)==LOW)
and(digitalRead(WIND6)==LOW)))))))
{
windvalue = 2;
}
if(((((((digitalRead(WIND0)==LOW)
and(digitalRead(WIND1)==LOW)
and(digitalRead(WIND2)==LOW)
and(digitalRead(WIND3)==LOW)
and(digitalRead(WIND4)==LOW)
and(digitalRead(WIND5)==LOW)
and(digitalRead(WIND6)==LOW)))))))
{
windvalue = 0;
}
else
{
if(((((((digitalRead(WIND0)==HIGH)
and(digitalRead(WIND1)==LOW)
and(digitalRead(WIND2)==LOW)
and(digitalRead(WIND3)==LOW)
and(digitalRead(WIND4)==LOW)
and(digitalRead(WIND5)==LOW)
and(digitalRead(WIND6)==LOW)))))))
{
windvalue = 1;
}
}
if(((((((digitalRead(WIND0)==LOW)
and(digitalRead(WIND1)==HIGH)
and(digitalRead(WIND2)==LOW)
and(digitalRead(WIND3)==LOW)
and(digitalRead(WIND4)==LOW)
and(digitalRead(WIND5)==LOW)
and(digitalRead(WIND6)==LOW)))))))
{
windvalue = 2;
}
〜
省略(延々とwindvalue=127まで同じスケッチでLOW,HIGH設定)
〜
tft.setTextColor(ST7735_YELLOW);
tft.setCursor (30, 95);
//tft.print(windvalue);
//tft.print ("038");
sprintf(ce,"%3d",windvalue);
tft.print(ce);
delay(150);
tft.setTextSize(4);
tft.setCursor(30,95);
tft.setTextColor(ST7735_BLACK);
tft.print(ce);
//tft.print(" ");
delay(10);
}
■デコード部詳細
バイナリー出力を受ける入力ポート(D0〜D8)のデコード部は0〜127までのカウンタ出力の瞬間値7ビット入力値を判断し表示用カウント変数のwindvalueにカウンタ値のデコード値を入れるスケッチです。
■TFT液晶Display表示部詳細
フォント色を黄色、サイズ4に設定しchar変数ce
をsprintf書式で3桁の数値の右詰めでtft.setCursorでの設定位置にデコードカウント値を表示します。表示後は時間をおいて、フォント色、黒色、サイズ4で同じ位置に再度ceを上書きして表示を消しています。これをしないと文字が残りどんどん重なり黄色の■になります。
実際のカウントデコード値表示動画
カウント値が上がっていくLED発光ダイオードとTFT液晶Displayのカウント表示です。
入力信号D2ポート波形
単に入力ポートに信号が来てるかの確認の為、撮ったものです。
カウンタでの信号パルス(OSCからの信号)でスケルトンで作製しTFT液晶に仮表示してた”038"固定数値をバイナリーデコード値に変えて表示することができました。
表示までは上手くこぎつけましたが、若干気になっている事があります。
現状の入力値に対しての表示部との時間関係で周波数が上がった時(風速が早くなった時)に0から順番に表示されず、数値が飛んでしまう現象があります。時間のデレー設定が固定なので、全部の風速スピードで表示出来るタイミングでない事によるものです。
次の画像の表示に変更して対策を行なっています。どのように対応を検討してるかは次回に!
つづく?
愛知タワー風速値表示追加その4
(2023/1/28 5:17:50)
風速バイナリーデータ7ビット分のポートを割り当てて、デコードスケッチをコーディングですが、まずはArduinoNanoの端子情報を準備しました。1.8inch TFT液晶Displayで使ったポート以外から使用できる7ポート分を選びます。
風速値表示ユニットからの信号線をCMOS IC 4024
バイナリーリップルカウンタでカウント値をバイナリーに変換した出力7ビットをデコードし表示する1.8inch
TFT液晶を使いたかった為、CPUとしてESP32DevKitCを予定して回路図を作製しました。ただ表示だけなら小型のArduinoNANOでもいいのではと思い、並行して1.8inch
TFT液晶ディスプレーを繫いでの表示が上手く出来るか確認してみることにしました。ネット情報を探ると結構Arduino系でのTFT液晶ディスプレーの表示は可能の様です。ArduinoNANOを使った1.8inch
TFT液晶ディスプレーのサンプルがありました。
動作確認した所、色の設定が上手くありません。スケッチを最初コピペした所、液晶表時上の文字化けがありましたが、スケッチを一端消キーボードから打ち直しでOKとなりました。また、位置ずれもあり、直接ライブラリの書き換えで対応出来る情報より変更対応して位置ずれも治りました。
■位置ずれ修正
ライブラリはAdafruit_ST7735_and_ST7789_Library
で、その中のAdafruit_ST7735.cpp ファイルの下記2箇所です。
void Adafruit_ST7735::initR(uint8_t options) {
commonInit(Rcmd1);
if (options == INITR_GREENTAB) {
displayInit(Rcmd2green);
_colstart = 0;//2->0
_rowstart = 0;//1->0
} else if ((options == INITR_144GREENTAB) || (options == INITR_HALLOWING)) {
commonInit(Rcmd1);
if (options == INITR_GREENTAB) {
displayInit(Rcmd2green);
_colstart = 0;//2->0
_rowstart = 0;//1->0
} else if ((options == INITR_144GREENTAB) || (options == INITR_HALLOWING)) {
■色修正
他、RGBカラーでなくBGRカラーの為、数カ所色の入れ替わりとオレンジ色が出ない事象もありました。入れ替わりは単に適当なカラー設定値で何回か直接色を設定し目的の色になった事を確認した上で、直接Adafruit_ST77xx.h
ファイルを書き換え手直しし、設定カラー通りに色表示できるようにしました。
// Some ready-made 16-bit
('565') color settings:
#define ST77XX_BLACK 0x0000 //OK
#define ST77XX_WHITE 0xFFFF //OK
#define ST77XX_RED 0x001F //ORIGIN BLUE:0xF800
#define ST77XX_GREEN 0x07E0 // LIME
#define ST77XX_BLUE 0xF800 //ORIGIN RED:0x001F
#define ST77XX_CYAN 0xFFE0 //ORIGIN YELLOW:0x07FF
#define ST77XX_MAGENTA 0xF81F //OK
#define ST77XX_YELLOW 0x07FF //ORIGIN CYAN:0xFFE0
#define ST77XX_ORANGE 0x0BFF //SET MAKE 0x0BFF ORANGE ORIGIN 0xFC00
#define ST77XX_BLACK 0x0000 //OK
#define ST77XX_WHITE 0xFFFF //OK
#define ST77XX_RED 0x001F //ORIGIN BLUE:0xF800
#define ST77XX_GREEN 0x07E0 // LIME
#define ST77XX_BLUE 0xF800 //ORIGIN RED:0x001F
#define ST77XX_CYAN 0xFFE0 //ORIGIN YELLOW:0x07FF
#define ST77XX_MAGENTA 0xF81F //OK
#define ST77XX_YELLOW 0x07FF //ORIGIN CYAN:0xFFE0
#define ST77XX_ORANGE 0x0BFF //SET MAKE 0x0BFF ORANGE ORIGIN 0xFC00
オレンジ色は手探りで色確認です。他の順当な方法もあるようでしたが、設定通りに色が出ればそれでOKとしました。力ずくです。このスケッチだけで、他では通用しません。Hi!
書き換えたライブラリファイルは元の状態に後で戻す必要もあります。他のスケッチで使う場合不具合となります。
設定通りの色がちゃんと表示出来る様になったので、早速、設定した数値に風速がなった状態を想定して数値38を表示させてみました。
風速バイナリーデータ7ビット分のポートを割り当てて、デコードスケッチをコーディングですが、まずはArduinoNanoの端子情報を準備しました。1.8inch TFT液晶Displayで使ったポート以外から使用できる7ポート分を選びます。
つづく?
愛知タワー風速値表示追加その3
(2023/1/25 23:24:56)
愛知タワー付属の風速計へつながっているインプット情報のカウント入力、リセット入力、電源、COMMONの各端子からCMOS
IC 4024の7Stage Binary Ripple
Counterへのカウント入力と4024の論理にあわせる為、リセット信号は1石のスィッチングトランジスタの反転回路を通して繋ぎます。回路図とパターン作製ができたので、このバイナリー出力の7ビットをESP32DevKitCに繫ぐインターフェース部を別基板で作製するための回路図を作製しました。スケッチは回路図での端子を決めてから検討してゆく事になります。単に入力の7ビットバイナリーデータのデコードです。単純に必要なものは入力の7ビットを繋ぐポート、電源、1.8inch
TFT液晶ディスプレーを繋ぐポートがあれば事足ります。今は使いませんが、余分なシリアルポート端子も回路には入れてあります。
1.8 inch
TFT液晶ディスプレーは、今まで使った実績がある物なので、過去の他の実績のある回路と同じ端子接続で使うことができます。スケッチ上のTFT設定は過去使ったものがそのまま使える利点があります。(検討が不要)実は回路図のTFT液晶部分や電源、シリアル端子部は前の他の回路をそのままそっくり流用です。使わないところを消して、必要な箇所を部品を置いて繫いでゆくやり方です。
カウンターからの7ビットの出力を受ける入力ポートも、過去同じ様な用途で使った実績がありますから、安心してスケッチできます。Hi!
回路図も作製できたので、ついでにパターンも作製してしまいました。回路が単純な引き回しなので、100X80mm基板は、スカスカです。
今回は2枚基板の接続の合理的な端子の接続は全く考慮していません。基板を2階建てにした設計も必要かもしれません。今は検討段階での試作です。
さてスケッチを開始しましょうか?
つづく?
愛知タワー風速値表示追加その2
(2023/1/22 7:53:27)
風速値表示回路のパターン作製でのジャンパー処理が必要でしたので、回路図を修正し若干のパターン修正を行ないました。当初LEDはピンヘッドジャックに差す予定でパターンを作製していましたが、ジャックを省き、確認時使うパターンということで入れてあります。確認時のみ使うだけで良く、風速値表示はESP32DevKitCに繋ぐTFTカラー液晶で数値として表示されるため特に問題がなければ部品としては取り付けしない予定です。
修正回路図:どうしても繋がらない箇所をジャンパーワイヤーを使いパターン
を修正しました。
※ちょっとしたeagle操作!
当初CMOSの電源とグランドの接続パターンがピン配線できなかったのですが、ちゃんと機能がありました。今までは、専用のICは使わないでソケットで配線していました。ないわけがないのはわかっていましたが、探すのが面倒でソケットで足りていました。Hi!知ってしまえば、やはり専用のICを使うと便利です。(ピンを調べなくても、回路図に出てきます。)
invokeでICをクリックして電源を選択すると回路図に表示されランドとしてパターン配線出来る様になりました。
実際に修正した最終ボトムパターンです。100X80mmの基板サイズに十分入ります。
切削待ち基板が既に1枚あるので、コレを合わせて2枚になりました。
EAGLE
CADは最初のparts選びが一番最初に悩むところかと思います。習うより慣れろという言葉が本当に当てはまると思います。部品のパーツも秋月の部品もありますからとても助かります。ESP32もあります。回路図でよく使うGND
,+12Vとかレギュレータ、コンデンサ、抵抗、インダクタンス、ピンヘッド、(ピンジャック代用)取り付け穴、LED、各ICソケット、ジャンパー、トランジスタ、ダイオード、基本的なパーツを押さえて於けば、一通り回路図がかけると思います。片面基板が対象ですので、EAGLE
CAD
では回路図ができてしまえば、後は部品を選んで基板上に置いて、ボトムパターンにてランド間を繫いでゆく手順です。特に最初によく使うパターン太さとドリル穴を選んで、一覧にパターン幅がなければ、手入力で数値を入れます。私はよく2mm幅を使いますが、この2mmは手入力になります。パターンをICの中を通したりする時はパターン幅を1.5mm幅とか、1mm幅とかに変えてます。ドリル穴径はディスクリートパーツリードが入る0.9Φにしています。ICソケットも0.9Φでokです。これらを設定してからパタ−ン化してゆきます。片面基板は、なれるとサッサと回路図を横にして、繫いでゆき、行き詰まったところで、ジャンパーを使います。全配線分が終了したら、微調整を行なう段取りです。(パターンの太さや、ランド補強、基板取り付け穴追加等)調整が終わったら、ベターアース化でパターン設計は終了です。後は切削マシーン用にガーバーデータ(パターン用とドリル用、切り抜き用)を作製です。コレぐらいの回路だと1日かからないで簡単に出来る様になります。当面はDIPタイプのICとディスクリートL,C,Rでいいのではないかと思っています。すすんでいる人はICもSOPとかチップL,C,Rで、基板業者にたのんでいますね。綺麗に出来上がるようですね。作ることが好きでやっていますので、簡単なのが私には向いていると思っています。今の所はブレッドボードでの実験で使った部品をまるまるそのまま使うやり方で行なっています。超アナログですが、一番楽しい所、醍醐味は回路を考えボードで確認している時です。Hi!
つづく?
愛知タワー風速値表示追加その1
(2023/1/16 1:28:46)
タワーには風速カウンター表示部がユニットでついていますが、他のところへカウンターを新たに追加したくて、久々にゲート回路を組んでみる事にしました。タワーのUPボタン、DOWNボタン、停止ボタンの高さ表示ユニット近くにおいてある風速値のカウンターです。同じ仕様の物を購入するのが一番手っ取り早いですが、調べて見ると、パルスカウントをするだけなので、ゲートICを選べばできそうな内容です。元のカウンター部分には一切手を入れないでのパルス信号と電源だけパラレルに繋ぐやり方です。本来ならば元々のカウンターの接続線を延長して行う方法が別の場所へ設置する方法もありますが、高さ表示ユニット部はそのままにしておきたいのです。こういう理由からいま付いているカウンターと同じ動作をするカウント表示回路を作製します。
まず最初に調べたのは、信号線2本です。電源は単に電圧+12VとGNDなので特に問題ありません。風速回転のパルス信号線の動作です。
信号線は回転している風速部から回転に合わせて矩形パルスが来ています。正論理信号です。
もう一つの信号線はタイマー信号線です。Nomally+で10secで”L”信号がパルス状に来ています。
上記の信号線より、10秒間のタイマー”H"状態の時に正パルス信号をカウントする仕様です。ここで考えなければいけない事は、カウントを幾つまでカウント出来る様にするかを決めなければなりません。コレはタワーの下に付いているコントロールボックスに、アラームを鳴らしタワーをダウンさせる回転数を設置するユニットがあります。私の設定は経験上かなりの風が吹いているよりも前の風速値38にしてあります。早めにタワーを下げるためです。この38という設定値を十分に範囲内カウントするには6ビットのカウンターで事足りますが、ゲートICのカウンターから見るとCMOS
4024で対応できそうです。
カウントは0から127までです。実績的にカウント表示で今まで100を超えたことはありませんのでコレにしました。他にも1セグメント表示回路も付いている4026もありましたが、セグメント表示でなくTFT液晶ディスプレーにしたいので使いません。(また、2桁だと2個もゲートが必要です。Hi!)
インターフェースとなる回路図です。
表示ユニット端子に繋がっている線を5本繋ぎます。(電源とGND,タイマー信号線、パルス信号線、COMMON)
テストで使用したOSCは矩形波ですが±信号でしたので、パルス入力にはダイオードをいれてあります。
実際の接続時は信号を繫いでみて、はずすか確認します。タイマー信号の”L”パルスはプッシュSWでGNDに落とす様にしてシミュレーションしています。4024のリセットは”H"パルスでかかるので信号と同じ動作で”L”となる様にタクトSWでGNDに落とした時にSWトランジスタで反転させてリセット信号としています。
カウンターがOSCの低周波矩形波信号周波数で表示カウントアップしていくだけの動画です。
バイナリー出力です。(各LED出力7ポートの重みは、それぞれ1,2,4,8,16,32,64です。)
回路図にもあるように信号出力はバイナリーの7ポート出力です。信号が出ているのが分かるように発光ダイオードを付けています。パルス発生間隔が風速によって違う場合と同じようにOSCで矩形波の周波数を1Hzから7Hzぐらいの間で上げ下げすると実際の風速と同じ様にゆらぎカウントしてくれています。
またタイマーはタクトSWでGNDレベルに適当におおよそ10sec過ぎた当たりで疑似パルスとしてチョンと押すと全出力が消えリセットがかかった後にまた1からカウント始めます。
目で出力信号が見える様にパルスカウンター出力には、発光LEDを繋ぐため4050のバッファーを入れています。今回は単にゲートICのパルスカウントを準備し、インターフェースを付けただけです。
この後の予定としては、ソフトウェア設計が大半となります。
7ビットのバイナリーの信号出力分の入力ポートを用意して、スケッチで全ポートを読み取りし、カウント値を液晶に表示する様にするスケッチです。ArduinoNanoかESP32DevKitCのどちらかをつかいたいと思います。現在は信号線のワイヤーが5本繋がり表示する仕様で進めていますが、完成後はUDPを使ったサーバー化をおこない、風速値を別のESP32DevKitCに表示できる展開にしてクライアントのWiFi信号が届く範囲でUDP通信での風速値をリアルタイム表示させる拡張も考えたいと思います。となるとやはりESP32DevKitCを使わないとできないですね!
つづく?
ESP32DevKitCでの周波数カウンタその1
(2023/1/11 3:06:55)
あるWebページからのきっかけで、ESP32DevkitC対応のカウンタをためしてみたくなり、ESP32DevKitCでの周波数カウンタのサンプルをWebで探したところ、説明がポルトガル語ですが、ありました。ESPを楽しむ上ではとても良いサンプルだと思います。割り込みを使った安定動作するカウンタです。入力波形が矩形波である程度きれいな場合は1Hz桁の変動だけありますが精度よく動作してくれるようです。
早速、サンプル作製と詳細な動作説明がありましたのでWebアプリを使いポルトガル語を和訳してみました。和訳はフリーのWebアプリを使いました。和訳説明は最後に添付します。
因みにこの周波数カウンタでは校正確認用のOSCも内蔵されています。内蔵OSCを1Hzから最大40MHzまで変えてみて実際に40MHzまでカウントできました。
ブログは次のurlです。
ブログサンプルの回路図通りに液晶を準備し、接続します。
周波数入力はGPIO34
OSC出力はGPIO33
端子接続GPIO32とGPIO35
LCD GNDはGND
LCD VCCは+5V
LCD SDAはGPIO21
LCD SCLはGPIO22
内蔵OSC発振周波数を使っての確認時は周波数入力GPIO34とOSC出力GPIO33を繋ぎます。
【主な変更箇所】
サンプルで使用してる液晶LCDは16x2のI2C接続ですが、ブログのLCDのスケッチでは手持ちのLCDと違う為表示は動作しませんので、手持ち用の実績のある1602AのLCDのスケッチに書き直してます。アドレスは手持ちで確認してある0x27です。自分のLCDに合わせてアドレスは事前確認必要です。
オリジナルスケッチ
#include <LiqudCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x3F);
手持ちのLCDのスケッチへ変更
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);
LiquidCrystal_I2C lcd(0x27,16,2);
ほか,修正箇所として、LCDの種類切り替えは削除してます。
動作の保証はあくまでも私の手持ち部品での動作確認を行なった内容なのでありませんし、しません。
下記に全スケッチ(和訳コメントあり)を示します。
***********************************************
// file:FREQ-COUNTER-2023JAN10-001.ino
// Modefy by JL7GMN
// ESP32DivKitC-FREQ-Counter
// ----ORIGINAL-------------------------------------------------
// BLOG Eletrogate
// ESP32 Frequencimetro
// ESP32 DevKit 38 pinos + LCD
// https://blog.eletrogate.com/esp32-frequencimetro-de-precisao
// Rui Viana e Gustavo Murta agosto/2020
// -------------------------------------------------------------
#include "stdio.h" // Biblioteca STDIO //stdioライブラリ
#include "driver/ledc.h" // Biblioteca ESP32 LEDC //ESP32 LEDCライブラリ
#include "driver/pcnt.h" // Biblioteca ESP32 PCNT //ESP32 PCNTライブラリ
#include "soc/pcnt_struct.h"
#define LCD_ON //LCDを使用する場合はLCD_ONを、使用しない場合はLCD_OFFを設定する。
#define LCD_I2C_OFF //I2C LCDを使用する場合はLCD_I2C_ONを、使用しない場合はLCD_I2C_OFFを設定する。
//-------------------------------------------------------------
#define I2C_SDA 21 //液晶ディスプレイ i2c SDA - Gpio_21
#define I2C_SCL 22 //液晶ディスプレイ i2c SDA - Gpio_22
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);
//--------------------------------------------------------------
#define PCNT_COUNT_UNIT PCNT_UNIT_0 //ESP32 パルスカウンター PCNT ユニット 0
#define PCNT_COUNT_CHANNEL PCNT_CHANNEL_0 //ESP32 パルスカウンター PCNT チャンネル 0
#define PCNT_INPUT_SIG_IO GPIO_NUM_34 //周波数計入力 - GPIO 34
#define LEDC_HS_CH0_GPIO GPIO_NUM_33 //LEDC出力 - パルスジェネレータ - GPIO_33
#define PCNT_INPUT_CTRL_IO GPIO_NUM_35 //PCNT制御端子 - HIGH=カウントアップ、LOW=カウントダウン
#define OUTPUT_CONTROL_GPIO GPIO_NUM_32 //タイマ出力 - カウントを制御する - GPIO_32
#define PCNT_H_LIM_VAL overflow //カウント上限値
#define IN_BOARD_LED GPIO_NUM_2 //ESP32 ネイティブLED - GPIO 2
bool flag = true; //カウント終了インジケーター - 印刷を再開する
uint32_t overflow = 20000; //PCNTカウンタオーバーフローの最大値
int16_t pulses = 0; //カウントされたパルス数
uint32_t multPulses = 0; //カウンタオーバーフロー回数 PCNT
uint32_t janela = 1000000; //パルスカウントのための1秒間のサンプリング時間 999990
//uint32_t oscilador = 12543; //発振器の初期周波数 - 12543 Hz -> 1MHz
uint32_t oscilador = 1000000;//resol:3 1,000,008Hz (1MHz)
uint32_t mDuty = 0; //ロードサイクルの計算値
uint32_t resolucao = 0; //解像度の計算値
float frequencia = 0; //周波数計算用変数
char buf[32]; //スコアを記録するためのバッファー
esp_timer_create_args_t create_args; //ESP-Timerの引数
esp_timer_handle_t timer_handle; //ESP-Timerインスタンス
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; //同期用変数型portMUX_TYPE
//----------------------------------------------------------------------------------------
void setup()
{
Serial.begin(115200); //シリアル115200Bpsの初期化
//Serial.println(" Digite uma frequencia - 1 a 40 MHz"); // Print na console
lcd.init();
lcd.backlight();
lcd.clear();
// Modefy by JL7GMN
// ESP32DivKitC-FREQ-Counter
// ----ORIGINAL-------------------------------------------------
// BLOG Eletrogate
// ESP32 Frequencimetro
// ESP32 DevKit 38 pinos + LCD
// https://blog.eletrogate.com/esp32-frequencimetro-de-precisao
// Rui Viana e Gustavo Murta agosto/2020
// -------------------------------------------------------------
#include "stdio.h" // Biblioteca STDIO //stdioライブラリ
#include "driver/ledc.h" // Biblioteca ESP32 LEDC //ESP32 LEDCライブラリ
#include "driver/pcnt.h" // Biblioteca ESP32 PCNT //ESP32 PCNTライブラリ
#include "soc/pcnt_struct.h"
#define LCD_ON //LCDを使用する場合はLCD_ONを、使用しない場合はLCD_OFFを設定する。
#define LCD_I2C_OFF //I2C LCDを使用する場合はLCD_I2C_ONを、使用しない場合はLCD_I2C_OFFを設定する。
//-------------------------------------------------------------
#define I2C_SDA 21 //液晶ディスプレイ i2c SDA - Gpio_21
#define I2C_SCL 22 //液晶ディスプレイ i2c SDA - Gpio_22
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);
//--------------------------------------------------------------
#define PCNT_COUNT_UNIT PCNT_UNIT_0 //ESP32 パルスカウンター PCNT ユニット 0
#define PCNT_COUNT_CHANNEL PCNT_CHANNEL_0 //ESP32 パルスカウンター PCNT チャンネル 0
#define PCNT_INPUT_SIG_IO GPIO_NUM_34 //周波数計入力 - GPIO 34
#define LEDC_HS_CH0_GPIO GPIO_NUM_33 //LEDC出力 - パルスジェネレータ - GPIO_33
#define PCNT_INPUT_CTRL_IO GPIO_NUM_35 //PCNT制御端子 - HIGH=カウントアップ、LOW=カウントダウン
#define OUTPUT_CONTROL_GPIO GPIO_NUM_32 //タイマ出力 - カウントを制御する - GPIO_32
#define PCNT_H_LIM_VAL overflow //カウント上限値
#define IN_BOARD_LED GPIO_NUM_2 //ESP32 ネイティブLED - GPIO 2
bool flag = true; //カウント終了インジケーター - 印刷を再開する
uint32_t overflow = 20000; //PCNTカウンタオーバーフローの最大値
int16_t pulses = 0; //カウントされたパルス数
uint32_t multPulses = 0; //カウンタオーバーフロー回数 PCNT
uint32_t janela = 1000000; //パルスカウントのための1秒間のサンプリング時間 999990
//uint32_t oscilador = 12543; //発振器の初期周波数 - 12543 Hz -> 1MHz
uint32_t oscilador = 1000000;//resol:3 1,000,008Hz (1MHz)
uint32_t mDuty = 0; //ロードサイクルの計算値
uint32_t resolucao = 0; //解像度の計算値
float frequencia = 0; //周波数計算用変数
char buf[32]; //スコアを記録するためのバッファー
esp_timer_create_args_t create_args; //ESP-Timerの引数
esp_timer_handle_t timer_handle; //ESP-Timerインスタンス
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; //同期用変数型portMUX_TYPE
//----------------------------------------------------------------------------------------
void setup()
{
Serial.begin(115200); //シリアル115200Bpsの初期化
//Serial.println(" Digite uma frequencia - 1 a 40 MHz"); // Print na console
lcd.init();
lcd.backlight();
lcd.clear();
#if defined
LCD_ON //
LCDまたはI2C LCDを使用している場合
lcd.begin(16, 2); // LCD初期化 16列2行
//lcd.print(" Frequencia:"); //LCDに周波数("FREQUENCY:")文字を表示
lcd.print(" FREQUENCY:"); //Change Portugal to English
#endif
Serial.println(" Input Frequency 1 to 40 MHz"); // Print message for input freq
inicializa_frequencimetro(); // 周波数メーターの初期化
}
//----------------------------------------------------------------------------
void inicializa_oscilador () //パルスジェネレータの初期化
{
resolucao = (log (80000000 / oscilador) / log(2)) / 2 ; //発振器の解を計算する
if (resolucao < 1) resolucao = 1; // 最小分解能
Serial.print("resolucao :");
Serial.println(resolucao); // Print //SERIAL MONITOR PRINT
mDuty = (pow(2, resolucao)) / 2; //ロードサイクル計算 パルスの50%
// Serial.println(mDuty); //SERIAL MONITOR PRINT mDuty
ledc_timer_config_t ledc_timer = {}; //LEDC タイマー設定のインストール
ledc_timer.duty_resolution = ledc_timer_bit_t(resolucao); //解像度を設定する
ledc_timer.freq_hz = oscilador; //発振周波数を設定
ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE; //高速動作モード
ledc_timer.timer_num = LEDC_TIMER_0; //LEDC タイマー0を使用
ledc_timer_config(&ledc_timer); //LEDCタイマーを設定
ledc_channel_config_t ledc_channel = {}; //LEDCのチャンネル構成をインスタンス化します。
ledc_channel.channel = LEDC_CHANNEL_0; //チャンネル0を設定する
ledc_channel.duty = mDuty; //充電サイクルを設定する
ledc_channel.gpio_num = LEDC_HS_CH0_GPIO; //LEDC出力のGPIO設定 - 発振器
ledc_channel.intr_type = LEDC_INTR_DISABLE; //LEDC割り込み禁止
ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE; //高速チャンネル動作モード
ledc_channel.timer_sel = LEDC_TIMER_0; //LEDC タイマー0を選択
ledc_channel_config(&ledc_channel); //LEDCチャンネルを設定
}
//----------------------------------------------------------------------------------
static void IRAM_ATTR pcnt_intr_handler(void *arg) //オーバーフローカウンタカウント
{
portENTER_CRITICAL_ISR(&timerMux); //それ以上の割り込みをブロック
multPulses++; //オーバーフローカウンタをインクリメント
PCNT.int_clr.val = BIT(PCNT_COUNT_UNIT); //インタラプションインジケーターワイパー
portEXIT_CRITICAL_ISR(&timerMux); //新しい割り込みをリリース
}
//----------------------------------------------------------------------------------
void inicializa_contador(void) //パルスカウンタの初期化
{
pcnt_config_t pcnt_config = { }; //インスタンスPCNT設定
pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_IO; //GPIOをパルス入力に設定
pcnt_config.ctrl_gpio_num = PCNT_INPUT_CTRL_IO; //カウント制御用GPIOの設定
pcnt_config.unit = PCNT_COUNT_UNIT; //カウントユニット PCNT - 0
pcnt_config.channel = PCNT_COUNT_CHANNEL; //カウントチャネル PCNT - 0
pcnt_config.counter_h_lim = PCNT_H_LIM_VAL; //最大カウント数 20000
pcnt_config.pos_mode = PCNT_COUNT_INC; //パルスの立ち上がりでカウントアップ
pcnt_config.neg_mode = PCNT_COUNT_INC; //パルスの立ち下がりでカウントを増加させる
pcnt_config.lctrl_mode = PCNT_MODE_DISABLE; //PCNT - lctrlモード無効
pcnt_config.hctrl_mode = PCNT_MODE_KEEP; //PCNT - hctrlモード - HIGHならカウントアップ
pcnt_unit_config(&pcnt_config); //PCNTカウンターの設定
pcnt_counter_pause(PCNT_COUNT_UNIT); //PCNTカウンターを一時停止
pcnt_counter_clear(PCNT_COUNT_UNIT); //PCNTカウンターを0にリセット
pcnt_event_enable(PCNT_COUNT_UNIT, PCNT_EVT_H_LIM); //カウント上限値の設定
pcnt_isr_register(pcnt_intr_handler, NULL, 0, NULL);//PCNT割り込みルーチンの設定
pcnt_intr_enable(PCNT_COUNT_UNIT); //PCNT割り込みの有効化
pcnt_counter_resume(PCNT_COUNT_UNIT); //PCNTカウンターのカウントをリセットする
}
//----------------------------------------------------------------------------------
void tempo_controle(void *p) //パルス読み出し終了時間
{
gpio_set_level(OUTPUT_CONTROL_GPIO, 0); //PCNTコントロール - メーター用
pcnt_get_counter_value(PCNT_COUNT_UNIT, &pulses);//PCNTにカウントされた値を取得
flag = true; //制御の中断が発生したことを通知
}
//---------------------------------------------------------------------------------
void inicializa_frequencimetro()
{
inicializa_oscilador (); //発振器でパルスの発生を開始する。
inicializa_contador(); //PCNTパルスカウンタの初期化
gpio_pad_select_gpio(OUTPUT_CONTROL_GPIO); //制御ポートを設定する
gpio_set_direction(OUTPUT_CONTROL_GPIO, GPIO_MODE_OUTPUT); //制御ポートを出力に設定
create_args.callback = tempo_controle; //制御時間のインスタンス化
esp_timer_create(&create_args, &timer_handle); //タイマーのパラメータを作成する
gpio_set_direction(IN_BOARD_LED, GPIO_MODE_OUTPUT); //ポートLEDを出力
gpio_matrix_in(PCNT_INPUT_SIG_IO, SIG_IN_FUNC226_IDX, false); //パルス入力を指示する
gpio_matrix_out(IN_BOARD_LED, SIG_IN_FUNC226_IDX, false, false);//ESP32のLEDの場合
}
//----------------------------------------------------------------------------------------
//ドットを含む32ビット長数値の書式設定
char *ultos_recursive(unsigned long val, char *s, unsigned radix, int pos)
{
int c;
if (val >= radix)
s = ultos_recursive(val / radix, s, radix, pos + 1);
c = val % radix;
c += (c < 10 ? '0' : 'a' - 10);
*s++ = c;
//if (pos % 3 == 0) *s++ = '.';
if (pos % 3 == 0) *s++ = ',';
return s;
}
//----------------------------------------------------------------------------------------
//ドットを含む32ビット長数値の書式設定
char *ltos(long val, char *s, int radix)
{
if (radix < 2 || radix > 36) {
s[0] = 0;
} else {
char *p = s;
if (radix == 10 && val < 0) {
val = -val;
*p++ = '-';
}
p = ultos_recursive(val, p, radix, 0) - 1;
*p = 0;
}
return s;
}
//---------------------------------------------------------------------------------
void loop()
{
if (flag == true) //カウントダウンが終了した場合
{
flag = false; //COUNTDOWN NOT FINISH FLAG SETTING
frequencia = (pulses + (multPulses * overflow)) / 2 ; //PCNTでカウントされたパルスの合計を計算する
//printf("Frequencia : %s", (ltos(frequencia, buf, 10))); // Print frequencia com pontos
printf("FREQUENCY : %s", (ltos(frequencia, buf, 10))); // Print frequencia com pontos
printf(" Hz \n"); // Print unidade Hz
//#if defined LCD_ON || defined LCD_I2C_ON //LCDまたはI2C LCDを使用する場合
#if defined LCD_ON
lcd.setCursor(2, 1); //カーソルを1行目の2番目に位置させる
lcd.print((ltos(frequencia, buf, 10))); //LCDに表示される周波数プリント頻度
lcd.print(" Hz "); //LCDにHz単位を表示
#endif
multPulses = 0; //オーバーフローカウンターのクリア
delay (100); // Delay 100 ms あらゆる用途に対応できるdelaytimer
// Espaco para qualquer função
pcnt_counter_clear(PCNT_COUNT_UNIT); //PCNTカウンターをゼロにリセット
esp_timer_start_once(timer_handle, janela); //1秒タイムカウンター開始
gpio_set_level(OUTPUT_CONTROL_GPIO, 1); //制御ポート - パルスカウントを有効にする
}
String inputString = ""; //データ入力用クリア文字列 初期化
oscilador = 0; //周波数値をゼロにリセット
while (Serial.available()) //シリアルでデータを持っている間
{
char inChar = (char)Serial.read(); //1 バイトの読み出し。
inputString += inChar; //文字列を追加
if (inChar == '\n') //ENTERを押した場合
{
oscilador = inputString.toInt(); //文字列を整数に変換する
inputString = ""; //文字列を消去する
}
}
if (oscilador != 0) //何らかの値が入力されている場合
{
inicializa_oscilador (); //発振器の周波数をリセットする
}
}
lcd.begin(16, 2); // LCD初期化 16列2行
//lcd.print(" Frequencia:"); //LCDに周波数("FREQUENCY:")文字を表示
lcd.print(" FREQUENCY:"); //Change Portugal to English
#endif
Serial.println(" Input Frequency 1 to 40 MHz"); // Print message for input freq
inicializa_frequencimetro(); // 周波数メーターの初期化
}
//----------------------------------------------------------------------------
void inicializa_oscilador () //パルスジェネレータの初期化
{
resolucao = (log (80000000 / oscilador) / log(2)) / 2 ; //発振器の解を計算する
if (resolucao < 1) resolucao = 1; // 最小分解能
Serial.print("resolucao :");
Serial.println(resolucao); // Print //SERIAL MONITOR PRINT
mDuty = (pow(2, resolucao)) / 2; //ロードサイクル計算 パルスの50%
// Serial.println(mDuty); //SERIAL MONITOR PRINT mDuty
ledc_timer_config_t ledc_timer = {}; //LEDC タイマー設定のインストール
ledc_timer.duty_resolution = ledc_timer_bit_t(resolucao); //解像度を設定する
ledc_timer.freq_hz = oscilador; //発振周波数を設定
ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE; //高速動作モード
ledc_timer.timer_num = LEDC_TIMER_0; //LEDC タイマー0を使用
ledc_timer_config(&ledc_timer); //LEDCタイマーを設定
ledc_channel_config_t ledc_channel = {}; //LEDCのチャンネル構成をインスタンス化します。
ledc_channel.channel = LEDC_CHANNEL_0; //チャンネル0を設定する
ledc_channel.duty = mDuty; //充電サイクルを設定する
ledc_channel.gpio_num = LEDC_HS_CH0_GPIO; //LEDC出力のGPIO設定 - 発振器
ledc_channel.intr_type = LEDC_INTR_DISABLE; //LEDC割り込み禁止
ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE; //高速チャンネル動作モード
ledc_channel.timer_sel = LEDC_TIMER_0; //LEDC タイマー0を選択
ledc_channel_config(&ledc_channel); //LEDCチャンネルを設定
}
//----------------------------------------------------------------------------------
static void IRAM_ATTR pcnt_intr_handler(void *arg) //オーバーフローカウンタカウント
{
portENTER_CRITICAL_ISR(&timerMux); //それ以上の割り込みをブロック
multPulses++; //オーバーフローカウンタをインクリメント
PCNT.int_clr.val = BIT(PCNT_COUNT_UNIT); //インタラプションインジケーターワイパー
portEXIT_CRITICAL_ISR(&timerMux); //新しい割り込みをリリース
}
//----------------------------------------------------------------------------------
void inicializa_contador(void) //パルスカウンタの初期化
{
pcnt_config_t pcnt_config = { }; //インスタンスPCNT設定
pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_IO; //GPIOをパルス入力に設定
pcnt_config.ctrl_gpio_num = PCNT_INPUT_CTRL_IO; //カウント制御用GPIOの設定
pcnt_config.unit = PCNT_COUNT_UNIT; //カウントユニット PCNT - 0
pcnt_config.channel = PCNT_COUNT_CHANNEL; //カウントチャネル PCNT - 0
pcnt_config.counter_h_lim = PCNT_H_LIM_VAL; //最大カウント数 20000
pcnt_config.pos_mode = PCNT_COUNT_INC; //パルスの立ち上がりでカウントアップ
pcnt_config.neg_mode = PCNT_COUNT_INC; //パルスの立ち下がりでカウントを増加させる
pcnt_config.lctrl_mode = PCNT_MODE_DISABLE; //PCNT - lctrlモード無効
pcnt_config.hctrl_mode = PCNT_MODE_KEEP; //PCNT - hctrlモード - HIGHならカウントアップ
pcnt_unit_config(&pcnt_config); //PCNTカウンターの設定
pcnt_counter_pause(PCNT_COUNT_UNIT); //PCNTカウンターを一時停止
pcnt_counter_clear(PCNT_COUNT_UNIT); //PCNTカウンターを0にリセット
pcnt_event_enable(PCNT_COUNT_UNIT, PCNT_EVT_H_LIM); //カウント上限値の設定
pcnt_isr_register(pcnt_intr_handler, NULL, 0, NULL);//PCNT割り込みルーチンの設定
pcnt_intr_enable(PCNT_COUNT_UNIT); //PCNT割り込みの有効化
pcnt_counter_resume(PCNT_COUNT_UNIT); //PCNTカウンターのカウントをリセットする
}
//----------------------------------------------------------------------------------
void tempo_controle(void *p) //パルス読み出し終了時間
{
gpio_set_level(OUTPUT_CONTROL_GPIO, 0); //PCNTコントロール - メーター用
pcnt_get_counter_value(PCNT_COUNT_UNIT, &pulses);//PCNTにカウントされた値を取得
flag = true; //制御の中断が発生したことを通知
}
//---------------------------------------------------------------------------------
void inicializa_frequencimetro()
{
inicializa_oscilador (); //発振器でパルスの発生を開始する。
inicializa_contador(); //PCNTパルスカウンタの初期化
gpio_pad_select_gpio(OUTPUT_CONTROL_GPIO); //制御ポートを設定する
gpio_set_direction(OUTPUT_CONTROL_GPIO, GPIO_MODE_OUTPUT); //制御ポートを出力に設定
create_args.callback = tempo_controle; //制御時間のインスタンス化
esp_timer_create(&create_args, &timer_handle); //タイマーのパラメータを作成する
gpio_set_direction(IN_BOARD_LED, GPIO_MODE_OUTPUT); //ポートLEDを出力
gpio_matrix_in(PCNT_INPUT_SIG_IO, SIG_IN_FUNC226_IDX, false); //パルス入力を指示する
gpio_matrix_out(IN_BOARD_LED, SIG_IN_FUNC226_IDX, false, false);//ESP32のLEDの場合
}
//----------------------------------------------------------------------------------------
//ドットを含む32ビット長数値の書式設定
char *ultos_recursive(unsigned long val, char *s, unsigned radix, int pos)
{
int c;
if (val >= radix)
s = ultos_recursive(val / radix, s, radix, pos + 1);
c = val % radix;
c += (c < 10 ? '0' : 'a' - 10);
*s++ = c;
//if (pos % 3 == 0) *s++ = '.';
if (pos % 3 == 0) *s++ = ',';
return s;
}
//----------------------------------------------------------------------------------------
//ドットを含む32ビット長数値の書式設定
char *ltos(long val, char *s, int radix)
{
if (radix < 2 || radix > 36) {
s[0] = 0;
} else {
char *p = s;
if (radix == 10 && val < 0) {
val = -val;
*p++ = '-';
}
p = ultos_recursive(val, p, radix, 0) - 1;
*p = 0;
}
return s;
}
//---------------------------------------------------------------------------------
void loop()
{
if (flag == true) //カウントダウンが終了した場合
{
flag = false; //COUNTDOWN NOT FINISH FLAG SETTING
frequencia = (pulses + (multPulses * overflow)) / 2 ; //PCNTでカウントされたパルスの合計を計算する
//printf("Frequencia : %s", (ltos(frequencia, buf, 10))); // Print frequencia com pontos
printf("FREQUENCY : %s", (ltos(frequencia, buf, 10))); // Print frequencia com pontos
printf(" Hz \n"); // Print unidade Hz
//#if defined LCD_ON || defined LCD_I2C_ON //LCDまたはI2C LCDを使用する場合
#if defined LCD_ON
lcd.setCursor(2, 1); //カーソルを1行目の2番目に位置させる
lcd.print((ltos(frequencia, buf, 10))); //LCDに表示される周波数プリント頻度
lcd.print(" Hz "); //LCDにHz単位を表示
#endif
multPulses = 0; //オーバーフローカウンターのクリア
delay (100); // Delay 100 ms あらゆる用途に対応できるdelaytimer
// Espaco para qualquer função
pcnt_counter_clear(PCNT_COUNT_UNIT); //PCNTカウンターをゼロにリセット
esp_timer_start_once(timer_handle, janela); //1秒タイムカウンター開始
gpio_set_level(OUTPUT_CONTROL_GPIO, 1); //制御ポート - パルスカウントを有効にする
}
String inputString = ""; //データ入力用クリア文字列 初期化
oscilador = 0; //周波数値をゼロにリセット
while (Serial.available()) //シリアルでデータを持っている間
{
char inChar = (char)Serial.read(); //1 バイトの読み出し。
inputString += inChar; //文字列を追加
if (inChar == '\n') //ENTERを押した場合
{
oscilador = inputString.toInt(); //文字列を整数に変換する
inputString = ""; //文字列を消去する
}
}
if (oscilador != 0) //何らかの値が入力されている場合
{
inicializa_oscilador (); //発振器の周波数をリセットする
}
}
***********************************************
上記のスケッチではOSC出力は12.543KHzを1MHzに変更して動作確認できています。
OSCは最大40MHzまでカウント動作しました。各周波数でのカウンタ動作確認時のスケッチと周波数を示します。*の表示桁はバラツキ動作がある桁です。
(一部resol値記載がありますが、個人的に分解能変数を知りたくて調べた時の値です。)
//uint32_t
oscilador = 12543; //発振器の初期周波数 - 12543 Hz -> 10MHz
//uint32_t oscilador = 1; //1Hz
//uint32_t oscilador = 10; //10Hz
//uint32_t oscilador = 50; //50Hz
//uint32_t oscilador = 100; //100Hz
//uint32_t oscilador = 500; //resol:8 500Hz
//uint32_t oscilador = 1000; //1,000Hz
//uint32_t oscilador = 5000; //5,000Hz
//uint32_t oscilador = 10000;//resol:6 10,000Hz
//uint32_t oscilador = 12500;//resol:6 12,500Hz
//uint32_t oscilador = 20000;//resol:5 20,000Hz
//uint32_t oscilador = 50000;//resol:5 50,000Hz
//uint32_t oscilador = 60000;//resol:5 60,000Hz
//uint32_t oscilador = 70000;//resol:5 70,007Hz
//uint32_t oscilador = 80000;//resol:4 80,000Hz
//uint32_t oscilador = 90000;//resol:4 90,002Hz
//uint32_t oscilador = 100000;//resol:4 100,000Hz
//uint32_t oscilador = 200000;//resol:4 200,002Hz
//uint32_t oscilador = 300000;//resol:4 300,049Hz
//uint32_t oscilador = 400000;//resol:3 400,004Hz
//uint32_t oscilador = 500000;//resol:3 500,005Hz
//uint32_t oscilador = 600000;//resol:3 600,099Hz
//uint32_t oscilador = 700000;//resol:3 700,033Hz
//uint32_t oscilador = 800000;//resol:3 800,007Hz
//uint32_t oscilador = 900000;//resol:3 900,149Hz
uint32_t oscilador = 1000000;//resol:3 1,000,008Hz (1MHz)
//uint32_t oscilador = 5000000;//resol:2 5,000,050Hz
//uint32_t oscilador = 10000000;//resol:1 10,000,099Hz
//uint32_t oscilador = 15000000;//resol:1 15,014,80*Hz
//uint32_t oscilador = 20000000;//20,000,184Hz
//uint32_t oscilador = 25000000;//25,036,9**Hz
//uint32_t oscilador = 30000000;//30,029,59*Hz
//uint32_t oscilador = 35000000;//35,068,8**Hz
//uint32_t oscilador = 40000000;//40,000,352Hz
//uint32_t oscilador = 10; //10Hz
//uint32_t oscilador = 50; //50Hz
//uint32_t oscilador = 100; //100Hz
//uint32_t oscilador = 500; //resol:8 500Hz
//uint32_t oscilador = 1000; //1,000Hz
//uint32_t oscilador = 5000; //5,000Hz
//uint32_t oscilador = 10000;//resol:6 10,000Hz
//uint32_t oscilador = 12500;//resol:6 12,500Hz
//uint32_t oscilador = 20000;//resol:5 20,000Hz
//uint32_t oscilador = 50000;//resol:5 50,000Hz
//uint32_t oscilador = 60000;//resol:5 60,000Hz
//uint32_t oscilador = 70000;//resol:5 70,007Hz
//uint32_t oscilador = 80000;//resol:4 80,000Hz
//uint32_t oscilador = 90000;//resol:4 90,002Hz
//uint32_t oscilador = 100000;//resol:4 100,000Hz
//uint32_t oscilador = 200000;//resol:4 200,002Hz
//uint32_t oscilador = 300000;//resol:4 300,049Hz
//uint32_t oscilador = 400000;//resol:3 400,004Hz
//uint32_t oscilador = 500000;//resol:3 500,005Hz
//uint32_t oscilador = 600000;//resol:3 600,099Hz
//uint32_t oscilador = 700000;//resol:3 700,033Hz
//uint32_t oscilador = 800000;//resol:3 800,007Hz
//uint32_t oscilador = 900000;//resol:3 900,149Hz
uint32_t oscilador = 1000000;//resol:3 1,000,008Hz (1MHz)
//uint32_t oscilador = 5000000;//resol:2 5,000,050Hz
//uint32_t oscilador = 10000000;//resol:1 10,000,099Hz
//uint32_t oscilador = 15000000;//resol:1 15,014,80*Hz
//uint32_t oscilador = 20000000;//20,000,184Hz
//uint32_t oscilador = 25000000;//25,036,9**Hz
//uint32_t oscilador = 30000000;//30,029,59*Hz
//uint32_t oscilador = 35000000;//35,068,8**Hz
//uint32_t oscilador = 40000000;//40,000,352Hz
上記のカウントした周波数の誤差はOSC出力波形が歪をおこしている事が原因の様でした。オシロスコープでの波形確認は大切です。Hi!
カウンタ入力に波形成形回路やレベルアンプを追加すると精度良く使用出来ると思われます。ちなみにサンプリングは1secです。また直接のカウンタ入力への正弦波入力では精度は取れません。波形成形回路を入れることで精度良くなると思われます。波形成形回路を追加する時には、カウント確認ポートとしてGPIO2のポートが動作している時に反転出力が出ますのでレベルの調整とかの時に使えます。(カウント時の出力ポートです。)
一部周波数の入力のスケッチ部もありますが、確認してません。
*********************************************
【動作説明の和訳】おかしな訳部分は適当に修正理解お願いします。(アプリでの和訳です。)
■PULSE COUNT
CONTROLLER
PCNTパルスカウンタモジュールは、入力信号の立ち上がりや立ち下がりのエッジ数をカウントするように設計されています。独立した8つのユニットを搭載しているのです 各PCNTユニットは、16ビットカウンタと、立ち上がりまたは立ち下がりカウントを有効にすることができる2つのチャンネルを備えています。各チャンネルには、カウントするパルスの入力と、カウントの有効/無効を切り替えるコントロールポートがあります。 また、各PCNTユニットには、カウンターの設定に使用するレジスタがあります。これらのカウンタは、最大カウンタ値、最小カウンタ値、あるカウンタ値など、選択されたいくつかのパラメータに従って割り込みを発生させるようにプログラムすることができます。今回のケースでは、ESP32で割り込みを発生させるために、カウンタの最大値を使用します。
■TIMER
ESP32には、4つの汎用タイマが内蔵されています。これらはいずれも16ビットのプリスケーラ(分周器)と64ビットのカウンタをベースとした汎用的な64ビットタイマである。
ESP32には2つのタイマモジュールがあり、それぞれ2つのタイマが搭載されています。タイマーの特徴は以下の通りです。
- 2~65536の16ビットプリスケーラです。
- 64ビットのタイムベースカウンターです。
- タイムベースカウンターのアップ/ダウン:カウントの増減を設定可能。
- タイムベースカウンターの停止と再開。
- アラームで自動充電。
- ソフトウェア制御による瞬時充電。
- レベル、パルスエッジ割り込み発生。
各タイマは,APBクロック(APB_CLK,通常80MHz)を基本クロックとして使用します。このクロックを16ビットのプリスケーラで分周し、タイムベースパルスを生成します。このパルスは,構成によってタイムベースカウンタのインクリメントまたはデクリメントに使用することができます。
■高分解能タイマー Temporizador de alta resolução (High Resolution Timer)
ESPRESSIFは、ハードウェアタイマーをより正確かつ高速に制御できるように、ESP32タイマー用のAPI(Application Programming Interface)セットを作成しました。 esp_timerのAPIセットは、シングルおよびピリオディックタイマー、マイクロ秒の分解能と64ビット範囲を提供します。内部的には、esp_timerは64ビットハードウェアタイマーを使用します。このプロジェクトでは、PCNTのパルスカウントを計時するためにesp_timerが使用されています。周波数計測の単位はヘルツで、1秒あたりのパルス数に換算されるため、1秒ごとにPCNTカウンターに入るパルスのカウントが行われる。
■LEDC
LEDCまたはLED_PWMコントローラは、主にLEDの輝度を制御するために設計されていますが、他の目的のためにPWM信号を生成するために使用することも可能です。16個のチャンネルを持ち、独立したパルスを生成してカラーRGB LEDデバイスを駆動することができます。LED_PWMコントローラは、高速PWM8チャンネル、低速PWM8チャンネルを搭載しています。これらのチャンネルは,80MhzのAPB_CLKクロックを使用し,分周器,カウンタ,コンパレータの応用で,周波数とDuty Cycleを調整したパルスを発生させることが可能である。このPWM LEDコントローラのすべての設定は,いくつかの内部レジスタを介して行われます。
■動作原理
周波数計は5つのパーツに分かれています。
1. パルスカウンターです。
2. カウントタイム制御。
3. プログラマブル信号発生器(1Hz~40Mhz)。
4. その他の機能用スペース。
5. 結果のプリントアウト。
1. パルスカウンタはPCNTカウンタモジュールを使用します。PCNTの設定には、以下のパラメータを使用します。
・ゲートウェイ
・入力チャンネルになります。
・制御ポート
・パルスの立ち上がりに応じてカウントされます。
・カウントは、立下りパルスで行います。
・高水準で制御して初めてカウントされる。
・最大カウント数制限
2. カウントタイム制御はesp-timerを使用します。esp-timerは以下のパラメータを持ちます。
・時間制御を行います。
3. 周波数メーターのテスト用周波数発生器は、ledcを使用しています。ledcは以下のパラメータを持つ。
・出力ポートになります。
・lcdチャンネル。
・周波数を使用します。
・ledcの解像度です。
・デューティサイクル
■周波数計の仕組み
・周波数計は、1秒の時間の間にパルスを数えることが基本です。
まず、LEDC発振器とPCNTカウンタの設定と初期化を行います。 そして、esp-timer、カウンターの制御ポートを出力として、カウンターの入力ポートをESP32ボードのLedに接続します。
・LEDC発振器は発振器変数で設定された12.543KHzの周波数の発生を開始します。
この周波数を選んだのは、周波数メーターの精度が分かるようにするためです。この発振器初期化機能では、周波数値に応じて分解能とデューティサイクルが既に自動計算されています。 デューティサイクルとは、生成されたパルスのHIGH部分とLOW部分の比率のことです。例えば、今回のプログラムでは、このDutyは50%、つまりHIGH部分の幅はパルスの全周期の半分となる。
パルスのカウントには、PCNTカウンターを使用した。32,768パルスの制限値があるため、このプログラムでは20,000の値を最大値として設定した。カウント時間中に20,000パルスを超えた場合、オーバーフローレジスタが発生します。 オーバーフローが発生するたびに、変数multPulsesにカウントされます。
カウント制御ポート(GPIO 35)がハイレベルになると、パルス入力ポート(GPIO 34)から入力されるパルスをカウントするようにカウンタを解放します。制御パルスの立ち上がりと立ち下がりの両方でパルスをカウントし、平均的なカウントを向上させます。この2つのカウントを2で割ると頻度が算出される。
・カウント時間は、esp-timerで設定します。
可変窓から1秒に設定されています。タイマーの1パルスが1マイクロ秒に相当するので、100万パルスをカウントすると1秒の周波数サンプリングが完了します。
割り込みに対応した2つの機能がプログラム上で定義されています。最初の関数IRAM_ATTR pcntは、PCNTカウンタが満杯になるたびに、オーバーフローカウンタをインクリメントします。もう一つの関数time_controlは、esp-timerの時間切れ後、PCNTカウンターのレジスタに含まれる値を取得します。
1秒経過後、PCNTカウンタレジスタが読み出され、カウント終了を示すFlagがtrueに変更されます。プログラムループでは、Flagがtrueであることがわかると、周波数値が計算される。 オーバーフロー回数に20,000を乗じ、残りパルス数に加算します。この和を2で割ると、カウントが2回行われるため(制御パルスの立ち上がりと立ち下がりでパルスをカウント)、2回目のカウントが行われます。
ディスプレイの周波数を読みやすくするために、ultosとltosという機能を使って、3桁ごとにドットを挿入しています。この周波数は、LCDディスプレイに表示される以外に、Arduino IDEのシリアルコンソールにも送信されます。周波数サンプリング後、レジスタをリセットし、時刻とパルスカウントを再開します。
また、Arduino IDEのシリアルコンソールを使用して、テスト用に発振器の周波数を変更することも可能です。入力フィールドに1Hz~40MHzの値を入力し、ENTERを押します。
発振器のパルス出力はGPIO33ピンに設定されていますので、このパルス出力をGPIO34の周波数メータ入力に接続して、テストを行う必要があります。ただし、外部信号の周波数測定では、この接続を外してください。ESP32は3.3Vの電圧信号で動作するため、それ以外の電圧レベルの信号を測定したい場合は、入力ポートにロジックレベルコンバータ 3.3V-5V Bidirectional - 4 Channelを使用することを推奨します。内部ではGPIOマトリックスを使って、周波数計からの入力パルスをESP32のネイティブLEDに導き、周波数に応じてLEDを点滅させるようにしています。
■■使用したライブラリ■■
このプロジェクトで使用したArduino IDEのバージョンはV 1.8.12ですが、コードの非互換性を避けるため、バージョンが古い場合は更新してください。
2023年1月10日(火曜日)現在【【Arduino IDE 2.0.3】】
ESP32 Boardで使用するためのArduino IDEの設定がまだの場合は、以下のリンク先のチュートリアルの手順に従ってください。この設定は、プロジェクトが正常に動作するために必要不可欠です。 ESP32 BoardがTutorialと異なる場合は、Arduino IDEで設定を変更してください。
今回使用したArduino IDEのESP32ファームウェアのバージョンはV 1.0.4です。もし古い場合は、何らかの不具合を避けるために、プログラムをコンパイルする前にアップデートしてください。必要であれば、Board Managerを使用して更新します。
I2Cインターフェース(PCF8574)の液晶ディスプレイを使用するには、LiquidCrystal_PCF8574ライブラリのインストールが必要です。Arduino IDEのLibrary Managerを使用してインストールします。
また、パラレルLCDディスプレイ(4ビット)を使用する場合は、Arduino IDEのライブラリマネージャでLiquidCrystalライブラリもインストールしてください。
■回路図 Diagramas dos circuitos:
I2Cインターフェース搭載ディスプレイ(PCF8574)の構成図(画像を拡大するには、別のタブで開いてください。)
ディスプレイの裏に接続されているI2C Interfaceボード(PCF8574)のポテンショメーターで、ディスプレイの明るさを調整することを忘れないでください。ジャンパーは接続したままにしてください。
■ESP32 周波数メーターのプログラム。
表示選択指示
Arduino IDEコンパイラは、プログラムコンパイラのディレクティブを使用して、LCDディスプレイの種類を有効にしたり選択したりすることができます。
LCD並列使用 - LCD_ONまたはLCD_OFFに変更してください。
#define LCD_OFF ou #define LCD_ON // ON se for usar esse display
I2C LCDの使用 - LCD_I2C_ONまたはLCD_I2C_OFFに変更します。
#define LCD_I2C_ON ou #define LCD_I2C_OFF // ON se for usar esse display
OB:LCDのI2Cインターフェースのアドレスが分からない場合は、ESP32 I2C Scannerを使って調べてください:(私のボードのアドレスは0x3Fです)。
PCNTパルスカウンタモジュールは、入力信号の立ち上がりや立ち下がりのエッジ数をカウントするように設計されています。独立した8つのユニットを搭載しているのです 各PCNTユニットは、16ビットカウンタと、立ち上がりまたは立ち下がりカウントを有効にすることができる2つのチャンネルを備えています。各チャンネルには、カウントするパルスの入力と、カウントの有効/無効を切り替えるコントロールポートがあります。 また、各PCNTユニットには、カウンターの設定に使用するレジスタがあります。これらのカウンタは、最大カウンタ値、最小カウンタ値、あるカウンタ値など、選択されたいくつかのパラメータに従って割り込みを発生させるようにプログラムすることができます。今回のケースでは、ESP32で割り込みを発生させるために、カウンタの最大値を使用します。
■TIMER
ESP32には、4つの汎用タイマが内蔵されています。これらはいずれも16ビットのプリスケーラ(分周器)と64ビットのカウンタをベースとした汎用的な64ビットタイマである。
ESP32には2つのタイマモジュールがあり、それぞれ2つのタイマが搭載されています。タイマーの特徴は以下の通りです。
- 2~65536の16ビットプリスケーラです。
- 64ビットのタイムベースカウンターです。
- タイムベースカウンターのアップ/ダウン:カウントの増減を設定可能。
- タイムベースカウンターの停止と再開。
- アラームで自動充電。
- ソフトウェア制御による瞬時充電。
- レベル、パルスエッジ割り込み発生。
各タイマは,APBクロック(APB_CLK,通常80MHz)を基本クロックとして使用します。このクロックを16ビットのプリスケーラで分周し、タイムベースパルスを生成します。このパルスは,構成によってタイムベースカウンタのインクリメントまたはデクリメントに使用することができます。
■高分解能タイマー Temporizador de alta resolução (High Resolution Timer)
ESPRESSIFは、ハードウェアタイマーをより正確かつ高速に制御できるように、ESP32タイマー用のAPI(Application Programming Interface)セットを作成しました。 esp_timerのAPIセットは、シングルおよびピリオディックタイマー、マイクロ秒の分解能と64ビット範囲を提供します。内部的には、esp_timerは64ビットハードウェアタイマーを使用します。このプロジェクトでは、PCNTのパルスカウントを計時するためにesp_timerが使用されています。周波数計測の単位はヘルツで、1秒あたりのパルス数に換算されるため、1秒ごとにPCNTカウンターに入るパルスのカウントが行われる。
■LEDC
LEDCまたはLED_PWMコントローラは、主にLEDの輝度を制御するために設計されていますが、他の目的のためにPWM信号を生成するために使用することも可能です。16個のチャンネルを持ち、独立したパルスを生成してカラーRGB LEDデバイスを駆動することができます。LED_PWMコントローラは、高速PWM8チャンネル、低速PWM8チャンネルを搭載しています。これらのチャンネルは,80MhzのAPB_CLKクロックを使用し,分周器,カウンタ,コンパレータの応用で,周波数とDuty Cycleを調整したパルスを発生させることが可能である。このPWM LEDコントローラのすべての設定は,いくつかの内部レジスタを介して行われます。
■動作原理
周波数計は5つのパーツに分かれています。
1. パルスカウンターです。
2. カウントタイム制御。
3. プログラマブル信号発生器(1Hz~40Mhz)。
4. その他の機能用スペース。
5. 結果のプリントアウト。
1. パルスカウンタはPCNTカウンタモジュールを使用します。PCNTの設定には、以下のパラメータを使用します。
・ゲートウェイ
・入力チャンネルになります。
・制御ポート
・パルスの立ち上がりに応じてカウントされます。
・カウントは、立下りパルスで行います。
・高水準で制御して初めてカウントされる。
・最大カウント数制限
2. カウントタイム制御はesp-timerを使用します。esp-timerは以下のパラメータを持ちます。
・時間制御を行います。
3. 周波数メーターのテスト用周波数発生器は、ledcを使用しています。ledcは以下のパラメータを持つ。
・出力ポートになります。
・lcdチャンネル。
・周波数を使用します。
・ledcの解像度です。
・デューティサイクル
■周波数計の仕組み
・周波数計は、1秒の時間の間にパルスを数えることが基本です。
まず、LEDC発振器とPCNTカウンタの設定と初期化を行います。 そして、esp-timer、カウンターの制御ポートを出力として、カウンターの入力ポートをESP32ボードのLedに接続します。
・LEDC発振器は発振器変数で設定された12.543KHzの周波数の発生を開始します。
この周波数を選んだのは、周波数メーターの精度が分かるようにするためです。この発振器初期化機能では、周波数値に応じて分解能とデューティサイクルが既に自動計算されています。 デューティサイクルとは、生成されたパルスのHIGH部分とLOW部分の比率のことです。例えば、今回のプログラムでは、このDutyは50%、つまりHIGH部分の幅はパルスの全周期の半分となる。
パルスのカウントには、PCNTカウンターを使用した。32,768パルスの制限値があるため、このプログラムでは20,000の値を最大値として設定した。カウント時間中に20,000パルスを超えた場合、オーバーフローレジスタが発生します。 オーバーフローが発生するたびに、変数multPulsesにカウントされます。
カウント制御ポート(GPIO 35)がハイレベルになると、パルス入力ポート(GPIO 34)から入力されるパルスをカウントするようにカウンタを解放します。制御パルスの立ち上がりと立ち下がりの両方でパルスをカウントし、平均的なカウントを向上させます。この2つのカウントを2で割ると頻度が算出される。
・カウント時間は、esp-timerで設定します。
可変窓から1秒に設定されています。タイマーの1パルスが1マイクロ秒に相当するので、100万パルスをカウントすると1秒の周波数サンプリングが完了します。
割り込みに対応した2つの機能がプログラム上で定義されています。最初の関数IRAM_ATTR pcntは、PCNTカウンタが満杯になるたびに、オーバーフローカウンタをインクリメントします。もう一つの関数time_controlは、esp-timerの時間切れ後、PCNTカウンターのレジスタに含まれる値を取得します。
1秒経過後、PCNTカウンタレジスタが読み出され、カウント終了を示すFlagがtrueに変更されます。プログラムループでは、Flagがtrueであることがわかると、周波数値が計算される。 オーバーフロー回数に20,000を乗じ、残りパルス数に加算します。この和を2で割ると、カウントが2回行われるため(制御パルスの立ち上がりと立ち下がりでパルスをカウント)、2回目のカウントが行われます。
ディスプレイの周波数を読みやすくするために、ultosとltosという機能を使って、3桁ごとにドットを挿入しています。この周波数は、LCDディスプレイに表示される以外に、Arduino IDEのシリアルコンソールにも送信されます。周波数サンプリング後、レジスタをリセットし、時刻とパルスカウントを再開します。
また、Arduino IDEのシリアルコンソールを使用して、テスト用に発振器の周波数を変更することも可能です。入力フィールドに1Hz~40MHzの値を入力し、ENTERを押します。
発振器のパルス出力はGPIO33ピンに設定されていますので、このパルス出力をGPIO34の周波数メータ入力に接続して、テストを行う必要があります。ただし、外部信号の周波数測定では、この接続を外してください。ESP32は3.3Vの電圧信号で動作するため、それ以外の電圧レベルの信号を測定したい場合は、入力ポートにロジックレベルコンバータ 3.3V-5V Bidirectional - 4 Channelを使用することを推奨します。内部ではGPIOマトリックスを使って、周波数計からの入力パルスをESP32のネイティブLEDに導き、周波数に応じてLEDを点滅させるようにしています。
■■使用したライブラリ■■
このプロジェクトで使用したArduino IDEのバージョンはV 1.8.12ですが、コードの非互換性を避けるため、バージョンが古い場合は更新してください。
2023年1月10日(火曜日)現在【【Arduino IDE 2.0.3】】
ESP32 Boardで使用するためのArduino IDEの設定がまだの場合は、以下のリンク先のチュートリアルの手順に従ってください。この設定は、プロジェクトが正常に動作するために必要不可欠です。 ESP32 BoardがTutorialと異なる場合は、Arduino IDEで設定を変更してください。
今回使用したArduino IDEのESP32ファームウェアのバージョンはV 1.0.4です。もし古い場合は、何らかの不具合を避けるために、プログラムをコンパイルする前にアップデートしてください。必要であれば、Board Managerを使用して更新します。
I2Cインターフェース(PCF8574)の液晶ディスプレイを使用するには、LiquidCrystal_PCF8574ライブラリのインストールが必要です。Arduino IDEのLibrary Managerを使用してインストールします。
また、パラレルLCDディスプレイ(4ビット)を使用する場合は、Arduino IDEのライブラリマネージャでLiquidCrystalライブラリもインストールしてください。
■回路図 Diagramas dos circuitos:
I2Cインターフェース搭載ディスプレイ(PCF8574)の構成図(画像を拡大するには、別のタブで開いてください。)
ディスプレイの裏に接続されているI2C Interfaceボード(PCF8574)のポテンショメーターで、ディスプレイの明るさを調整することを忘れないでください。ジャンパーは接続したままにしてください。
■ESP32 周波数メーターのプログラム。
表示選択指示
Arduino IDEコンパイラは、プログラムコンパイラのディレクティブを使用して、LCDディスプレイの種類を有効にしたり選択したりすることができます。
LCD並列使用 - LCD_ONまたはLCD_OFFに変更してください。
#define LCD_OFF ou #define LCD_ON // ON se for usar esse display
I2C LCDの使用 - LCD_I2C_ONまたはLCD_I2C_OFFに変更します。
#define LCD_I2C_ON ou #define LCD_I2C_OFF // ON se for usar esse display
OB:LCDのI2Cインターフェースのアドレスが分からない場合は、ESP32 I2C Scannerを使って調べてください:(私のボードのアドレスは0x3Fです)。
わたしのコメントです。★手持ちのLCDのボードアドレス:0x27
しかし、LCDディスプレイを使いたくない場合は、Arduino IDEのSerial Consoleで周波数の測定値を表示することができます。また、同じコンソールから、1Hzから40MHzの値の間で希望の試験周波数を入力することができます。とてもクールです。この方法で、プロジェクトが正しく組み立てられたことを確認し、周波数メーターをテストすることができます。
■周波数計の校正。
この設計のさらなる利点は、周波数測定の校正を可能にすることです。ESP32で通常表示される測定値は、非常に満足のいくものです。基準として使用される精密な周波数メーターを使用すると、プログラム内の変数ウィンドウの値を調整することができます。この値を変更することで、得られた精度よりもさらに高い精度を得ることができます。オシロスコープの周波数測定機能を使った周波数計のテストでは、ウィンドウの値を変えて、なんとかオシロスコープと同じ値を得ることができたんだ!」。
どちらのタイプの液晶ディスプレイも搭載しないことにした場合、周波数の測定値を確認するために
Arduino IDEシリアルコンソール
. コンソールスピードは、次のように設定します。
115200 Bps
. 周波数計の試験周波数を変更するには、入力フィールドに1Hz~40MHzの値を入力し、Enterキーを押します。ヘルツ(Hz)の単位は入力する必要がありません。しかし、このテストを行うには、次のことを忘れないでください。
周波数メータ入力 (GPIO34)
Oscilador (GPIO33)の出力に接続する必要があります。
しかし、LCDディスプレイを使いたくない場合は、Arduino IDEのSerial Consoleで周波数の測定値を表示することができます。また、同じコンソールから、1Hzから40MHzの値の間で希望の試験周波数を入力することができます。とてもクールです。この方法で、プロジェクトが正しく組み立てられたことを確認し、周波数メーターをテストすることができます。
■周波数計の校正。
この設計のさらなる利点は、周波数測定の校正を可能にすることです。ESP32で通常表示される測定値は、非常に満足のいくものです。基準として使用される精密な周波数メーターを使用すると、プログラム内の変数ウィンドウの値を調整することができます。この値を変更することで、得られた精度よりもさらに高い精度を得ることができます。オシロスコープの周波数測定機能を使った周波数計のテストでは、ウィンドウの値を変えて、なんとかオシロスコープと同じ値を得ることができたんだ!」。
どちらのタイプの液晶ディスプレイも搭載しないことにした場合、周波数の測定値を確認するために
Arduino IDEシリアルコンソール
. コンソールスピードは、次のように設定します。
115200 Bps
. 周波数計の試験周波数を変更するには、入力フィールドに1Hz~40MHzの値を入力し、Enterキーを押します。ヘルツ(Hz)の単位は入力する必要がありません。しかし、このテストを行うには、次のことを忘れないでください。
周波数メータ入力 (GPIO34)
Oscilador (GPIO33)の出力に接続する必要があります。
*********************************************
参考文献やWeb情報、他は割愛してます。
サンプリング時間変更や、TFT液晶への変更もできますね!
5MHz、6MHzのVFOの周波数などの利用でも100Hz桁も精度良く動作しているので十分使えると思います。
ESP32DevKitCは色々できて、やはりいいですね。
つづく?
execution time : 0.126 sec