ساخت اسیلوسکوپ با ESP32 ارزان قیمت: اسیلوسکوپ یک ابزار آزمایشی ضروری برای هر مهندس الکترونیک است. برای مشاهده سیگنال‌های مختلف، معمولاً به صورت یک نمودار دو بعدی با یک یا چند سیگنال در زمان استفاده می‌شود.

 این دستگاه در طراحی و اشکال زدایی دستگاه های الکترونیکی برای مشاهده و مقایسه شکل موج ها و تعیین سطوح ولتاژ، فرکانس، نویز و سایر پارامترهای سیگنال اعمال شده در ورودی آن با تغییر با زمان استفاده می شوند. این امر اسیلوسکوپ را به ابزاری بسیار مهم بر روی میز یک مهندس یا سازنده الکترونیک تبدیل می کند.

 با این حال، اسیلوسکوپ ها بسیار گران هستند. مدل های پایه می توانند از 500 تا 2000 دلار قیمت داشته باشند. و اسیلوسکوپ های پیشرفته چند هزار دلار قیمت دارند که آنها را از دسترس کاربران اصلی خارج می کند.

 اما چه می‌شد اگر بتوانیم یکی را بسازیم که ارزان‌تر، فشرده‌تر و آسان‌تر ساخته شود؟ این سوالی است که منجر به آموزش امروز شد.

ویژگی های اسیلوسکوپ با ESP32

  • تک کانال
  • 1Msps
  • بافر 50000 @ 16bit (50ms داده در 1Msps)
  • مقیاس از 10us/div به 5ms/div در 1Msps
  • حداکثر VPP 3.3 ولت در 1X و 33V در حالت 10X
  • کنترل سریع و پاسخگو با استفاده از سوئیچ های فشاری.
  • محاسبات فرکانس (20 هرتز به دلیل اندازه بافر)
  • فیلتر mean ساده روشن/خاموش
  • حداکثر، حداقل، متوسط و ولتاژ پیک پیک
  • افست زمان و ولتاژ
  • حالت آنالوگ، دیجیتال/داده
  • تک TRIGGER
  • AUTOSCALE

اجزای مورد نیاز برای ساخت اسیلوسکوپ با ESP32

  • ESP32 Devkit
  • 1.69” 240×280 Rounded Corner TFT display(ST7789s)
  • Tactile switches
  • SPDT switches
  • 100K resistor
  • 10K resistor
  • 100nF capacitor
  • Copper clad or perfboard
  • Soldering tools

شماتیک مدار اسیلوسکوپ با ESP32

شماتیک مدار کامل اسیلوسکوپ با ESP32 در زیر آورده شده است.

ساخت اسیلوسکوپ با ESP32 به همراه شماتیک، کد و PCB

ESP32 به عنوان کنترل کننده برای جمع آوری داده ها استفاده می شود. ما از بافر داخلی I2S برای ذخیره و دستکاری سیگنال ها استفاده خواهیم کرد. در اینجا از نوع 38 پین استفاده می شود، اما می توانید از ماژول های توسعه دیگر نیز استفاده کنید.

ساخت اسیلوسکوپ با ESP32 به همراه شماتیک، کد و PCB

برای نمایشگر، ما از یک ماژول صفحه نمایش 1.69 اینچی TFT استفاده می کنیم. وضوح تصویر 240×280 پیکسل است. کنترلر نمایشگر ST7789S است و برای درایو آن، از ارتباط SPI استفاده خواهیم کرد.

ساخت اسیلوسکوپ با ESP32 به همراه شماتیک، کد و PCB

ماژول همچنین دارای یک اسلات کارت SD است که ما از آن استفاده نکرده ایم. ما می توانیم از این برای ضبط شکل موج یا کاربرد های مشابه در به روز رسانی آینده استفاده کنیم.

ساخت اسیلوسکوپ با ESP32 به همراه شماتیک، کد و PCB

صفحه کلید بسیار ساده است. برای این منظور از کلیدهای لمسی با مقاومت پول آپ استفاده می شود. ما از وقفه سخت افزاری برای تشخیص هر فشار کلید استفاده می کنیم. 

ساخت اسیلوسکوپ با ESP32 به همراه شماتیک، کد و PCB

بخش ورودی آنالوگ نسبتاً ساده است. از دو سوئیچ SPDT برای انتخاب محدوده و انتخاب کوپلینگ AC/DC تشکیل شده است. برای انتخاب محدوده، ما یک تقسیم کننده ولتاژ اضافه کرده ایم که می تواند برای تغذیه سیگنال هایی که ولتاژ پیک بالاتر از 3.3 ولت دارند استفاده شود. تقسیم کننده ولتاژ سیگنال را به نسبت 10:1 تبدیل می کند.

