اصول پروگرم کردن میکروپایتون با ESP32 و ESP8266

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

اگر شما برنامه نویسی در پایتون را می‌دانید، برنامه نویسی در میکروپایتون هم همان است. شما فقط باید در نظر بگیرید که میکروپایتون برای دستگاه های محدود استفاده می‌شود پس کد شما تا حد امکان باید ساده باشد.

این مقاله اصول زبان برنامه نویسی پایتون را توضیح می‌دهد که برای میکروپایتون هم قابل اعمال است. مانند:
عملگرهای ریاضی
عملگرهای رابطه‌ای
انواع داده
تابع print
عبارت‌های شرطی
حلقه‌های for و while
توابعی که توسط کاربر تعریف می‌شوند
کلاس‌ها و اشیا
ماژول‌ها

پیشنیازها

در این آموزش ما از uPyCraft IDE به عنوان محیط توسعه استفاده می‌کنیم اما شما می‌توانید از برنامه‌های دیگر هم استفاده کنید.

عملگرهای ریاضی

میکروپایتون می‌تواند عمل‌های ریاضی را انجام دهد. جدول زیر عملگرهای قابل استفاده را نشان می‌دهد.

عملگرعملیات ریاضی
+جمع
_تفریق
*ضرب
/تقسیم
//تقسیم بدون محاسبه اعشار
%باقیمانده تقسیم
جدول عملگرهای ریاضی

برای این که ببینید عملگرها چگونه کار می‌کنند، چند تا از آن‌ها را در Shell امتحان کنید. برای مثال:

>>> 2+2*9-3
۱۷
>>> 28594/2312
۱۲.۳۶۷۶۵
>>> 214522236/7.5
۲.۸۶۰۲۹۷e+07
>>> 23//2
۱۱
>>> 25%3
۱

اگر شما ماژول math را وارد کنید، می‌توانید سایر اعمال ریاضی مانند ریشه دوم، توابع مثلثاتی، لگاریتم، نمایی و… را استفاده کنید.

عملگرهای رابطه‌ای

با استفاده از عملگرهای رابطه‌ای شما می‌توانید مقایسه انجام دهید. این عملگرها مقادیر دو طرف را با هم مقایسه می‌کنند و رابطه بین آن‌ها را نشان می‌دهند.

عملگرتوضیح
==مساوی است با
=!مساوی نیست با
بزرگتر
کوچکتر
=<بزرگتر مساوی
=>کوچکتر مساوی
جدول علمگرهای رابطه‌ای

سعی کنید چند مقایسه را انجام دهید و نتیجه را امتحان کنید:

>>> 2 == 3
False
>>> 4 == 4
True
>>> 3 > 2
True
>>> 489808234 != 2223
True
>>> 4.5 >= 4.5
True

اختصاص دادن مقادیر به متغیرها:

در پایتون نیازی نیست که نوع هر داده را مشخص کنید. اگر شما قبلا بردهای خود را با Arduino IDE پروگرم کرده باشید، می‌دانید که وقتی متغیر جدید تعریف می‌کنید، نیاز دارید که نوع آن را مشخص کنید. چنین چیزی در پایتون نیست.
متغیرها یک محل نگه داری برای مقادیر(اعداد یا متن) هستند. برای اختصاص یک مقدار به یک متغیر از علامت مساوی(=) استفاده می‌شود. نام متغیر در سمت چپ و و مقدار در سمت راست  مساوی قرار می‌گیرند.
برای مثال، برای ایجاد یک متغیر برای نگه داری مقدار GPIO وقتی LED وصل است، می‌توانید به صورت زیر بنویسید:

led_pin = 23

در Arduino IDE ، شما چیزی شبیه دستور زیر را دارید:

const int led_pin = 23;

همان طور که می‌بینید، برنامه نویسی در پایتون خیلی ساده‌تر از برنامه نویسی در C است. (در Arduino IDE)
توجه: نام‌هایی که به متغیرها می‌دهید نمی‌توانند فاصله (space) داشته باشند و حساس به حروف کوچک و بزرگ هستند. بنابراین led_pin با LED_PIN یا Led_Pin فرق دارد.

انواع داده

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

نوع دادهتوضیح
Int(Int)عدد صحیح
Float(Float)عدد اعشاری
str(string)رشته
Bool(Boolean)بولین
انواع داده

بیاید متغیرهایی با انواع مختلف داده تعریف کنیم:

>>> a = 6
>>> b = 95.32
>>> c = 'Hello World!'
>>> d = True

مقدار اول که به a اختصاص داد شده است، یک عدد صحیح است. (عددی کامل است.)
متغیر b شامل یک مقدار اعشاری است که یک عدد با اعشار است.
مقدار سوم ‘Hello World!’ یک رشته است که مجموعه‌ای از کاراکترها می‌باشد. یک رشته باید داخل تک کوتیشن (‘Hello World!’) یا دابل کوتیشن (“Hello World!”) قرار داده شود.
d یک بولین است. نوعی داده است که میتواند True یا False باشد.

