Best Frequency Meter ever made with ESP32 - awesome!

User avatar
jgustavoam
Posts: 165
Joined: Thu Feb 01, 2018 2:43 pm
Location: Belo Horizonte , Brazil
Contact:

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby jgustavoam » Sun Jul 31, 2022 2:56 pm

Ahmet58 wrote:
Thu Apr 28, 2022 8:01 pm
Thank you so much. I will use this code for firebeetle esp32 iot. I even uploaded it. However, I guess I'll have to make a change to the schema. I need to define a differential input. I don't know how to do this with this card. Also, is external adc used in your project?
Hi,
We do not use ADC in this project.
What is your intention? Add a voltmeter with the frequencymeter?
Retired IBM Brasil
Electronic hobbyist since 1976.

User avatar
jgustavoam
Posts: 165
Joined: Thu Feb 01, 2018 2:43 pm
Location: Belo Horizonte , Brazil
Contact:

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby jgustavoam » Sun Jul 31, 2022 2:59 pm

Ahmet58 wrote:
Fri Apr 29, 2022 9:11 am
Also, I think the sample_time is a bit too much since the frequency range I want to measure is at most three digits for now. Can you tell me about the changes I can make to the code in this case?
Hi,

The sampling time is defined by the high resolution esp-timer, and it is defined in 1 second, in the sample-time variable.

Code: Select all

uint32_t        sample_time   = 1000000;                                  // sample time of 1 second to count pulses
Change the counter value to your need.
Retired IBM Brasil
Electronic hobbyist since 1976.

User avatar
jgustavoam
Posts: 165
Joined: Thu Feb 01, 2018 2:43 pm
Location: Belo Horizonte , Brazil
Contact:

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby jgustavoam » Sun Jul 31, 2022 3:06 pm

SarahC wrote:
Tue Jul 05, 2022 6:18 pm
Fantastic!

Why are pins 32 and 35 tied together? Is there a hardware reason... I thought any interrupt lock could be done in software?
Hi,

The only way we can control the counter. If you find another way, please let us know.

Code: Select all

#define PCNT_INPUT_CTRL_IO    GPIO_NUM_35                                 // Set Pulse Counter Control GPIO pin - HIGH = count up, LOW = count down  
#define OUTPUT_CONTROL_GPIO   GPIO_NUM_32                                 // Timer output control port - GPIO_32
Retired IBM Brasil
Electronic hobbyist since 1976.

Ahmet58
Posts: 21
Joined: Sat Jan 22, 2022 8:38 pm

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby Ahmet58 » Wed Nov 30, 2022 6:10 pm

Hi, can I use the code in firebeetle esp32? Is it possible?
What changes are needed.
Thank you.

User avatar
jgustavoam
Posts: 165
Joined: Thu Feb 01, 2018 2:43 pm
Location: Belo Horizonte , Brazil
Contact:

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby jgustavoam » Thu Dec 01, 2022 12:30 pm

Hi Ahmet,

I don't know this Firebleet, but seeing the characteristics on the site, I can say that the frequency meter can be assembled using it.
Retired IBM Brasil
Electronic hobbyist since 1976.

Ahmet58
Posts: 21
Joined: Sat Jan 22, 2022 8:38 pm

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby Ahmet58 » Thu Dec 01, 2022 1:52 pm

Thank you for the code. I'm installing on firebeetel esp32-e processor without any problems. In my project, I will use the 10hz-1000hz pulse frequency (not fixed, variable frequency) counted with this code in another code. I guess I need to use the "frequency" variable to call it with code.

Ahmet58
Posts: 21
Joined: Sat Jan 22, 2022 8:38 pm

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby Ahmet58 » Sat Dec 17, 2022 5:10 pm

Hi jgustavoam,
Frequency refresh while checking code execution on ide monitor
I see that the intervals are 1sec.

Frequency: 0 Hz
Frequency: 0 Hz
Frequency: 0 Hz
...........................
I wonder if this time is valid on the LCD screen as well. Therefore, even though I removed the delay(100) below, the refresh time on the ide monitor did not change. Where can I fix this situation?

