آموزش میکروکنترلر Stm32f1 به صورت رجیستری قسمت اول: GPIO-خروجی

0
196
GPIO-خروجی
GPIO-خروجی

مقدمه

شاید برای شما سوال‌ شده‌باشه چرا اصلا رجیستری، مگر توابع cmsis و یا توابع Hal جواب‌گوی پروژه‌هایمان نیستند و نمی‌توانیم از توابع آماده استفاده‌کنیم؟ خب به این سوال هرکسی با هر اندازه تجربه می‌تواند پاسخ‌دهد اما پاسخی که حداقل من را به خود قانع می‌کند این است که درسته ما توابع متنوعی را در اجرای پروژه‌هایمان می‌توانیم استفاده‌کنیم اما آیا در کنار اجرای پروژه‌ها به درک عمیقی خواهیم رسید؟ و آیا نسبت به توابعی که دیگران آن را نگارش کردند اطمینان‌خاطر داریم؟ و… اکنون با این دید که می‌خواهیم درکی متفاوت و عمیق در زمینه میکروکنترلرهای آرم سری Cortex-m3 از خانواده‌ی بزرگ شرکت ST پیدا کنیم کار خود را شروع می‌کنیم. طبق روال‌ما از ایجاد پروژه، کار خود را شروع می‌کنیم و سعی می‌کنیم یک پین را خروجی کرده و led ای را روشن و خاموش کنیم. برای کدنویسی میکروکنترلرهای ARM نرم‌افزارهای زیادی موجود است که انصافا باتوجه‌به قدرت دیباگ نرم‌افزار کیل، من از نرم‌افزار کیل استفاده می‌کنم اما شما می‌توانید از IAR ،eclips و … استفاده‌کنید، مهم اصول کارکردن است که باهم و در کنارهم یاد می‌گیریم. من درمورد نصب‌کردن نرم‌افزار کیل چیزی نمی‌گم چون دوستان لطف‌کردن در این سایت و فضای اینترنت مطالب زیادی رو تهیه و به اشتراک گذاشتند و اگر باز‌هم مشکل داشتید در آخر این پست کامنت کنید و درقالب پستی نو برای شما آموزشی خواهم گذاشت.

ایجاد پروژه

برای ایجاد پروژه کاملا طبق عکس‌های زیر عمل خواهیم کرد:

1 – ایجاد پروژه جدید:

پروژه جدید در کیل
پروژه جدید در کیل

 

2 – مشخص‌کردن محل ذخیره فایل پروژه و تعیین نامی مناسب برای پروژه:

ذخیره فایل در کیل
ذخیره فایل در کیل

 

3 – انتخاب میکروکنترلر مورداستفاده(من از STM32f103ret6 استفاده می‌کنم) برای انجام پروژه:

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

 

4 – انتخاب امکانات اولیه برای کدنویسی و انتقال فایل startup به پروژه:

انتقال فایل startup به پروژه در کیل
انتقال فایل startup به پروژه در کیل

 

5 – اضافه‌کردن فایل main به پروژه:

 

خب بعد ایجاد پروژه، طبق معمول در همه‌ی پروژه‌ها به زبان C، تابع main را به پروژه خود اضافه می‌کنیم.

void main(int)
{
while(1)
{

}
}

اما برای اینکه به امکانات میکروکنترلرهای سری M3 دسترسی داشته‌باشیم باید فایل هدر میکروکنترلر را به پروژه اضافه کنیم.

# include "stm32f10x.h"

اما با اضافه‌کردن این هدر کار تمام‌شده نیست، بلکه باید وارد این هدر شده و میکروکنترلر موردنظر خود را از حالت کامنت خارج‌کرده تا از امکانات این میکروکنترلر بهره‌مند شویم طبق عکس‌زیر:

اضافه‌کردن کتابخانه میکروکنترلر در کیل
اضافه‌کردن کتابخانه میکروکنترلر در کیل
رفع کامنت در کیل
رفع کامنت در کیل

 

اما اگر فایل stm32f10x.h را در پوشه‌ی پروژه ذخیره نکنیم نمی‌توانیم define STM32F10X_HD # را از حالت کامنت خارج‌کنیم.

حالا می‌ریم سروقت اصل ماجرا. برای اینکه یک پین را on یا off کنیم اول باید یک‌سری توضیحات درمورد بعضی رجیسترها بدهم تا اصل ماجرا رو بفهمیم، بعد بریم سراغ پروژه. دانستن این نکته مهمه که شرکت ST علاقه دارد هر پورت خود را ۱۶بیتی تقسیم کند و این ۱۶بیت را به دو دسته ۸بیت کم ارزش و ۸بیت پرارزش تقسیم کند و برای کنترلشان نیز رجیستری را درنظر می‌گیرد. برای خروجی‌کردن هر پین می‌توانیم از دو مدل آرایش مداری که به‌صورت نرم‌افزاری انتخاب می‌شود استفاده‌کنیم (PushPull و یا OpenDrin) برای ورودی‌کردن هم طبق معمول حالت‌ها PullUp ,PullDown ,Float و آنالوگ را پشتیبانی می‌کند. و یک حالت Alternate Function هم وجود دارد که به‌موقع توضیح‌خواهم‌داد.

لیست حالت‌های پین IO
لیست حالت‌های پین IO

 

نکته بعدی هم اینکه در حالت خروجی ما می‌توانیم حداکثر فرکانسی را که از پین موردنظرمون عبور کند را هم مشخص‌کنیم (۱۰Mhz ,۲Mhz ,۵۰Mhz)

خب می‌ریم سروقت رجیستری که ورودی-خروجی را مشخص می‌کند. اگر یادتان‌باشد گفتم هر پورت به دو دسته ۸بیتی تقسیم می‌شود پس به‌خاطر این دسته‌بندی ما از دو رجیستر برای تنظیم حالت‌های ورودی–خروجی استفاده می‌کنیم که اسمشان CRL و CRH است؛ که CRL برای رجیسترهای ۸بیت کم ارزش و CRH برای رجیسترهای ۸بیت پر ارزش است.

رجیستر CRL:

رجیستر CRL
رجیستر CRL

 

همانطورکه در عکس بالا نمایش‌داده‌شده‌است این رجیستر ۳۲بیتی است و برای تنظیم هر پین ما ۴بیت را دراختیار خواهیم‌داشت که به‌صورت جدول‌زیر تنظیم می‌شود.

CNF-MODE
CNF-MODE

 

جدول‌بالا به ما این را می‌فهماند که اگر بخواهیم پین موردنظر را خروجی از نوع پوش-پول کنیم باید در ۴بیتی که دراختیار داریم، در دو بیت CNF عدد “۰۰” را نوشته و در دوبیت mode براساس سرعتی که می‌خواهیم، عدد موردنظر را قرار دهیم، که من می‌خواهم از سرعت ۵۰Mhz استفاده‌کنم، که میشود “۱۱” و اگر بخواهیم به‌صورت هگز بنویسیم می‌شود 0x3 اما چگونه باید کد نوشت؟

مثلا من برای پورت A.0 می‌‎خواهم تنظیمات رو پیکربندی کنم:

GPIOA->CRL &= ~(0x0000000F);
GPIOA->CRL |= 0x00000003;

حالا شاید برای شما سوال‌شده‌باشه که چرا اول(0x0000000F)~ را با رجیستر CRL به‌صورت AND بیتی نوشتم! جوابتون هم یک جمله‌ست: چون درحالت اولیه تمام پین‌ها، ورودی و از نوع شناور یا همان float هستند(باتوجه‌به مقدار Reset value = 0x4444 4444) و ما در ابتدا باید بیت‌های موردنظر را صفر کنیم، سپس در آن‌ها بنویسیم. عبارت (0x0000000F)~ برابر است با 0xFFFFFFF0، یعنی وقتی این عبارت با رجیستر CRL به‌صورت بیتی AND شود، ۴بیت اول رجیستر CRL صفر می‌شوند.

خب بعداز شناخت‌اولیه نسبت‌به رجیستر CRL‌(نگران‌نباشید در آینده آنقدر با این رجیستر سروکله خواهیم‌زد که شما قطعا بر این موضوع اشراف پیدا خواهید کرد) می‌ریم سروقت مقداردهی به پین موردنظرمون.

برای روشن و خاموش‌کردن یک پین ما سه رجیستر کاملا مجزا داریم، رجیسترهای ODR ,BRR ,BSRR که هر سه تاشو توضیح می‌دم.

رجیستر ODR:

رجیستر ODR
رجیستر ODR

 

این رجیستر همانطورکه در عکس‌بالا مشخص‌است یک رجیستر ۳۲بیتی است که فقط ۱۶بیت آن دردسترس است که هر بیت برای مقداردهی به هر پین منتاظر است.

از این رجیستر برای نوشتن مقدار صفر و یک در پین موردنظر استفاده می‌شود اما بهتر است فقط برای نوشتن مقدار یک از این رجیستراستفاده کنیم چون با هربار مقداردهی به این رجیستر اگر مقدار قبلی را OR با مقدار جدید نکنیم کل مقدار قبلی را پاک می‌کنه و مقدار جدید را رایت می‌کنه(جایگزینش BSRR است)

GPIOA->ODR |= (1<<0);

یک را شیفت به چپ میدهیم صفرتا =>یعنی بیت صفرم پورت Aرا یک کن

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

رجیستر BRR :

رجیستر BRR
رجیستر BRR

 

این رجیستر هم ۳۲بیتی است که ۱۶بیت آن دردسترس است که با نوشتن مقدار یک در این رجیستر پین موردنظر را صفر می‌کند(به‌همین‌سادگی) این رجیستر برای صفرکردن پین‌هایی استفاده‌میشه که ازطریق ODR یک شدن(البته در هرصورت برای صفرکردن استفاده میشه اما بیشترین کاربردش برای clear کردن پینی است که ازطریق ODR یک شده است)

GPIOA->BRR = (1<<0);

اما رجیستری که هم خودش می‌تونه پینی رو یک کنه و هم صفر کنه!

رجیستر BSRR:

رجیستر BSRR
رجیستر BSRR

 

این رجیستر ۳۲بیتی است که ۱۶بیت کم ارزش آن برای یک کردن پین‌ها استفاده می‌شود و ۱۶بیت پر ارزش آن برای صفرکردن پین‌ها مورداستفاده قرار می‌گیرد.

GPIOA->BSRR = (1<<0);
Delay(100);
GPIOA->BSRR = (1<<16);
Delay();

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

بلوک STM32-Cortex-m3
بلوک STM32-Cortex-m3

 

طبق عکس‌بالا که طراحی هسته‌های ARM سری Cortex-m3 شرکت ST را نشان می‌دهد، هرکدام از پریفرال‌ها(امکانات) این میکروکنترلر ازطریق باس(رابط)هایی با هسته‌ی مرکزی در ارتباط هستند. حال اگر بخواهیم مثلا پریفرال‌های مانند USART ,i2C ,TIMER ,GPIO و… را راه‌اندازی کنیم و استفاده داشته‌باشیم باید باس متصل‌به آن پریفرال را فعال‌کنیم تا(به‌قول‌معروف اول خون به اعضاء برسه و بعد استفاده‌کنیم) بتوانیم استفاده‌کنیم. خب برای فعال‌سازی کلاک GPIOها اول به عکس‌بالا نگاه می‌کنیم تا به کدام یک از باس‌ها متصل هستند، اگر خوب نگاه کنیم می‌بینیم GPIOها به باس APB2 متصل هستند.

رجیستر APB2ENR:

این رجیستر عمل فراهم‌سازی کلاک رو برای پریفرال‌های متصل‌به‌خود فراهم می‌سازد.

رجیستر APB2ENR
رجیستر APB2ENR

 

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

RCC->APB2ENR |= (1<<2);

این کد یعنی بیت شماره دو که برای پورت A است را یک کن تا کلاکش مهیا شود.

کد نهایی:

Code
Code

 

با توضیحات بالا فکر می‌کنم همه‌ی شما قطعا می‌تونید اولین پروژه کاملا رجیستری خودتون رو پیاده‌سازی کنید و درکی درست از برنامه نویسی میکروکنترلر ARM کسب‌کنید. در جلسه آینده باهم حالت ورودی IOها را بررسی خواهیم‌کرد و بعد سراغ وقفه خارجی خواهیم رفت.

 

منبع:‌سیسوگ

برای این مقاله نظر بگذارید:

لطفا دیدگاه خود را بنویسید
لطفا نام خود را وارد کنید