سلام دوستان! در قسمت قبل، تنظیمات GPIO را برای میکروکنترلر STM32 در محیط نرمافزار CubeMX انجام دادیم. در این قسمتاز آموزش قصدداریم تا این تنظیمات را به محیط نرمافزاری Keil منتقل کنیم و برنامهنویسی برای میکروکنترلر STM32 را در این محیط را آغاز کنیم. پس با ما همراه باشید.
باز کردن پروژه در نرمافزار Keil
پروژه ذخیرهشدهی خود را باز میکنیم و از منو project گزینه setting را انتخاب میکنیم تا صفحهای مطابق عکسزیر باز شود:
همانطورکه در عکسبالا مشاهده میکنید، باید نام پروژه و محل ذخیره آن و همچنین نام کامپایلر موردنظرمان (keil) را انتخاب کنیم و سپس دکمه OK را بزنیم و بعداز این عمل از همان منو Project گزینه generate code را بزنیم تا کدهای مربوط میکروکنترلر تولیدشود و سپس دیالوگ مشابه عکسدوم برای ما ظاهر شود:
حالا باید دکمه open project را بزنیم تا برنامه ما در محیط نرمافزار keil مطابق عکسزیر باز شود:
همین ابتدا کار یک نکته خیلی مهم را اعلام میکنیم:
توجه داشته باشید موقع اضافهکردن کد حتما کدهای خودتان را بین USER CODE BEGIN و USER CODE ENDهای مشخصشده در برنامه قراردهید. درغیر اینصورت اگر دوباره با CubeMX تغییراتی اعمال و سپس دوباره خروجی بگیرید خودبهخود کدهایی که خارج از این کادرها قرار دادهاید، پاک میشوند!!!
در ابتدا دکمه F7 یا دکمه Build را میزنیم تا برنامه یکبار در محیط Keil کامپایل شود. پساز اتمام کامپایل برنامه، اگر بهسمت چپ برنامه Keil توجهکنید، در کادر Project و در شاخه Drivers میتوانید کتابخانههای HAL را که برای راهاندازی ادوات مختلف این میکروکنترلر قرارداده شدهاند، مشاهدهکنید:
قرار است توابع کتابخانههای stm32f1xx_hal_gpio.c و stm32f1xx_hal.c را مورد بررسی قراردهیم و از آنها استفادهکنیم. همانطورکه در عکسزیر مشاهده میکنید اگر در پایین همین کادر روی تب Functions کلیککنید میتوانید توابع بکار رفته در هر فایل را ببینید.
توابع موجود در کتابخانه HAL میکروکنترلر STM32 :
با توضیح کتابخانه stm32f1xx_hal_gpio.c آغاز میکنیم:
void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin)
این تابع همانطورکه از نامش برمیآید برای برگرداندن تنظیمات یک پین مشخصاز یک پورت مشخص بهحالت پیشفرض است. در کتابخانه stm32f1xx_it.c تابع زیر را داریم که درزمان رخدادن وقفه خارجی به داخل آن میرویم.
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
منظوراز آرگومان GPIO_Pin پین از پورت موردنظر است که اینتراپت خارجی روی آن فعالشده و از داخل همین تابع هم هست که ابتدا وقفه اینتراپت پاک میشود و سپس تابع HAL_GPIO_EXTI_Callback فراخوانی میشود بهعنوان مثال به عکسهای زیر توجهکنید:
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
این تابع هم همان روتین وقفه خارجی است و همانطورکه پیشاز این گفتهشد از داخل تابع HAL_GPIO_EXTI_IRQHandler فراخوانی میشود که باتوجهبه اینکه کلمه “weak __” در ابتدا آن بکاررفته بهاین معنیاست که شما میتوانید همین تابع را به فایل main خودتان انتقالدهید و در آنجا کدهای خودتان را داخل آن جاسازی کنید. توضیحاتبیشتر درمورد وقفه خارجی را موکول میکنیم به بخش آموزش کار با وقفه خارجی که در قسمتهای٬بعدی بیان خواهیمکرد فقط توجهداشتهباشید که همین قضیه کلمه “weak __” را درمورد وقفههای ادوات دیگر میکروکنترلر مثل رابطهای سریال و تایمرها و غیره نیز داریم.
HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
این تابع هم برای پیکرهبندی یک پین یا پین های خاص از یک پورت مشخص کاربرد دارد پیکرهبندی اعم از ورودی و یا خروجی بودن پورت، پوشپول یا کلکتورباز بودن آن، حداکثر سرعت پورت،اینکه ورودی آنالوگ یا غیره باشد، است. البته توجهداشتهباشد کدهای مربوطبه پیکرهبندی پورتها در تابع MX_GPIO_Init داخل main برنامه تولید میشود.
HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
توسط این تابع میتوانیم تنظیمات پیکرهبندی را روی پین یا پینهای موردنظر از یک پورت قفل کنیم که دیگر با تغییر مقادیر رجیسترهای پیکرهبندی تغییری حاصل نشود.
HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
توسط این تابع میتوانیم اطلاعات ورودی یک پین از پورت مشخص را درحالتیکه بهصورت ورودی پیکرهبندی شده به شکل صفر و یک بخوانیم.
HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
این تابع همانطورکه از نامش برمی آید وظیفه بالعکسکردن وضعیت یک یا چند پین از پورت مشخص که بصورت خروجی پیکرهبندی شدهاند را برعهده دارد.
HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
این تابع وظیفه تغییر وضعیت یک یا چند پین از پورت مشخص که بصورت خروجی پیکرهبندی شدهاند به صفر یا یک را برعهده دارد. تااینجا با توابع کتابخانه gpio آشنایی مختصری پیداکردیم ولیکن قرار براینشد که برای برنامنویسی اصولی تاآنجاکه میتوایم کمتر از توابع کتابخانه hal استفاده کنیم از اینرو در ادامه به بررسی رجیسترهای رابط gpio میپردازیم.
رجیسترهای رابط GPIO میکروکنترلر STM32:
-
رجیسترهای GPIOx->CRH و GPIOx->CRL
دو رجیستر ۳۲بیتی خواندنی و نوشتنی بههمین نامها برای هر پورت میکروکنترلر درنظر گرفتهشده، که بهدلیلاینکه هر پورت در میکروکنترلر STM32 حداکثر ۱۶بیتی است برای هر پین از پورت،۴بیت تنظیمات خواهیمداشت که توسط رجیسترهای GPIOx->CRH و GPIOx->CRL اعمال میگردد. در اسامی رجیسترها منظوراز x همان نام پورت خاص است که از A شروع میشود تا B و C و … برای فهم بیشتر به عکسهای زیر درمورد مشخصات این رجیسترها در رفرنس منوال توجه نمائید:
-
رجیستر GPIOx->IDR
این یک رجیستر خواندنی ۳۲بیتی هست که ۱۶بیت اول آن برایما قابلاستفادهاست و ازطریق این ۱۶بیت میتوانیم مقدار لاجیک صفر و یک روی پینهای پورت موردنظرمان را بخوانیم. توجهداشتهباشید اگر پورت موردنظر بجای ورودی بصورت خروجی پیکرهبندی شدهباشد در هرلحظه مقدار این رجیستر مساوی مقدار رجیستر GPIOx->ODR خواهدبود. برای فهم بیشتر به عکسزیر درمورد مشخصات این رجیستر در رفرنس منوال میکروکنترلر توجه نمائید:
-
رجیستر GPIOx->ODR
این یک رجیستر خواندنی و نوشتنی ۳۲بیتی هست که۱۶بیت اول آن برایما قابلاستفادهاست و ازطریق این ۱۶بیت میتوانیم مقدار لاجیک صفر و یک روی پینهای پورت موردنظرمان را تنظیمکنیم. دقیقاً مشابه رجیستر PORT در میکرو کنترولر AVR که هرکدام از بیتها را که صفرکنیم پین متناظر آن صفر منطقی میشود و هرکدام از بیتها را که یک نمائیم پین متناظر آن یک منطقی خواهد شد. برای فهم بیشتر به عکسزیر درمورد مشخصات این رجیستر در رفرنس منوال توجه نمائید:
-
رجیستر GPIOx->BSRR
این یک رجیستر خواندنی و نوشتنی 32بیتی هست که هر 32بیت آن برایما قابلاستفادهاست و از طریق 16بیت اول میتوانیم پین یا پینهای مشخص از پورتمان را یک منطقی و ازطریق 16بیت دوم میتوانیم پین یا پینهای مشخصاز پورتمان را صفر منطقی کنیم. برای فهم بیشتر مسئله به عکسزیر توجهکنید:
کادر قرمز رنگ برای یک کردن پین موردنظر استفاده میشود و کادر بنفش رنگ برای صفرکردن پین موردنظر استفاده میشود. نمونهمثال عملی برای کاربرد این رجیستر را میتوانیم در متن تابع HAL_GPIO_WritePin هم ببنیم برای فهمبیشتر به عکسزیر توجهکنید:
کاربرد این رجیستر خیلیساده و جالب است در عکسبالا اگر توجهکنید از همان ۱۶بیت اول برای یک کردن استفادهکرده ولی برای صفر کردن با 16بیت شیفتدادن به سمت چپ و بیتهای پر ارزشتر از ۱۶بیت دوم استفاده میکنیم .توجهداشتهباشید در اینجا منظور از GPIO_Pin که پین موردنظر را مشخص میکند عدد ۰ و ۱ و ۲و … تا ۱۵ نیست بلکه همان ۱ و ۲ و ۴ و ۸ و … تا ۳۲۷۶۸ است در شکلزیر قضیه قابلفهم میشود که چطور ماکرو پینهای مختلف نوشته شدهاند:
-
رجیستر GPIOx->BRR
این یک رجیستر خواندنی و نوشتنی ۳۲بیتی هست که ۱۶بیت اول آن برای ما قابلاستفادهاست و ازطریق این ۱۶بیت میتوانیم مقدار لاجیک صفر و یک روی پینهای پورت موردنظرمان را صفر کنیم. ما اگر هرکدام از بیتها را که یک نمائیم پین متناظر آن صفر منطقی خواهد شد. برای فهمبیشتر به عکسزیر درمورد مشخصات این رجیستر در رفرنس منوال توجه نمائید:
-
رجیستر GPIOx->LCKR
این یک رجیستر خواندنی و نوشتنی ۳۲بیتی است که ۱۷بیت اول آن برایما قابلاستفاده است و ازطریق ۱۶بیت اول با یک کردن هرکداماز بیتهای موردنظر، میتوانیم پیکرهبندی پینهای متناظر رجیسترشده را قفل کنیم. بعداز این عمل تازمانیکه بیت موردنظر با آن پین را در رجیستر GPIOx->LCKR صفر نکنیم، نمیتوانیم پیکرهبندی آن پینها را عوضکنیم. بیت هفدهم برای این است که محتویات ۱۶بیت اول تا زمان ریستشدن میکروکنترلر STM32 قفل شود. برای فهمبیشتر به عکسهایزیر درمورد مشخصات این رجیستر در رفرنس منوال توجه نمائید:
درقسمت بعدی آموزش میکروکنترلر STM32 قصدداریم بهصورت عملی با رجیسترهای STM32 کارکنیم. پس ما را همراهی کنید.
منبع: سیسوگ