" multPulses = 0; // Clear overflow counter
// Put your function here, if you want
//delay(100); // Delay 100 ms
// Put your function here, if you want "

User avatar
jgustavoam
Posts: 165
Joined: Thu Feb 01, 2018 2:43 pm
Location: Belo Horizonte , Brazil
Contact:

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby jgustavoam » Sun Dec 18, 2022 1:21 pm

Hi Ahmet,
Are you using the same program available here? Did you make any changes?
How are you testing the frequency meter? To test it connect the GPIO 32 (Oscillator) with the GPIO 35 (frequency meter) .
Please answer these questions.
Retired IBM Brasil
Electronic hobbyist since 1976.

Ahmet58
Posts: 21
Joined: Sat Jan 22, 2022 8:38 pm

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby Ahmet58 » Sun Dec 18, 2022 3:32 pm

Hi jgustavoam. No, I wanted to use the frequency counter in a generic code. I rearranged the pins according to the Firebeetle ESP32-e card. As I said, there is a problem with the IDE monitor. I am attaching the code.

I defined pin D7 (13) for osc output. When I measure this pin with an oscilloscope, I can see the 12.5khz pulse output. When I combine the pin number D9(2), which I defined for the signal input, with the osc output, the frequency appears as 14.043khz on the monitor. Also, when I use pin 34 as input pin, I see the frequency of 14.043khz in the same way.

Code: Select all

#include "stdio.h"             // Library STDIO
#include "driver/ledc.h"       // Library ESP32 LEDC
#include "driver/pcnt.h"
#include <pitches.h>
#include <Tone32.h>
#include <SPI.h>
#include <Wire.h>
#include <LIS3MDL.h>
#include <LiquidCrystal_I2C.h>// Library ESP32 PCNT

//int PotV, x=0 , y=0 , z=0;             
int k1=10, k2=20, k3=30, k4=40, k5=50, k6=60; // coefficent
int f[6],k[6];        // base frequencies
int fa[6],fb[6];      // intra group range
int Buzzer = 25;
int redLed = 16;
int greenLed = 17;
//int buttonState = 0;
const int PotPin = 35;
//const int BatPin = 36;
//int BatValue;
//int Voltage = 0;

LIS3MDL mag;
char report[80];

LiquidCrystal_I2C lcd(0x3f,16,2);
 
#define LCD_OFF                                             // LCD_ON, if want use LCD 4 bits interface 
#define LCD_I2C_OFF                                         // LCD_I2C_ON, if want use I2C LCD (PCF8574) 

//#ifdef LCD_I2C_ON                                           // If I2C LCD enabled 
//#define I2C_SDA 21                                          // LCD I2C SDA - GPIO_21
//#define I2C_SCL 22                                          // LCD I2C SCL - GPIO_22
                                                          
//#include <LiquidCrystal_PCF8574.h>                        // Library LCD with PCF8574
//LiquidCrystal_PCF8574 lcd(0x3F);                          // Instance LCD I2C - adress x3F
//#endif                                                      // LCD I2C

#ifdef LCD_ON                                               // LCD with 4 bits interface enabled 
#include <LiquidCrystal.h>                                  // Library LCD
LiquidCrystal lcd(4, 16, 17, 5, 18, 19);                    // Instance - ports RS,ENA,D4,D5,D6,D7
#endif                                                      // LCD

#define PCNT_COUNT_UNIT       PCNT_UNIT_0                   // Set Pulse Counter Unit - 0 
#define PCNT_COUNT_CHANNEL    PCNT_CHANNEL_0                // Set Pulse Counter channel - 0 

#define PCNT_INPUT_SIG_IO     GPIO_NUM_2                   // Set Pulse Counter input - Freq Meter Input GPIO 2
#define LEDC_HS_CH0_GPIO      GPIO_NUM_13                   // Saida do LEDC - gerador de pulsos - GPIO_13
#define PCNT_INPUT_CTRL_IO    GPIO_NUM_14                   // Set Pulse Counter Control GPIO pin - HIGH = count up, LOW = count down  
#define OUTPUT_CONTROL_GPIO   GPIO_NUM_0                   // Timer output control port - GPIO_0
#define PCNT_H_LIM_VAL        overflow                      // Overflow of Pulse Counter 

