You are on page 1of 116

‫دوره ترکیبی مباحث برق و الکترونیک‬

‫مدرس دوره ‪:‬‬


‫سید مصباح تجویدی‬
‫فهرست‬

‫‪3‬‬ ‫جلسه اول‬

‫‪5‬‬ ‫جلسه دوم‬

‫‪25‬‬ ‫جلسه سوم‬

‫‪76‬‬ ‫جلسه چهارم‬

‫‪90‬‬ ‫جلسه پنجم‬

‫‪104‬‬ ‫آموزش پروگرام کردن‬


‫*جلسه اول‪:‬‬

‫‪-‬میکرو کنترلر ها ادواتی برنامه پذیر هستند‪ .‬و برای این که کاری‬
‫انجام بدهند ‪ .‬باید یک برنامه نوشت و آن را روی میکروکنترلر‬
‫پروگرام کرد‪ .‬و سپس یک سخت افزار طراحی کرد که این برنامه با‬
‫این سخت افزار کار بکند‪.‬‬

‫تصویری که در باال مشاهده می کنید ‪ ,‬دارای یک ورودی و یک‬


‫خروجی می باشد‪.‬‬

‫‪-‬اینکه از ورودی به یک خروجی خاص برسیم ‪ ,‬راه های مختلفی دارد‬


‫و این موضوع همان مفهوم الگوریتم می باشد‪.‬‬
‫‪-‬زبان برنامه نویسی مانند یک ابزار می ماند ‪ .‬این که ما می خواهیم‬
‫کجا از این ابزار استفاده بکنیم ‪ ,‬بستگی به ما دارد‪.‬‬

‫روش های کلی استفاده از ابزار ها و مشخصات ظاهری ابزار ها می‬


‫تواند یکسان باشد ولی جایی که قصد استفاده از آن را داریم ‪ ,‬روش‬
‫ها و نکات مربوط به خودش را دارد‪.‬‬

‫‪-‬اصوال در برنامه نویسی میکرو کنترلر ما می آییم و دسترسی به‬


‫میکرو کنترلر و سخت افزار را به چند بخش تبدیل می کنیم ‪.‬‬

‫یکی الیه خود سخت افزار می باشد که در آن سخت افزار از خانه‬


‫های کوچک به نام رجیستر تشکیل شده است ‪.‬‬

‫این روش سریع ترین حالت و مستقیم ترین حالت می باشد اما‬
‫حالتی است که برای عموم افراد دشوار و زمان بر می باشد ‪.‬‬

‫الیه ‪ HAL‬می تواند وجود‬


‫نداشته باشد و الیه ‪User‬‬
‫و ‪ Hardware‬مستقیما با‬
‫هم در ارتباط باشند‬
‫*جلسه دوم ‪ :‬مفاهیم پایه الکترونیک و برنامه نویسی‬

‫‪-‬پارامتر های اساسی الکترونیک‬

‫ولتاژ → 𝑡𝑙𝑜𝑉 = 𝑉‬

‫جریان → 𝑝𝑚𝐴 = 𝐼‬ ‫ارتباط بین این سه مشخصه‬


‫چیست ؟‬
‫مقاومت → 𝑚‪𝑅 = 𝑂ℎ‬‬

‫‪-‬مثال عملی‪:‬‬

‫مخزن آب‬

‫در این شکل اگر شیر آب را‬


‫باز بکنیم ‪ ,‬آب به سمت پایین‬
‫سرازیر می شود‪.‬‬

‫سطح زمین‬
‫‪-‬اگر سطح زمین را دارای یک پتانسیل گرانشی بدانیم و مکانی که‬
‫منبع آب آنجا قرار دارد را هم دارای یک پتانسیل گرانشی بدانیم ‪ .‬و‬
‫دلیل آنکه این دو نقطه با هم اختالف ارتفاع دارند ‪ ,‬بنابراین‬
‫اختالف پتانسیل گرانشی نیز دارند ‪ ,‬پس آب در این شرایط جریان‬
‫پیدا می کند ‪.‬‬

‫‪-‬در الکترونیک هم ‪ ,‬چنین مسئله ای مطرح می باشد‪.‬‬

‫یک اختالف پتانسیلی بین‬ ‫یک منبع تغذیه را فرض می گیریم‬


‫دو قطب منبع تغذیه وجود دارد‪( .‬پتانسیل الکتریکی=ولتاژ)‬

‫𝑣‪+5‬‬ ‫𝑣‪0‬‬ ‫𝑣‪𝛥𝑣 = +5‬‬


‫𝑣‪𝛥𝑣 ≠ 0‬‬
‫‪-‬قطعا میزان و سرعت آبی که بین این دو‬
‫ارتفاع جابجا می شود با حالت قبلی که‬
‫مخزن آب‬ ‫شلنگی وجود نداشت فرق می کند‪.‬‬

‫*بسته به اینکه فضایی که آب از آن عبور‬


‫می کند ‪ ,‬چه نوع فضایی می باشد ‪ .‬دبی‬
‫آب و سرعت آب و حجم آبی که عبور‬
‫می کند تفاوت می کند‪.‬‬

‫𝑸𝜟‬
‫=𝑰‬
‫𝑻𝜟‬

‫سطح زمین‬
‫‪-‬فرض می کنیم که در سیرکی شیر ها درون حلقه ای حرکت می‬
‫کنند‪ .‬مثال در هر ثانیه ‪ 1⁄4‬شیر عبور می کند‪ .‬یعنی در هر ‪ 4‬ثانیه‬
‫یک شیر عبور می کند‪ .‬به این عمل آهنگ عبور شیر از حلقه می‬
‫گویند‪.‬‬

‫اختالف پتانسیل الکتریکی ← اختالف ارتفاع منبع آب با سطح زمین‬

‫دبی آب و عبور شیر ها از حلقه← جریان الکتریکی‬

‫موانع و محیط عبور آب← مقاومت‬

‫رابطه ی اختالف پتانسیل الکتریکی و جریان الکتریکی و مقاومت را‬


‫قانون اهم گویند ‪.‬‬

‫𝑅∗𝐼= 𝑉‬ ‫نکته ‪ :‬تنها در صورتی جریان عبوری‬

‫>= ‪OHM Law‬‬ ‫=𝐼‬


‫𝑉‬ ‫خواهیم داشت که یک مقاومت‬
‫𝑅‬
‫مناسب داشته باشیم‬
‫𝑉‬
‫=𝑅‬
‫𝐼‬
‫مدار ساده ‪:‬‬

‫𝑣‪5𝑣 5‬‬
‫‪Resistor‬‬

‫‪Battery‬‬ ‫𝑣‪10‬‬
‫این دو از نظر عملکرد یکسان می‬
‫‪Batteries‬‬ ‫باشند‬
‫*مشخصه های فنی قطعه مقاومت ‪:‬‬

‫خواندن توسط نوار های رنگی‬

‫‪ -1‬مقدار مقاومت ‪:‬‬

‫خواندن توسط اعداد‬

‫‪ -2‬مقدار توان 𝑉 ∗ 𝐼 = 𝑊 ‪ :‬میزان جریان مجازی که براساس‬


‫ولتاژی که به آن وارد می کنید ‪ ,‬می توانیم از مقاومت عبور دهیم‬
‫تا آن مقاومت از بین نرود‬

‫‪SMD: Surface Mount Device‬‬

‫‪ -3‬پکیج بسته بندی‬

‫‪THD: Through Hole Technology‬‬

‫پکیج ‪SMD‬‬

‫پکیج ‪THD‬‬
‫نحوه خواندن رنگ های مقاومت‬
‫∎ خواندن کد مقاومت ‪SMD‬‬

‫‪-1‬در مقاومت های ‪ SMD‬هرگاه حرف دیدیم همان جا ‪ ,‬به جای حرف‬
‫اعشار قرار میدهیم ‪.‬‬

‫‪0𝑅22 = 0.22 Ω‬‬


‫‪𝑅47 = 0.47Ω‬‬
‫‪47𝑅 = 47.0 = 47Ω‬‬
‫‪-2‬در اندازه گیری مقدار مقاومت های ‪ , SMD‬مقاومت هایی که ‪ 3‬و ‪4‬‬
‫رقمی هستند ‪ ,‬مالک ما رقم اخر می باشد ‪ .‬رقم آخر هرچه که باشد می‬
‫شود حاصل ضرب سایر رقم در ‪ 10‬به توان رقم آخر‬

‫رقم آخر‬
‫‪) ∗ 10‬حاصلضرب عدد های باقی مانده(‬

‫‪223 = 22 ∗ 103 = 22𝐾Ω‬‬


‫‪823 = 820 ∗ 102 = 82 ∗ 103 = 82𝐾Ω‬‬
‫‪741 = 74 ∗ 101 = 740Ω‬‬
‫*عدد یک پایانی در اندازه گیری مقدار مقاومت ‪ SMD‬مانند یک صفر‬
‫جلوی مقدار مقاومت قرار می گیرد‪.‬‬

‫*همان طور که گفتیم حروف به معنای ممیز می باشد ‪.‬‬

‫حرف ‪ K‬اعشار است ‪ ,‬منتهی برای مقاومت های درشت تر که بیانگر کیلو‬
‫اهم می باشد هستند‪.‬‬

‫‪7𝐾4 = 7.4𝐾Ω‬‬
‫‪47𝐾 = 47.0 = 47𝐾Ω‬‬
‫*با همین قانون حرف ‪ M‬بیانگر مقاومت های مگا اهم هست‪.‬‬

‫‪4𝑀7 = 4.7𝑀Ω‬‬

‫‪47𝑀 = 47.0 = 47𝑀Ω‬‬

‫‪-3‬صفر آخر در مقاومت های ‪ SMD‬هیچ تاثیری ندارد و خنثی است‪.‬‬


‫‪470 = 47Ω‬‬

‫‪4610 = 461Ω‬‬

‫‪ -4‬در اندازه گیری مقاومت ‪ SMD‬هر کجا همه رقم های ما ‪ 0‬بود‬

‫(یک رقمی ‪ ,‬دو رقمی ‪ ,‬سه رقمی ‪ ,‬چهار رقمی ) فرقی نمی کند ‪ ,‬مقدار‬
‫مقاومت ما ‪ 0Ω‬می باشد ‪.‬‬

‫یا به عبارتی المان ما‬


‫یک جامپر می باشد ‪.‬‬

‫آنالوگ به صورت یک بازه‬


‫پیوسته می باشد‪.‬‬ ‫‪-‬ورود به دنیای ‪ Analog‬و ‪:Digital‬‬
‫‪Analog:‬‬ ‫𝑣‪0‬‬ ‫𝑣‪3.3‬‬

‫‪0 logical‬‬ ‫‪1 logical‬‬


‫‪Digital:‬‬

‫ورود به دنیای میکروکنترلر ها‪:‬‬

‫دمای کاری میکرو‬

‫پکیج از نظر‬
‫سری بندی میکروکنترلر‬
‫طبقه بندی‬
‫ظاهری‬
‫ها‬ ‫خانواده‬
‫میکروکنترلر‬

‫تعداد پایه میکروکنترلر‬


‫مقدار حافظه‬
‫میکرو‬
‫‪ : ST‬نام شرکت ‪ : M ,‬به معنای میکروکنترلر ‪ : 32 ,‬به معنای خانواده میکروکنترلر‬

‫‪-‬ساخت پروژه جدید و شروع برنامه نویسی‪:‬‬


‫‪-1‬برای برنامه نویسی ابتدا یک پروژه جدید درست می کنیم‪.‬‬

‫‪File → New → Project‬‬

‫در پنجره باز شده در قسمت ‪ MCU/MPU‬میتوانیم میکروکنترلر‬


‫مورد نظرمان را براساس پارامتر هایی از قبیل انواع واحد های‬
‫مختلف میکرو ‪ ,‬مقدار حافظه ‪ ,‬ولتاژ کاری ‪ ,‬پکیج بسته بندی و‬
‫غیره فیلتر کرد ‪ .‬و به میکروکنترلر مورد نظر رسید‪.‬‬

‫در قسمت ‪ Commercial part number‬پارت نامبر میکرو را‬


‫سرچ کرده و میکروکنترلر ‪ STM32F103C8T6‬را انتخاب کرده و‬
‫بعد روی گزینه ‪ Next‬کلید می کنیم‪.‬‬

‫حال در این قسمت اسم پروژه را نوشته و محلی را برای ذخیره‬


‫فایل های برنامه انتخاب کرده و گزینه ‪ Finish‬را می زنیم‪.‬‬
‫‪ -3‬در صفحه باز شده می توان شکل ظاهری میکرو را مشاهده‬
‫کرد ‪ .‬و با کلید بر روی هر پایه نیز می توان امکانات آن پایه را‬
‫مشاهده و انتخاب کرد ‪.‬‬
‫‪ -‬اصوال اولین کاری که در هر پروژه باید انجام بدهیم ‪ ,‬این است‬
‫که ضربان قلب میکرو را تعیین بکنیم و یا به عبارتی کالک‬
‫پردازنده میکرو را تعیین بکنیم ‪ .‬در این برنامه از کالک داخلی‬
‫میکرو استفاده می کنیم ‪ .‬برای تعین کالک میکرو به تب ‪Clock‬‬
‫‪ Configuration‬می رویم ‪.‬‬

‫که در این قسمت خود برنامه یک کالک 𝑧𝐻𝑀‪8‬برای میکرو‬


‫معین کرده ‪ .‬ما این عدد را به 𝑧𝐻𝑀‪72‬تغیر داده و ‪ enter‬را می‬
‫زنیم‪.‬و در پنجره باز شده ‪ ok‬را می زنیم‪.‬‬

‫ولی چون کالک داخلی میکرو بدون کریستال تا 𝑧𝐻𝑀‪64‬بیشتر‬


‫نیست ‪ .‬خود نرم افزار کالک را روی 𝑧𝐻𝑀‪ 64‬مگا هرتز تنطیم‬
‫می کند‪ .‬اگر کالک 𝑧𝐻𝑀‪ 72‬مگا هرتز بخواهیم باید از کریستال‬
‫خارجی استفاده کنیم‪.‬‬

‫واحد ‪ : GPIO‬در این بخش از آموزش می خواهیم اولین قابلیت‬


‫میکرو را بررسی کنیم‪.‬‬

‫‪General-Purpose-Input/Output = GPIO‬‬

‫تمامی پین های میکرو کنترلر که قابلیت استفاده دارند را می توان‬


‫به ‪ GPIO‬تبدیل کرد‪.‬‬

‫∎‪ : GPIO Output‬در حالت خروجی این گونه بررسی می کنیم‬


‫که ما درون میکرو کنترلر نشسته ایم و به پایه ها دستور می‬
‫دهیم که ‪ 3.3‬ولت وصل بشوند یا به ‪.GND‬‬

‫برای مثال با صفر کردن و یک کردن خروجی به شکل زیر می‬


‫توان یک ‪ LED‬را خاموش و یا روشن کرد ‪.‬‬
‫‪0 Logical = LED Off‬‬ ‫‪0 Logical = LED On‬‬

‫‪1 Logical = LED On‬‬ ‫‪1 Logical = LED Off‬‬

‫∎مثال برنامه نویسی‪:‬‬

‫‪ LED‬که بر روی برد ‪ BluePhill‬نصب شده ‪ ,‬به پایه ‪PC13‬‬


‫متصل می باشد ‪ .‬برای خاموش و روشن کردن آن در محیط‬
‫‪ CubeIDE‬در منوی ‪ Pinout Configuration‬بر روی پایه‬
‫مورد نظر کلید می کنیم و حالت پایه میکرو را بر روی ‪GPIO‬‬
‫‪ Output‬میگذاریم‪.‬‬

‫االن این پایه نه ‪ 0‬می باشد و نه ‪ 1‬می باشد‪ .‬این پایه آماده این‬
‫می باشد که به آن اطالع بدهیم که صفر بشود و یا یک بشود‪.‬‬
‫اکنون که تنظیمات پایه ها را انجام داده ایم ‪ ,‬و کالک میکروکنترلر‬
‫را هم تنظیم کرده ایم باید به قسمت کامپایلر رفته و برنامه را‬
‫بنویسیم‪.‬‬

‫← برای این کار در منوی ابزار باالی صفحه بر روی‬

‫‪ Device Configuration Tool Code Generation‬زده و یا‬


‫از منوی ‪ Project‬و ‪ Generate Code‬و کلید ترکیبی ‪Alt + K‬‬
‫این کار را انجام داد‪.‬‬

‫سپس در پنجره بعدی گزینه ‪ Yes‬را انتخاب میکنیم ‪.‬‬

‫‪-‬بعد از تولید کد های الزم به صفحه ‪ main.c‬منتقل می شویم‪.‬‬


‫‪-‬متن های سبز رنگ که میان اسلش و ستاره می باشند را کامنت‬
‫می گوییم‪ .‬و توضیحاتی می باشد که برنامه اضافه می کنیم‪ .‬ولی‬
‫هیچ نقشی در اجرا شدن برنامه ندارند‪.‬‬

‫∎ساختار اصلی زبان برنامه نویسی ‪: C‬‬


‫)(‪int main‬‬
‫{‬
‫کالک سیستم را روی ‪ 64‬مگاهرتز تنظیم کن;‬

‫پایه ‪ A5‬را خروجی کن;‬ ‫*یک کد اصلی داریم که داخل‬


‫این خطوط می نویسیم‪.‬و این‬
‫پایه ‪ A5‬را یک کن;‬
‫برنامه ها خط به خط اجرا می‬
‫)‪while (1‬‬ ‫شود‪.‬‬
‫{‬
‫تکرار یک سیکل به‬
‫صورت مداوم‬
‫}‬
‫}‬ ‫به معنای بینهایت‬

‫در برنامه یک ساختار الگوریتمی وجود دارد که کد را به ترتیب اجرا می کند‪.‬‬

‫‪-‬برای ‪0‬و‪ 1‬کردن پایه ‪ PC13‬از توابع ‪ HAL‬استفاده می کنیم‪.‬‬


‫‪-‬حالت کلی فراخوانی ‪ GPIO‬به این شکل می باشد‪.‬‬
‫;) ‪HAL_GPIO_WritePin( GPIOx , GPIO_Pin , PinState‬‬

‫نشان دهنده این می باشد که با کدام‬


‫خانواده از پایه ها کار داریم‪.‬و به جای‬ ‫نشان دهنده این می باشد که می‬

‫حرف ‪ x‬حرف پایه ای که نیاز داریم را‬ ‫نشان دهنده این می باشد که با کدام‬ ‫خواهیم پایه ‪ 1‬باشد یا ‪0‬‬

‫وارد می کینم‬ ‫شماره پایه کار داریم‬ ‫‪SET = 1 , RESET = 0‬‬

‫‪HAL_GPIO_WritePin(GPIOC , GPIO_PIN_13 ,‬‬


‫;)‪GPIO_PIN_SET‬‬

‫‪-‬االن اگر برنامه باال را روی برد پروگرام کنیم‪ LED .‬روی برد روشن‬
‫خواهد شد و روشن خواهد ماند‪.‬‬

‫زمانی که برنامه را کامپایل می کنیم ‪ ,‬هم به ما خطای برنامه‬


‫نویسی و هم مشکالت مدیریت حافظه را اطالع می دهد‪.‬‬

‫بعد از پروگرام کردن میکرو ‪ ,‬یک دفعه کلید ریست را می زنیم و‬


‫بعد از آن برنامه ما به درستی کار می کند ‪.‬‬

‫برای کامپایل کردن از کلید ترکیبی ‪ Ctrl+B‬استفاده می کنیم‪.‬‬

‫∎نوشتن برنامه چشمک زن‪:‬‬


‫به این علت که ‪ LED‬موجود‬
‫روی برد ‪ .‬به صورت زیر بسته‬
‫شده ‪ .‬با ‪ 0‬کردن پایه میکرو‬
‫"‪#include "main.h‬‬
‫)( ‪int main‬‬
‫{‬
‫)‪while (1‬‬
‫{‬
‫‪HAL_GPIO_WritePin(GPIOC , GPIO_PIN_13 ,‬‬
‫;)‪GPIO_PIN_RESET‬‬ ‫به علت این که دستورات به سرعت خیلی‬
‫زیاد اجرا نشود و قابل مشاهده باشد‪ .‬از‬
‫;)‪HAL_DELAY(1000‬‬ ‫دستور تاخیر یا ‪Delay‬استفاده می کنیم‪.‬‬

‫‪HAL_GPIO_WritePin(GPIOC , GPIO_PIN_13 ,‬‬


‫;)‪GPIO_PIN_SET‬‬
‫;)‪HAL_DELAY(1000‬‬
‫}‬
‫}‬
‫‪-‬اگر برنامه قبل از ‪ while‬و در قسمت )‪ int (main‬نوشته شود ‪.‬‬
‫تنها یکبار اجرا می شود ‪ .‬پس برای اجرای درست برنامه آن را در‬
‫حلقه ‪ while‬می نویسیم‪.‬‬
‫‪-‬برای پاک نشدن برنامه بعد از بستن شدن‬
‫‪ ,‬آن را برنامه را میان ‪ Begin‬و ‪ End‬می‬
‫نویسیم‪.‬‬

‫∎دستور ‪: Toggle‬این دستور به این صورت عمل می کند که‬


‫اگر پایه ای ‪ 1‬باشد آن را ‪ 0‬می کند ‪ .‬و اگر پایه ای ‪ 0‬بود آن را ‪1‬‬
‫می کند‪.‬‬

‫*حالت کلی فراخوانی ‪ Toggle‬به این شکل می باشد‪.‬‬


‫;)‪HAL_GPIO_TogglePin(GPIOx ,GPIO_Pin_x‬‬

‫نشان دهنده این می باشد که با کدام خانواده‬ ‫نشان دهنده این می باشد که‬
‫از پایه ها کار داریم‪.‬و به جای حرف ‪ x‬حرف‬
‫با کدام شماره پایه کارداریم‬
‫پایه ای که نیاز داریم را وارد می کنیم‪.‬‬

‫‪-‬برنامه ‪ led‬چشمک زن با دستور ‪: Toggle‬‬


‫;)‪HAL_GPIO_TogglePin(GPIOC, GPIO_Pin_13‬‬
‫;)‪HAL_Delay(1000‬‬
‫‪-‬با قرار دادن کد میان ‪ /* code */‬متن برنامه تبدیل به کامنت‬
‫می شود ‪.‬‬
‫*جلسه سوم ‪ :‬فلوچارت و برنامه نویسی ‪GPIO Input‬‬

‫دایره ‪ :‬شروع و پایان فلوچارت ما می باشد‬

‫لوزی ‪ :‬جایی که نیاز به شرط داریم ‪ ,‬اگر اتفاق ‪ X‬رخ داد ‪ ,‬کار ‪ Y‬را‬
‫انجام بده ‪.‬‬

‫متوازی االضالع ‪ :‬ورودی و خروجی می باشد ‪.‬‬

‫مستطیل ‪ :‬اتفاقاتی که درون فلوچارت می افتد را شامل می شود‪.‬‬


‫شروع‬

‫وارد کردن کارت به‬


‫دستگاه‬ ‫دریافت کارت‬

‫نمایش پیام ‪ :‬رمز کارت‬ ‫وارد کردن رمز‬ ‫دریافت پول‬


‫اشتباه است‬
‫فشردن دکمه‬
‫دریافت وجه‬
‫آیا رسید می‬ ‫خیر‬
‫خواهید ؟‬
‫وارد کردن مقدار‬
‫وجه‬ ‫بلی‬
‫چاپ و دریافت‬
‫فشردن دکمه‬
‫تایید‬ ‫رسید‬

‫خیر‬ ‫آیا رمز‬ ‫بلی‬


‫صحیح است‬ ‫پایان‬
‫‪-‬فلوچارت دستگاه ‪ ATM‬در حالتی که اگر ‪ 3‬بار رمز را اشتباه زدیم ‪,‬‬
‫دستگاه کارت را نزد خود نگه دارد‪.‬‬
‫شروع‬

‫وارد کردن کارت به‬


‫دستگاه‬ ‫دریافت کارت‬

‫نمایش پیام ‪ :‬رمز کارت‬ ‫وارد کردن رمز‬ ‫دریافت پول‬


‫اشتباه است‬
‫فشردن دکمه‬
‫دریافت وجه‬
‫آیا رسید می‬ ‫خیر‬
‫خواهید ؟‬
‫وارد کردن مقدار‬
‫وجه‬ ‫بلی‬
‫چاپ و دریافت‬
‫فشردن دکمه‬
‫تایید‬ ‫رسید‬

‫آیا دفعات اشتباه‬


‫خیر‬ ‫آیا رمز‬ ‫بلی‬
‫وارد کردن رمز ‪3‬‬ ‫صحیح است‬ ‫پایان‬
‫بار شده ؟‬

‫نمایش پیام ‪ :‬کارت شما به‬


‫علت تعدد در اشتباه وارد‬ ‫دریافت کارت‬
‫کردن رمز توسط دستگاه‬
‫توسط دستگاه‬
‫دریافت شد‬
‫∎برنامه نویسی ‪C & C++‬‬

‫یک توضیح مختصر درباره ‪ C‬و ‪: C++‬‬

‫این گونه نیست که بگوییم ‪ C‬یک زبان می باشد و ‪ C++‬یک زبان‬


‫دیگر می باشد ‪ C++ .‬همان ‪ C‬می باشد که ‪ ++‬دارد‪.‬‬

‫حال این ‪ ++‬به معنایی تحت عنوان شی گرایی می باشد به عالوه‬


‫تعداد زیادی اضافات ‪.‬‬

‫‪-‬اکنون می خواهیم یک برنامه ساده به زبان ‪ C‬بنویسیم‪.‬‬

‫برای همین منظور یک فایل جدید باز کرده‬

‫‪File→New→Project→Consol Application‬‬
‫حال بعد از ساخت یک پروژه و انتخاب گزینه ‪ OK‬به محیط برنامه‬
‫نویسی می رویم‪.‬‬
‫‪-‬چون زبان های برنامه نویسی که ما استفاده می کنیم ‪ ,‬زبان های‬
‫سطح باال هستند ‪ .‬دستوراتی که می نویسیم بسیار به چشم ما‬
‫آشنامی باشد ‪.‬‬

‫*به علت این که دستورات زبان ‪ C‬بسیار زیاد می باشد ‪ .‬این‬


‫دستورات را دسته بندی و اسمشان را کتابخانه می گذارند‪.‬و اگر ما‬
‫نیاز به کتابخانه ها داشته باشیم ‪ ,‬آن ها را فراخوانی می کنیم‪.‬‬

‫∎مبحث بعدی که به سراغ آن می رویم ‪ ,‬بدنه برنامه نویسی می‬


‫باشد ‪ .‬بدنه برنامه نویسی دارای شروع و پایان می باشد ‪.‬‬

‫‪-‬در برنامه نویسی همیشه نیاز به تعدادی ظرف به اسم متغیر‬


‫داریم تا مقادیری که داریم را توی آن ها بریزیم‪.‬‬

‫‪-‬حال می خواهیم که دو عدد را با هم جمع کنیم‪.‬‬

‫در برنامه نویسی برای جمع دو عدد نمی توان فقط یک فرمول‬
‫ساده نوشت ‪.‬ابتدا باید مکانی برای ذخیره عدد ها و جوابی که قرار‬
‫است بدست بیاید در حافظه اختصاص بدهیم‪.‬‬

‫و این عمل را با استفاده از متغیر ها انجام می دهیم‪.‬‬


‫در آخر هر خط برنامه نویسی ; فراموش نشود‬
‫‪-‬متن برنامه‬
‫>‪#include <iostream‬‬ ‫حال برای اینکه جواب متغیر ‪ sum‬را بتوانیم‬

‫;‪using namespace std‬‬ ‫در خروجی چاپ بکنیم ‪ ,‬این تابع را قبل از‬
‫‪ int main‬اضافه می کنیم‪.‬‬
‫; ‪int a , b , sum‬‬
‫{ ) ‪int main ( int argc , char** argv‬‬
‫; ‪a = 3‬‬ ‫عملگر تخصیص ‪ :‬مقدار سمت راست را‬
‫; ‪b = 2‬‬ ‫در متغیر سمت چپ می ریزد‪.‬‬

‫; ‪sum = 2 + 3‬‬
‫این عبارت برای این می باشد که مقدار‬
‫;‪cout<<sum‬‬ ‫‪ sum‬را در خروجی چاپ بکند ‪.‬‬

‫; ‪return 0‬‬
‫این عبارت برای این می باشد که‬
‫}‬ ‫برنامه متوجه بشود به آخر برنامه‬
‫رسیده است ‪.‬‬

‫حال که برنامه را نوشتیم باید آن را تست بکنیم‪.‬‬


‫برای این کار باید نرم افزار را کامپایل کنیم ‪ .‬که‬
‫هم کد را تست کند و هم برنامه را اجرا کند ‪ .‬و یا‬
‫می توان از کلید ‪ F11‬استفاده کنیم‪.‬‬

‫برنامه بعد ‪ run‬شدن ↑‬


‫‪-‬در این برنامه می خواهیم که متغیر های ‪ a‬و ‪ b‬را از کاربر‬
‫بگیریم‪.‬‬
‫>‪#include <iostream‬‬
‫; ‪using namespace std‬‬
‫; ‪int a , b ,sum‬‬
‫{)‪int main (int argc , char** argv‬‬
‫; ‪cin>>a>>b‬‬ ‫عدد اولی که از کاربر گرفته شد را در متغیر ‪ a‬قرار بده و‬
‫;‪cout<<sum‬‬ ‫عدد دومی که از کاربر گرفته شد را در متغیر ‪ b‬قرار بده‬
‫; ‪return 0‬‬
‫}‬

‫برنامه دو عدد را از کاربر گرفته و جمع کرده ونتیجه را اعالم می کند‪.‬‬


‫‪-‬برنامه قبلی را می توان با همان عملکرد زیبا تر نوشت‪.‬‬
‫>‪#include <iostream‬‬ ‫اگر متغیری فراخوانی شد ولی در برنامه‬

‫; ‪using namespace std‬‬ ‫مورد استفاده قرار نگرفت بهتر است پاک‬
‫شود تا عمل حافظه میکرو را اشغال نکند‬
‫; ‪int a , b ,sum‬‬
‫{)‪int main (int argc , char** argv‬‬
‫;"‪cout<<"enter a:‬‬
‫;‪cin>>a‬‬
‫;"‪cout<<"enter b:‬‬ ‫در این قسمت عالمت های‬
‫;‪cin>>b‬‬ ‫دیگر هم می توان گذاشت‬
‫;‪sum=a+b‬‬
‫‪+ − ∗ /‬‬
‫;‪cout<<"sum is :"<<sum‬‬
‫;‪return 0‬‬
‫}‬

‫برنامه بعد ‪ run‬شدن ↑‬


‫در این حالت مقداری که داخل ‪ sum‬قرار دارد را چاپ می کند‪.‬‬
‫;‪cout<<sum‬‬
‫ولی در این حالت عینا مقداری که داخل دابل کوتیکشن می باشد‬
‫"‪cout<<"hello‬‬ ‫را چاپ می کند ‪.‬‬

‫∎ دستورات شرطی ‪:‬‬

‫دستور ‪:if‬‬

‫{)شرط( ‪if‬‬

‫;دستور العمل ‪1‬‬


‫}‬
‫دستور ‪: if-else‬‬

‫{)شرط( ‪if‬‬

‫;دستور العمل ‪1‬‬


‫}‬
‫{ ‪else‬‬
‫;دستورالعمل ‪2‬‬
‫}‬
100 ‫می خواهیم یک برنامه بنویسیم که اگر عددمان بزرگ تر از‬-
‫ بود عبارت‬100 ‫و اگر کوچکتر از‬. ‫ را چاپ بکند‬ok ‫بود عبارت‬
.‫ را چاپ کند‬error
#include <iostream>
using namespace std;
int a,sum;
int main(int argc, char** argv) {
cout<<"enter number:";
cin>>a;
if (a>100)
{
cout<<"ok";
}
else
{
cout<<"error";
}
return 0;
}
‫در دستور ‪ if else‬اگر تنها یک دستور داشته باشیم ‪ .‬می‬
‫توانیم اکوالد قرار ندهیم ولی بهتر است که بگذاریم‪.‬‬

‫در نرم افزار با زدن کلید ترکیبی ‪ shift + tab‬متن چنتایی به‬
‫عقب می گردد و با زدن کلید ‪ tab‬متن چنتایی به جلو می رود ‪.‬‬

‫عدد کمتر از‬


‫‪100‬‬

‫عدد بیشتر از‬


‫‪100‬‬

‫; ‪int a‬‬ ‫; ‪int a‬‬ ‫; ‪int a‬‬


‫;‪a=5‬‬ ‫;‪a=5‬‬ ‫;‪a=5‬‬
‫;‪a++‬‬ ‫;‪a=a+1‬‬ ‫;‪b=6‬‬
‫‪a=a+b‬‬
‫;‪cout<<a‬‬ ‫;‪cout<<a‬‬ ‫;‪cout<<a‬‬

‫مقدار ‪ a‬را ‪ 5‬در نظر‬ ‫مقدار ‪ a‬را ‪ 5‬در‬ ‫‪ a‬را برابر ‪ 5‬و ‪ b‬را‬
‫بگیر و یک واحد به آن‬ ‫نظر بگیر و ‪ a‬را به‬ ‫برابر‪ 6‬قرار دهید و‬
‫اضافه کن‬ ‫‪ a+b‬را جمع کنید و‬
‫عالوه ‪ 1‬کن‬
‫مقدار آن را در ‪a‬‬
‫قرار دهید‪.‬‬
‫∎مبحث بعدی که می خواهیم به آن بپردازیم ‪ ,‬حلقه می باشد‪.‬‬

‫‪-‬زمان هایی که می خواهیم یک کاری را چند بار انجام شود ‪,‬‬


‫مثال ده بار انجام بشود و یا تا زمانی که یک اتفاقی نیفتاده است‬
‫فالن کار به صورت مداوم انجام شود ‪.‬‬
‫چه اتفاقی برای مقدار‬
‫مقدار اولیه‬ ‫شرط حلقه‬ ‫اولیه می افتد‬
‫دستور حلقه ‪: for‬‬
‫) ‪for ( int i=0 ; i<10 ; i++‬‬
‫{‬
‫}‬
‫‪-‬مقدار اولیه حلیه ‪ 0‬می باشد ‪ .‬هر دفعه که شرط حلقه اجرا شد و‬
‫‪ i<10‬بود یک واحد به ‪ i‬اضافه می شود و زمانی که ‪ i=10‬شد ‪ .‬از‬
‫حلقه خارج می شود ‪.‬‬
‫‪-‬میخواهیم یک برنامه بنویسیم که کلمه ‪ salam‬را ده بار چاپ‬
‫بکند‪.‬‬
‫>‪#include <iostream‬‬
‫;‪using namespace std‬‬
‫;‪int i,sum‬‬
‫{ )‪int main(int argc, char** argv‬‬
‫)‪for (i=1 ; i<=10 ; i++‬‬ ‫‪ i++‬نقش شمارنده را‬
‫{‬
‫ایفا می کند‪.‬‬
‫;"‪cout<<"salam‬‬
‫اگر برنامه باال را اجرا‬
‫}‬
‫کنیم‪ .‬خروجی برنامه به‬
‫; ‪return 0‬‬
‫}‬ ‫شکل زیر در می آید ‪.‬‬
‫‪-‬برای اینکه بعد از متنی که در خروجی چاپ می شود به خط‬
‫بعدی برویم و بعد متن بعدی را چاپ بکنیم‪ .‬می بایست ‪ \n‬به‬
‫صورت زیر در ادامه متن خروجی بنویسیم‪.‬‬
‫;"‪cout<<"salam\n‬‬
‫وقتی این تغیرات را در برنامه بدهیم‪ .‬خروجی برنامه به شکل زیر‬
‫می شود ‪.‬‬
‫‪-‬حال می خواهیم معادل ‪ while‬برنامه باال را بنویسیم‪.‬‬

‫این دو برنامه از نظرعملکرد هیچ تفاوتی با هم نمی کنند‪.‬‬


‫>‪#include <iostream‬‬
‫;‪using namespace std‬‬
‫;‪int i‬‬
‫{ )‪int main(int argc, char** argv‬‬
‫)‪while(i<=10‬‬
‫{‬
‫;"‪cout<<"salam\n‬‬
‫;‪i++‬‬
‫}‬
‫;‪return 0‬‬
‫}‬
‫*در مواقعی که درون شرط با عدد و رقم سر و کار داریم از ‪for‬‬
‫استفاده می کنیم‪.‬‬

‫*در مواقعی که اتفاق ها شمارشی نیستند و زمان دقیق رویداد‬


‫ها را نمی دانیم از ‪ while‬استفاده می کنیم‪.‬‬
‫ تا‬5 ‫ تا‬5 ‫ بصورت‬15 ‫می خواهیم یک برنامه بنویسیم که از عدد‬-

.100 ‫بشمارد تا عدد‬


#include <iostream>
using namespace std;
int i;
int main(int argc, char** argv) {
for ( i=15 ; i<=100 ; i=i+5 )
{
cout<<"salam\n";
}
return 0 ;
}
‫توضیح برنامه باال ‪ i :‬در اول ‪ 15‬می باشد ‪ .‬سپس ‪ salam‬چاپ‬
‫می شود ‪.‬و در آخر ‪ 5‬تا به ‪ i‬اضافه می کند ‪.‬یعنی ‪ i‬در مرحله بعد‬
‫تبدیل به ‪ 20‬می شود ‪ .‬وخیلی زود تر به عدد ‪ 100‬می رسد‪ .‬و‬
‫این شمارش ‪ ,‬شمارش محدود تری می باشد ‪.‬‬

‫;‪i=i+15‬‬
‫هر دو این عبارات یک معنی می دهد‪.‬‬
‫;‪i+=15‬‬
‫‪-‬اکنون به جای انکه ‪ salam‬چاپ بکنیم‪ i .‬را چاپ می کنیم‪.‬‬
‫>‪#include <iostream‬‬
‫;‪using namespace std‬‬
‫; ‪int i‬‬
‫{ )‪int main(int argc, char** argv‬‬
‫)‪for ( i=1 ; i<=10 ; i++‬‬
‫{‬
‫;"‪cout<<i<<"\n‬‬
‫}‬
‫;‪return 0‬‬
‫}‬
‫‪-‬مثال‪ :‬ما می خواهیم مجموع اعداد ‪ 1‬تا ‪ 10‬را چاپ بکنیم‪.‬‬

‫راه حل ‪ :‬استفاده از متغیر واسطی که در هر مرحله عددی که‬


‫االن داریم رابا عدد قبلی جمع کرده و بریزیم در متغیر واسط‪.‬‬
‫;‪int i,sum‬‬
‫‪sum = 0‬‬
‫) ‪for ( i=1 ; i<=10 ; i++‬‬
‫{‬
‫;‪sum = sum + i‬‬
‫}‬
‫∎‪: GPIO Input‬‬

‫‪-‬یادآوری ‪ :‬در ‪ GPIO Output‬فرض بر این بود که ما داخل‬


‫میکرو نشسته ایم و از داخل میکرو ‪ ,‬خارج میکر ورا کنترل می‬
‫کنیم‪ .‬ولی در حالت ‪ GPIO Input‬قضیه برعکس می باشد ‪,‬در‬
‫این حالت ما در میکرو منتظر نشسته ایم که از بیرون یک نفر‬
‫پایه های میکرو را ‪ 0‬ویا ‪ 1‬بکند‪.‬‬

‫‪-‬برای درک بهتر این موضوع باید یک کلید به پایه میکرو متصل‬

‫برای مثال زمانی که کلید فشرده می شود ‪ ,‬مقدار‬ ‫بکنیم ‪.‬‬


‫پایه ‪ input‬برابر ‪ 0‬می شود ‪ .‬و داخل برنامه هم می توان گفت‬
‫اگر پایه مورد نظر ‪ 0‬شد ‪ ,‬فالن کار را برای من انجام بده ‪.‬‬

‫‪-‬محدودیتی در این که کلید را به ‪ GND‬متصل بکنیم و یا به ‪VCC‬‬


‫وصل کنیم نداریم‪.‬‬
‫در کلید فشاری تا زمانی که دستمان روی کلید باشد ‪ ,‬وضعیت اتصال‬
‫برقرار می باشد ‪ .‬و زمانی که دستمان را برداریم اتصال قطع می شود ‪.‬‬

‫تک سوییچ ‪SMD‬‬ ‫تک سوییچ ‪DIP‬‬ ‫تک سوییچ رایت‬


‫‪-‬دیپ سوییچ ‪:‬‬

‫دیپ سوییچ‬ ‫دیپ سوییچ‬


‫‪DIP‬‬ ‫‪SMD‬‬

‫‪-‬کلید فشاری ‪:‬‬


‫‪-‬کلید راکر ‪:‬‬

‫‪-‬کیپد ‪:‬‬
‫‪-‬میکرو سوییچ ‪:‬‬

‫‪-‬سلکتور چند حالته ‪:‬‬


‫‪-‬برنامه نویسی ‪ :‬خواندن تغیر وضعیت یک پوش باتن با میکرو‬

‫‪-‬ابتدا یک پروژه ساخته و نوع میکرو را ‪STM32f103c8t6‬‬


‫انتخاب می کنیم‪.‬‬

‫‪-‬در قسمت ‪ Pinout Configuration‬پایه ‪ PC13‬را برای ‪LED‬‬


‫می باشد را به صورت خروجی تنظیم کرده و سپس به سراغ پایه‬
‫‪ PC14‬رفته و آن را به صورت ورودی تنظیم کرده ‪.‬‬

‫سپس به سراغ کالک میکرو رفته و مقداری دلخواه به آن‬


‫اختصاص می دهیم‪.‬برای مثال مقدار آن را 𝑧𝐻𝑀‪ 64‬می گذاریم‪.‬‬

‫ولی برای برنامه های اینچنینی همان مقدار اولیه کافی و حتی‬
‫مقدار های کمتر هم اوکی می باشد ‪.‬‬
‫‪-‬بعد از تنظیم کالک و پایه ها بر روی گزینه ‪Generate Code‬‬

‫)‪ (alt+K‬را میزنیم تا پایه کد ما تولید بشود ‪.‬‬

‫حال که کد ما تولید شده ‪ ,‬نوبت برنامه نویسی می باشد ‪.‬‬

‫از آنجایی که قرار است ما از روی پین میکرو بخوانیم و چک کنیم‬


‫‪ ,‬می آییم و یک متغیر تعریف می کنیم ‪.‬‬
‫"‪#include "main.h‬‬
‫)‪int main(void‬‬
‫{‬
‫;)(‪MX_GPIO_Init‬‬
‫‪/* USER CODE BEGIN 2 */‬‬
‫;‪int pin_state‬‬
‫‪/* USER CODE END 2 */‬‬

‫‪/* Infinite loop */‬‬


‫‪/* USER CODE BEGIN WHILE */‬‬
‫)‪while (1‬‬
‫{‬
‫‪/* USER CODE END WHILE */‬‬
‫‪pin_state = HAL_GPIO_ReadPin(GPIOC,‬‬
‫;)‪GPIO_Pin_14‬‬
‫;)‪if(pin_state == GPIO_PIN_RESET‬‬
‫{‬ ‫چون کلید ما روی ‪ GND‬متصل شده ‪ ,‬از ‪ RESET‬استفاده می کنیم‪.‬‬

‫;)‪HAL_GPIO_TogglePin(GPIOC_GPIO_Pin_13‬‬
‫;)‪HAL_Delay(1000‬‬
‫}‬
‫‪/* USER CODE BEGIN 3 */‬‬
‫}‬
‫}‬
‫‪-‬برای اتصال کلید به میکرو اگر صرفا کلید را به منفی متصل‬
‫بکنیم و بعد مستقیم به میکرو متصل بکنیم‪.‬‬

‫میکرو در حاالتی نمی تواند وضعیت پایه را به درستی بخواند‪ .‬ما‬


‫با این نحوه اتصال کلید نمی توانیم بگوییم که زمانی که کلید ما‬
‫متصل نیست ‪ ,‬حتما ‪ +‬به میکرو می رسد ‪.‬‬

‫زمانی میکرو ‪ 100%‬متوجه اتصال ‪ +‬و یا – به پایه هایش می‬


‫شود ‪ .‬که عینا ‪ +‬یا – به پایه متصل بشود ‪.‬‬
‫‪-‬زمانی که ما کلید را می زنیم پایه میکرو مستقیم به – متصل می‬
‫شود ‪ .‬ولی وقتی دکمه را رها می کنیم‪ .‬وضعیت ورودی به پایه‬
‫میکرو نوسانی می شود (یعنی نه ‪ 0‬است و نه ‪.) 1‬‬

‫‪-‬اصطالحا می گوییند حالت پایه ‪( Float‬رها) شده است ‪ .‬که این‬


‫حالت باعث می شود هر چیزی روی پایه میکرو تاثیر بگذارد که‬
‫به این معنا می باشد که پایه میکرو دچار نویز شده است و‬
‫عملکردش مختل شده ‪.‬‬

‫‪-‬حال برای این حل این موضوع راه حل های مختلفی به ذهنمان‬


‫می آید ‪.‬‬

‫‪-‬یکی راه حل هایی که به ذهنمان می رسد ‪ ,‬مدار زیر می باشد ‪.‬‬

‫در این راه حل شاید زمانی که دستمان بر روی کلید نباشد ‪,‬‬
‫میکرو دچار نویز نشود ‪ .‬ولی زمانی که کلید را فشار می دهیم‪+ .‬‬
‫و – به هم متصل می شوند که به حالت اتصال کوتاه می‬
‫گویند‪.‬که میکرو و برد آسیب می زند‪ .‬پس این راه حل کاربرد‬
‫ندارد ‪.‬‬
‫پس برای حل ‪ float‬شدن پایه میکرو یک مقاومت به کلید و میکرو‬
‫اضافه می کنیم‪.‬‬

‫مقاومت باال کش ‪pull up :‬‬ ‫مقاومت پایین کش ‪pull down :‬‬

‫‪-‬کلید یک قطعه مکانیکی می باشد ‪.‬‬

‫‪-‬در حالت ایده آل وقتی ما کلید را فشار می دهیم انتظار داریم که‬
‫صفحات کلید بدون هیچ لغزشی به هم بچسند ‪ .‬و هیچ قطع و‬
‫وصلی حین این کار رخ ندهد‪.‬‬

‫‪-‬ولی در واقعیت این اتفاق نمی افتد ‪ .‬زمانی که دستمان را روی‬


‫کلید می گذاریم ‪ ,‬تا زمانی که صفحات به طور کامل بر روی هم‬
‫سوار بشوند و به هم بچسبند ‪ ,‬چندین بار در حد میلی ثانیه و میکرو‬
‫ثانیه ‪ ,‬به هم می چسبند و از هم جدا می شوند‪ .‬به این نوسان‬

‫‪ Switch Bounce‬می گویند‪.‬‬

‫‪-‬برای حل این مشکل دو راه حل وجود دارد‬


‫راه حل نرم افزاری ‪ :‬زمانی که کلید را خواندیم ‪ .‬بگوییم مثال ‪50ms‬‬
‫صبر بکنیم‪ .‬وبعد دوباره کلید را بخوانیم‪ .‬اگر دفعه دوم هم همان‬
‫مقدار بود ‪ ,‬یعنی واقعا کلید فشار داده شده است ‪.‬و گرنه همان‬
‫بانس می باشد و فاقد اهمیت است ‪.‬‬

‫‪-‬به طور خالصه چون سرعت اجرا شدن حلقه ‪ while‬بسیار زیاد‬
‫می باشد‪.‬‬

‫و هر نوسان کلید یکبار برنامه اجرا می شود ‪ .‬پس برای حل این‬


‫مشکل یک تاخیر قبل از متن برنامه خواندن کلید می گذاریم تا این‬
‫مشکل حل بشود ‪.‬‬
‫) ‪if ( pin_state==GPIO_PIN_RESET‬‬
‫{‬
‫;)‪HAL_Delay(100‬‬
‫)‪if(pin_state==GPIO_PIN_RESET‬‬
‫{‬
‫_‪HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO‬‬
‫;)‪PIN_SET‬‬
‫}‬
‫}‬
‫راه حل سخت افزاری‪ :‬برای این کار یک خازن را به صورت موازی به‬
‫دو پایه کلید متصل کرده ‪ .‬این خازن می آید و تمامی آن نقاط اشتباه‬
‫را (ولتاژ های نوسان گونه ) و زمان هایی که نمی خواهیم کلید کار‬
‫بکند را پر می کند ‪ .‬مقدار خازن را فعال ‪ 100nF‬انتخاب می کنیم‪.‬‬

‫خازن ‪bounce‬‬ ‫خازن ‪bounce‬‬

‫𝑂𝑉‬
‫‪Switch‬‬
‫‪Bounce‬‬
‫‪Switch‬‬
‫‪Pressed‬‬
‫𝐶𝐶𝑉‬
‫‪Unoppressed‬‬
‫‪Switch‬‬
‫𝐷𝑁𝐺‬
‫𝑇‬
‫∎سون سگمنت _ ‪ _ Seven Segment‬هفت قطعه ای‬

‫قطعه ای تشکیل شده از ‪ 7‬عدد ‪ LED‬می باشد که کنار هم به‬


‫شکل خاصی چیده است ‪ .‬به عالوه یک ‪ dot‬که در سمت راست‬
‫پایین سون سگمنت می باشد ‪.‬‬
‫‪com‬‬

‫‪g f‬‬ ‫‪a b‬‬

‫‪a‬‬ ‫‪COM‬‬

‫‪f‬‬ ‫‪b‬‬ ‫‪A‬‬ ‫‪dot‬‬


‫‪B‬‬ ‫‪C‬‬ ‫‪D‬‬ ‫‪E‬‬ ‫‪F‬‬ ‫‪G‬‬
‫‪g‬‬

‫‪e‬‬ ‫‪c‬‬

‫‪d‬‬

‫‪e d‬‬ ‫‪c dot‬‬


‫‪com‬‬

‫سون سگمنت سه تایی‬ ‫سون سگمنت دو تایی‬ ‫سون سگمنت تکی‬


‫مالتی پلکس‬ ‫مالتی پلکس‬
‫‪-‬به این خانه های کوچک یک سگمنت می گویند‪.‬‬

‫سون سگمنت ها در دو نوع آند مشترک و کاتد مشترک تولید می‬


‫شوند‪.‬‬

‫سون سگمنت هایی که پایه منفی مشترک دارد را کاتد مشترک‬

‫‪Anode‬‬ ‫‪Cathode‬‬ ‫می گویند‪.‬‬

‫سون سگمنت هایی که پایه مثبت مشترک دارند را آند مشترک‬


‫می گویند‪.‬‬

‫برای اتصال سون سگمنت ها به میکرو و یا منبع ولتاژ حتما باید‬


‫از مقاومت استفاده کرد تا ‪ LED‬های داخل سون سگمنت‬
‫نسوزد‪.‬‬

‫‪A‬‬ ‫‪B‬‬ ‫‪C‬‬ ‫‪D‬‬ ‫‪E‬‬ ‫‪F‬‬ ‫‪G‬‬ ‫‪dot‬‬ ‫‪A‬‬ ‫‪B‬‬ ‫‪C‬‬ ‫‪D‬‬ ‫‪E‬‬ ‫‪F‬‬ ‫‪G‬‬ ‫‪dot‬‬

‫‪Common Anode‬‬ ‫‪Common Cathode‬‬


‫‪-‬راه اندازی سون سگمنت ‪:‬‬

‫‪-‬ابتدا یک پروژه جدید با میکرو ‪ STM32f103c8t6‬ساخته ‪ .‬سپس‬


‫به سراغ کالک میکرو رفته و آن را تنطیم می کنیم‪ .‬برای راه اندازی‬
‫سون سگمنت به صورت شمارنده نیز به ‪ 7‬پایه میکرو داریم‪ .‬و اگر‬
‫بخواهیم از ‪ dot‬هم استفاده کنیم ‪ ,‬یک پایه دیگر هم نیاز پیدا‬
‫خواهیم کرد ‪ .‬پورت ‪ A‬میکرو کنترلر دارای ‪ 16‬پایه می باشد ‪ .‬به‬
‫عبارتی ‪ 16‬بیت می باشد که ما تنها به ‪ 7‬پایه نیاز پیدا خواهیم کرد‪.‬‬
‫اکنون در صفحه ‪ pinout configuration‬پایه های ‪ A0‬تا ‪ A6‬را‬
‫به صورت خروجی تنظیم می کنیم‪.‬زمانی که بخواهیم سون سگمنت‬
‫ها را روشن کنیم ‪ ,‬باید یک مقدار ‪ 16‬بیتی به پورت ‪ A‬ارسال بکنیم‪.‬‬

‫‪8 Bit = 1 Byte‬‬ ‫*نکته ‪:‬‬

‫‪-‬اگر عدد ‪ 1111 0011 0000 0000‬را که نشان دهنده عدد‬


‫صفر می باشد در نظر بگیریم ‪ .‬کم ارزش ترین بیت ‪ LSB‬از سمت‬
‫راست شروع شده و سمت چپ که پرازش ترین بیت ‪ MSB‬می‬
‫باشد ‪ ,‬می رسد ‪.‬‬
‫‪-‬اکنون به سراغ برنامه نویسی می رویم‪.‬‬

‫چون برای راه اندازی سون سگمنت نیاز داریم به آن داریم که‬
‫چند پایه را همزمان ‪ 0‬و ‪ 1‬کنیم‪ .‬دیگر نمی توانیم با ‪GPIO‬‬
‫‪ Output‬این کار را انجام بدهیم‪ .‬پس به سراغ رجیستر ‪ODR‬‬
‫می رویم‪.‬‬

‫برای آدرس دهی آسان تر به رجیستر ‪ ODR‬باید از مبنای هگزا‬


‫دسیمال استفاده کنیم‪.‬‬

‫‪-‬ساختار کلی رجیستری ‪ ODR‬به شکل زیر می باشد ‪.‬‬


‫;‪GPIOX->ODR=0x0000‬‬

‫نشان دهنده آن می‬ ‫این حرف ‪ x‬به این‬


‫باشد که با کدام پورت‬ ‫معنا می باشد که با‬
‫میکرو کارداریم‬ ‫مبنای هگزا دسیمال‬
‫آدرس دهی می کنیم‬
‫‪ODR‬فراخوانی رجیستر‬

‫این چهار رقم در مبنای هگزا‬


‫دسیمال معادل ‪ 16‬بیت و یا ‪ 2‬بایت‬
‫می باشد ‪.‬‬
‫‪-‬جدول کد های سون سگمنت به صورت هگزا دسیمال‬

‫‪Common Cathode‬‬ ‫‪Common Anode‬‬


‫کد هگزا دسیمال‬ ‫عدد دسیمال‬ ‫کد هگزا دسیمال‬ ‫عدد دسیمال‬
‫‪0x003F‬‬ ‫‪0‬‬ ‫‪0x00C0‬‬ ‫‪0‬‬
‫‪0x0006‬‬ ‫‪1‬‬ ‫‪0x00F9‬‬ ‫‪1‬‬
‫‪0x005B‬‬ ‫‪2‬‬ ‫‪0x00A4‬‬ ‫‪2‬‬
‫‪0x004F‬‬ ‫‪3‬‬ ‫‪0x00B0‬‬ ‫‪3‬‬
‫‪0x0066‬‬ ‫‪4‬‬ ‫‪0x0099‬‬ ‫‪4‬‬
‫‪0x006D‬‬ ‫‪5‬‬ ‫‪0x0092‬‬ ‫‪5‬‬
‫‪0x007D‬‬ ‫‪6‬‬ ‫‪0x0082‬‬ ‫‪6‬‬
‫‪0x0007‬‬ ‫‪7‬‬ ‫‪0x00F8‬‬ ‫‪7‬‬
‫‪0x007F‬‬ ‫‪8‬‬ ‫‪0x0080‬‬ ‫‪8‬‬
‫‪0x006F‬‬ ‫‪9‬‬ ‫‪0x0090‬‬ ‫‪9‬‬

‫‪-‬حال با توجه به نوع سون سگمنتی که در اختیار داریم یکی از کد‬


‫های باال را در برنامه زیر جایگذاری می کنیم‪.‬‬

‫"‪#include "main.h‬‬
int main(void)
{
while (1)
{
/* USER CODE END WHILE */
GPIOA->ODR = 0x003F; //Displaying 0
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x0006; //Displaying 1
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x005B; //Displaying 2
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x004F; //Displaying 3
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x0066; //Displaying 4
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x006D; //Displaying 5
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x007D; //Displaying 6
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x0007; //Displaying 7
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x007F; //Displaying 8
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x006F; //Displaying 9
HAL_Delay(1000); //One second delay

/* USER CODE BEGIN 3 */


}
}

‫ و با توجه‬.‫اکنون برنامه را دیباگ کرده و روی برد پروگرام می کنیم‬-


.‫ یکی از مدار های زیر را می بندیم‬, ‫به برنامه ای که نوشتیم‬
Common Cathode

Common Anode
‫‪ -‬سون سگمنت ها به علت این که دارای پایه های زیادی می‬
‫باشد اگر بخواهیم مستقیما به میکرو متصل بکنیم‪ .‬پایه های‬
‫زیادی از میکرو را اشغال می کند ‪ .‬برای همین از ‪IC BCD‬‬
‫استفاده می کنیم‪(7448=CC & 7447=CA).‬‬

‫‪ -‬نحوه کارکرد ‪: IC BCD‬‬

‫این ‪ IC‬در ورودی از ما یک‬


‫عدد ‪ 4‬رقمی باینری می گیرد‬
‫و آن را تبدیل به ‪ 7‬خروجی‬
‫دیجیتال مورد نیاز برای سون‬
‫سگمنت می کند ‪.‬‬
‫‪ -‬برای مثال می خواهیم عدد ‪ 9‬را روی سون سگمنت با کمک‬
‫‪ IC BCD‬نشان بدهیم ‪ .‬عدد ‪ 9‬دسیمال در مبنای باینری‬
‫معادل عدد ‪ 1001‬می باشد ‪.‬و اگر ما این عدد را به صورت زیر‬
‫به ‪ IC BCD‬بدهیم ‪ .‬در خروجی برای ما عدد ‪ 9‬را در سون‬
‫سگمنت نشان می دهد‪.‬‬

‫‪A=1‬‬ ‫‪B=0‬‬ ‫‪C=0‬‬ ‫‪D=1‬‬


‫‪Logical‬‬ ‫‪Logical‬‬ ‫‪Logical‬‬ ‫‪Logical‬‬

‫پایه ‪IC BCD‬‬ ‫‪-‬‬


‫‪7-segment outputs‬‬

‫‪+5V‬‬ ‫‪f‬‬ ‫‪g‬‬ ‫‪a‬‬ ‫‪b‬‬ ‫‪c‬‬ ‫‪d‬‬ ‫‪e‬‬

‫‪16‬‬ ‫‪15‬‬ ‫‪14‬‬ ‫‪13‬‬ ‫‪12‬‬ ‫‪11‬‬ ‫‪10‬‬ ‫‪9‬‬

‫‪Display driver‬‬

‫‪BCD to 7-segment decoder‬‬

‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪4‬‬ ‫‪5‬‬ ‫‪6‬‬ ‫‪7‬‬ ‫‪8‬‬


‫‪BI/RBO‬‬

‫‪B‬‬ ‫‪C‬‬ ‫‪LT‬‬ ‫‪RBI‬‬ ‫‪D‬‬ ‫‪A‬‬ ‫‪GND‬‬

‫‪BCD-input‬‬
‫‪-‬کارایی پایه های )‪(LT , BI/RBO , RBI‬‬

‫‪-‬پایه )‪ : LT(Lamp Test‬این پایه برای تست کردن ‪ led‬های‬


‫سون سگمنت می باشد ‪ .‬به این صورت که اگر مقدار این پایه را‬
‫‪ 0‬منطقی بدهیم ‪ .‬و پایه ‪ BI/RBO‬را هم ‪ 1‬منطقی بدهیم‪ .‬تمامی‬
‫سون سگمنت ها برای تست روشن می شوند‪.‬‬

‫‪-‬حال اگر پایه ‪ LT‬را ‪ 1‬منطقی بکنیم‪ .‬و پایه ‪ BI/RBO‬همچنان ‪1‬‬
‫منطقی باشد ‪ .‬خروجی ‪ BCD‬برای نشان دادن اعداد فعال می‬
‫شود ‪BI/RBO(Ripple Blanking Output) .‬‬
‫‪-‬جدول تبدیل اعداد باینری به دسیمال‬
‫‪Binary‬‬ ‫‪Decimal‬‬
‫‪D‬‬ ‫‪C‬‬ ‫‪B‬‬ ‫‪A‬‬ ‫‪-‬‬
‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬
‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬
‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪2‬‬
‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪3‬‬
‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪4‬‬
‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪5‬‬
‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪6‬‬
‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪7‬‬
‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪8‬‬
‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪9‬‬
‫‪1‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪10‬‬
‫‪1‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪11‬‬
‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪12‬‬
‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪13‬‬
‫‪1‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪14‬‬
‫‪1‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪15‬‬
‫‪-‬نحوه نمایش اعداد ‪ 0‬تا ‪15‬‬
‫توسط یک سون سگمنت‬
IC BCD ‫ و‬ODR ‫راه اندازی سون سگمنت با رجیستر‬-

‫ ساخته و سپس‬STM32f103C8T6 ‫ابتدا یک پروژه با میکرو‬


‫سپس در صفحه‬.‫کالک میکرو را تعیین می کنیم‬

‫ را به صورت‬A3 ‫ تا‬A0 ‫ پین های‬Pinout Configuration


‫ می‬Generate Code ‫خروجی انتخاب کرده و بعد از آن بر روی‬
‫ می‬While ‫ سپس به سراغ حلقه‬. ‫زنیم تا کد ما ساخته شود‬
.‫رویم و کد شمارنده زیر را می نویسیم‬
GPIOA->ODR = 0x0000; //Displaying 0
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x0001; //Displaying 1
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x0002; //Displaying 2
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x0003; //Displaying 3
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x0004; //Displaying 4
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x0005; //Displaying 5
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x0006; //Displaying 6
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x0007; //Displaying 7
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x0008; //Displaying 8
HAL_Delay(1000); //One second delay
GPIOA->ODR = 0x0009; //Displaying 9
HAL_Delay(1000); //One second delay
‫‪-‬کد ورودی به‬

‫‪ IC BCD‬در دو‬
‫نوع کاتد مشترک و‬
‫آند مشترک یکسان‬
‫می باشد ‪ .‬ولی‬
‫سطح ولتاژ خروجی‬
‫شان فرق می کند‪.‬‬

‫حال بعد از دیباگ‬


‫کردن و کامپایل‬
‫کردن برنامه روی‬
‫میکرو ‪ ,‬با توجه به‬
‫نوع سون سگمنتی‬
‫که داریم یکی از‬
‫مدار های روبرو را‬
‫می بندیم‪.‬‬
‫‪-‬راه اندازی ماژول تشخیص حرکت ‪HC-SR501‬‬

‫‪-‬از این ماژول برای تشخیص حرکت استفاده می شود ‪ .‬خروجی‬


‫این ماژول ‪ 0‬و ‪ 1‬منطقی با سطح ولتاژ ‪ 3.3‬ولت می باشد ‪ .‬زمانی‬
‫که حرکتی را تشخیص بدهد خروجی ماژول ‪ 1‬منطقی می باشد و‬
‫اگر حرکتی را تشخیص ندهد خروجی ‪ 0‬می باشد ‪.‬‬

‫‪-‬رنج ولتاژ ورودی این ماژول ‪ 4.5‬تا ‪ 12‬ولت می باشد ‪.‬‬


‫‪High / LOW‬‬
‫‪GND‬‬ ‫‪VCC‬‬
‫‪Output‬‬

‫جامپر‬
‫حالت کاری‬

‫‪H‬‬
‫‪L‬‬

‫پتانسیومتر‬ ‫پتانسیومتر‬
‫حساسیت‬ ‫زمان‬
‫‪-‬بر روی برد دو عدد پتانسیومتر وجود دارد‬

‫‪ -1‬پتانسیومتر حساسیت (‪ :)Sensitivity‬از این پتانسیومتر برای‬


‫تنظیم حداکثر مسافتی که در آن فاصله حرکت قابل تشخیص‬
‫باشد ‪ .‬رنج فاصله قابل تنظیم بین ‪ 3m‬تا ‪ 7m‬می باشد ‪.‬‬

‫‪ -2‬پتانسومتر زمان (‪ : )Time‬این پتانسیومتر مشخص کننده‬


‫مدت زمان فعال بودن خروجی سنسور بعد از آشکار سازی‬
‫هست که این زمان بین حداقل ‪ 3s‬تا ‪ 300s‬قابل تنظیم می‬
‫باشد‪.‬‬

‫‪-‬بر روی این برد یک جامپر قرار دارد که نوع مد کاری ماژول را‬
‫مشخص می کند ( در برخی مدل ها این جامپر به صورت پین‬
‫هدر می باشد و در برخی مدل ها دارای جامپر ‪ SMD‬می باشد )‬
‫‪ ← H‬مد کاری (‪ )Hold/Repeat/Retriggering‬که در این حالت‬
‫خروجی سنسور تا زمانی که سنسور حرکت را اشکار کند کماکان فعال‬
‫خواهد ماند‪.‬‬

‫سنسور ‪PIR‬‬

‫تشخیص‬
‫حرکت‬

‫حالت جامپر‬

‫خروجی‬

‫‪ ← L‬مد کاری (‪ )Repeat/non-Retriggering‬که در این حالت به‬


‫محض تشخیص حرکت توسط سنسور ‪ ,‬خروجی سنسور برای مدت‬
‫زمان مشخص که توسط پتانسیومتر زمان تنظیم شده است ‪ .‬فعال نگه‬
‫داشته خواهد شد ‪.‬‬

‫سنسور ‪PIR‬‬

‫تشخیص‬
‫حرکت‬

‫حالت جامپر‬

‫خروجی‬
‫‪-‬پس از اعمال تغذیه الکترونیکی ‪ ,‬این سنسور به مدت ‪ 30s‬تا‬
‫‪ 60s‬برای سازگاریبا سطح انرژی تشعشعات مادون قرمز محیط‬
‫نیاز دارد ‪ .‬که در این مدت ممکن است چندین بار خروجی فعال‬
‫شود ‪.‬‬

‫‪-‬این سنسور پس از هر بار تشخیص حرکت در یک بازه ‪ 5s‬تا ‪6s‬‬

‫هیچ حرکتی را تشخیص نمی دهد‪.‬‬

‫‪-‬برای ایجاد انعطاف روی کاربری این ماژول دو پد به نام های ‪RT‬‬
‫و ‪ RL‬روی ماژول قرار گرفته است‪.‬‬

‫‪ : RT‬این پد برای یک ترمیستور یا مقاومت حرارتی می باشد که‬


‫در صورت اتصال ‪ ,‬امکان کار در دمای باال را فراهم می سازد ‪ .‬و‬
‫همچنین جهت اندازه گیری سنسور در برخی دما های خاص را‬
‫افزایش می دهد‪.‬‬

‫‪ : RL‬این پد برای اتصال یک مقاومت حساس به نور ‪LDR‬یا‬


‫فتوسل می باشد ‪ .‬که با اضافه کردن مقاومت ‪ , LDR‬سنسور‬
‫‪PIR‬فقط در محیط های تاریک کار خواهد کرد‪ .‬که برای سیستم‬
‫روشنایی حساس به حرکت قابل استفاده می باشد ‪.‬‬
‫‪-‬ما برای استفاده از ماژول ‪ PIR‬می توانیم از میکروکنترلر هم‬
‫استفاده نکنیم و از خود ماژول به عنوان واحد مستقل به شکل‬
‫زیر استفاده کرد ‪.‬‬
‫‪-‬حال به سراغ برنامه نویسی می رویم‪.‬‬

‫ابتدا یک پروژه جدید با میکروی ‪ STM32f103c8t6‬ساخته و‬


‫سپس به صفحه ‪ Pinout Configuration‬می رویم‪.‬در این‬
‫قسمت پایه ‪ PC13‬را به صورت خروجی و پایه ‪ PC14‬را به صورت‬
‫ورودی تنظیم می کنیم‪.‬‬

‫اکنون بر روی ‪ Generate Code‬می زنیم تا کد ما ساخته شود ‪.‬‬


‫حال در متن برنامه باید یک متغیر اضافه بکنیم که مقدار ورودی‬
‫از ماژول را در آن بریزیم‪.‬‬
‫;‪int pin_state‬‬
‫‪-‬سپس به سراغ حلقه ‪ while‬رفته و مقدار خوانده شده توسط‬
‫پایه ‪ PC14‬را درون متغیری که باال تعریف کرده ایم بریزیم‪.‬‬
‫;)‪pin_state = HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14‬‬

‫‪-‬سپس باید با استفاده از دستورات ‪ if‬و ‪ else‬کاری کنیم که‬


‫میکرو با توجه به ورودی که از ماژول می گیرد کاری انجام بدهد‪.‬‬
‫)‪if(pin_state == GPIO_PIN_SET‬‬
‫{‬
‫‪HAL_GPIO_WritePin(GPIOC , GPIO_PIN_13 ,‬‬
‫;)‪GPIO_PIN_RESET‬‬

‫}‬
‫‪else‬‬
‫{‬
‫‪HAL_GPIO_WritePin(GPIOC , GPIO_PIN_13 ,‬‬
‫;)‪GPIO_PIN_SET‬‬
‫}‬

‫اول می گوییم که اگر پایه ‪ PC14‬به صورت ‪ 1‬منطقی در آمد ‪LED‬‬


‫روی برد را روشن کن و این کار را تا زمانی ادامه بده که ورودی به‬
‫پایه ‪ PC14‬به صورت ‪ 0‬منطقی در بیاید و بعد ‪ LED‬روی برد را‬
‫خاموش کن‬
‫متن اصلی برنامه‬
#include "main.h"
int main(void)
{
int pin_state;

while (1)
{
pin_state = HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14);

if(pin_state == GPIO_PIN_SET)
{
HAL_GPIO_WritePin(GPIOC , GPIO_PIN_13 ,
GPIO_PIN_RESET);

}
else
{
HAL_GPIO_WritePin(GPIOC , GPIO_PIN_13 ,
GPIO_PIN_SET);
}
}
}
‫‪-‬پس پرورگرام کردن برنامه روی میکرو ‪ ,‬با بستن مدار زیر می‬
‫توانیم مدار را تست کنیم‪.‬‬
‫* جلسه چهارم‬

‫راه اندازی واحد ‪Analog to Digital Convertor : ADC‬‬

‫در جا هایی مختلف و اتفاقات مختلف نیاز داریم تا با ولتاژ به صورت‬


‫عددی و جزئی کار کنیم ‪ .‬اگر ولتاژی بین ‪ 0‬تا ‪ 3.3‬ولت داشته باشیم‬
‫‪ .‬باید مقدار هایی مثل 𝑉‪1.5𝑉 , 1.8𝑉 , 2.7‬برایمان متفاوت باشد‪.‬‬
‫در مبحث ‪ GPIO‬درباره ‪ 0‬و ‪ 1‬صحبت کردیم‪.‬‬

‫𝑙𝑎𝑐𝑖𝑔𝑜𝐿 ‪2.7 − 3.3 = 1‬‬ ‫𝑙𝑎𝑐𝑖𝑔𝑜𝐿 ‪ 0 − 0.4 = 0‬و‬

‫زمانی که می خواهیم سنسور هایی استفاده کنیم که کمیت های‬


‫فیزیکی را بسنجیم ‪ ,‬مثل دما ‪ ,‬فشار ‪ ,‬رطوبت ‪ ,‬سطح ‪ ,‬اکسیژن ‪ ,‬دود‬
‫و غیر ‪ ...‬باید از واحد ‪ ADC‬استفاده کنیم‪.‬‬

‫‪-‬عمده سنسور هایی که با آن ها کار می کنیم برای ما مقادیر‬


‫متفاوتی ارائه می دهند که معانی مختلفی دارند‪.‬‬

‫‪-‬اگر سنسور دمایی داریم که خروجی به ما ‪ 27°‬داده و دمای آن به‬


‫‪ 27.5°‬می رسد‪ ,‬همین تغیر کوچک برای ما مهم می باشد ‪.‬‬

‫‪-‬این ‪ 27°‬یا ‪ 27.5°‬یا ‪ 30°‬برای ما بسیار متفاوت می باشد ‪.‬‬

‫‪-‬این سنسور ها یکسری عدد مختلف و پیوسته به ما می دهند که‬


‫نمی توانیم با منطق ‪0‬و ‪ 1‬میکرو آن را بسنجیم ‪.‬‬
‫خب ما برای این مشکل دو راه حل داریم‪.‬‬

‫راه حل اول‪ :‬مثال می خواهیم عدد ‪ 27‬را به میکرو به صورت ‪ 0‬و ‪1‬‬
‫ارسال کنیم‪.‬‬

‫پس اول عدد ‪ 27‬را به مبنای باینری تبدیل می کنیم که برابر‬

‫‪ 0001 1011‬می شود ‪.‬و این ‪ 0‬و ‪ 1‬هارا با یک بازه زمانی مشخص و‬
‫منظم که برای ما و میکرو از قبل استاندارد سازی ارسال می کنیم‪.‬‬

‫یعنی به این صورت پین را ‪ 1‬کنیم ‪ ,‬مدتی صبر کنیم‪ .‬دوباره ‪ 0‬را‬
‫ارسال کنیم و مدتی صبر کنیم‪ 0 .‬را ارسال کنیم و مدتی صبر کنیم ‪.‬و‬
‫همین طور بیت های بعدی را ارسال می کنیم‪.‬‬

‫‪-‬مثال یک سنسور داریم که مقدار فشار را خوانده و هر ‪ 20ms‬یک‬


‫بیت ‪ 0‬و ‪ 1‬را ارسال می کند ویک فاصله میان آخرین رقمی که می‬
‫خواهد اعالم کند تا اولین رقمی که از عدد بعدی می خواهد اعالم‬
‫کند ‪ 500ms‬تاخیر می دهد‪.‬‬

‫‪-‬پس هر زمان که دیدیم ‪ 500ms‬هیچ دیتایی ارسال نشد ‪ ,‬پس‬


‫متوجه می شویم عدد تمام شده و سراغ عدد بعدی می رویم‪.‬‬
‫𝑉‬

‫𝑇‬
‫‪-‬حال به سراغ سنسور هایی می رویم که خروجی که به ما می دهند‬
‫‪ 0‬و ‪ 1‬نیست و یک سطح ولتاژی به ما می دهند ‪ .‬مثل ‪lm35‬‬

‫‪-‬این سنسور دما را تبدیل به مدل سطح ولتاژ می کند ‪.‬‬

‫حال اگر بخواهیم خروجی این سنسور را به واحد ‪ GPIO‬میکرو‬


‫بدهیم‪ .‬فقط توانایی تشخیص ‪ 0‬و ‪ 1‬را داریم ‪ .‬به همین خاطر نیاز به‬
‫واحدی به اسم ‪ ADC‬داریم‪.‬‬

‫‪-‬واحد ‪ ADC‬چگونه کار می کند ؟ پین میکرو ولتاژ پیوسته و یا‬


‫آنالوگ رو به صورت ورودی از ما می گیرد و به واحد ‪ADC‬تحویل‬
‫می دهد‪.‬و این واحد یک مقدار دیجیتال قابل فهم برای میکرو‬
‫درست می کند و سپس آن را به میکرو تحویل می دهد‪ .‬و ما می‬
‫آییم این مقدار دیجیتال را خوانده و این مسیر را بر می گردیم تا به‬
‫عدد آنالوگمان می رسیم ‪.‬‬

‫‪-‬یعنی زمانی که ما در برنامه می نویسیم که مقادیر آنالوگ را به من‬


‫برگردان ‪ ,‬یک عدد دیجیتال به ما برگشت داده می شود ‪ .‬این عدد ‪,‬‬
‫عددی می باشد که میکرو آن را متوجه می شود ‪ .‬و خروجی واحد‬
‫‪ ADC‬می باشد ‪ .‬و ما الزم است یکبار این راه را برگردیم و برسیم به‬
‫عدد آنالوگی که داشتیم‪.‬‬
‫حال واحد ‪ ADC‬چگونه این کار را انجام می دهد ؟‬

‫ما یک مفهومی داریم به اسم ولتاژ مرجع ) 𝑓𝑒𝑟𝑉( که در این جا می‬


‫گوییم سقف ولتاژی که می خواهیم بدهیم ‪(.‬یعنی خروجی سنسور‬
‫ما که می خواهیم به ورودی پایه میکرو بدهیم نهایت ‪ 3.3‬ولت می‬
‫باشد ‪) .‬و بازه ولتاژ ورودی ولتاژ ما یک عدد بین ‪ 0‬تا ‪ 3.3‬ولت می‬
‫باشد ‪.‬‬

‫حداکثر ولتاژی که به صورت آنالوگ به ورودی میکرو داده می شود‬

‫سقف ولتاژ = )𝑉‪𝑉𝑟𝑒𝑓 (0 − 3.3‬‬

‫‪-‬حال واحد ‪ ADC‬میکرو با دقتی تعین شده ولتاژ ‪ 0‬تا ‪ 3.3‬را تقسیم‬
‫(‪ = )Resolution‬دقت تقسیم بندی‬ ‫بندی می کند‪.‬‬

‫‪-‬به عنوان مثال رزولوشن ‪ 12 Bit‬به این معنا می باشد که میکرو‬


‫محدوده ولتاژی که در اختیارش می باشد را به ‪ 212‬واحد تقسیم می‬
‫‪3.3V‬‬
‫‪0‬‬
‫‪4095‬‬
‫کند‪212 = 4096 .‬‬
‫‪0‬‬

‫𝑛𝑜𝑖𝑡𝑢𝑙𝑜𝑠𝑒𝑅∗ 𝑁𝐼𝑉‬
‫= 𝐶𝐷𝐴‬ ‫مقدار ولتاژ ‪ ADC‬برابر است با ‪:‬‬
‫𝑓𝑒𝑟𝑉‬
‫‪-‬تقسیم مقاومتی ‪ :‬تعدیل و تعویض بازه ولتاژی که به کار می رود ‪.‬‬

‫) ‪(𝑉1 𝑅2‬‬
‫𝑡𝑢𝑜𝑉‬ ‫=‬
‫ورودی ‪ 0‬تا ‪ 18‬ولت‬ ‫) ‪(𝑅1 + 𝑅2‬‬
‫خروجی یک سنسور‬

‫‪ 0‬تا ‪ 3.3‬ولت متغیر ‪,‬‬


‫همسان با مقدار‬
‫خروجی سنسور‬

‫‪-‬پتانسیومتر ‪ :‬قطعه ای ‪ 3‬پایه می باشد ‪ .‬دارای دو مقاومت سری‬


‫است ‪ .‬که مجموعشان ثابت می باشد‪ .‬زمانی که محور را می‬
‫چرخانیم مقدارمقاومت بین پایه ‪1‬و‪ 2‬و ‪2‬و‪ 3‬تغیر می کند ‪.‬‬
‫‪-‬حاال می توانیم با پتانسیومتر‬
‫یک تقسیم مقاومتی متغیر‬
‫داشته باشیم‪.‬‬

‫‪-‬رئوستا ‪ :‬نقطه مقابل پتانسیومتر ‪ .‬فقط دارای یک مقاومت می باشد‬


‫و جریان را کنترل می کند ‪ .‬از پتانسیومتر می توان به صورت رئوستا‬
‫استفاده کرد ولی یکی از پایه های پتانسیومتر بال استفاده می شود ‪.‬‬
‫‪-‬ما در این میکرو هایی که کار می کنیم ‪ 1‬تا ‪ 3‬واحد ‪ ADC‬داریم‪.‬‬

‫هر کدام از واحد های ‪ ADC‬متشکل از تعدادی ورودی که در‬


‫درون میکرو است و بصورت مالتی پلکس به هم متصل شده است ‪.‬‬

‫و هر کدام از این ورودی ها می توانند به صورت جداگانه ولتاژی را‬


‫بخوانند و جداگانه به ما تحویل بدهند‪.‬که به این کار سوییچ کردن‬
‫بین چنل ها می گویند‪.‬‬

‫∎برنامه نویسی ‪: ADC‬‬

‫‪-‬مثال ‪ :‬برنامه ای بنویسم که ولتاژ خروجی از یک پتانسیومتر را‬


‫بخواند‪.‬‬

‫ابتدا یک پروژه جدید ساخته و میکرو را ‪ STM32f103c8t6‬انتخاب‬


‫می کنیم‪ .‬سپس در صفحه باز شده به سربرگ‬

‫‪ clock configuration‬رفته و کالک میکرو را تنظیم کرده ‪.‬‬

‫‪-‬سپس در صفحه ‪ pinout configuration‬به تب ‪ Analog‬رفته‬


‫و یکی از این واحد ‪ ADC‬را انتخاب کرده ‪ .‬و در قسمت ‪ mode‬یکی‬
‫از چنل های این واحد ‪ ADC‬را به دلخواه انتخاب می کنیم ‪.‬‬
‫‪-‬و در پایین ‪ ,‬در قسمت ‪ Parameter setting‬می توانیم تنظیمات‬
‫این واحد را تغیر بدهیم و اگر واحد ‪ ADC‬میکروی انتخابی‬
‫رزولوشن های متفاوتی داشت ‪ ,‬از این قسمت تغیر بدهیم ‪.‬‬

‫‪ -‬سپس پس از این مراحل ‪ Generate Code‬را می زنیم تا کد ما‬


‫تولید بشود ‪.‬‬

‫‪1‬‬
‫‪3‬‬
‫‪2‬‬

‫‪4‬‬

‫‪-‬قبل از نوشتن کد ‪ .‬دو عدد متغیر به برنامه اضافه می کنیم‪.‬‬


‫;‪int value‬‬
‫;‪float Voltage‬‬
‫‪-‬ما یک تابعی داریم که واحد ‪ ADC‬را با آن استارت می زنیم‪.‬‬
‫;)‪HAL_ADC_Start(&hadc1‬‬

‫‪ &hadc1‬پوینتر یا اشاره گر می باشد ‪ .‬با این المان‬


‫تعین می کنیم که واحد ‪ ADC‬را استارت بکنیم یا نه ؟‬

‫‪-‬یک تابع دیگر هم داریم که مقدار خوانده شده توسط ‪ ADC‬را‬


‫داخل این تابع می ریزیم‬
‫;)‪HAL_ADC_GetValue(&hadc1‬‬
‫‪-‬اکنون این ‪ Value‬را باید دریافت کرد و در یک متغیر دیگر ریخت‬

‫‪-‬هر دفعه که مقدار واحد ‪ ADC‬خوانده می شود و داخل ‪Value‬‬


‫ریخته می شود عددی بین ‪ 0‬تا ‪ 4095‬دارد‪.‬‬

‫‪-‬اکنون که مقدار خروجی واحد ‪ ADC‬را داریم‪.‬باید آن را تبدیل به‬


‫مقدار ولتاژی بکنیم که به ورودی میکرو وارد شده است ‪.‬‬

‫‪-‬پس یک متغیر به اسم ‪ voltage‬به صورت ‪ float‬تعریف می‬


‫کنیم‪.‬دلیل انتخاب متغیر ‪ float‬این است که ممکن است مقدار‬
‫ولتاژی که می خوانیم اعشاری باشد ‪.‬‬
‫‪-‬حال مقدار ولتاژ را خواندیم‪ .‬و باید آن را نمایش بدهیم‪ .‬پس اول‬
‫باید این مقدار را چاپ بکنیم‪.‬‬

‫برای چاپ مقادیر باید از تابع )(‪ printf‬استفاده بکنیم‪.‬‬


‫برای زیبا سازی یک ‪ \n‬هم‬
‫می نویسیم که هر بار مقدار‬
‫‪ voltage‬را خواندیم ‪ ,‬به‬
‫;) ‪printf ("%f \n" , voltage‬‬ ‫خط بعد برویم‪.‬‬

‫در آرگومان اول نوع متغیری‬ ‫متغیری که می خواهیم‬


‫که می خواهیم چاپ کنیم را‬ ‫مقدارش را بخوانیم ‪ ,‬در این‬
‫می نویسیم‪.‬‬ ‫قسمت می نویسیم‪.‬‬

‫‪-‬برای اینکه ‪ printf‬در برنامه کار و ‪ LCD‬مجازی کار کند باید یک‬
‫کد ثابت به برنامه اضافه بکنیم‪.‬‬
‫‪/* USER CODE BEGIN PTD */‬‬
‫)‪int fputc(int ch,FILE *f‬‬
‫{‬
‫;)‪return ITM_SendChar(ch‬‬
‫}‬
‫‪/* USER CODE END PTD */‬‬
‫ به اول برنامه اضافه‬#include "stdio.h" ‫و همین طور یک‬-
.‫می کنیم‬

‫ به سرعت اتفاق می‬while ‫و برای اینکه برنامه های داخل حلقه‬-


.‫ یک تاخیر به برنامه اضافه می کنیم‬,‫افتد‬
HAL_Delay(500);
↓ ‫متن اصلی برنامه‬
#include "main.h"
#include "stdio.h"
/* USER CODE BEGIN PTD */
int fputc(int ch,FILE *f)
{
return ITM_SendChar(ch);
}
/* USER CODE END PTD */
int main(void)
{
/* USER CODE BEGIN 1 */
int value;
float voltage;
/* USER CODE END 1 */
while (1)
{
/* USER CODE END WHILE */
HAL_ADC_Start(&hadc1);
value = HAL_ADC_GetValue(&hadc1);
voltage = (value * 3.3) /4096.0 ;
HAL_ADC_Stop(&hadc1);
‫‪printf ("%f\n", voltage); // @suppress("Float‬‬
‫)"‪formatting support‬‬
‫;)‪HAL_Delay(500‬‬
‫‪/* USER CODE BEGIN 3 */‬‬
‫}‬
‫‪/* USER CODE END 3 */‬‬
‫}‬
‫‪-‬اکنون اگر بخواهیم به جای پتانسیومتر از ‪ lm35‬استفاده کنیم چه‬
‫کاری باید بکنیم؟‬

‫در این سنسور نسبت ولتاژ خروجی با دما مستقیم است ‪.‬‬

‫با هر درجه زیاد شدن دما ‪ 10mV‬خروجی داریم‪.‬‬

‫‪-‬اگر بخواهیم دمای هوا را بدست بیاوریم‪ .‬باید ولتاژ خوانده شده را‬
‫ضربدر مقدار نسبت ولتاژ خروجی نسبت به دما ‪ ,‬بکنیم‪.‬‬
: lm35 ‫ متن برنامه‬-
#include "main.h"
#include "stdio.h"
/* USER CODE BEGIN PTD */
int fputc(int ch,FILE *f)
{
return ITM_SendChar(ch);
}
/* USER CODE END PTD */
int main(void)
{
/* USER CODE BEGIN 1 */
int value;
float voltage , temp ;
/* USER CODE END 1 */
while (1)
{
/* USER CODE END WHILE */
HAL_ADC_Start(&hadc1);
value = HAL_ADC_GetValue(&hadc1);
voltage = (value * 3.3) /4096.5 ;
temp = voltage * 0.01;
HAL_ADC_Stop(&hadc1);
printf ("%f%f\n",temp , voltage); //
@suppress("Float formatting support")
HAL_Delay(500);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
‫‪Light (Decreasing or Dependent) Resistor : LDR-‬‬
‫یک مقاومت متغیر می باشد که با کم و زیاد شدن نور ‪ ,‬مقاومت دو سرش کم و زیاد‬
‫می شود ‪.‬‬

‫نتابیدن نور = زیاد شدن مقاومت‬ ‫تابیده شدن نور = کم شدن مقاومت‬

‫‪-‬ما در میکرو واحدی نداریم که مقدار‬


‫مقاومت را بسنجد ولی از راه دیگری‬
‫می توانیم این کار را انجام دهیم‪.‬‬

‫اگر روی پایه میکرو تغیری ببینیم ‪ .‬به‬


‫دلیل این که مقاومت ‪ 2‬ثابت می باشد‬
‫‪ ,‬ولتاژ هم ثابت است ‪ .‬پس این ‪LDR‬‬
‫بوده که تغیر کرده ‪ .‬پس به وسیله مقاومت ثابت و یک مقاومت متغیر ‪ ,‬یک تقسیم‬
‫مقاومتی درست کرده ایم‪.‬و به نسبتی که مقاومت ‪ LDR‬تغیر می کند ‪ .‬ولتاژ روی پایه‬
‫میکرو هم تغیر می کند ‪ .‬که می توان آن را خواند و تبدیل کرد‪.‬‬
‫∎ادامه جلسه پنجم ‪ :‬تایمر ‪Timer‬‬
‫‪-‬ما اگر بخواهیم زمانی داشته باشیم که زمانی برای ما تلف بشود و یا‬
‫بگذرد ‪ ,‬می توانیم با اضافه کردن ‪ Delay‬به برنامه کارمان را به هر‬
‫ترتیبی که هست حل بکنیم‪.‬هر چند با دقت کم این کار انجام شود‬
‫و باعث اختالل شود ‪.‬‬
‫ولی اگر ما بخواهیم زمان سنجی دقیق بکنیم‪ .‬یعنی بگوییم از نقطه‬
‫اول تا نقطه دوم چه قدر زمان گذشته ‪ ,‬دیگر نمی توانیم این کار را با‬
‫‪ Delay‬انجام بدهیم‪.‬‬
‫‪-‬مثال می خواهیم متوجه بشویم که کاربر چند ثانیه دستش را روی‬
‫کلید نگه داشته ‪.‬‬
‫برای این کار به تایمر نیاز داریم‪ .‬که این تایمر باید کلید & ‪Start‬‬
‫‪ Stop‬داشته باشد ‪ .‬عالوه بر این که باید یک خروجی هم به ما‬
‫بدهد‪ .‬که هر کجا که نیاز بود از آن استفاده کنیم ‪.‬از این خروجی‬
‫این مفهوم می شود که پری فرال تایمر میکرو کنترلر به نوعی در‬
‫کنار اینتراپت کار می کند ‪.‬و دیگر نمی آید برای زمان سنجی میکرو‬
‫را درگیر کند ‪.‬و می گوید که ما جایی که می خواهیم زمان شروع‬
‫بشود ‪ ,‬دکمه استارت را بزنید ‪ .‬و حاال یا به من بگو چند ثانیه باید‬
‫بشمارم که بعد از اتمام زمان خودم دکمه استاپ را بزنم و به شما‬
‫خبر بدهم‪ .‬یا هر جا خواستی بیا چک کن و ببین که من چه اندازه‬
‫شمرده ام ‪.‬‬
‫حالت اول که مقدار زمان شمارش رو به واحد تایمر اعالم می کنم‪.‬‬
‫و بعد از شمارش به ما اطالع می دهد ‪ .‬به روش می گویند اینتراپت‬
‫داخلی ‪.‬‬
‫‪-‬چکیده مطالب باال ‪ :‬چه بخواهیم یک زمانی بگذرد و چه زمان را‬
‫حساب کنیم ‪ .‬ما نیاز به یک تایمر یا کورنومتر داریم‪ .‬توی حالت اول‬
‫اگر بخواهیم چندین وسیله را با زمان های مختلف کنترل کنیم‪.‬‬
‫در حلقه ‪ while‬نمی شود این موارد را مدیریت کرد ‪.‬‬
‫‪-‬جایی که بخواهیم زمان سنجی داشته باشیم ‪.‬‬
‫مثال واقعی ‪( :‬سنسور فاصله سنج ‪) Ultrasonic‬‬
‫این سنسور به این شکل کار می کند یک لگد به سنسور می زنیم و‬
‫سپس سنسور یک موج می فرستد ‪ .‬موج صوتی بر می خورد به مانع‬
‫و بازتاب می شود به سنسور و یک لگد به میکرو می زند ‪.‬فاصله‬
‫بین لگد ما و لگد بازتاب موج صوتی را باید حساب کرد ‪ .‬سرعت‬
‫صوت را هم داریم ‪ .‬این زمان را هم بدست می آوریم ‪.‬‬
‫𝑥‬
‫=𝑉‬
‫𝑡‬
‫در این جا نمی دانیم که مانع جلوی ما فاصله اش با ما چه قدر می‬
‫باشد ‪.‬پس ما در این جا به واحد تایمر نیاز پیدا می کنیم‪ .‬که سرعت‬
‫برگشت موج صوتی را بدست بیاوریم‪.‬‬
‫‪-‬یک نکته ‪ :‬تایمری که درون میکرو کنترلر وجود دارد ‪ .‬بر اساس‬
‫ثانیه کار نمی کند‪ .‬یعنی به ما خروجی زمان بر اساس واحد ثانیه‬
‫نمی دهد‪ .‬پس به چه نحوی کار می کند ؟‬
‫یک مثال ‪ :‬فرق بین سرعت حرکت عقربه های ساعت چیست ؟‬
‫هر کدام از عقربه های ساعت با یک ریتم خاصی حرکت می کنند‪.‬‬
‫و تفاوت این سه عقربه در ریتم حرکت هایشان می باشد ‪ .‬و اساس‬
‫کار عقربه شمارش می باشد‪.‬‬
‫‪-‬در میکرو کنترلر واحد تایمر همراه واحد کانتر ‪ Counter‬می آید ‪.‬‬
‫‪-‬این واحد تایمر بر اساس شمارش کار می کند ‪.‬‬
‫یعنی تایمر را که استارت می کنیم‪ .‬به فاصله خاصی یک واحد می‬
‫شمارد ‪ .‬و تا زمانی که از تایمر بپرسیم که چه قدر گذشته ؟تایمر‬
‫می گوید من مثال ‪ 255‬تا شمرده ام ‪.‬حاال یکی ممکن است با ریتم‬
‫تند بشمارد و یکی با ریتم کند بشمارد ‪ .‬این دو مورد در چه چیزی با‬
‫هم تفاوت دارند ؟ در فاصله زمان شمارش فرق دارند ‪.‬یا به عبارت‬
‫علمی تر ‪ ,‬فرکانس شمارش فرق می کند ‪ .‬شمارشی که فرکانس‬
‫بیشتری داشته باشد سریع تر می شمارد و شمارشی که فرکانس‬
‫پایین تری داشته باشد کند تر می شمارد ‪.‬‬
‫‪-‬ما اگر بگوییم تایمر چند واحد و با چه فرکانسی شمرده و یک ضرب‬
‫ساده می فهمیم که چه زمانی بر حسب ثانیه گذشته ‪.‬‬
‫𝑠𝑡‬

‫‪0 1 2 3‬‬ ‫𝑋‬


‫‪-‬تایمر زمانی که استارت می شود ‪ ,‬با توجه به فرکانسی که دارد‬
‫𝑙𝑎𝑡𝑡𝑜𝑡𝑇 = 𝑡 ∗ 𝑥‬ ‫شروع به شمردن می کند‪.‬‬

‫یعنی به تایمر نمی گوییم ‪ 5‬ثانیه بشمار‪ .‬به جای آن می گوییم با‬
‫فرکانس ‪ 1Hz‬و با فاصله زمانی بین هر شمارش ‪ 1ms‬برای ما‬
‫‪ 1000‬واحدشمارش انجام بده‪ .‬که برابر می شود با ‪1s=1000ms‬‬

‫‪-‬این شمارش به موازات ‪ CPU‬انجام می شود ‪.‬‬

‫‪-‬ما یک مفهومی داریم به اسم ‪( Over Flow‬سرریز) ‪ :‬این تایمر‬


‫نهایتا تا یه عدد خاص می تواند بشمارد ‪ .‬بسته به نوع تایمر ‪ ,‬مثال‬
‫می گوییم تایمر ‪ 16‬بیت می باشد ‪.‬‬

‫‪ 0‬تا ‪ 216 − 1‬می شمارد ‪ .‬مثال وقتی تا عدد‪ 65535‬رسید ‪ ,‬این تایمر‬
‫سرریز می شود و مجددا مقدار ‪ 0‬می شود ‪ .‬و دوباره شروع می‬
‫کند به شمردن‪ .‬در ساده ترین شکل ممکن اینتراپت داخلی روی‬
‫نقطه ‪ Over flow‬می باشد ‪.‬یعنی به حداکثر شمارش که می رسد‬
‫به ما اینتراپت می دهد ‪.‬هرچه فرکانس شمارش بیشتر باشد ‪ .‬شیب‬
‫این خط بیشتر می شود و سریع تر ‪ Over flow‬می شود ‪.‬‬
‫‪-‬حال به سراغ برنامه نویسی می رویم ‪.‬یک پروژه جدید با‬
‫میکروکنترلر ‪ STM32f103c8t6‬می سازیم‪ .‬و سپس پایه‬

‫‪ PC14 & PC15‬را به صورت خروجی تعین می کنیم ‪.‬‬

‫‪-‬در این مرحله می توانیم برای پایه ای که خروجی کرده ایم یک اسم‬
‫انتخاب بکنیم‪ .‬شبیه کاری که در محیط کد نویسی با ‪#define‬‬

‫می کردیم‪.‬‬
‫‪-‬برای این کار در قسمت پایین منوی ‪ GPIO‬به سراغ قسمت ‪user‬‬
‫‪ label‬رفته و اسم مورد نظرمان را می نویسیم و بینیم که در سمت‬
‫راست صفحه ‪ ,‬اسم پایه تغیر پیدا کرده ‪.‬‬

‫‪1‬‬

‫‪-‬اکنون به سراغ تایمر می رویم‪ .‬کل هسته مرکزی میکرو کنترلر با‬
‫یک فرکانس کار می کند ‪.‬که اگر آن را یک موج مربعی در نظر‬
‫بگیریم‪.‬‬

‫که این موج نشانه زنده بودن میکروکنترلر می باشد‪ .‬فرکانس تایمر‬
‫نمی تواند از فرکانس اصلی میکروکنترلر بیشتر باشد ‪ .‬فرکانس تایمر‬
‫باید مساوی یا یک ضریبی از فرکانس میکرو باشد ‪.‬اکنون که‬
‫فرکانس میکروکنترلر ما 𝑧𝐻𝑀‪ 8‬می باشد‪ .‬فرکانس تایمر ما چگونه‬
‫محاسبه می شود ؟‬
‫‪-‬فرکانس تایمر ما یک رجیستر به اسم ‪ Prescaler‬دارد ‪ .‬که به‬
‫معنای تقسیم کننده فرکانسی می باشد ‪ .‬که اگر ‪Prescaler‬‬
‫𝑜𝑟𝑐𝑖𝑚𝐹‬
‫می باشد ‪.‬‬ ‫مساوی ‪ x‬باشد ‪ .‬فرکانس تایمر ما برابر‬
‫𝑥‬

‫یعنی می آید مشخص می کند که فرکانس تایمر ما چه ضریبی از‬


‫‪1‬‬
‫=𝑓‬ ‫فرکانس میکرو باشد ‪.‬‬
‫𝑇‬

‫زمان مورد نیاز = زمان هر شمارش * میزان شمارش شده کل‬

‫زمان هر شمارش = یک تقسیم بر فرکانس تایمر‬

‫فرکانس تایمر = فرکانس میکرو تقسیم بر پری اسکیلر‬

‫و ما با ترکیب کردن این فرمول ها به فرمول زیر می رسیم ‪.‬‬


‫‪1‬‬
‫= 𝑙𝑎𝑡𝑡𝑜𝑡𝑇‬
‫𝑞𝑒𝑟𝐹𝑈𝐶𝑀‬
‫(‬ ‫𝑡𝑛𝑢𝑜𝐶 ∗‬
‫‪Prescaler‬‬
‫که ما با ساده سازی فرمول باال به فرمول اصلی زیر می رسیم‪.‬‬
‫‪Prescaler ∗ Count‬‬
‫𝑙𝑎𝑡𝑡𝑜𝑡𝑇‬ ‫=‬
‫𝑞𝑒𝑟𝐹𝑈𝐶𝑀‬
‫‪-‬برای محاسبه فرکانس تایمر از نرم افزاری به اسم‬

‫‪ Timer Calculator‬استفاده می کنیم‪.‬‬

‫در این قسمت کد‬


‫پیشنهادی را به ما‬

‫یعنی برای ما ‪ 25ms‬بشمار‬ ‫نشان می دهد‪.‬‬

‫‪ :1‬ابتدا نوع میکرو کنترلر را تعین می کنیم‬

‫‪ :2‬سپس در قسمت ‪ MCU clock frequency‬کالک میکرو را‬


‫تعین می کنیم‪ .‬و در قسمت بعدی در صورتی که نیاز به تقسیم‬
‫فرکانسی داشته باشیم‪ .‬این قسمت را پر می کنیم‪.‬‬

‫‪ :3‬سپس نوع تایمر را انتخاب می کنیم‪(.‬برای اینکه نرم افزار بداند‬


‫تایمر چند بیتی می باشد که مراقب ‪ over flow‬شدن باشد ‪).‬‬

‫‪ :4‬زمانی که می خواهیم به ما اینتراپت بدهد ‪.‬‬


‫‪-‬در کد ساخته شده دو قسمت برای ما مهم می باشد ‪.‬‬
‫‪//Timer2 Prescaler :3; Preload = 49999; Actual Interrupt‬‬
‫‪Time = 25 ms‬‬
‫در این خط می گوید که ‪ Prescaler‬را روی ‪ 3‬بگذار ‪ .‬که‬
‫{)(‪void InitTimer2‬‬
‫;‪RCC_APB1ENR.TIM2EN = 1‬‬ ‫به این معنی می باشد که فرکانس میکرو را باید تقسیم بر‬
‫;‪TIM2_CR1.CEN = 0‬‬ ‫این عدد بکنیم‬
‫;‪TIM2_PSC = 3‬‬
‫;‪TIM2_ARR = 49999‬‬ ‫عنوان ‪ ARR‬می گویید که مقدار‬
‫;)‪NVIC_IntEnable(IVT_INT_TIM2‬‬ ‫‪ Over flow‬شدن تایمر چه‬
‫;‪TIM2_DIER.UIE = 1‬‬ ‫مقدار باشد ‪.‬‬
‫;‪TIM2_CR1.CEN = 1‬‬
‫‪} //ARR = Auto Reload Register‬‬

‫‪ :1‬اکنون در صفحه ‪ Pinout Configuration‬به سربرگ‬


‫‪ Category‬رفته و بر روی ‪ Timer‬کلید می کنیم‪.‬‬

‫‪ :2‬حال در صفحه ی ‪ mode‬مقدار ‪ clock source‬را بر روی‬


‫‪ Internal clock‬می گذاریم و به پایین صفحه ‪ ,‬قسمت‬
‫‪ Parameter Setting‬می رویم‪.‬‬

‫یک ‪ counter mode‬داریم که می تواند ‪ up‬یا ‪ down‬باشد ‪.‬‬

‫در این قسمت هم باید ‪ Prescaler‬را وارد کنیم‪.‬‬

‫در قسمت ‪ counter Period‬مقدار ‪ ARR‬را وارد می کنیم‪.‬‬

‫و همین طور مقدار ‪ Prescaler‬را ‪ 8000‬می دهیم‪.‬پس تایمر با‬


‫فرکانس 𝑧𝐻𝐾‪ 1‬می شود (باید مقدار ‪ 8000‬را ‪ 7999‬وارد کنیم‪).‬‬
‫حاال که فرکانس تایمر 𝑧𝐻𝐾‪ 1‬می باشد ‪ .‬فاصله زمانی بین هر‬
‫شمارش ‪ 1ms‬می باشد ‪.‬‬

‫‪:3‬حال ما ‪ counter period‬را روی ‪ 1000‬می گذاریم‪.‬که هر یک‬


‫ثانیه به ما یک اینتراپت می دهد‪.‬‬

‫‪1‬‬
‫‪2‬‬

‫‪3‬‬

‫حاال ما یک تایمر داریم که اگر دکمه استارت را بزنیم‪ .‬هر ‪ 1s‬به ما اینتراپت‬
‫می دهد‪.‬‬
‫‪-‬اکنون می خواهیم دو ‪ led‬چشمک زن درست بکنیم ‪ .‬یکی با حلقه‬
‫‪ while‬و دیگری با ‪. Timer‬‬

‫کاربرد این روش این است که ممکن است در حلقه ‪ while‬تعداد‬


‫زیادی ‪ delay‬وجود داشته باشد‪ .‬و ما می خواهیم خارج از این‬
‫‪ delay‬یک ‪ led‬چشمک زن داشته باشیم‪.‬‬

‫‪-‬اکنون در قسمت ‪ NVIC‬تیک آپدیت تایمر مربوطه را می زنیم ‪.‬‬

‫برای فعال شدن اینتراپت تیک آپدیت را می زنیم‪.‬‬


‫‪-‬اکنون بر روی ‪ Generate Code‬را می زنیم و به سراغ برنامه‬
‫نویسی می رویم‪.‬‬

‫‪-‬ابتدا در حلقه ‪ while‬یک ‪ led‬چشمک زن می نویسیم‪.‬‬


‫;)‪HAL_GPIO_TogglePin(LED_GREEN_PORT , LED_GREEN_PIN‬‬
‫;)‪HAL_Delay(1000‬‬

‫‪-‬ما در این برنامه نمی خواهیم که ‪ led‬ها به صورت سری چشمک بزنند‪.‬‬
‫می خواهیم که بهصورت همزمان چشمک بزنند‪.‬‬

‫اکنون باید یک تابع ‪ Callback‬بنویسیم ‪.‬‬


‫)‪void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim‬‬
‫{‬
‫)‪if (htim -> Instance == TIM1‬‬ ‫باید اینجا ببینیم که‬
‫اکنون از هر‬
‫{‬ ‫روی تایمر چند‬
‫تایمری که‬
‫این فلش >‪ -‬پوینتر می باشد‬ ‫اینتراپت آمده؟‬
‫اینتراپت بیاید ‪.‬‬
‫این ‪ htim‬همان هندلر تایمر می باشد ‪.‬‬ ‫این کانال‬
‫توسط سخت‬
‫‪ Instance‬رجیستری می باشد که مقدار شمارش تایمر مورد استفاده‬
‫افزار صدا زده‬
‫را از درون تایمر می خواند‪.‬‬
‫می شود ‪.‬‬
‫;)‪HAL_GPIO_TogglePin(LED_BLUE_PORT , LED_BLUE_PIN‬‬
‫;)‪HAL_Delay(500‬‬
‫}‬
‫}‬
‫‪-‬می توانیم برای تایمر ‪ 1‬ماکرونویسی انجام بدهیم‪.‬‬
‫‪#define LED_BLUE_BLINK_TIMER‬‬ ‫‪TIM1‬‬
‫‪-‬کاری که تا اکنون انجام نداده این ‪ Start & Stop‬کردن تایمر بوده ‪.‬‬
‫‪/* USER CODE BEGIN 2 */‬‬
‫;)‪HAL_TIM_Base_Start(&htim1‬‬
‫‪/* USER CODE END 2 */‬‬
‫این قسمت از کد را قبل از حلقه ‪ while‬می نویسیم‪.‬‬

‫‪-‬و همین طور برای ‪ Stop‬کردن تایمر از کد زیر استفاده می کنیم‪.‬‬


‫;)‪HAL_TIM_Base_Stop(&htim1‬‬
↓ ‫متن اصلی برنامه‬
/* Includes -------------------------*/
#include "main.h"
#include "gpio.h"
#include "tim.h"
#include "stdio.h"
/* USER CODE BEGIN Includes */
#define LED_RED_PORT GPIOC
#define LED_RED_PIN GPIO_PIN_14
#define LED_GREEN_PORT GPIOC
#define LED_GREEN_PIN GPIO_PIN_15
#define DELAY_ON_LED_RED 4500
#define DELAY_OFF_LED_RED 1500
#define LED_BLUE_BLINK_TIMER TIM1
/* USER CODE END Includes */
/* USER CODE BEGIN PTD */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim -> Instance == TIM1)
{
HAL_GPIO_TogglePin(LED_BLUE_PORT , LED_BLUE_PIN);
HAL_Delay(500);
}
}
/* USER CODE END PTD */
int main(void)
{
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim1);
/* USER CODE END 2 */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
HAL_GPIO_TogglePin(LED_GREEN_PORT , LED_GREEN_PIN);
HAL_Delay(1000);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
‫*جلسه ششم ‪ :‬ادامه مبحث تایمر‬
‫‪-‬میکروکنترلر های ‪ STM32‬در بحث تایمر و امکانات دارای‬
‫گستردگی زیادی هستند ‪ .‬در جلسه قبل تایمر را به صورت اینتراپت‬
‫یاد گرفتیم ‪ .‬در این جلسه می خواهیم تایمر را به صورت پولینگ نیر‬
‫یاد بگیریم‪ .‬ما در موقعیت هایی که می دانیم زمانمان در چه رنجی‬
‫می باشد می توانیم در نقاطی که می خواهیم اینتراپت بگذاریم ‪.‬‬
‫ولی در جاهایی که بخواهیم سر زمان های خاصی یک کاری را انجام‬
‫بدهیم و ممکن است در برخی مواقع بحث زمان سنجی در میان‬
‫باشد‪.‬‬
‫‪ -‬مثل راه اندازی سنسور ‪ ( Ultrasonic‬که قرار است فاصله ای‬
‫سنجیده شود و از طرفی زمانی که سیگنال صوت در حال رفت و‬
‫برگشت می باشد سنجیده شود )‬
‫‪-‬نحوه کارکرد سنسور ‪ :Ultrasonic‬ما توسط میکروکنترلر پین‬
‫تحریک سنسور را تحریک کرده و توسط سنسور یک موج صوتی به‬
‫سمت مانع می تابانیم ‪ .‬این موج صوتی بعد از برخورد به مانع بازتاب‬
‫شده و به سمت سنسور باز می گردد‪ .‬وبه ما اعالم می کند که موج‬
‫صوتی برگشت داده شده است‪ .‬اکنون ما باید زمان رفت و برگشت را‬
‫محاسبه کرد و با دانستن سرعت صوت ‪,‬فاصله سنسور تا مانع را‬
‫محاسبه کرد ‪.‬‬
‫*آموزش پروگرام کردن برد ‪ blue pill‬با پروگرامر ‪ ST-Link\v2‬با‬
‫استفاده از نرم افزار ‪: STM32 ST-LINK Utility‬‬

‫‪-‬ابتدا پروگرامر را به ‪ PC‬متصل کرده و سپس برد ‪ blue pill‬را به‬


‫پروگرامر متصل می کنیم‪.‬‬
‫سوکت ‪ SWD‬جهت پروگرام کردن‬
‫‪STM32‬‬
‫‪2‬‬ ‫‪20‬‬
‫‪1‬‬ ‫‪19‬‬
‫سوکت جهت پروگرام کردن ‪STM8‬‬

‫‪ LED‬نشان دهنده وضعیت پروگرامر‬

‫‪-‬شماتیک پایه های سوکت ‪ SWD‬روی پروگرامر‬

‫‪19‬‬ ‫‪17‬‬ ‫‪15‬‬ ‫‪13‬‬ ‫‪11‬‬ ‫‪9‬‬ ‫‪7‬‬ ‫‪5‬‬ ‫‪3‬‬ ‫‪1‬‬

‫‪20‬‬ ‫‪18‬‬ ‫‪16‬‬ ‫‪14‬‬ ‫‪12‬‬ ‫‪10‬‬ ‫‪8‬‬ ‫‪6‬‬ ‫‪4‬‬ ‫‪2‬‬

‫‪2‬‬
‫اسم پایه‬ ‫شماره پایه‬ ‫*‬ ‫اسم پایه‬ ‫شماره پایه‬
‫‪NC‬‬ ‫‪11‬‬ ‫*‬ ‫‪TVCC‬‬ ‫‪1‬‬
‫‪GND‬‬ ‫‪12‬‬ ‫*‬ ‫‪TVCC‬‬ ‫‪2‬‬
‫‪TDO‬‬ ‫‪13‬‬ ‫*‬ ‫‪TRST‬‬ ‫‪3‬‬
‫‪SWIM‬‬ ‫‪14‬‬ ‫‪* UART RX‬‬ ‫‪4‬‬
‫‪RST‬‬
‫‪STM32‬‬ ‫‪15‬‬ ‫*‬ ‫‪TDI‬‬ ‫‪5‬‬
‫‪RST‬‬
‫‪KEY‬‬ ‫‪16‬‬ ‫‪* UART TX‬‬ ‫‪6‬‬
‫‪NC‬‬ ‫‪17‬‬ ‫*‬ ‫‪TMS‬‬ ‫‪7‬‬
‫‪SWIO‬‬
‫‪GND‬‬ ‫‪18‬‬ ‫*‬ ‫‪BOOT 0‬‬ ‫‪8‬‬
‫‪VDD‬‬ ‫‪19‬‬ ‫*‬ ‫‪TCK‬‬ ‫‪9‬‬
‫‪3.3V‬‬ ‫‪SWCLK‬‬
‫‪GND‬‬ ‫‪20‬‬ ‫*‬ ‫‪SWIM‬‬ ‫‪10‬‬

‫‪-‬حاال اگر کابل روبرو را مثل‬


‫شکل زیر به پروگرامر‬
‫متصل کنیم‪ .‬خروجی پایه‬
‫های سوکت به شکل زیر‬
‫می شود ‪.‬‬
‫‪-‬شماتیک خروجی کابل فلت متصل به پروگرامر‬

‫‪19‬‬ ‫‪17‬‬ ‫‪15‬‬ ‫‪13‬‬ ‫‪11‬‬ ‫‪9‬‬ ‫‪7‬‬ ‫‪5‬‬ ‫‪3‬‬ ‫‪1‬‬

‫‪20‬‬ ‫‪18‬‬ ‫‪16‬‬ ‫‪14‬‬ ‫‪12‬‬ ‫‪10‬‬ ‫‪8‬‬ ‫‪6‬‬ ‫‪4‬‬ ‫‪2‬‬

‫‪2‬‬

‫‪-‬اکنون که پروگرامر رو به ‪ PC‬متصل کرده ایم ‪ ,‬برد ‪ blue pill‬را به‬


‫نحوه زیر به پروگرامر متصل می کنیم‪.‬‬

‫‪ST-Link\v2‬‬ ‫‪Blue Pill‬‬


‫‪VCC→ pin19‬‬ ‫‪3.3v‬‬
‫‪SWIO→ pin7‬‬ ‫‪SWIO‬‬
‫‪SWCLK→ pin9‬‬ ‫‪SWCLK‬‬
‫‪GND→ pin20‬‬ ‫‪GND‬‬
‫‪NRST→ pin15‬‬ ‫‪NRST‬‬

‫‪2‬‬ ‫‪1‬‬

‫‪4‬‬ ‫‪3‬‬

‫‪6‬‬ ‫‪5‬‬

‫‪7‬‬

‫‪9‬‬

‫‪12‬‬ ‫‪11‬‬

‫‪14‬‬ ‫‪13‬‬

‫‪16‬‬ ‫‪15‬‬

‫در این قسمت برد ‪ Blue pill‬را‬ ‫‪18‬‬ ‫‪17‬‬

‫‪20‬‬
‫به کابل فلت متصل کرده ایم‬ ‫‪19‬‬
‫‪-‬در این قسمت پروگرام کردن باید‬
‫فایل ‪ hex‬داشته باشیم‪ .‬برای همین‬
‫کار در نرم افزار به قسمت‬
‫‪ Project‬و ‪ Properties‬رفته ‪.‬‬

‫‪1‬‬
‫‪3‬‬
‫‪2‬‬
‫‪5‬‬
‫‪4‬‬

‫‪6‬‬
‫‪-‬سپس در صفحه ‪ Properties‬به منوی ‪ C/C++ Build‬رفته و‬
‫بر روی ‪ Setting‬کلید می کنیم‪ ,‬در صفحه ای که باز می شود در‬
‫سربرگ‪ Tool Setting‬بر روی ‪MCU Post Build Outputs‬‬
‫کلید می کنیم‪ .‬بعد از کلید کردن تعدادی گزینه برای ما نمایش‬
‫می دهد ‪ .‬ما‬

‫)‪ Convert to intel Hex file (-O ihex‬را فعال می کنیم و‬


‫سپس بر روی ‪ Apply and Close‬کلید می کنیم‪ .‬اکنون فایل‬
‫‪ hex‬برای ما ساخته شده است ‪ .‬محل ذخیره فایل ‪ hex‬در‬
‫محل ذخیره سازی پروژه و در پوشه ‪ debug‬می باشد‪.‬‬

‫‪-‬اکنون که فایل ‪ hex‬را ساختیم ‪ .‬باید آن را در نرم افزار‬

‫‪ STM32 ST-LINK Utility‬آپلود بکنیم و سپس برد ‪blue pill‬‬


‫را پروگرام بکنیم‪.‬‬
‫‪-‬برای پروگرام کردن در نرم افزار ‪ST-LINK Utility‬‬

‫بر روی‪ File → Open file‬کلید کرده و فایل ‪ hex‬مورد نظر‬


‫را انتخاب کرده ‪ .‬اگر فایل را به درستی انتخاب کرده باشیم‪.‬‬
‫صفحه زیر نمایش داده می شود ‪.‬‬
‫‪-‬اکنون پروگرامر را با کابل‬
‫مناسب به ‪ PC‬متصل کرده و از‬
‫منوی ‪ Target‬بر روی‬
‫‪ Connect‬کلید می کنیم‪.‬‬

‫‪-‬سپس صفحه نرم افزار به‬


‫شکل زیر در آمده و چراغ روی‬
‫پروگرامر چشمک زن سبز و‬
‫قرمز می شود ‪.‬‬
‫‪-‬اکنون باید برنامه را روی‬
‫میکروکنترلر پروگرام کنیم‪ .‬برای این‬
‫کار از منوی‬

‫‪target → Program and‬‬


‫‪ verify‬را انتخاب کرده ‪ .‬سپس‬
‫صفحه زیر باز می شود که باید بر‬
‫روی ‪ Start‬کلید کنیم‪.‬‬
‫‪-‬اکنون اگر فرایند پروگرام درست انجام شده باشد ‪ .‬صفحه زیر‬
‫نمایش داده می شود ‪.‬‬

‫‪-‬و در مرحله آخر اگر از منوی ‪target‬‬


‫بر روی ‪ disconnect‬کلید کنیم‪.‬‬
‫مراحل پروگرام ما به پایان می رسد‪.‬‬

You might also like