jl7gmnのblog

yahooブログから移行してきました。アマチュア無線を中心としたブログです。

愛知タワー風速値表示追加その1

タワーには風速カウンター表示部がユニットでついていますが、他のところへカウンターを新たに追加したくて、久々にゲート回路を組んでみる事にしました。タワーの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!)
インターフェースとなる回路図です。
anemometer-circuit

表示ユニット端子に繋がっている線を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

ある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);

ほか,修正箇所として、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();

 #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 ();  //発振器の周波数をリセットする
  }
}

***********************************************
上記のスケッチでは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

上記のカウントした周波数の誤差は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です)。

わたしのコメントです。★手持ちのLCDのボードアドレス:0x27

しかし、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は色々できて、やはりいいですね。

つづく?

FT-2000DをICOMチューナーに繋ぐ自動制御その6

ICOMのアンテナチューナーの接続端子を確認していて、インターフェース回路上での変更が必要なことが分かりました。内容は、+13Vの電源供給ラインがAC電源供給タイプのIC-AT100は不要で、電源供給必要なAT-150の場合のみFT-2000DのBAND-DATAから供給するという内容です。インターフェース回路上にショートピンヘッド(3P)で対応する様にパターンを修正します。パターン上のピンショートでも、あとから切り替えSWを外付けのどちらでも対応可能です。

■JP30(3P)でAT-150のときのみショートピンで13V供給になります。IC-AT100のときはIC-AT100の内蔵電源供給されているので端子からの13V供給は不要です。3PはオープンでIC-AT100です。
回路図はAT-150時の状態です。
修正13V供給ライン
■13Vライン修正パターン箇所
修正13Vライン

■ボトム全体のパターン(近くの部品のパターンレイアウトを若干修正しています。)
修正ボトムパターン

■最終GND ベタアース処理(Polygon ,Ratsnest処理)
POLYGON-RATSNEST
■ポリゴン、Ratsnest処理完了後のボトムパターン
パターンの外周は必ずアースパターンとなるようにパターン作製しています。
ボトムベタアース化

パターンを切削する前にICOMのチューナーの電源供給の違いに気がつき、修正できホットしています。
焦らずステップバイステップです。それぞれの全端子の仕様確認も怠ってはいけませんね!

あとの修正はないかと思いますが、もう少し冷静に確認してみます。
問題なければ、切削のマシーン設置の準備です。

つづく?

FT-2000DをICOMチューナーに繋ぐ自動制御その5

気が向いたので、EAGLE CADでパターンを作製してみました。今回は抵抗が結構本数あるので、ジャンパー無しでの対応でできそうです。それから今回は基板作製してから、結構回路変更があったりと、急な回路変更等にも対応出来る様に未使用のポートにもピン端子を付けてみました。空き端子を使った機能追加や、ポート変更対応も出来上がった基板にても容易に対応できる様になります。
基板サイズはEAGLE CADでフリーで使用出来るサイズ 100X80mmです。基板はFR4を使います。

■未使用ポート引き出しピンヘッド追加した回路図
四角い枠がピンヘッド端子です。回路図上での引き出しでパターン上に
ランドを作製するためです。パターン上でESP32の下のピンヘッドは
は取り付けできません。引き出しランドとして使用することになります。
それ以外はピンを取り付けします。

YtoI-ADCIRCUIT

■作製パターン(ボトムパターン)
ボトムパターン

パターンができましたが、切削マシーンを片付けてしまっているので、準備しないといけません。テーブルの上には、先に購入した実験用セットがあり、簡単には動かせません。切削マシーンを置くスペースがありません。少し考えないといけません。どこに設置しましょうか?他愛のない事で悩んでいます。

IC-AT100、AT-150でもレベル用ICに使う8Vのリファレンス電圧が必要でしたが、間に合わせでアジャストタイプのレギュレータを使用していましたが、8Vのレギュレータパーツが入手できましたので、確認してみました。リファレンス用ということでピッタリと8.0Vでないといけないと思っていましたが、レギュレータ自体の出力電圧は計ってみると7.8V台です。不良かと思いましたが仕様を見てみると最小7.7V、最大が8.3Vと結構幅があるのでビックリです。実際交換して使ってみましたが、特に問題は無い様でした。

REG8V


つづく?

FT-2000DをICOMチューナーに繋ぐ自動制御その4

FT-2000DのBAND-DATAの4BITデータを使い現在の周波数をESP32DevKitCで判別し対応する周波数帯に対応する電圧を出力するため、更にD/A変換を使いOPアンプでの電圧変換しICOMのチューナーのバンド自動選択用の電圧を得ています。BCDの周波数判別、そしてA/D出力電圧発生の動作確認は特に大した問題もありませんでした。次のステップとしてはチューナーに繫いでの動作確認です。チューナーの回路図をみていて肝心のリファレンス電圧の+8Vの用意をしていない事が分かり急遽、購入してあった可変式の電圧レギュレータを+8Vにアジャストし、確認回路とをIC-AT100に接続し確認してみることにしました。
結果は動作OKです。上手く動作してくれました。BCDコードSWで作製した仮のFT-2000DのBAND-DATAですが、100%動作してくれています。チュナーを運用中、途中で止まったり、バンドが変わったりしないか、同じバンド7MHzに設定したままで放置試験をしています。4、5時間点けっぱなしでしたが、何も起こらずOKの様です。
今も、継続して設定しっぱなしの確認続けています。

上手く動作してくれましたので、現状の回路図をEAGLE CADで纏めました。

'2022/dec/09回路図間違い修正差替
ytoi-circuit

回路図上ではピンヘッドで別々に記載したターミナルとしていますが、実際はまとまりが1つのコネクタになります。
(FT-2000D BAND-DATAの記載のピンヘッドと、チューナー側のAT-100 AT-150の記載のピンヘッド)
AT-100の接続用コネクタは変わった形状をしています。専用コネクタが準備できてないので、配線の引き出し場所とか検討が必要。AT-150はコネクタがあるので問題なし。FT-2000DのBAND-DATA用コネクタもあるので問題なし。

今回作製の回路と各機器はFT-2000Dのバンドデータ様コネクタ1つとチュナー側のコネクタの2つだけでの接続です。回路とチュナーの電源供給はFT-2000Dからでの構想です。電流が足りるかも実際の接続で確認します。

'2022/dec/09回路図間違い修正差替
ytoi-circuit

パターンの作製は後で行なう予定でいます。
毎回思いますが、回路部品も少なく、とてもシンプルになっています、8ピンのOPアンプ回路とコネクタと電源用のレギュレータが目立つ位です。ソフトウェアのウェイトがかなりしめていると言えます。スケッチ自体に時間がかかっていますから実際そうです。
インターフェース回路はESP32DevKitCでのD/A出力とOPアンプでの電圧変換回路構成です。使ったD/A出力はArduinoNano,UNOにはありませんから、D/A出力機能のあるESP32DevKitCはいろんな事に対応できる素晴らしいCPUだと思います。Hi!

つづく?

アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード
  • ライブドアブログ