ساخت اسیلوسکوپ با ESP32 به همراه شماتیک، کد و PCB

ساخت و تست مدار

شما می توانید این پروژه را در برد های هزار سوراخ یا برد بورد بسازید یا می توانید فایل ها را از لینک پایین صفحه دانلود کرده و یک PCB بسازید. هر دو فایل PDF برای روش انتقال تونر و فایل Gerber برای ساخت گنجانده شده است. در اینجا طرح PCB برای اسیلوسکوپ آمده است.

ساخت اسیلوسکوپ با ESP32 به همراه شماتیک، کد و PCB

نمای قظعات روی برد

ساخت اسیلوسکوپ با ESP32 به همراه شماتیک، کد و PCB

نمای PCB سمت پایین.

ساخت اسیلوسکوپ با ESP32 به همراه شماتیک، کد و PCB

کد آردوینو

کل کد آردوینو برای اسیلوسکوپ با ESP32 را از این قسمت، دانلود کنید

در مخزن GitHub، شما همچنین می توانید بایگانی به نام TFT_eSPI را پیدا کنید. این کتابخانه اصلاح شده برای درایو نمایشگر ضروری است. آن را در پوشه کتابخانه آردوینو استخراج کنید.اگر قبلاً کتابخانه TFT_eSPI را نصب کرده‌اید، قبل از استخراج کتابخانه ویرایش‌شده، حتماً آن را حذف کنید.

 پس از اتمام کار، esp32 را در board manager انتخاب کنید. سپس کد را کامپایل کرده و آپلود کنید. این اسیلوسکوپ DIY ما آماده استفاده است. شما می توانید اسیلوسکوپ را با استفاده از پورت Micro USB در پایین تغذیه کنید. این پورت فقط برای پاور است.

#include <Arduino.h>
#include <driver/i2s.h>
#include <driver/adc.h>
#include <soc/syscon_reg.h>
#include <TFT_eSPI.h>
#include <SPI.h>
#include "esp_adc_cal.h"
#include "filters.h"
//#define DEBUG_SERIAL
//#define DEBUG_BUFF
#define DELAY 1000
// Width and height of sprite
#define WIDTH  240
#define HEIGHT 280
#define ADC_CHANNEL   ADC1_CHANNEL_5  // GPIO33
#define NUM_SAMPLES   1000            // number of samples
#define I2S_NUM         (0)
#define BUFF_SIZE 50000
#define B_MULT BUFF_SIZE/NUM_SAMPLES
#define BUTTON_Ok        32
#define BUTTON_Plus        15
#define BUTTON_Minus        35
#define BUTTON_Back        34
TFT_eSPI    tft = TFT_eSPI();         // Declare object "tft"
TFT_eSprite spr = TFT_eSprite(&tft);  // Declare Sprite object "spr" with pointer to "tft" object
esp_adc_cal_characteristics_t adc_chars;
TaskHandle_t task_menu;
TaskHandle_t task_adc;
float v_div = 825;
float s_div = 10;
float offset = 0;
float toffset = 0;
uint8_t current_filter = 1;
//options handler
enum Option {
  None,
  Autoscale,
  Vdiv,
  Sdiv,
  Offset,
  TOffset,
  Filter,
  Stop,
  Mode,
  Single,
  Clear,
  Reset,
  Probe,
  UpdateF,
  Cursor1,
  Cursor2
};
int8_t volts_index = 0;
int8_t tscale_index = 0;
uint8_t opt = None;
bool menu = false;
bool info = true;
bool set_value  = false;
float RATE = 1000; //in ksps --> 1000 = 1Msps
bool auto_scale = false;
bool full_pix = true;
bool stop = false;
bool stop_change = false;

uint16_t i2s_buff[BUFF_SIZE];

bool single_trigger = false;
bool data_trigger = false;

