خدایا با نام تو، با یاد تو و برای تو
مهدی حسن زاده آملی هستم با یک آموزش پایهای و کاملا رجیستری در زمینه STM32f103 Cortex-m3، در خدمت شما هستم.
شاید برای شما سوال شده باشه چرا اصلا رجیستری، مگر توابع cmsis و یا توابع Hal جوابگوی پروژههایمان نیستند و نمیتوانیم از توابع آماده استفاده کنیم؟
خب به این سوال هر کسی با هر اندازه تجربه میتواند پاسخ دهد اما پاسخی که حداقل من را به خود قانع میکند این است که درسته ما توابع متنوعی را در اجرای پروژههایمان میتوانیم استفاده کنیم اما آیا در کنار اجرای پروژهها به درک عمیقی خواهیم رسید؟ و آیا نسبت به توابعی که دیگران آن را نگارش کردند اطمینان خاطر داریم؟ و …
اکنون با این دید که میخواهیم درکی متفاوت و عمیق در زمینه میکروکنترلرهای آرم سری Cortex-m3 از خانوادهی بزرگ شرکت ST پیدا کنیم کار خود را شروع میکنیم.
طبق روال ما از ایجاد پروژه، کار خود را شروع میکنیم و سعی میکنیم یک پین را خروجی کرده و led ای را روشن و خاموش کنیم. برای کدنویسی میکروکنترلرهای ARM نرمافزارهای زیادی موجود است که انصافا با توجه به قدرت دیباگ نرمافزار کیل من از نرمافزار کیل استفاده میکنم اما شما میتوانید از IAR ،eclips و … استفاده کنید، مهم اصول کار کردن است که باهم و در کنار هم یاد میگیریم.
من درمورد نصب کردن نرمافزار کیل چیزی نمیگم چون دوستان لطف کردن در این سایت و فضای اینترنت مطالب زیادی رو تهیه و به اشتراک گذاشتند و اگر باز هم مشکل داشتید در آخر این پست کامنت کنید و در قالب پستی نو برای شما آموزشی خواهم گذاشت.
اما ایجاد پروژه:
برای ایجاد پروژه کاملا طبق عکسهای زیر عمل خواهیم کرد:
1: ایجاد پروژه جدید
2: مشخص کردن محل ذخیره فایل پروژه و تعیین نامی مناسب برای پروژه:
3: انتخاب میکروکنترلر مورد استفاده (من از STM32f103ret6 استفاده میکنم) برای انجام پروژه:
4: انتخاب امکانات اولیه برای کدنویسی و انتقال فایل startup به پروژه:
5:اضافه کردن فایل main به پروژه:
خب بعد ایجاد پروژه، طبق معمول در همهی پروژهها به زبان C، تابع main را به پروژه خود اضافه میکنیم.
1 2 3 4 5 6 7 | int main(void) { while(1) { } } |
اما برای اینکه به امکانات میکروکنترلرهای سری M3 دسترسی داشته باشیم باید فایل هدر میکروکنترلر را به پروژه اضافه کنیم.
1 | # include "stm32f10x.h" |
اما با اضافه کردن این هدر کار تمام شده نیست، بلکه باید وارد این هدر شده و میکروکنترلر مورد نظر خود را از حالت کامنت خارج کرده تا از امکانات این میکروکنترلر بهرهمند شویم طبق عکس زیر:
اما اگر فایل stm32f10x.h را در پوشهی پروژه ذخیره نکنیم نمیتوانیم define STM32F10X_HD # را از حالت کامنت خارج کنیم.
حالا میریم سروقت اصل ماجرا. برای اینکه یک پین را on یا off کنیم اول باید یک سری توضیحات درمورد بعضی رجیسترها بدهم تا اصل ماجرا رو بفهمیم، بعد بریم سراغ پروژه.
دانستن این نکته مهمه که شرکت ST علاقه دارد هر پورت خود را 16 بیتی تقسیم کند و این 16 بیت را به دو دسته 8 بیت کم ارزش و 8 بیت پرارزش تقسیم کند و برای کنترلشان نیز رجیستری را در نظر میگیرد.
برای خروجی کردن هر پین میتوانیم از دو مدل آرایش مداری که به صورت نرمافزاری انتخاب میشود استفاده کنیم (PushPull و یا OpenDrin)
برای ورودی کردن هم طبق معمول حالت ها PullUp ,PullDown ,Float و آنالوگ را پشتیبانی میکند. و یک حالت Alternate Function هم وجود دارد که به موقع توضیح خواهم داد.
نکته بعدی هم اینکه در حالت خروجی ما میتوانیم حداکثر فرکانسی را که از پین مورد نظرمون عبور کند را هم مشخص کنیم (10Mhz ,2Mhz ,50Mhz)
خب میریم سر وقت رجیستری که ورودی-خروجی را مشخص میکند. اگر یادتان باشد گفتم هر پورت به دو دسته 8 بیتی تقسیم میشود پس به خاطر این دستهبندی ما از دو رجیستر برای تنظیم حالت های ورودی–خروجی استفاده میکنیم که اسمشان CRL و CRH است؛ که CRL برای رجیستر های 8 بیت کم ارزش و CRH برای رجیستر های 8 بیت پر ارزش است.
رجیستر CRL:
همانطور که در عکس بالا نمایش داده شده است این رجیستر 32 بیتی است و برای تنظیم هر پین ما چهار بیت را در اختیار خواهیم داشت که به صورت جدول زیر تنظیم میشود.
جدول بالا به ما این را میفهماند که اگر بخواهیم پین مورد نظر را خروجی از نوع پوش-پول کنیم باید در چهار بیتی که دراختیار داریم، در دو بیت CNF عدد “00” را نوشته و در دوبیت mode بر اساس سرعتی که میخواهیم، عدد موردنظر را قرار دهیم، که من میخواهم از سرعت 50Mhz استفاده کنم، که میشود “11” و اگر بخواهیم به صورت هگز بنویسیم میشود 0x3 اما چگونه باید کد نوشت؟
مثلا من برای پورت A.0 میخواهم تنظیمات رو پیکربندی کنم:
1 2 | GPIOA->CRL &= ~(0x0000000F); GPIOA->CRL |= 0x00000003; |
حالا شاید برای شما سوال شده باشه که چرا اول (0x0000000F)~ را با رجیستر CRL به صورت AND بیتی نوشتم! جوابتون هم یک جملست: چون درحالت اولیه تمام پین ها، ورودی و از نوع شناور یا همان float هستند (با توجه به مقدار Reset value = 0x4444 4444) و ما در ابتدا باید بیتهای موردنظر را صفر کنیم، سپس در آنها بنویسیم. عبارت (0x0000000F)~ برابر است با 0xFFFFFFF0، یعنی وقتی این عبارت با رجیستر CRL به صورت بیتی AND شود، 4 بیت اول رجیستر CRL صفر میشوند.
خب بعد از شناخت اولیه نسبت به رجیستر CRL (نگران نباشید در آینده آنقدر با این رجیستر سروکله خواهیم زد که شما قطعا بر این موضوع اشراف پیدا خواهید کرد) میریم سروقت مقداردهی به پین موردنظرمون.
برای روشن و خاموش کردن یک پین ما سه رجیستر کاملا مجزا داریم، رجیستر های ODR ,BRR ,BSRR که هر سه تاشو توضیح میدم.
رجیستر ODR:
این رجیستر همانطور که در عکس بالا مشخص است یک رجیستر 32 بیتی است که فقط 16 بیت آن در دسترس است که هر بیت برای مقداردهی به هر پین منتاظر است.
از این رجیستر برای نوشتن مقدار صفر و یک در پین موردنظر استفاده میشود اما بهتر است فقط برای نوشتن مقدار یک از این رجیستراستفاده کنیم چون با هر بار مقداردهی به این رجیستر اگر مقدار قبلی را OR با مقدار جدید نکنیم کل مقدار قبلی را پاک میکنه و مقدار جدید را رایت میکنه (جایگزینش BSRR است)
1 | GPIOA->ODR |= (1<<0); |
یک را شیفت به چپ میدهیم صفرتا =>یعنی بیت صفرم پورت Aرا یک کن
اما برای خاموش کردن این پین از رجیستر BRR استفاده میکنیم.
رجیستر BRR :
این رجیستر هم 32 بیتی است که 16 بیت آن در دسترس است که با نوشتن مقدار یک در این رجیستر پین مورد نظر را صفر میکند (به همین سادگی)
این رجیستر برای صفر کردن پین هایی استفاده میشه که از طریق ODR یک شدن (البته در هر صورت برای صفر کردن استفاده میشه اما بیشترین کاربردش برای clear کردن پینی است که از طریق ODR یک شده است)
1 | GPIOA->BRR = (1<<0); |
اما رجیستری که هم خودش میتونه پینی رو یک کنه و هم صفر کنه!
رجیستر BSRR:
این رجیستر 32بیتی است که 16 بیت کم ارزش آن برای یک کردن پینها استفاده میشود و 16 بیت پر ارزش آن برای صفر کردن پینها مورد استفاده قرار میگیرد.
1 2 3 4 | GPIOA->BSRR = (1<<0); Delay(100); GPIOA->BSRR = (1<<16); Delay(); |
کد بالا اول پین شماره صفر از پورت A را یک میکند و بعد از صرف زمانی خاص صفر میکند.
نکته مهم و پایانی که اگر این نکته را در کدنویسی خود رعایت نکنید قطعا جوابی حاصل نخواهد شد.
طبق عکس بالا که طراحی هستههای ARM سری Cortex-m3 شرکت ST را نشان میدهد، هر کدام از پریفرالها (امکانات) این میکروکنترلر از طریق باس (رابط) هایی با هستهی مرکزی در ارتباط هستند. حال اگر بخواهیم مثلا پریفرالهای مانند USART ,i2C ,TIMER ,GPIO و … را راهاندازی کنیم و استفاده داشته باشیم باید باس متصل به آن پریفرال را فعال کنیم تا (به قول معروف اول خون به اعضاء برسه و بعد استفاده کنیم) بتوانیم استفاده کنیم.
خب برای فعال سازی کلاک GPIOها اول به عکس بالا نگاه میکنیم تا به کدام یک از باس ها متصل هستند، اگر خوب نگاه کنیم میبینیم GPIOها به باس APB2 متصل هستند.
رجیستر APB2ENR:
این رجیستر عمل فراهمسازی کلاک رو برای پریفرالهای متصل به خود فراهم میسازد.
این رجیستر هم 32 بیتی است که بعضی قسمت های آن در دسترس ما است که میتوانیم با یک کردن این قسمتها کلاک را برای پریفرال مورد استفادهمان فراهم سازیم.
1 | RCC->APB2ENR |= (1<<2); |
این کد یعنی بیت شماره دو که برای پورت A است را یک کن تا کلاکش مهیا شود.
کد نهایی:
با توضیحات بالا فکر میکنم همهی شما قطعا میتونید اولین پروژه کاملا رجیستری خودتون رو پیادهسازی کنید و درکی درست از برنامه نویسی میکروکنترلر ARM کسب کنید.
در جلسه آینده ان شاالله باهم حالت ورودی IOها را برسی خواهیم کرد و بعد سراغ وقفه خارجی خواهیم رفت.
برای دسترسی به سایر قسمتهای این مجموعه آموزشی که تا به امروز منتشر شده است، میتوانید از طریق لینکهای زیر اقدام نمائید.
سلام
برای من ارور F:/ST_Packs/Keil/STM32F1xx_DFP/2.4.1/Device/Include\stm32f10x.h(486): error: ‘core_cm3.h’ file not found
داده . فایل core_cm3.h رو از کجا دانلود کنم ؟
توی اینترنت بگردید پیدا میکنید.
مثلا اینک زیر
https://github.com/ARM-software/CMSIS_4/blob/master/CMSIS/Include/core_cm3.h
خیلی خوب و زیبا توضیح دادید. دمتون گرم
با سلام و تشکر بابت مطلب بسیار مفیدتون
یک اشتباهی تایپی رو خواستم یادآوری کنم. بعد از ایجاد پروژه در Keil و برای نوشتن تابع main ، به اشتباه نوشته شده void main(int) که دقیقا ورودی و خروجی برعکس هستن و باید نوشته بشه int main(void) .
ممنون از شما . اصلاح شد 🙂
عالییییی ممنون از شما
اگه بخوایم بجای کیل از gcc-arm و ایکلیپس یا کد بلاکس استفاده کنیم !!
اونوقت باید چجوری اون فایل کتابخونه ها رو پیدا کنیم:(((
بسیار عاااالی
خدا خیرتون بده
زنده باشید 🙂
درود بیکران
سلام.عالی.من هرکاری میکنم نمیشه تو پروتیوس شبیه سازی کنم و نتیجه رو ببینم.اصلا اجرا نمیشه لطفا در صورت ممکن راهنمایی کنین.سپاس
سلام
وقتتون بخیر، راجب موضوع مد عملکردی GPIO در میکروکنترلرهای آرم، برای STM32F1 به این صورتی که گفتید هست ولی رجیسترای STM32F4 و STM32F7 متفاوته و من در قرار دادن پایه های اون میکروها به صورت Alternate function یا ۱۰ در رجیستر moder مشکل دارم و نمیتونم ارتباط پریفرالهارو با بیرون میکرو داشته باشم.
ممنون میشم اگه راجب این موضوح هم صحبت کنید.
سلام
وقتتون بخیر، راجب موضوع مد عملکردی GPIO در میکروکنترلرهای آرم، برای STM32F1 به این صورتی که گفتید هست ولی رجیسترای STM32F4 و STM32F7 متفاوته و من در قرار دادن پایه های اون میکروها به صورت Alternate function یا ۱۰ در رجیستر moder مشکل دارم و نمیتونم ارتباط پریفرالهارو با بیرون میکرو داشته باشم.
ممنون میشم اگه راجب این موضوح هم صحبت کنید.
من اون مشکل حل کردم اما مقدار رجیستر bsrr تغییر نمیکنه اصلا
سهند جان دقیقا بگید چه کدی مینویسید که تغییر نمیکنه؟ رجیستر BSRR برای ست و ریست کردن مقدار رجیستر ODR. شما میخواهید چه کاری انجام بدهید؟
با سلام.بنده قسمت از حالت کامند درآوردن رو نتونستم انجام بدم.اجازه ادیت فایلstm32f10x.h رو به من نمیده.در ضمن وقتی ابتدا برای تعریف پروژه فایل start up رو از قسمت device انتخاب می کنیم اونو اضافه میکنه به فایل مون و اون فایلstm32f10x.h که من اضافه می کنم زیر شاخه main نمیشه
سلام سهند
برای اینکار باید فایل stm32f10x.h رو ذخیره کنید. میتونید گزینه save as رو از منوی file بزنید تا به عنوان یک فایل جدید بتونید در محل پروژه اون رو ذخیره کنید. بعد از این کار میتونید بخش مورد نظر رو از حالت کامنت خارج کنید. بخش دوم سوال رو هم متوجه نشدم، اگر عکس ارسال بشه شاید بتونم کمکی کنم.
سلام واقعا حرف نداره و اگه میشه ادامشم به صورت رجیستری بزاری : ممنون میشم
سلام دوست عزیز. این مجموعه متاسفانه متوقف شد. در سایت مجموعههای دیگری برای STM32 نیز موجود است، لطفا آنها را دنبال کنید.
عالی دست مریزاد
خواهش میکنم دوست عزیز
سلام
سوالی که سالهاست ذهنم مشغول کرده
اصلا نیازی هست برای stm32 رجیستر ها رو یادبگیریم و رجیستری کار کنیم ؟
با توجه به حجم بالایی که دارن همیشه نیاز به مرور دارن
اصلا چه توجیهی وجود داره؟
همیشه نه نیازی نیست ولی باید اینو بگم که یادگرفتن رجیسترها خالی از لطف نیست و خیلی از مواقع میتونه کمک کننده باشه مخصوصا وقتی مشغول عیب یابی سیستم باشید.
واقعا خوب بود دستتون درد نکنه
عالی دستتون درد نکنه خیلی خوب بود
ممنون از توضیح های ساده و روان شما .امیدوارم همیشه موفق باشید
سلام من وقتی میخوام با کیل پروژه درست کنم میگه باید کیوب رو باز کنی چیکار کنم اینو نخواد همه ی پک ها هم آپدیت هستند میکروی من stm32f030k6t6 هست
سلام دوست عزیز متوجه منظورتون نشدم
اگه میشه عکسی چیزی بذارید
ولی این کد به نظر می رسه اشتباه باشه من چک کردم اصلا پین رو صفر نمی کنه
GPIOA->BSRR = (1<BSRR = (1<<16);
Delay();
بعد اینکه شما دارید A.0 رو یک می کنید درست ولی برای صفر کردن چرا 16بار یک روشیفت می دید ؟؟ من تو سیمولاتور هم چک کردم جواب نداد
اگر دقت کنید رجیستر BSRR که مخفف bit set reset register هست، هم کار ست کردن انجام میدهد و هم صفر کردن.
بهتر هست با توجه به شکل موجود در مطلب جواب من رو بخونید.
شما 2 سطر 16 تایی در نظر بگیرید. از 0 تا 15 در سطر پایین و در سطر بالا از 16 تا 31
برای یک کردن یک پین باید از سطر پایین بیت متناظر 1 شود و برای ریست کردن باید از سطر بالا بیت مورد نظر 1 شود.
همونطور که گفتم سطر بالا از 15 تا 31 هست شماره هاش، برای همین اگر پین 1 قراره ست بشه 1 شیفت داریم ولی همون رو بخوایم صفر کنیم باید از سطر بالاش استفاده کنیم و 16 بار شیف بدیم.
فکر میکنم در مطلب ارائه شده به اشتباه 16 نوشته شده در حالی که باید 15 باشد.
مثال برای ست و ریست کردن پایه A.1 :
reset : 0000 0000 0000 0010
set : 0000 0000 0000 0010
سلام ممنون بابت اشتراک دانشتون . یه سوال شما می فرمایید ما در CRL چهار بیت در اختیار داریم ولی چرا با F اند می کنید منظورم اینه که چرا با 7 اند نمی کنید ؟؟؟
ببیند با Fاند نمیکنیم اگر دقت کنید اند نقیض می کنیم – خوب این خیلی فرق میکنه با اند خالی ؛
از اونجایی که چهار بیت داریم 1111b معادل میشه با 0xF نه 0x7 به همین سادگی
خیلی ممنون .میشه درمورد محاسبه زمان دیلی هم یع توصیحی بدین ؟و کلاک میکرو رو روی جه مقداری تنظیم کرده بودین؟
سلام مهندس کلاک میکرو به صورت دیفالت قرار داره و از 8مگ داخلی و ضرب در 9 از طریق PLLاستفاده میکنه که فعلا یکم زوده درمورش صحبت کردن
خیالتون به صورت جدی و مجدانه پیگیرم تا بتونم تمام مطالب رو در بازه زمانی مناسب پوشش بدم و باهم یاد بگیریم
درمورد delay هم خیلی سادست شما بیا 1 رو تقسیم بر فرکانس کلت بکن ( 72000000) که عدد بدست امده به نوعی سرعت (به نوعی) میکروتونه که اگه با یه محاسبه ساده میتونید مشخص کنید که چه مقداری ایجاد کنید
به کد دیلی من با این نگاه یه توجه کنید و بقیه کد هارو درنظر نگیرید متوجه میشید ان شاالله
سلام
آموزش ها عالی … خدا قوت
فقط کیفیت تصاویر محیط Keil کمی تار هست … اگر کمی واضح تر بشه عالیه .
ممنونم.
سلام امیر نازنین. سپاس از نظر مثبت و همچنین انتقاد شما. در قسمتهای بعدی این مشکل رفع خواهد شد و تصاویر با وضوح بهتری آپلود خواهند شد.
سلام مهندس جان بله حق با شماست کیفیت مانیتورم یکمی بالاست و عکس های که اسکرین گرفتم برای انتقال به سایت و آپلود کردن دچار مشکل شد
ان شاالله در آموزش های بعدی تلاش میکنم این مشکل رو برطرف کنم
ممنونم که پیگیر هرچه بهتر شدن کیفیت مطالب آموزشی هستید
تشکر فراوان
int main(void
main اینت برمی گردونه
بیصبرانه منتظر ادامه ایم
بیشتر ترجیح میدادم از یک ادیتور رایگان مثل VScode (یا EmBitz یا emIDE به روزتر بهتر) استفاده بشه و همچنین از کامپایلر GCC
خواهش میکنیم دوست عزیز. بله خروجی هرتابعی در زبان C از جنسی است که در همان ابتدا قبل از اسم تابع تعریف شده است. به عنوان یک پیشنهاد، محصول جدید شرکت ST به نام STM32CubeIDE که یک IDE رایگان میباشد را نیز در نظر بگیرید. کامپایلر این IDE نیز GCC میباشد.
برای اطلاعات بیشتر و همچنین دانلود این نرمافزار به دو آدرس زیر مراجعه کنید:
https://sisoog.com/2019/05/%d8%b3%d9%88%d8%b1%d9%be%d8%b1%d8%a7%db%8c%d8%b2-%d8%b4%d8%b1%da%a9%d8%aa-st-%d9%86%d8%b1%d9%85%e2%80%8c%d8%a7%d9%81%d8%b2%d8%a7%d8%b1-stm32cubeide/
https://sisoog.com/2019/08/%d8%af%d8%a7%d9%86%d9%84%d9%88%d8%af-%d9%86%d8%b1%d9%85-%d8%a7%d9%81%d8%b2%d8%a7%d8%b1-stm32cubeide/
خوشحالم از اینکه خوشتون اومد
مهندسIDEهای مجانی در جایگاه خود عالی هستند ولی قدرت کیل درجای خود کم نظیره
صرفا این مطالب برای آموزش هستش
بعد یادگیری اگر مایل باشید میتوانید به هر Ide دیگری که خودتون راحتید سویچ کنید
درضمن شرکت ارم کیل رو خریده پس همچنان در رده بهترین ها میمونه حالا حالاها
از نظر شرعی مراجعی که من از دفترشون پرسیدم گفتند مشکلی نداره چون برای غیر مسلمان هستند (صرفا جهت پیگیری شخصی )
اگر خیلی مهمه براتون لطفا با مراجع دینی خودتون چک کنید
سلام.
بسیار عالی و آموزنده بود.
بی صبرانه منتظر آموزش بقیه قسمت ها هستیم.
خیلی ممنون از زحماتتون.
سلام مرتضی عزیز. سپاس از نظر مثبتتون و خوشحالیم که این آموزش برای شما مفید بوده است.
سلام مهندس خوشحالم که خوشتون اومد