ساخت متر دیجیتال آردوینو

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

قطعات مورد نیاز برای ساخت متر دیجیتال آردوینو

  1. آردوینو پرو مینی
  2. ماژول USB به TTL (برای پروگرم کردن Pro-Mini)
  3. روتاری انکودر (با تعداد پالس بالا در هر دور)
  4. باتری Li-Po 700mAh
  5. ماژول TP4056
  6. سوئیچ فشاری
  7. کلید کلنگی

نحوه عملکرد پروژه متر دیجیتال آردوینو

این پروژه از اصول اولیه کارکرد روتاری انکودر استفاده میکند. برای درک جامع تر از نحوه کار روتاری انکودر می توانید به این مقاله مراجعه کنید. به طور خلاصه کار روتاری انکودر این است که چرخش شفت روتاری انکودر را به یک سری پالس تبدیل می کند. انکودر دو پالس تولید میکند که دارای اختلاف فاز 90 درجه هستند که با ارزیابی این دو فاز به راحتی می توان جهت چرخش ماژول را تعیین کرد.

در کنار اینها، ما باید یک سوئیچ فشاری ساده داشته باشیم که به عنوان دکمه تنظیم مجدد عمل می کند، با استفاده از یک سیگنال از دکمه تنظیم مجدد می توانیم شمارنده را صفر کنیم. به عنوان مغز اصلی سیستم و برای کنترل همه ماژول های خود، از Arduino Pro-Mini استفاده خواهیم کرد. این به عنوان کنترل کننده اصلی ما برای پردازش پالس ها از روتاری انکودر عمل می کند و مقدار اندازه گیری شده را از طریق پروتکل SPI روی صفحه نمایش OLED نمایش می دهد.

شماتیک اتصال پروژه متر دیجیتال آروینو

ساخت متر دیجیتال آردوینو (آموزش کامل با ویدیو نحوه عملکرد)

این شماتیک باتری لیتیومی متصل به ماژول TP4056 را نشان می دهد که سپس به یک سوئیچ متصل می شود و تمام اجزای مدار را تغذیه می کند.

ماژول OLED، روتاری انکودر و سوئیچ فشاری به پین های زیر به Arduino Pro Mini متصل می شوند.

سوئیچ فشاری، متصل به پایه 3 برای استفاده از عملکرد وقفه پرو مینی

روتاری انکودر، یکی از فازها متصل به پین 2 پرو مینی برای وقفه، فاز دوم متصل به پین 6 که به عنوان یک ورودی دیجیتال ساده عمل می کند.

صفحه نمایش 0.96 اینچی OLED، با پین های 8، 9، 10، 12 و 13 به پروتکل SPI متصل است.

کد پروژه متر دیجیتال با آردوینو

اگرچه برنامه روتاری انکودر ما به هیچ کتابخانه ای نیاز ندارد، اما برای کار با ماژول OLED، ما به کتابخانه های OLED Adafruit نیاز داریم. ما با نصب Adafruit GFX و Adafruit SSD 1306 Library شروع می کنیم. بر روی library manager در منوی Tools در Arduino IDE کلیک کنید.

ساخت متر دیجیتال آردوینو (آموزش کامل با ویدیو نحوه عملکرد)

Adafruit GFX و Adafruit SSD1306 را جستجو می کنیم و به سادگی با کلیک بر روی دکمه install آنها را نصب می کنیم.

ساخت متر دیجیتال آردوینو (آموزش کامل با ویدیو نحوه عملکرد)

هنگامی که کتابخانه ها نصب شدند، می توانیم آنها را در ابتدای کد خود قرار دهیم.

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

پس از این، ما پین های OLED را کانفیگ اولیه می کنیم و پایه هایی را برای فازهای روتاری انکودر و همچنین سوئیچ فشاری ریست تعریف می کنیم.

#define OLED_MOSI  12
#define OLED_CLK   13
#define OLED_DC    9
#define OLED_CS    10
#define OLED_RESET  8
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
  OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
#define outputA 2
#define outputB 6
#define SetZero 3    

اکنون ثابت‌های دستگاه، قطر دیسک چرخشی و تعداد پالس در هر دور (CPR) روتاری انکودر را تعریف می‌کنیم. از آنجایی که ما یک دیسک به قطر 70 میلی متر را روی شفت روتاری انکودر نصب خواهیم کرد، قطر را 70 قرار دادیم.