برای چک کردن نوع یک متغیر تابعی وجود دارد: تابع ()type. آرگومان این تابع، متغیری است که می‌خواهیم نوع آن را بدانیم.

type(variable)

در مثال قبلی، بعد از این که متغیرهای a,b,c,d تعریف شدند، می‌توانیم نوع آن را مشخص کنیم. مثلا اگر بنویسید:

>>> type(a)

عبارت زیر نمایش داده می‌شود:

<class 'int'>

این عبارت به ما می‌گوید که a یک عدد صحیح است. برای سایر متغیرها نیز نتایج زیر به دست می‌آید:

>>> type(b)
<class 'float'>
>>> type(c)
<class 'str'>
>>> type(d)
<class 'bool'>

تابع ()print

تابع print عبارت بین دو پرانتز را در صفحه shell چاپ می‌کند و در پروژه‌ها برای دیباگ کردن کد کارآمد است چون می‌توانیم اجرای کد را دنبال کنیم. مثلا:

>>> print('LED is on')
LED is on

کامنت‌ها

کامنت‌ها یا توضیحات در پایتون با کاراکتر # شروع می‌شوند و تا آخر خط ادامه دارند. یک کامنت برای اضافه کردن یادداشت به برنامه به کار می‌رود و یا به کسی که برنامه را می‌خواند می‌گوید که هر تکه از کد نوشته شده چه کاری انجام می‌دهد. کامنت‌ها هیچ تابعی را به برنامه شما اضافه نمی‌کنند. برای مثال:

# This is just a comment

چون ما از میکروپایتون در شرایط محدود شده استفاده می‌کنیم، گاهی اوقات شما مجبورید برای ذخیره فضا در حافظه ESP، از کامنت‌گذاری پرهیز کنید.

عبارت‌های شرطی

برای نوشتن یک برنامه کارآمد، احتمالا شما بر اساس این که یک عبارت درست هست یا غلط (True or False)  کارهای متفاوتی را انجام می‌دهید. ما درباره‌ی عبارت‌های شرطی صحبت میکنیم. ساختار آن‌ها به شکل زیر است:

if <expr1>:
  <statement1>
elif <expr2>:
  <statement2>
elif <expr3>:
  <statement3>
(...)
else:
  <statementn>

<expr>یک عبارت بولین است که میتواند درست یا غلط باشد. <statement>باید نسبت به <expr> با فاصله بیشتری از ابتدای خط قرار بگیرد تا پایتون بفهمد که کدام حکم به کدام شرط مربوط است.
عبارت elif مخفف else if است و فقط اگر اولین شرط (اولین if) برقرار نباشد، اجرا می‌شود.
عبارت else نیز فقط زمانی اجرا می‌شود که عبارت‌های شرطی برقرار نباشند.
هیچ محدودیتی برای تعداد elif در برنامه وجود ندارد. همچنین لزومی ندارد که شرط حتما شامل else باشد اما اگر else داشتیم، حتما باید در انتهای شرط‌ها آورده شود.

در Arduino IDE از علامتهای {} برای بلوک کد استفاده می‌کنیم ولی در میکروپایتون از ایجاد فرورفتگی در ابتدای خط استفاده می‌کنیم و بعد از هر عبارت شرطی باید علامت : (colon) قرار دهیم و برخلاف Arduino IDE نیازی نیست که عبارات داخل پرانتز باشند.

توجه مهم: مقدار فرورفتگی در پایتون به اندازه ۴ فاصله (space) است. در میکروپایتون فرورفتگی‌ها باید به اندازه ۲ فاصله (space) باشد تا کد بیشتری در حافظه میکروکنترلر جا بگیرد.

حلقه‌های for و while

حلقه‌ها به شما اجازه می‌دهند تا یک بلوک از کد به تعدادی که برای آن مشخص کردید، اجرا شوند. دو نوع حلقه داریم: حلقه for و حلقه while . برای مثال شما می‌توانید تمام اعداد بین ۱ تا ۱۰ را با استفاده از حلقه while  چاپ کنید.

number = 1
while number <= 10:
  print(number)
  number = number + 1

کدی که به حلقه while  مربوط است، با ایجاد فرورفتگی از ابتدای خط مشخص شده است و تا زمانی که مقدار متغیر number  کوچکتر و مساوی ۱۰ باشد، اجرا می‌شود. در هر حلقه، مقدار فعلی متغیر number چاپ می‌شود و سپس یکی به مقدار آن اضافه می‌شود.
شما می‌توانید اعداد ۱ تا ۱۰ را با حلقه for هم چاپ کنید:

number = 1
for number in range(1, 11):
  print(number)

حلقه for  به تعدادی که مقدار متغیر number در محدوده‌ی ۱ تا ۱۱ باشد، اجرا می‌شود. تابع range تا زمانی که مقدار متغیر number یکی کمتر از مقدار آخری که مشخص کردید (۱۱) باشد، به طور اتوماتیک مقدار بعدی را به متغیر number اختصاص می‌دهد.

وقتی بخواهیم یک بلوک از کد به تعداد دفعات مشخصی اجرا شود، از حلقه for استفاده می‌کنیم و از حلقه whie زمانی استفاده می‌کنیم که بخواهیم یک قطعه کد تا زمانی که یک شرط برقرار است، اجرا شود. در بعضی موارد می‌توان از هر دو حلقه استفاده کرد ولی معمولا یکی بر دیگری ترجیح دارد.
مشابه عبارت‌های شرطی، دقیقا بعد از عبارت‌های بولین حلقه‌های for و while علامت : (colon) قرار میگیرد و کدی که باید اجرا شود، در ابتدای خط فرورفتگی دارد.

توابعی که توسط کاربر تعریف میشوند

برای تعریف یک تایع جدید، از کلمه def به همراه نامی که برای تابع انتخاب شده است و پرانتز استفاده میکنیم. (تابع میتواند آرگومان داشته باشد یا نداشته باشد.) بعد از پرانتز باید علامت : (colon) و سپس دستوری که قرار است اجرا شود، قرار بگیرند. دقت کنید که فرورفتگی باید به اندازه ۲ فاصله (space) باشد. (در میکروپایتون):

def my_function(<arg1>, <arg2>, ...):
  <statement>
  (...)
  return

برای مثال، یک تابعی که دما را سلسیوس به فارنهایت تبدیل می‌کند، به صورت زیر تعریف می‌شود:

def celsius_to_fahrenheit(temp_celsius): 
  temp_fahrenheit = temp_celsius * (9/5) + 32 
  return temp_fahrenheit

آرگومان تابع () celsius_to_fahrenheit دما برحسب سلسیوس (temp_celsius) است. محاسبات تبدیل دما انجام می‌شود و در نهایت دما بر حسب فارنهایت (temp_fahrenheit) برگردانده می‌شود.
توجه: نیازی نیست که تابع حتما چیزی را برگرداند. آنها میتوانند کاری را انجام دهند بدون این که چیزی برگردانند.

کلاس‌ها و اشیا

پایتون یک زبان برنامه نویسی شی گرا است. دو مفهوم مهم در شی گرایی، کلاس‌ها و اشیا هستند. کلاسها دستورالعملی برای اشیا هستند و به صورت ویژگیهایی هایی (توابع و داده‌ها) که شی را توصیف می‌کنند، تعریف می‌شوند. توابع داخل کلاس، «متد» نامیده می‌شوند. کلاس‌ها توسط کلمه کلیدی class و نامی که برای آن انتخاب می‌کنیم، تعریف می‌شوند. برای مثال:

class MyClass:
  (...)

توجه: به صورت قراردادی، اسامی کلاس‌ها در پایتون به صورت CapWords است. هر چند که شما می‌توانید هر اسمی را برای کلاس انتخاب کنید.

یک شی مثالی از یک کلاس و مجموعه‌ای از داده‌ها و متدهاست. در یک شی شما می‌توانید از تمام ویژگی‌های کلاس آن استفاده کنید. گیج‌کننده به نظر می‌رسد اما به مثال ساده زیر توجه کنید:

اگر بخواهیم چند شخص با ویژگی‌های یکسان را در برنامه پایتون تعریف کنیم، اشخاص را می‌توانیم کلاس‌ها در نظر بگیریم. ممکن است بخواهیم شخصی را با ویژگی‌هایی مانند نام، سن، کشور و … تعریف کنیم.

اشیا- کلاس

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

class Person:
  name = ""
  age = 0
  country = ""
  def description(self):
    print("%s is %d years old and he is from %s." %(self.name, self.age, self.country))

همان طور که می‌بینید، یک کلاس جدید را با کلمه کلیدی class ایجاد کردیم و نامی که می‌خواستیم (person) را به آن دادیم.

داخل کلاس person ما چند متغیر تعریف کردیم که مقادیر را در آنها نگه داریم. به طور پیش فرض متغیرهای name و  country رشته‌های خالی هستند و مقدار اولیه age نیز ۰ است. سپس ما تابعی (متد) تعریف کردیم که مقادیر متغیرها را درصفحه Shell چاپ کند.

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

پارامتر self به شی اشاره دارد و برای دسترسی به متغیرهایی که به کلاس تعلق دارند، استفاده می‌شود. برای مثال برای دسترسی به متغیر name در کلاس، از self.name استفاده می‌شود.