#define IN_BOARD_LED          GPIO_NUM_26                    // ESP32 native LED - GPIO 2

bool            flag          = true;                       // Flag to enable print frequency reading
uint32_t        overflow      = 1500;                       // Max Pulse Counter value
int16_t         pulses        = 0;                          // Pulse Counter value
uint32_t        multPulses    = 0;                          // Quantidade de overflows do contador PCNT
uint32_t        sample_time   = 1000000;                    // sample time of 1 second to count pulses
uint32_t        osc_freq      = 12543;                      // Oscillator frequency - initial 12543 Hz (may be 1 Hz to 40 MHz)
uint32_t        mDuty         = 0;                          // Duty value
uint32_t        resolution    = 0;                          // Resolution value
float           frequency     = 0;                          // frequency value
char            buf[32];                                    // Buffer

esp_timer_create_args_t create_args;                        // Create an esp_timer instance
esp_timer_handle_t timer_handle;                            // Create an single timer

portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;       // portMUX_TYPE to do synchronism

//----------------------------------------------------------------------------------------

void setup()
{

Serial.begin(115200);
while (!Serial) {
 }
  lcd.begin();
  lcd.backlight();
  //pinMode(buttonPin , INPUT);
  pinMode(PotPin, INPUT);
  pinMode(redLed , OUTPUT);
  pinMode(greenLed, OUTPUT);
  pinMode(Buzzer, OUTPUT);
 // pinMode(BatPin, INPUT);
    
  Wire.begin();
  
 // buttonState = digitalRead(buttonPin);
  
  Serial.println(" Input the Frequency - 1 to 40 MHz");                   // Console print

  #ifdef LCD_I2C_ON                                                         // If usinf I2C LCD
  Wire.begin(I2C_SDA, I2C_SCL);                                           // Begin I2C Interface
  lcd.setBacklight(255);                                                  // Set I2C LCD Backlight ON
  #endif

  #if defined LCD_ON || defined LCD_I2C_ON                                  // If using LCD or I2C LCD     
  lcd.begin(16, 2);                                                       // LCD init 16 x 2
  lcd(1);                                                                 // LCD print
  #endif

  init_frequencyMeter ();                                                 // Initialize Frequency Meter
}