bool updating_screen = false;
bool new_data = false;
bool menu_action = false;
uint8_t digital_wave_option = 0; //0-auto | 1-analog | 2-digital data (SERIAL/SPI/I2C/etc)
int btnok,btnpl,btnmn,btnbk;
void IRAM_ATTR btok()
{
  btnok = 1;
}
void IRAM_ATTR btplus()
{
  btnpl = 1;
}
void IRAM_ATTR btminus()
{
  btnmn = 1;
}
void IRAM_ATTR btback()
{
  btnbk = 1;
}
void setup() {
  Serial.begin(115200);

  configure_i2s(1000000);

  setup_screen();

  pinMode(BUTTON_Ok , INPUT);
  pinMode(BUTTON_Plus , INPUT);
  pinMode(BUTTON_Minus , INPUT);
  pinMode(BUTTON_Back , INPUT);
  attachInterrupt(BUTTON_Ok, btok, RISING);
  attachInterrupt(BUTTON_Plus, btplus, RISING);
  attachInterrupt(BUTTON_Minus, btminus, RISING);
  attachInterrupt(BUTTON_Back, btback, RISING);

  characterize_adc();
#ifdef DEBUG_BUF
  debug_buffer();
#endif

  xTaskCreatePinnedToCore(
    core0_task,
    "menu_handle",
    10000,  /* Stack size in words */
    NULL,  /* Task input parameter */
    0,  /* Priority of the task */
    &task_menu,  /* Task handle. */
    0); /* Core where the task should run */

  xTaskCreatePinnedToCore(
    core1_task,
    "adc_handle",
    10000,  /* Stack size in words */
    NULL,  /* Task input parameter */
    3,  /* Priority of the task */
    &task_adc,  /* Task handle. */
    1); /* Core where the task should run */
}


void core0_task( void * pvParameters ) {

  (void) pvParameters;

  for (;;) {
    menu_handler();

    if (new_data || menu_action) {
      new_data = false;
      menu_action = false;

      updating_screen = true;
      update_screen(i2s_buff, RATE);
      updating_screen = false;
      vTaskDelay(pdMS_TO_TICKS(10));
      Serial.println("CORE0");
    }

    vTaskDelay(pdMS_TO_TICKS(10));
  }

}

void core1_task( void * pvParameters ) {

  (void) pvParameters;

  for (;;) {
    if (!single_trigger) {
      while (updating_screen) {
        vTaskDelay(pdMS_TO_TICKS(1));
      }
      if (!stop) {
        if (stop_change) {
          i2s_adc_enable(I2S_NUM_0);
          stop_change = false;
        }
        ADC_Sampling(i2s_buff);
        new_data = true;
      }
      else {
        if (!stop_change) {
          i2s_adc_disable(I2S_NUM_0);
          i2s_zero_dma_buffer(I2S_NUM_0);
          stop_change = true;
        }
      }
      Serial.println("CORE1");
      vTaskDelay(pdMS_TO_TICKS(300));
    }
    else {
      float old_mean = 0;
      while (single_trigger) {
        stop = true;
        ADC_Sampling(i2s_buff);
        float mean = 0;
        float max_v, min_v;
        peak_mean(i2s_buff, BUFF_SIZE, &max_v, &min_v, &mean);

        //signal captured (pp > 0.4V || changing mean > 0.2V) -> DATA ANALYSIS
        if ((old_mean != 0 && fabs(mean - old_mean) > 0.2) || to_voltage(max_v) - to_voltage(min_v) > 0.05) {
          float freq = 0;
          float period = 0;
          uint32_t trigger0 = 0;
          uint32_t trigger1 = 0;

          //if analog mode OR auto mode and wave recognized as analog
          bool digital_data = !false;
          if (digital_wave_option == 1) {
            trigger_freq_analog(i2s_buff, RATE, mean, max_v, min_v, &freq, &period, &trigger0, &trigger1);
          }
          else if (digital_wave_option == 0) {
            digital_data = digital_analog(i2s_buff, max_v, min_v);
            if (!digital_data) {
              trigger_freq_analog(i2s_buff, RATE, mean, max_v, min_v, &freq, &period, &trigger0, &trigger1);
            }
            else {
              trigger_freq_digital(i2s_buff, RATE, mean, max_v, min_v, &freq, &period, &trigger0);
            }
          }
          else {
            trigger_freq_digital(i2s_buff, RATE, mean, max_v, min_v, &freq, &period, &trigger0);
          }

          single_trigger = false;
          new_data = true;
          Serial.println("Single GOT");
          //return to normal execution in stop mode
        }

        vTaskDelay(pdMS_TO_TICKS(1));   //time for the other task to start (low priorit)

      }
      vTaskDelay(pdMS_TO_TICKS(300));
    }
  }
}
void loop() {}

ویدیو نحوه عملکرد

در این قسمت ویدیویی از نحوه عملکرد پروژه اسیلسکوپ با ESP32 آورده شده توجه کنید که این ویدیو در یوتیوب اپلود شده در صورت نیاز از تحریم شکن استفاده کنید

برای امتیاز به این نوشته کلیک کنید!
[کل: 0 میانگین: 0]
بازگشت به لیست

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد.