مهندس موفق الکترونیک

چگونه یک کتابخانه آردوینو بنویسیم؟

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

کتابخانه آردوینو

منظور از کتابخانه در برنامه نویسی چیست؟

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

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

معمولا در برنامه نویسی آردوینو و زبان های برنامه نویسی مشابه بدین صورت هست که ما دوتا فایل داریم در یکی تعاریف و مقادیر اولیه را مینویسیم که در حقیقت ظاهر برنامه کتابخانه هست h. و در یک فایل دیگر توابع را پیاده سازی میکنیم با پسوند cpp. برای آردوینو.  در این مثال ما دو فایل  Segment.h ،  Segment.cpp و یک فایل اضافی برای توضیحات کتابخانه برای جست و جوی راحتر در بین هزاران کتابخانه موجود  Segment.txt را مینویسیم.

شی چیست؟

در اینجا من مفهوم شی(Object) را خیلی ساده مینویسم ولی برای توضیحات بیشتر به یک منبع برنامه نویسی شی گرا مراجعه کنید. چون زبان برنامه نویسی آردوینو هم شی گرا هست پس در نتیجه دونستن این مفاهیم خیلی کمکتون میکنه برنامه های نوشته شده توسط دیگران و این نوشته را درک کنید.

مثال اول: یک برنامه نویسی میخواهد یک ربات انسان نما درست کند و آن را برنامه نویسی کند. این برنامه نویس کل ربات را یک شی(مدل) با یکسری خصوصیات در نظر میگیرد. وقتی اینکار را میکند دستش باز هست و میتواند انواع  یکسان ربات ها را درست کند ولی دارای ویژگی های متفاوتی باشند. در حقیقت دوباره سادتر بگویم یک شی در حقیقت یک مدل از اون شی هست.

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

مطلب پیشنهادی:  USART در آردوینو Uno

کلاس چیست؟

اگر تا به حال با مفهوم کلاس آشنایی نداشته اید، به صورت ساده می توان گفت کلاس به مجموعه ای از توابع و متغیرها به منظور پیاده سازی یک شی مشخص گفته می شود. به عنوان مثال فرض کنید یک انسان مرد را به عنوان یک کلاس در نظر بگیریم. در این صورت میتوان برای آن خصوصیاتی مانند ضریب هوشی، قد، ریش و سبیل و… تعریف کرد. اگر به عنوان برنامه نویس به آن نگاه کنیم، ضریب هوشی یک نوع متغیر int است، قد و وزن نیز متغیری از نوع float هستند، و داشتن یا نداشتن ریش و سبیل نیز به عنوان یک متغیر Boolean در نظر گرفته می شود.

فایل هدر (سرآمد) :

فایل سرآمد (فایل‌هدر ، هدر‌فایل و یا فایل Header هم میگن) با پسوند h. ذخیره می شود.داخل این فایل یکسری تعاریف متغیر ، توابع،کلاس هاو… قرار میگیرد. با توجه به این که تنظیمات اولیه در برنامه اصلی انجام نمی شود(مثلا یک ثابتی آدرس شروع حافظه میکروکنترلر را در نظر بگیرید که در میکروکنترلرهای مختلف متفاوت هست)، در این فایل همه آنچیزی که برای استفاده از کتابخانه لازم داریم را تعریف می کنیم.

در این فایل ما دو نوع کلاس تعریف می کنیم :

  • کلاس عمومی (public) : در این کلاس توابع و متغیرهایی را که لازم است در برنامه اصلی آردوینو و در محیط نرم افزار آردوینو آنها را فراخوانی کنیم تعریف می شوند.
  • کلاس خصوصی (private) : در این کلاس توابع و متغیرهایی را که فقط درون کتابخانه لازم است و در خارج از آن در برنامه آردوینو فراخوانی نمی شوند تعریف می شوند.

مفهوم کلاس

با در نظر گرفتن این موارد، حال میخواهیم یک کتابخانه برای موارد مطرح شده بسازیم. یک نرم افزار ویرایشگر متن (مثلا نوت پد) باز کرده و کدهای زیر را در آن کپی کنید :

// creating a class that we will call in Arduino IDE
class Segment 
{
// functions that user of the library works with
public:
Segment(uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4, uint8_t pin5, uint8_t pin6, uint8_t pin7, uint8_t pin8); 
void Broj(int n); // function 
void Tocka(); // function  
void Ocisti(); // function 
// internal variables
private:
uint8_t _pin1;
uint8_t _pin2;
uint8_t _pin3;
uint8_t _pin4;
uint8_t _pin5;
uint8_t _pin6;
uint8_t _pin7;
uint8_t _pin8;
bool b;
};

توضیحات کد :

یک کلاس به اسم Segment ایجاد میکنیم.
همانطور که در بالا گفتیم داخل کلاس یکسری توابع و متغیر ها عومی یا public هستن و یکسری توابع و متغییر های خصوصی یا private که بیشتر تفاوت در سطح دسترسی کاربر به داخل کلاس هست که کاربر میتونه به عمومی ها دسترسی پیدا کنه…خب فقط در این حد بدونید کافیه و میتونیم ادامه بدیم.

اولین تابع یا Segment که هم اسم کلاس هست بهش Constractor میگن و فقط یکبار فراخوانی میشه. در هنگام فراخوانی شماره پین های متصل شده به 7سگمنت ارسال میشن.

تابع بعدی Broj هست که مقدار عدد مورد نظر بین 0 تا 9 را دریافت میکنه و روی نمایشگر نشون میده.

تابع Tocka نقطه روی سگمنت را خاموش و روشن میکنه.

تابع Ocisti هم سگمنت های روشن را خاموش میکنه.

اگر بخش هایی از این کدها را متوجه نمی شوید جای نگرانی وجود ندارد، بخش مهم کدها در فایل اصلی( source file  ) قرار می گیرد که آنها را توضیح خواهیم داد. به غیر از کدهای بالا، کدهای دیگری نیز باید در فایل سرآمد قرار گیرد. فایل Arduino.h نیز باید اضافه شود تا کامپایلر بتواند به درستی کدها را کامپایل نماید اما نوشتن آن در هنگام ساخت کتابخانه لزومی ندارد. همچنین این یک مثال است و هدف اصلی ما نحوه نوشتن کتابخونه هست.

#include "Arduino.h"

کدهای این بخش به نسخه ای از نرم افزار آردوینو که نصب نموده اید وابسته است، لذا باید در اضافه کردن این کدها دقت بیشتری به خرج دهید.

مطلب پیشنهادی:  پروتکل I2C در آردوینو

معمولا مرسوم است که در فایل سرآمد کدهایی را اضافه می کنیم تا بررسی شود که آیا کتابخانه های مورد نظر در فایل اصلی sketch اضافه شده اند یا خیر. این بخش باید مطابق کدهای زیر باشد :

#ifndef Segment_h
#define Segment_h
// part for code
#endif

در نهایت فایل هدر ما مطابق کدهای زیر تکمیل می شود :

/*
Segment.h - Library for 7 segment display common cathode
Created by Melec.ir.
*/

#ifndef Segment_h
#define Segment_h


#include "Arduino.h"

class Segment
{
public:
Segment(uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4, uint8_t pin5, uint8_t pin6, uint8_t pin7, uint8_t pin8);
void broj(int n);
void tocka();
void ocisti();
private:
uint8_t _pin1;
uint8_t _pin2;
uint8_t _pin3;
uint8_t _pin4;
uint8_t _pin5;
uint8_t _pin6;
uint8_t _pin7;
uint8_t _pin8;
bool b;
};
#endif

این فایل را ذخیره نمایید. یک پوشه در بخش :

Documents -> Arduino –> Libraries

به نام Segment یا نامی دلخواه ایجاد نمایید(توجه نمایید باید از اسامی مجاز ASCII استفاده شود). کد نوشته شده را در پوشه ذخیره نمایید و پسوند آن .h را به تغییر دهید. در نتیجه نام آن باید به عنوان مثال Segment.h باشد. مطمئن شوید که در کنار این نام پسوند دیگری مانند .txt وجود نداشت باشد.

فایل اصلی یا سورس فایل :

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

در ابتدا باید فایل های Arduino.h  و Segment.h  را که ساختیم اضافه نماییم.یا به عبارت ساده تر این فایل ها را در برنامه فراخوانی کنیم. میتوانیم این کدها را نیز در یک ویرایشگر معمولی متن بنویسیم.

#include "Arduino.h"
"include "Segment.h"

حال کدهای مربوط به ساختار ایجاد شده در فایل Header را مینویسیم :

Segment::Segment(uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4, uint8_t pin5, uint8_t pin6, uint8_t pin7, uint8_t pin8)
{
pinMode(pin1, OUTPUT);
pinMode(pin2, OUTPUT);
pinMode(pin3, OUTPUT);
pinMode(pin4, OUTPUT);
pinMode(pin5, OUTPUT);
pinMode(pin6, OUTPUT);
pinMode(pin7, OUTPUT);
pinMode(pin8, OUTPUT);
//
_pin1 = pin1;
_pin2 = pin2;
_pin3 = pin3;
_pin4 = pin4;
_pin5 = pin5;
_pin6 = pin6;
_pin7 = pin7;
_pin8 = pin8;
//
b = false;
}

در ابتدا ساختار Segment از نوع Segment تعریف می شود. در این بخش تعریف می کنیم که کدام پایه های آردوینو باید به کدام پایه های سون سگمنت متصل شوند. این ساختار در برنامه اصلی آردوینو در نرم افزار آردوینو به شکل زیر فراخوانی می شود :

معنی کد زیر این است ، یک شی با نام segment (اسمش هر چی میتونه باشه) و از نوع Segment ایجاد میکنیم و برای مقادیر اولیه شماره پایه ها را بترتیب میفرستیم.

Segment segment ( 2, 3, 4,5,6,7,8,9);

pin  را تعریف کردیم زیرا میخواهیم متغیرهای خصوصی را از متغیرهایی که کاربر به آنها دسترسی دارد جدا نماییم. در نتیجه اگر کاربر بر روی متغیرهای عمومی تغییر اشتباهی ایجاد نماید، عملکرد برنامه مختل نمی شود.

b = false;  را به منظور روشن یا خاموش کردن نقطه اعشار سون سگمنت تعریف کردیم. ساختار آن مطابق کدهای زیر است :

void Segment::tocka()
{
b = !b; // saves switched value
digitalWrite(_pin8, b); // it will turn on the dot if it's off and vice versa
}

در بخش بعدی ساختاری به نام broj ایجاد می کنیم. این ساختار عددی بین 0 تا 9 را به عنوان پارامتر دریافت کرده و آن را بر روی LCD نمایش می دهد. کدهای آن مطابق زیر است :

void Segment::broj(int n)
{

switch(n)
{
case 0:
digitalWrite(_pin1, 0);
digitalWrite(_pin2, 1);
digitalWrite(_pin3, 1);
digitalWrite(_pin4, 1);
digitalWrite(_pin5, 1);
digitalWrite(_pin6, 1);
digitalWrite(_pin7, 1);
digitalWrite(_pin8, 0);
break;

}
}

در نرم افزار آردوینو مطابق زیر آن را فراخوانی می کنیم :

مطلب پیشنهادی:  پروتکل های ارتباطی در آردوینو

برای مثال میخواهیم عدد 0 روی سگمنت نمایش داده شود.