void loop()
{

//BatValue = analogRead(BatPin); //BatValue High=4095
//Voltage = ((12.6/4095.0)*BatValue); //!! 12.6v için uygun dirençle voltaj bölünmeli; BatValue High=4095.
 
PotV = analogRead(PotPin);
PotV = map(PotV,0,4095,0,100);//manyetik büyüklük yerine geçecek pot değeri.

f[0]= k[0]*PotV; f[1]= k[1]*PotV; f[2]= k[2]*PotV; 
f[3]= k[3]*PotV; f[4]= k[4]*PotV; f[5]= k[5]*PotV;
  
// calculation of intra group frequencies
// lower range  .... upper range

  fa[0] = f[0] * 0.9;    fb[0] = f[0] * 1.1;              
  fa[1] = f[1] * 0.9;    fb[1] = f[1] * 1.1;
  fa[2] = f[2] * 0.9;    fb[2] = f[2] * 1.1;
  fa[3] = f[3] * 0.9;    fb[3] = f[3] * 1.1;
  fa[4] = f[4] * 0.9;    fb[4] = f[4] * 1.1;
  fa[5] = f[5] * 0.9;    fb[5] = f[5] * 1.1;

   
  if (flag == true)                                                     // If count has ended
  {
    flag = false;                                                       // change flag to disable print
    frequency = (pulses + (multPulses * overflow)) / 2  ;               // Calculation of frequency
    printf("Frequency : %s", (ltos(frequency, buf, 10)));               // Print frequency with commas
    printf(" Hz \n");                                                   // Print unity Hz


    #if defined LCD_ON || defined LCD_I2C_ON                                // If using LCD or I2C LCD  
    
     if ((frequency >= fa[0]) && (frequency <= fb[0]))
     {                                                           
      lcd2();
      }
      else if((frequency >= fa[1]) && (frequency <= fb[1]))
      {                                                           
      lcd3();
      }
      else if ((frequency >= fa[2]) && (frequency <= fb[2]))
      {                                                           
      lcd4();
       }
      else if ((frequency >= fa[3]) && (frequency <= fb[3]))
      {                                                           
      lcd5();
      }
      else if ((frequency >= fa[4]) && (frequency <= fb[4]))
      {                                                           
      lcd6();
      }
      else if ((frequency >= fa[5]) && (frequency <= fb[5]))
      {                                                           
      lcd7();
      }
  
      else { 
      lcd8();  
      }                                     
    
      #endif

    multPulses = 0;                                                     // Clear overflow counter
    // Put your function here, if you want
    delay (100);                                                        // Delay 100 ms
    // Put your function here, if you want

    pcnt_counter_clear(PCNT_COUNT_UNIT);                                // Clear Pulse Counter
    esp_timer_start_once(timer_handle, sample_time);                    // Initialize High resolution timer (1 sec)
    gpio_set_level(OUTPUT_CONTROL_GPIO, 1);                             // Set enable PCNT count
  }

  String inputString = "";                                               // clear temporary string
  osc_freq = 0;                                                          // Clear oscillator frequency
  while (Serial.available())
  {
    char inChar = (char)Serial.read();                                   // Reads a byte on the console
    inputString += inChar;                                               // Add char to string
    if (inChar == '\n')                                                  // If new line (enter)
    {
      osc_freq = inputString.toInt();                                    // Converts String into integer value
      inputString = "";                                                  // Clear string
    }
  }
  
  if (osc_freq != 0)                                                     // If some value inputted to oscillator frequency
  {
    init_osc_freq ();                                                    // reconfigure ledc function - oscillator 
  }
  
  // ----------------- frequency osc end ------------------------------//    
    
      
  
}

void lcd1()
{
  lcd.setCursor(0,0);
  lcd.print("LF SIGNAL DETECTION ");
  lcd.setCursor(0,1);
  lcd.print(" ..PLEASE WAIT..");
}

void lcd2(){
     digitalWrite(greenLed, HIGH);      
     lcd.setCursor(0,0);     
     lcd.print("S: ");
     lcd.print( (ltos(frequency, buf, 1)));
     lcd.print(" Hz");
     lcd.setCursor(0,1);
     lcd.print("Gr: 1" );
     lcd.print("    M:" );
     lcd.print(PotV);     
     tone(Buzzer , 2000 , 100);
     }
     
void lcd3(){
     digitalWrite(greenLed, HIGH);      
     lcd.setCursor(0,0);     
     lcd.print("S: ");
     lcd.print( (ltos(frequency, buf, 1)));
     lcd.print(" Hz");
     lcd.setCursor(0,1);
     lcd.print("Gr: 2" );
     lcd.print("    M:" );
     lcd.print(PotV);
     tone(Buzzer , 2000 , 100);
     }
void lcd4(){
     digitalWrite(greenLed, HIGH);      
     lcd.setCursor(0,0);     
     lcd.print("S: ");
     lcd.print( (ltos(frequency, buf, 1)));
     lcd.print(" Hz");
     lcd.setCursor(0,1);
     lcd.print("Gr: 3" );
     lcd.print("    M:" );
     lcd.print(PotV);
     tone(Buzzer , 2000 , 100);
     }
void lcd5(){
     digitalWrite(greenLed, HIGH);      
     lcd.setCursor(0,0);     
     lcd.print("S: ");
     lcd.print( (ltos(frequency, buf, 1)));
     lcd.print(" Hz");
     lcd.setCursor(0,1);
     lcd.print("Gr: 4" );
     lcd.print("    M:" );
     lcd.print(PotV);
     tone(Buzzer , 2000 , 100);
     }