با مشاهده دیتا شیت روتاری انکودر خود، می دانیم که هر فاز 400 پالس در هر دور ارسال می کند، از آنجایی که هر پالس دارای دو فاز خواهد بود، تعداد 800 (400X2) به دست می آید. بنابراین ما CPR را به عنوان 800 قرار میدهیم .

ما همچنین متغیری به نام factor تعریف می کنیم که در واقع مسافت طی شده با هر شمارش است. بعداً این ضریب را در تعداد محاسبه شده توسط اردوینو ضرب می کنیم.

#define Diameter 70 //in mm
#define CPR 800 //Counts per revolution of each phase.
float factor= (3.1415*Diameter)/(CPR);

اکنون چند متغیر اضافی را که در طول کار کد مورد نیاز خواهند بود، تعریف می کنیم.

bool aState;
bool aLastState;
unsigned long int lastdata=0;
unsigned long int lastDisplay=0;
bool led=0;
long units=0;
bool i=0;

در تابع کانفیگ یا همان setup، ما باید پین های ورودی را با پول اپ داخلی فعال کنیم. پین های وقفه و عملکردهای وقفه را تعریف کنید، صفحه نمایش OLED را کانفیگ اولیه کنید و مقدار اندازه گیری را به صورت صفر نمایش دهید.

void setup() {
  pinMode (outputA,INPUT_PULLUP);
  pinMode (outputB,INPUT_PULLUP);
  pinMode (SetZero,INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2),ISR1,CHANGE);
  attachInterrupt(digitalPinToInterrupt(3),ISR2,FALLING);
  Serial.begin(9600);
  if(!display.begin(SSD1306_SWITCHCAPVCC)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  // Clear the buffer
  display.clearDisplay();
  display.display();
  display.setTextColor(WHITE);
  aLastState = PIND&(1<<2)?1:0;
        display.clearDisplay();
        display.setTextSize(2);
        displayCenter("Distance",2);
        display.setTextSize(3);
        displayCenter(String(units),30);
        lastDisplay=millis();
}

در تابع حلقه بینهایت، ما کارهای بسیار کمی را انجام می دهیم، بیشتر به این دلیل که اکثر کارها در توابع وقفه و همچنین تابع updateDisplay() انجام می شود. از متغیر i به عنوان پرچم استفاده میشود که هر زمان که پالسی توسط روتاری انکودر ایجاد شود یا زمانی که متغیر شمارنده را ریست می کنیم، یک می شود. در تابع حلقه بینهایت، تابع updateDisplay() را فقط زمانی فراخوانی می

همچنین یک کد ساده را با استفاده از متغیر lastData و تابع millis () برای بازنشانی شمارنده به صفر در صورت عدم وجود ورودی بعد از 10 ثانیه فراخوانی می کنیم.

void loop() {
    if(i==1)
    {
      updateDisplay();
    }
   if(millis()-lastdata>10000) {
     units=0;
     updateDisplay();
     lastdata=millis();
   }    
}

از آنجایی که ما یک فاز از خروجی روتاری انکودر را روی پایه 2 Pro-Mini وصل کردیم، ISR1 هر بار که یک تغییر حالت وجود داشته باشد، اجرا می‌شود. با توجه به عملکرد انکودرهای چرخشی، می دانیم که اگر فازها نابرابر باشند، انکودر خلاف جهت عقربه های ساعت می چرخد، بنابراین مقدار شمارنده را کاهش می دهیم و اگر فازها برابر باشند، مقدار شمارنده را افزایش می دهیم.

توجه داشته باشید که به جای استفاده از تابع digitalRead() ، از دستور bool(PIND&(1<<6)) استفاده کرده ایم. این دستور برای خواندن مستقیم کامل پورت D و استفاده از بیت ششم (برای پایه 6) استفاده می شود.

void ISR1() {
  if ( bool(PIND&(1<<6)) != bool(PIND&(1<<2)) )
     {
       units --;
     }
     else
     {
       units ++;
     }
     i=1; 
}

سوئیچ فشاری به پایه 3 متصل است که وقفه دوم یعنی ISR2 را اجرا می کند. این تابع متغیر شمارنده را صفر می کند.

void ISR2() {
  units=0;
  i=1;
}