// turn on number 0
segment.broj(0);
  • شی segment  را به کمک ساختار Segment که در خطوط بالا تعریف کردیم، ایجاد نمودیم.
  • broj نیز ساختاری است که در خطوط بالا ایجاد کردیم.
  • 0 عددی است که میخواهیم بر روی 7سگمنت نمایش دهیم.

نتیجه کدهای نوشته شده که در فایل .cpp باید ذخیره شوند مطابق زیر است :

/*
Segment.cpp - Library for 7 segment display common cathode
Created by Melec.ir.
*/

#include "Arduino.h"
#include "Segment.h"

Segment::Segment(uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4, uint8_t pin5, uint8_t pin6, uint8_t pin7, uint8_t pin8)
{
pinMode(pin1, OUTPUT);
pinMode(pin2, OUTPUT);
pinMode(pin3, OUTPUT);
pinMode(pin4, OUTPUT);
pinMode(pin5, OUTPUT);
pinMode(pin6, OUTPUT);
pinMode(pin7, OUTPUT);
pinMode(pin8, OUTPUT);
//
_pin1 = pin1;
_pin2 = pin2;
_pin3 = pin3;
_pin4 = pin4;
_pin5 = pin5;
_pin6 = pin6;
_pin7 = pin7;
_pin8 = pin8;
//
b = false;
}

void Segment::broj(int n)
{

switch(n)
{
case 0:
digitalWrite(_pin1, 0);
digitalWrite(_pin2, 1);
digitalWrite(_pin3, 1);
digitalWrite(_pin4, 1);
digitalWrite(_pin5, 1);
digitalWrite(_pin6, 1);
digitalWrite(_pin7, 1);
digitalWrite(_pin8, 0);
break;

case 1:
digitalWrite(_pin1, 0);
digitalWrite(_pin2, 0);
digitalWrite(_pin3, 0);
digitalWrite(_pin4, 1);
digitalWrite(_pin5, 0);
digitalWrite(_pin6, 0);
digitalWrite(_pin7, 1);
digitalWrite(_pin8, 0);
break;

case 2:
digitalWrite(_pin1, 1);
digitalWrite(_pin2, 0);
digitalWrite(_pin3, 1);
digitalWrite(_pin4, 1);
digitalWrite(_pin5, 1);
digitalWrite(_pin6, 1);
digitalWrite(_pin7, 0);
digitalWrite(_pin8, 0);
break;

case 3:
digitalWrite(_pin1, 1);
digitalWrite(_pin2, 0);
digitalWrite(_pin3, 1);
digitalWrite(_pin4, 1);
digitalWrite(_pin5, 0);
digitalWrite(_pin6, 1);
digitalWrite(_pin7, 1);
digitalWrite(_pin8, 0);
break;

case 4:
digitalWrite(_pin1, 1);
digitalWrite(_pin2, 1);
digitalWrite(_pin3, 0);
digitalWrite(_pin4, 1);
digitalWrite(_pin5, 0);
digitalWrite(_pin6, 0);
digitalWrite(_pin7, 1);
digitalWrite(_pin8, 0);
break;

case 5:
digitalWrite(_pin1, 1);
digitalWrite(_pin2, 1);
digitalWrite(_pin3, 1);
digitalWrite(_pin4, 0);
digitalWrite(_pin5, 0);
digitalWrite(_pin6, 1);
digitalWrite(_pin7, 1);
digitalWrite(_pin8, 0);
break;

case 6:
digitalWrite(_pin1, 1);
digitalWrite(_pin2, 1);
digitalWrite(_pin3, 1);
digitalWrite(_pin4, 0);
digitalWrite(_pin5, 1);
digitalWrite(_pin6, 1);
digitalWrite(_pin7, 1);
digitalWrite(_pin8, 0);
break;

case 7:
digitalWrite(_pin1, 0);
digitalWrite(_pin2, 0);
digitalWrite(_pin3, 1);
digitalWrite(_pin4, 1);
digitalWrite(_pin5, 0);
digitalWrite(_pin6, 0);
digitalWrite(_pin7, 1);
digitalWrite(_pin8, 0);
break;

case 8:
digitalWrite(_pin1, 1);
digitalWrite(_pin2, 1);
digitalWrite(_pin3, 1);
digitalWrite(_pin4, 1);
digitalWrite(_pin5, 1);
digitalWrite(_pin6, 1);
digitalWrite(_pin7, 1);
digitalWrite(_pin8, 0);
break;

case 9:
digitalWrite(_pin1, 1);
digitalWrite(_pin2, 1);
digitalWrite(_pin3, 1);
digitalWrite(_pin4, 1);
digitalWrite(_pin5, 0);
digitalWrite(_pin6, 1);
digitalWrite(_pin7, 1);
digitalWrite(_pin8, 0);
break;
}
}