void lcd6(){
     digitalWrite(greenLed, HIGH);      
     lcd.setCursor(0,0);     
     lcd.print("S: ");
     lcd.print( (ltos(frequency, buf, 1)));
     lcd.print(" Hz");
     lcd.setCursor(0,1);
     lcd.print("Gr: 5" );
     lcd.print("    M:" );
     lcd.print(PotV);
     tone(Buzzer , 2000 , 100);
     }
void lcd7(){
     digitalWrite(greenLed, HIGH);      
     lcd.setCursor(0,0);     
     lcd.print("S: ");
     lcd.print( (ltos(frequency, buf, 1)));
     lcd.print(" Hz");
     lcd.setCursor(0,1);
     lcd.print("Gr: 6" );
     lcd.print("    M:" );
     lcd.print(PotV);
     tone(Buzzer , 2000 , 100);
     }                        

void lcd8(){
     digitalWrite(redLed, HIGH);      
     lcd.setCursor(0,0);     
     lcd.print("S: ");
     lcd.print( (ltos(frequency, buf, 1)));
     lcd.print(" Hz");
     lcd.setCursor(0,1);     
     lcd.print("M: " );
     lcd.print(PotV);
     tone(Buzzer , 100 , 500);
     }

      void init_osc_freq ()                                                     // Initialize Oscillator to test Freq Meter
{
  resolution = (log (80000000 / osc_freq)  / log(2)) / 2 ;                // Calc of resolution of Oscillator
  if (resolution < 1) resolution = 1;                                     // set min resolution 
  // Serial.println(resolution);                                          // Print
  mDuty = (pow(2, resolution)) / 2;                                       // Calc of Duty Cycle 50% of the pulse
  // Serial.println(mDuty);                                               // Print

  ledc_timer_config_t ledc_timer = {};                                    // LEDC timer config instance

  ledc_timer.duty_resolution =  ledc_timer_bit_t(resolution);             // Set resolution
  ledc_timer.freq_hz    = osc_freq;                                       // Set Oscillator frequency
  ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE;                           // Set high speed mode
  ledc_timer.timer_num = LEDC_TIMER_0;                                    // Set LEDC timer index - 0
  ledc_timer_config(&ledc_timer);                                         // Set LEDC Timer config

  ledc_channel_config_t ledc_channel = {};                                // LEDC Channel config instance

  ledc_channel.channel    = LEDC_CHANNEL_0;                               // Set HS Channel - 0
  ledc_channel.duty       = mDuty;                                        // Set Duty Cycle 50%
  ledc_channel.gpio_num   = LEDC_HS_CH0_GPIO;                             // LEDC Oscillator output GPIO 33
  ledc_channel.intr_type  = LEDC_INTR_DISABLE;                            // LEDC Fade interrupt disable
  ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;                         // Set LEDC high speed mode
  ledc_channel.timer_sel  = LEDC_TIMER_0;                                 // Set timer source of channel - 0
  ledc_channel_config(&ledc_channel);                                     // Config LEDC channel
}


//----------------------------------------------------------------------------------
static void IRAM_ATTR pcnt_intr_handler(void *arg)                        // Counting overflow pulses
{
  portENTER_CRITICAL_ISR(&timerMux);                                      // disabling the interrupts
  multPulses++;                                                           // increment Overflow counter
  PCNT.int_clr.val = BIT(PCNT_COUNT_UNIT);                                // Clear Pulse Counter interrupt bit
  portEXIT_CRITICAL_ISR(&timerMux);                                       // enabling the interrupts
}

