سلام دوستان! در قسمت قبل، تنظیمات GPIO را برای میکروکنترلر STM32 در محیط نرمافزار CubeMX انجام دادیم. در این قسمت از آموزش قصد داریم تا این تنظیمات را به محیط نرمافزار Keil منتقل کنیم و برنامهنویسی برای میکروکنترلر STM32 را در این محیط آغاز کنیم. پس با سیسوگ همراه باشید.
باز کردن پروژه در نرمافزار Keil
پروژه ذخیرهشدهی خود را باز میکنیم و از منو project گزینه setting را انتخاب میکنیم تا صفحهای مطابق عکس زیر باز شود:
همانطور که در عکس بالا مشاهده میکنید، باید نام پروژه و محل ذخیره آن و همچنین نام کامپایلر موردنظرمان (keil) را انتخاب کنیم و سپس دکمه OK را بزنیم و بعدازاین عمل از همان منو Project گزینه generate code را بزنیم تا کدهای مربوط میکروکنترلر تولید شود و سپس دیالوگ مشابه عکس دوم برای ما ظاهر شود:
حالا باید دکمه open project را بزنیم تا برنامه ما در محیط نرمافزار Keil مطابق عکس زیر باز شود:
همین ابتدای کار یک نکته خیلی مهم را اعلام میکنیم:
در ابتدا دکمه F7 یا دکمه Build را میزنیم تا برنامه یکبار در محیط نرمافزار Keil کامپایل شود. پس از اتمام کامپایل برنامه، اگر به سمت چپ برنامه Keil توجه کنید، در کادر Project و در شاخه Drivers میتوانید کتابخانههای HAL را که برای راهاندازی ادوات مختلف این میکروکنترلر قرار دادهشدهاند، مشاهده کنید:
قرار است توابع کتابخانههای stm32f1xx_hal_gpio.c و stm32f1xx_hal.c را در نرمافزار Keil موردبررسی قرار دهیم و از آنها استفاده کنیم. همانطور که در عکس زیر مشاهده میکنید اگر در پایین همین کادر روی تب Functions کلیک کنید میتوانید توابع بکار رفته در هر فایل را ببینید.
توابع موجود در کتابخانه HAL میکروکنترلر STM32 :
با توضیح کتابخانه stm32f1xx_hal_gpio.c آغاز میکنیم:
1 | void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin) |
این تابع همانطور که از نامش برمیآید برای برگرداندن تنظیمات یک پین مشخص از یک پورت مشخص به حالت پیشفرض است.
در کتابخانه stm32f1xx_it.c تابع زیر راداریم که در زمان رخ دادن وقفه خارجی به داخل آن میرویم.
1 | void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin) |
منظور از آرگومان GPIO_Pin پین از پورت موردنظر است که اینتراپت خارجی روی آن فعالشده و از داخل همین تابع هم هست که ابتدا وقفه اینتراپت پاک میشود و سپس تابع HAL_GPIO_EXTI_Callback فراخوانی میشود بهعنوانمثال بهعکسهای زیر توجه کنید:
1 | __weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) |
این تابع هم همان روتین وقفه خارجی است و همانطور که پیشازاین گفته شد از داخل تابع HAL_GPIO_EXTI_IRQHandler فراخوانی میشود که با توجه به اینکه کلمه “weak __” در ابتدا آن بکار رفته به این معنی است که شما میتوانید همین تابع را به فایل main خودتان انتقال دهید و در آنجا کدهای خودتان را داخل آن جاسازی کنید. توضیحات بیشتر در مورد وقفه خارجی را موکول میکنیم به بخش آموزش کار با وقفه خارجی که در قسمتهای بعدی بیان خواهم کرد فقط توجه داشته باشید که همین قضیه کلمه “weak __” را در مورد وقفههای ادوات دیگر میکروکنترلر مثل رابطهای سریال و تایمرها و غیره نیز داریم.
1 | HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) |
این تابع هم برای پیکرهبندی یک پین یا پینهای خاص از یک پورت مشخص کاربرد دارد پیکرهبندی اعم از ورودی و یا خروجی بودن پورت، پوش پول یا کلکتورباز بودن آن، حداکثر سرعت پورت، اینکه ورودی آنالوگ یا غیره باشد است. البته توجه داشته باشد کدهای مربوط به پیکرهبندی پورتها در تابع MX_GPIO_Init داخل main برنامه تولید میشود.
1 | HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) |
توسط این تابع میتوانیم تنظیمات پیکرهبندی را روی پین یا پینهای موردنظر از یک پورت قفل کنیم که دیگر با تغییر مقادیر رجیسترهای پیکرهبندی تغییری حاصل نشود.
1 | HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) |
توسط این تابع میتوانیم اطلاعات ورودی یک پین از پورت مشخص را در حالتی که بهصورت ورودی پیکرهبندی شده به شکل صفر و یا یک بخوانیم.
1 | HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) |
این تابع همانطور که از نامش برمیآید وظیفه بالعکس کردن وضعیت یک یا چند پین از پورت مشخص که بهصورت خروجی پیکرهبندی شدهاند را بر عهده دارد.
1 | HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState) |
این تابع وظیفه تغییر وضعیت یک یا چند پین از پورت مشخص که بهصورت خروجی پیکرهبندی شدهاند به صفر یا یک را بر عهده دارد.
تا اینجا با توابع کتابخانه gpio آشنایی مختصری پیدا کردیم ولیکن قرار بر این شد که برای برنامهنویسی اصولی تا آنجا که میتوانیم کمتر از توابع کتابخانه hal استفاده کنیم از اینرو در ادامه به بررسی رجیسترهای رابط gpio میپردازیم.
رجیسترهای رابط GPIO میکروکنترلر STM32:
رجیسترهای GPIOx->CRH و GPIOx->CRL
دو رجیستر 32 بیتی خواندنی و نوشتنی به همین نامها برای هر پورت میکروکنترلر در نظر گرفتهشده، که به دلیل اینکه هر پورت در میکروکنترلر STM32 حداکثر 16 بیتی است برای هر پین از پورت، 4 بیت تنظیمات خواهیم داشت که توسط رجیسترهای GPIOx->CRH و GPIOx->CRL اعمال میگردد. در اسامی رجیسترها منظور از x همان نام پورت خاص است که از A شروع میشود تا B و C و … برای فهم بیشتر بهعکسهای زیر در مورد مشخصات این رجیسترها در رفرنس منوال توجه نمایید:
رجیستر GPIOx->IDR
اینیک رجیستر خواندنی 32 بیتی هست که 16 بیت اول آن برای ما قابلاستفاده است و از طریق این 16 بیت میتوانیم مقدار لاجیک صفر و یک روی پینهای پورت موردنظرمان را بخوانیم. توجه داشته باشید اگر پورت موردنظر بجای ورودی بهصورت خروجی پیکرهبندی شده باشد در هرلحظه مقدار این رجیستر مساوی مقدار رجیستر GPIOx->ODR خواهد بود. برای فهم بیشتر بهعکس زیر در مورد مشخصات این رجیستر در رفرنس منوال میکروکنترلر توجه نمایید:
رجیستر GPIOx->ODR
اینیک رجیستر خواندنی و نوشتنی 32 بیتی هست که 16 بیت اول آن برای ما قابلاستفاده است و از طریق این 16 بیت میتوانیم مقدار لاجیک صفر و یک روی پینهای پورت موردنظرمان را تنظیم کنیم. دقیقاً مشابه رجیستر PORT در میکرو کنترولر AVR که هرکدام از بیتها را که صفر کنیم پین متناظر آن صفر منطقی میشود و هرکدام از بیتها را که یک نماییم پین متناظر آن یک منطقی خواهد شد. برای فهم بیشتر بهعکس زیر در مورد مشخصات این رجیستر در رفرنس منوال توجه نمایید:
رجیستر GPIOx->BSRR
اینیک رجیستر خواندنی و نوشتنی 32 بیتی هست که هر 32 بیت آن برای ما قابلاستفاده است و از طریق 16 بیت اول میتوانیم پین یا پینهای مشخص از پورتمان را یک منطقی و از طریق 16 بیت دوم میتوانیم پین یا پینهای مشخص از پورتمان را صفر منطقی کنیم. برای فهم بیشتر مسئله بهعکس زیر توجه کنید:
کادر قرمزرنگ برای یک کردن پین موردنظر استفاده میشود و کادر بنفشرنگ برای صفر کردن پین موردنظر استفاده میشود. نمونه مثال عملی برای کاربرد این رجیستر را میتوانیم در متن تابع HAL_GPIO_WritePin هم ببینم برای فهم بیشتر بهعکس زیر توجه کنید:
کاربرد این رجیستر خیلی ساده و جالب است در عکس بالا اگر توجه کنید از همان 16 بیت اول برای یک کردن استفاده کرده ولی برای صفر کردن با 16 بیت شیفت دادن به سمت چپ و بیتهای پرارزشتر از 16 بیت دوم استفاده میکنیم. توجه داشته باشید در اینجا منظور از GPIO_Pin که پین موردنظر را مشخص میکند عدد 0 و 1 و 2 و … تا 15 نیست بلکه همان 1 و 2 و 4 و 8 و … تا 32768 است در شکل زیر قضیه قابلفهم میشود که چطور ماکرو پینهای مختلف نوشتهشدهاند:
رجیستر GPIOx->BRR
این یک رجیستر خواندنی و نوشتنی 32 بیتی هست که 16 بیت اول آن برای ما قابلاستفاده است و از طریق این 16 بیت میتوانیم مقدار لاجیک صفر و یک روی پینهای پورت موردنظرمان را صفر کنیم. ما اگر هرکدام از بیتها را یک کنیم پین متناظر آن صفر منطقی خواهد شد. برای فهم بیشتر بهعکس زیر در مورد مشخصات این رجیستر در رفرنس منوال توجه نمایید:
رجیستر GPIOx->LCKR
این یک رجیستر خواندنی و نوشتنی 32 بیتی است که 17 بیت اول آن برای ما قابل استفاده است و از طریق 16 بیت اول با یک کردن هر کدام از بیت های مورد نظر، میتوانیم پیکره بندی پین های متناظر رجیستر شده را قفل کنیم. بعد از این عمل تا زمانی که بیت مورد نظر با آن پین را در رجیستر GPIOx->LCKR صفر نکنیم، نمیتوانیم پیکره بندی آن پین ها را عوض کنیم. بیت هفدهم برای این است که محتویات 16 بیت اول تا زمان ریست شدن میکروکنترلر STM32 قفل شود. برای فهم بیشتر به عکسهای زیر در مورد مشخصات این رجیستر در رفرنس منوال توجه نمائید:
در قسمت بعدی آموزش میکروکنترلر STM32 قصد داریم به صورت عملی با رجیسترهای STM32 کار کنیم. پس سیسوگ را همراهی کنید.
درود اگه هگز یا الف کامپایل شده توسط gcc رو توسط کیل روی میکرو بریزیم مشکلی داره؟ البته میکرویی که کار میکنم زیاد استاندارد نیست میکروی چینی hk32f030mf4p6 البته کتابخونه داره pack و svd و کیل میشناسه آدرسها هم درسته پروگرمر stlink هم بهش متصل میشه erase هم میکنه حتی دانلود هم میکنه اما وریفای نه. ارور میده. و میکرو روشن نمیشه. دیباگ هم میشه کرد اما ظاهرا فقط ادای کار کردن در میاره و حافظه میکرو به نظر خالیه. هیچ عکسالعملی نشون نمیده. pyocd هم خواستم تست کنم اما stlink رو روی ویندوز نشناخت. چون این حرکت زیاد اصولی نیست گزینه های زیادی برای پروگرم کردن یه میکروی کلون با پروگرمر st نیست، اما دیدم کیل تا یه مرحله ای رو انجام میده گفتم اگه راهی ممکنه که امتحان نکرده باشم بد نیست مطمئن بشم.
سلام. متشکر از سایت خوبتون مختصر و مفید بود واقعا
سلام. میخواستم بدونم اطلاعات مربوط به رجیسترهای یه میکرو از این سری (مثلا STM32L052R8) رو از کجا میتونم ببینم؟ دیتاشیتش رو دارم ولی بر خلاف AVR و PIC خبری از رجیسترها نیست. اگه میشه زودتر پاسخ بدین یه مقدار عجله دارم. ممنون.
آها شما باید فایل رفرنس منوال این میکروکنترلر رو دانلود کنید از خود سایت st میشه این کار رو انجام داد.
به قول شاعر «آمدی جانم به قربانت ولی حالا چرا؟»
جواب شما حکم نوشدارو بعد از «درمان» سهراب رو داشت. چون اون موردی که براش عجله داشتم خودش رفع شد! 🙂
به هر حال، ممنون از جوابتون. این مورد رو پیدا کردم که به سری STM32L0x1 مربوط میشه:
https://www.st.com/resource/en/reference_manual/dm00108282-ultra-low-power-stm32l0x1-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf
ولی برای STM32L052 یا در کل STM32L0x2 چیزی پیدا نکردم. همون pdf بالا برای L052 جواب میده یا باید دنبال چیز دیگهای بگردم؟
یه سوال دیگه: برد خاصی بر پایه STM32L052 وجود داره؟ منظورم مثلا برد آموزشی یا development board و اینجور چیزاست. یه نفر یه چیزایی در مورد چنین بردی بهم گفته بود.
سلام
باید بگم خوشحالم که مشکلتون حل شده :)، برای دیر شدن پاسخ پوزش میخوام – این روزها درگیری ها خیلی زیاد شده
+ الان من نگاه کردم شرکت st این مدل میکرویی که میگید رو تولید نکرده !!! تو نرم افزار stmcube چک کردم سری ۵۱ رو داره ولی سری ۵۲ چیزی نیست :/
فکر کنم یه جای رو اشتباه میکنید
من الان توی STM32CubeMX دارم ۸ تا میکرو از سری STM32L052 میبینم! مثلا STM32L052T8. از قسمت Line گزینهی STM32L0x2 رو تیک بزنید.
فایلهای مربوطه رو توی Cube پیدا کردم. بعد انتخاب یکی از میکروهای این سری (همون 52T8) رفتم قسمت Docs & Resources این دو تا لینک به دردم خورد:
https://www.st.com/resource/en/datasheet/stm32l052t8.pdf
این همون دیتاشیته که قبلا دیدم و رجیسترها رو نداشت.
https://www.st.com/resource/en/reference_manual/DM00108281-.pdf
این یکی reference manual برای سری L0x2 هست.
در مورد اون برد که گفتم چی؟ توی Cube دو تا برد بر پایه L053 دیدم ولی L052 نه!
اها – ببخشید اشتباه از من بود به جای l میزدم f ، اینقدری که با سری جنرال کار کردم ،
البته هفته پیش سری ۵۱ رو داشتم روش کار میکردم هر کاری میکردم پروگرام نمیشد نگو اونجام اشتباهی stm32f051 رو انتخاب کرده بودم :دی کلی وقت از دست دادم
سری های l توان مصرفیش خیلی مناسبه
در مورد برد هم برای من همون یک سری ۵۳ میآد ولی فکر میکنم اینا همخوان باشن – مثلا الان فرق سری ۵۱ و ۵۲ چیه ؟ – برنماه ۵۱ احتمال خیلی زیاد روی سری ۵۲ جواب میده
سلام
در برنامه keil با تعریف کردن تابع delay هنگام debug کردن وقتی دیباگر به خط delay میرسه با ارور undefined line number مواجه میشم تو اموزشی که دارم کد رو اجرا میکنه ولی برد وصله و من برد رو ندارم و در محیط سیمولیشن اجرا میکنم.
ایا امکان داره که تابع delay به سخت افزار نیاز داشته باشه؟
این در صورتی که وقتی تابع delay رو کامنت یا حذف میکنم، برنامه راحت debug میشه و اون ارور رو نمیده.
اونطور که من متوجه شدم شما برنامه رو دیباگ نمی کنید – سیمولیت میکنید- یعنی از سخت افزار استفاده نمیکنید –
توی سیمولیت کردن بسته به شکل تاخیری که ایجاد شده (با حلقه بوده یا تایمر) میتونه جواب های غیر دقیقی دریافت کنید و اینو دقیقا نمیدونم راه حلی داره یا نه باید توی سایت keil ببینید.
با سلام
ببخشید در شبیه سازی کامپایلر keil قسمت لاجیک آنالایزر هر سیگنال و متغیری را که اضافه میکنم خطا میده و میگه سیگنال شناخته نمی شود.
می تونید راهنماییم کنید
با تشکر
من کیل کار نمیکنم ولی امیدارم لینک زیر بهتون کمک کنه
http://www.keil.com/support/man/docs/uv4/uv4_db_dbg_logicanalyzer.htm
چطوری میتونیم از تابع write pin برای مقدار دهی همزمان چند پایه استفاده کنیم؟
مثلا میخام عدد ۳ روی پایه های pa0 تا pa1 قرار بگیره
چجوری با write pin این کارو بکنیم؟!
تنها وقتی میتونید از این روش استفاده کنید که پین های مروبطه روی یک gpio باشه.
با سادگی or کردن بایه هایی که مد نظر دارید.
سلام و خسته نباشید . مهندس با stm 32 میشه مستقیم با keil کار کرد و نیازی به cube mx نباشه؟
بله میشه صد در صد چنین کاری انجام داد.
باید پروژه رو از صفر خودتون پیاده سازی کنید.
من همه مراحل رو انجام دیدم ولی
کد ها generate نمیشه
البته jtag ها قرمز میشود که شاید به منزله ارور هستش نمیدونم
که البته این قسمت در نرم افزار من ورژن 4.7.1 کمی با مال شما فرق داره
شاید کتابخونه های مورد نیاز رو نتونسته دانلود کنه – متاسفانه st ایران رو تحریم کرده و این مشکل از این جهته که نرم افزارش کار نمیکنه
با ف… وصل بشید و آپدیت کنید.
خدا خیرتون بده
همین
متشکریم 🙂
بسیار عالی
🙂
با سلام خدمت دوستان
من بعد از generate کد در cube mx و اجرای برنامه keil صفحه مربوط به pack installer ران می شه وقتی می بندمش ارور زیر ظاهر می شه
one or more device familly pack device are not peresent
بعدش چند تا ارور دیگه می اد
کسی می دونه مشکل از کجاست؟؟؟؟
سلام دوست عزیز ،
اگر از کیل 5 به بعد استفاده می کنید احتمالا با این خطا مواجه میشید ؛ دلیلش هم اینه که توی این نسخه های شرکت ARM بسته های نصبی برای هر پکیج قرار داده به این صورت حجم فایل نصبی کم میشه و بهینه تر خواهد بود ؛ برای رفع این خطا تنها لازمه پکیج مورد نیاز رو نصب کنید – روی پک منیجر که باز میشه پکیج هایی رو که لازم دارید مثل STM32Fxxx رو نصب کنید CmSIS و…