حالا که ما کلاس را ساخته‌ایم می‌توانیم تعداد زیادی شی با عنوان person را ایجاد کنیم. شی person، یک نام، سن و کشور را خواهد داشت. همچنین ما می‌توانیم توصیفات شخص را با متد () description چاپ کنیم.
برای مثال، برای یک شخصی که person1  نام دارد، خواهیم داشت:

>>> person1 = Person()

مشخص کردن ویژگی‌های شی

برای مشخص کردن نام، سن و کشور شی person1 مانند زیر عمل می‌کنیم:

>>> person1.name = "Rui"
>>> person1.age = 25
>>> person1.country = "Portugal"

فراخوانی متدها

شما می‌توانید برای شی person از متد ساخته شده () description استفاده کنید. برای فراخوانی تابع ()description برای شی person1 می‌توانیم بنویسیم:

>>> person1.description()

در نتیجه عبارت زیر چاپ می‌شود:

Rui is 25 years old and he is from Portugal.

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

ایجاد اشیا

متد سازنده

به جای تعریف کلاس و سپس مشخص کردن ویژگی‌های شی که زمان‌بر است، می‌توانید از متد سازنده در داخل کلاس خود استفاده کنید. از متد سازنده برای شروع داده‌ها به محض ایجاد یک شیء از کلاس استفاده می‌شود. متد سازنده به صورت __init__ است. با استفاده از متد  __init__، کلاس ()Person به شکل زیر نوشته می‌شود:

class Person():
  def __init__(self, name, age, country):
    self.name = name
    self.age = age
    self.country = country
  def description(self):
    print("%s is %d years old and he is from %s." %(self.name, self.age, self.country))

برای نمونه، شی Person با همان ویژگی‌هایی که بالاتر تعریف کردیم، به صورت زیر در می‌آید:

>>> person1 = Person("Rui", 25, "Portugal")

اگر شما تابع () description را برای شی person1 فراخوانی کنید، همان نتیجه قبل را خواهد داشت:

>>> person1.description()
Rui is 25 years old and he is from Portugal.

ماژول‌ها

یک ماژول فایلی شامل مجموعه‌ای از کلاس‌ها و توابع است که شما می‌توانید در کدتان استفاده کنید. می‌توان آنها را کتابخانه نیز نامید. برای دسترسی به کلاس‌ها و توابع در داخل کد، شما نیاز دارید که آن ماژول را به کدتان وارد کنید. (import)

شما می‌توانید ماژول خودتان را بسازید یا از ماژول‌هایی که از کتابخانه‌های استاندارد پایتون که ایجاد شده‌اند استفاده کنید. در میکروپایتون، از زیرمجموعه‌ای کوچک از کتابخانه‌های استاندارد پایتون برای کنترل GPIOها، ارتباط شبکه‌ها و… استفاده می‌شود.

وارد کردن ماژول‌ها (کتابخانه‌ها) به صورت زیر است:

import module_name

برای مثال، برای وارد کردن کتابخانه machine که شامل کلاس‌هایی برای کنترل GPOIها است، نوشته می‌شود:

import machine

در بیشتر برنامه‌ها شما نیاز ندارید که تمام کلاس‌های یک ماژول را استفاده کنید و ممکن است که فقط یک کلاس آن را احتیاج داشته باشید. برای مثال، برای وارد کردن کلاس Pin از ماژول machine داریم:

from machine import Pin
وارد کردن کلاس Pin از ماژول machine

جمع‌بندی

در این آموزش، ما اصول اولیه پایتون برای استفاده در میکروپایتون را بررسی اجمالی کردیم. اگر شما از Arduino IDE برای پروگرم کردن استفاده کرده باشید، متوجه شدید که میکروپایتون بسیار ساده‌تر و کاربرپسندتر است. بعضی تفاوت‌های اصلی بین Arduino و میکروپایتون عبارت‌اند از:

  • در میکروپایتون نیازی نیست که انتهای عبارت‌ها علامت ;  (semicolon) گذاشته شود.
  • در میکروپایتون بعد از عبارت‌های بولین در گزاره‌های شرطی و حلقه‌ها علامت : (colon) می‌آید.
  • در میکروپایتون برای تعریف بلوک کد به جای آکلاد از فرورفتگی از ابتدای خط استفاده می‌شود.
  • در میکروپایتون وقتی متغیری تعریف می‌کنید، نیازی نیست که نوع آن را مشخص کنید.
  • در میکروپایتون فرورفتگی از ابتدای خط به اندازه ۲ فاصله (space) است.

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

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

قبلا حساب کاربری ایجاد کرده اید؟
گذرواژه خود را فراموش کرده اید؟
Loading...