//----------------------------------------------------------------------------------
void init_PCNT(void)                                                      // Initialize and run PCNT unit
{
  pcnt_config_t pcnt_config = { };                                        // PCNT unit instance

  pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_IO;                         // Pulse input GPIO 34 - Freq Meter Input
  pcnt_config.ctrl_gpio_num = PCNT_INPUT_CTRL_IO;                         // Control signal input GPIO 35
  pcnt_config.unit = PCNT_COUNT_UNIT;                                     // Unidade de contagem PCNT - 0
  pcnt_config.channel = PCNT_COUNT_CHANNEL;                               // PCNT unit number - 0
  pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;                             // Maximum counter value - 20000
  pcnt_config.pos_mode = PCNT_COUNT_INC;                                  // PCNT positive edge count mode - inc
  pcnt_config.neg_mode = PCNT_COUNT_INC;                                  // PCNT negative edge count mode - inc
  pcnt_config.lctrl_mode = PCNT_MODE_DISABLE;                             // PCNT low control mode - disable
  pcnt_config.hctrl_mode = PCNT_MODE_KEEP;                                // PCNT high control mode - won't change counter mode
  pcnt_unit_config(&pcnt_config);                                         // Initialize PCNT unit

  pcnt_counter_pause(PCNT_COUNT_UNIT);                                    // Pause PCNT unit
  pcnt_counter_clear(PCNT_COUNT_UNIT);                                    // Clear PCNT unit

  pcnt_event_enable(PCNT_COUNT_UNIT, PCNT_EVT_H_LIM);                     // Enable event to watch - max count
  pcnt_isr_register(pcnt_intr_handler, NULL, 0, NULL);                    // Setup Register ISR handler
  pcnt_intr_enable(PCNT_COUNT_UNIT);                                      // Enable interrupts for PCNT unit

  pcnt_counter_resume(PCNT_COUNT_UNIT);                                   // Resume PCNT unit - starts count
}

//----------------------------------------------------------------------------------
void read_PCNT(void *p)                                                   // Read Pulse Counter
{
  gpio_set_level(OUTPUT_CONTROL_GPIO, 0);                                 // Stop counter - output control LOW
  pcnt_get_counter_value(PCNT_COUNT_UNIT, &pulses);                       // Read Pulse Counter value
  flag = true;                                                            // Change flag to enable print
}

//---------------------------------------------------------------------------------
void init_frequencyMeter ()
{
  init_osc_freq();                                                        // Initialize Oscillator
  init_PCNT();                                                            // Initialize and run PCNT unit

  gpio_pad_select_gpio(OUTPUT_CONTROL_GPIO);                              // Set GPIO pad
  gpio_set_direction(OUTPUT_CONTROL_GPIO, GPIO_MODE_OUTPUT);              // Set GPIO 32 as output

  create_args.callback = read_PCNT;                                       // Set esp-timer argument
  esp_timer_create(&create_args, &timer_handle);                          // Create esp-timer instance

  gpio_set_direction(IN_BOARD_LED, GPIO_MODE_OUTPUT);                     // Set LED inboard as output

  gpio_matrix_in(PCNT_INPUT_SIG_IO, SIG_IN_FUNC226_IDX, false);           // Set GPIO matrin IN - Freq Meter input
  gpio_matrix_out(IN_BOARD_LED, SIG_IN_FUNC226_IDX, false, false);        // Set GPIO matrix OUT - to inboard LED
}

//----------------------------------------------------------------------------------------
char *ultos_recursive(unsigned long val, char *s, unsigned radix, int pos) // Format an unsigned long (32 bits) into a string
{
  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++ = ',';
  return s;
}
//----------------------------------------------------------------------------------------
char *ltos(long val, char *s, int radix)                                  // Format an long (32 bits) into a string
{
  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;
}

Ahmet58
Posts: 21
Joined: Sat Jan 22, 2022 8:38 pm

Re: Best Frequency Meter ever made with ESP32 - awesome!

Postby Ahmet58 » Sun Dec 18, 2022 7:11 pm

Ok jgustavoam. I found what is causing the wrong frequency measurement.
in the original code;
uint32_t overflow = 20000;
Although,
i then this line;
uint32_t overflow = 1500;
I changed it to. I fixed it now and the count is correct. Despite this, unfortunately, the problem of the refresh rate of the lines on the monitor with 1 second intervals still persists. So, when I try your original code, the lines are refreshed on the monitor with a delay of 1 second.

Who is online

Users browsing this forum: Majestic-12 [Bot] and 143 guests