در نهایت ما توابع updateDisplay() و displayCenter() را داریم. تابع updateDisplay() به برای پاک کردن صفحه OLED و نمایش مقادیر جدید فاصله اندازه گیری شده استفاده می شود. این عملکرد فقط هر 500 میلی ثانیه نمایشگر را به روز می کند تا منابع CPU را حفظ کنیم و اطمینان حاصل کنیم که هیچ پالسی از روتاری انکودر را از دست نمی دهیم. این کار همچنین از فلیکر یا چشمک زدن صفحه جلوگیری می کند.

تابع displayCenter() همانطور که از نام پیداست، متن را در مرکز افقی صفحه تراز می کند.

void updateDisplay() {
        if(millis() - lastDisplay>500)
        {
        display.clearDisplay();
        display.setTextSize(2);
        displayCenter("Distance",2);
        display.setTextSize(3);     
        displayCenter(String(float(units*factor)),30);
        lastDisplay=millis();
        lastdata = lastDisplay;
        i=0;
        }
}
void displayCenter(String text, int line)
{
  int16_t x1;
  int16_t y1;
  uint16_t width;
  uint16_t height;
  display.getTextBounds(text, 0, 0, &x1, &y1, &width, &height);
  // display on horizontal center
  display.setCursor((SCREEN_WIDTH - width) / 2, line);
  display.println(text); // text to display
  display.display();
}

مونتاژ پروژه متر دیجیتال آردوینو DIY

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

پروژه متر دیجیتال آردوینو

دیسک باید به شفت روتاری انکودر متر دیجیتال متصل شود.

ساخت متر دیجیتال آردوینو

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

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for SSD1306 display connected using software SPI (default case):
#define OLED_MOSI  12
#define OLED_CLK   13
#define OLED_DC    9
#define OLED_CS    10
#define OLED_RESET  8
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
  OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);


#define outputA 2
#define outputB 6
#define SetZero 3

#define Diameter 70 //in mm
#define CPR 800 //Counts per revolution of each phase.
float factor= (3.1415*Diameter)/(CPR);

bool aState;
bool aLastState;  
unsigned long int lastdata=0;
unsigned long int lastDisplay=0;
bool led=0;
long units=0;
bool i=0;

void setup() {
  pinMode (outputA,INPUT_PULLUP);
  pinMode (outputB,INPUT_PULLUP);
  pinMode (SetZero,INPUT_PULLUP);
  
  attachInterrupt(digitalPinToInterrupt(2),ISR1,CHANGE);
  attachInterrupt(digitalPinToInterrupt(3),ISR2,FALLING);
  Serial.begin(9600);

  if(!display.begin(SSD1306_SWITCHCAPVCC)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  // Clear the buffer
  display.clearDisplay();
  display.display();
  display.setTextColor(WHITE);
  aLastState = PIND&(1<<2)?1:0;

        display.clearDisplay();
        display.setTextSize(2);
        displayCenter("Length(mm)",15); 
        display.setTextSize(3);      
        displayCenter(String(units),42);
        lastDisplay=millis();

}

void loop()
{
    if(i==1)
    {
      updateDisplay();
    }
      
   if(millis()-lastdata>10000)
   {
     units=0;
     updateDisplay();
     lastdata=millis();
   }     
}


void ISR1()
{
  
  if ( bool(PIND&(1<<6)) != bool(PIND&(1<<2)) ) 
     { 
       units --;
     }
     else
     {
       units ++;
     }
     i=1;
  
}

void ISR2()
{
  units=0;
  i=1;
  }
  
void updateDisplay()
{
        if(millis() - lastDisplay>500)
        {
        display.clearDisplay();
        display.setTextSize(2);
        displayCenter("Length(mm)",15); 
        display.setTextSize(3);      
        displayCenter(String(float(units*factor)),42);
        lastDisplay=millis();
        lastdata = lastDisplay;
         i=0;
        }
  
  }


void displayCenter(String text, int line) 
{
  int16_t x1;
  int16_t y1;
  uint16_t width;
  uint16_t height;

  display.getTextBounds(text, 0, 0, &x1, &y1, &width, &height);
  // display on horizontal center
  display.setCursor((SCREEN_WIDTH - width) / 2, line);
  display.println(text); // text to display
  display.display();
}
منبع: https://circuitdigest.com/microcontroller-projects/diy-arduino-measuring-wheel-using-rotary-encoder
برای امتیاز به این نوشته کلیک کنید!
[کل: 0 میانگین: 0]

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