void Segment::tocka()
{
b = !b;
digitalWrite(_pin8, b);
}

void Segment::ocisti()
{
digitalWrite(_pin1, 0);
digitalWrite(_pin2, 0);
digitalWrite(_pin3, 0);
digitalWrite(_pin4, 0);
digitalWrite(_pin5, 0);
digitalWrite(_pin6, 0);
digitalWrite(_pin7, 0);
digitalWrite(_pin8, 0);
}

مشابه فایل سرآمد، این فایل را نیز در همان پوشه ذخیره نمایید اما این بار با پسوند .cpp

کلمات کلیدی برای کتابخانه آردوینو :

کلمات کلیدی یا همان Keywords  ، فایلی با پسوند .txt است که نرم افزار آردوینو به کمک آن کلمات اصلی را در کتابخانه شناسایی کرده و رنگ آنها را به منظور کار کردن آسان تر با آنها تغییر می دهد. این کلمات مطابق زیر نوشته می شوند :

Segment KEYWORD1
7Segment KEYWORD2

این فایل را نیز در پوشه قبلی به پسوند .txt ذخیره می کنیم.

نرم افزار آردوینو و مثالی از کدهای نوشته شده :

به منظور نوشتن یک مثال برای فایل کتابخانه ایجاد شده، یک پوشه به نام examples در پوشه قبلی مطابق زیر ایجاد می کنیم :

کتابخانه آردوینو

در این پوشه میتوانیم مثالی از کتابخانه آردوینو (لایبری برای سون سگمنت کاتد مشترک) نوشته شده را ایجاد نماییم. به عنوان مثال یک شمانده پایین شمار را بر روی نمایشگر ایجاد می کنیم :

//add the created library "Segment.h"
//Modified by Melec.ir 
#include "Segment.h"

//define the Arduino pins according to the tutorial
Segment segment(2,3,4,5,6,7,8,9);

void setup() {
}

void loop() {
// countdown in loop
for(int i=9; i>=0; i--)
{
segment.broj(i); // call numbers from 9 to 0
delay(1000); // stop for 1 second
}

// in the end, blink couple of times
for(int j=0; j<3; j++)
{
segment.ocisti();
segment.tocka();
delay(500);
segment.broj(0);
segment.tocka();
delay(500);
}
}

این مثال را در پوشه examples ذخیره نمایید. سپس برای استفاده از کتابخانه، یکبار نرم افزار آردوینو را بسته و سپس باز نمایید.

دانلود فایل های لایبری ساخته شده

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

اگر این نوشته‌ برایتان مفید بود لطفا کامنت بنویسید.

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

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

5 دیدگاه

  1. ایا کد های نوشته شده در کتابخانه های دیگران را میشه دید

  2. سلام خسته نباشید چجوری میشه یه کتابخونه Closed-source برای Arduino نوشت؟؟؟ می دونم اکثر کتابخونه های Arduino به حالت Open-source و رایگان هستن اما بخاطر کاری که داره باید حتما از کد ها محافظت بشه ممنون

  3. سلام توضیحات فوق العاده بود

  4. عالی بود بینهایت سپاسگزارم.