پیش از این در پست معرفی انواع میکروکنترلرهای STM32 توضیحات مختصری درباره میکروکنترلرهای STM32 دادهایم. در صورتی که آشنایی کافی با میکروکنترلرهای STM32 را ندارید، ابتدا آموزش های قبل را مطالعه کنید. در این آموزش قصد داریم تا با استفاده از میکروکنترلر STM32F103 دستورات مربوط به GPIO را بررسی کنیم. در ادامه با مرجع تخصصی بردهای امبدد به زبان فارسی، دیجی اسپارک همراه باشید.
نرم افزار های مورد نیاز
برای برنامه نویسی میکروکنترلرهای stm32 نیاز است که ابتدا دو نرم افزار KEIL و STM32CubeMX را نصب کنید.همچنین درایور مورد نیاز برای پروگرامر STLINK V2 را از این لینک دانلود کنید. پیشنهاد میکنم نرم افزار KEIL را از سایت های ایرانی دانلود کنید. تا کرک آن نیز موجود باشد. اما نرم افزار STM32CubeMX بصورت رایگان از سایت شرکت ST قابل دانلود است.
اتصالات برد STM32
اتصالات میکروکنترلرهای stm32 مدار مطابق تصویر به صورت زیر است. پایه PC14 میکروکنترلر به یک سمت کلید، و سمت دیگر کلید به GND برد متصل میشود.
پایه های مربوط به پایه های مربوط به پروگرام میکروکنترلر را طبق نام آن به پراگرامر متصل کنید.
پیکربندی اولیه در نرم افزار STM32CubeMX
ابتدا بایستی داخل نرم افزار STM32CubeMX از منو File گزینه New Project را انتخاب کنید.
سپس در پنجره باز شده در قسمت Part Number Search نام میکروکنترلر مورد نظر خود را انتخاب کنید (برای مثال STM32F103C8). سپس از قسمت MCUs/MPUs List بر روی گزینه مورد نظر دوبار کلیک کنید.
پس از آن پنجره جدیدی باز میشود ک در آن تصوری گرافیکی از میکرو و GPIO های آن مشاهده خواهید کرد. در سمت چپ پنجره باز شده نوار ابزاری موجود است که از این قسمت میتوانید peripheral های میکروکنترلر را فعال و تنظیم نمایید. در این قسمت گزینه A->Z را انتخاب کنید تا تمامی peripheral های میکروکنترلر بصورت یک لیست درآید. در این قسمت بایستی دو بخش را تنظیم نمایید که در تمامی پروژه هایی که با STM32 با استفاده از نرم افزار STM32CubeMX انجام میشود مشترک است. ابتدا گزینه SYS را انتخاب نمایید و گزینه Debug را بر روی Serial Wire تنظیم نمایید. سپس وارد بخش RCC شده و گزینه High Speed Clock (HSE) را بر روی Crystal/Ceramic Resonator تنظیم نمایید. حال مشاهده میکنید که بر روی میکروکنترلر ۴ پایه به رنگ سبز درآمده است.
با توجه به میکروکنترلری که انتخاب میکنید. تعداد مشخصی GPIO در اختیار شما است. که میتوانید این GPIO ها را به صورت ورودی و یا خروجی تعریف کنید. برای تعریف GPIO بصورت ورودی و یا خروجی بایستی بر روی یکی از پایه های میکروکنترلر کلیک کنید تا گزینه های قابل تنظیم GPIO را مشاهده نمایید. سپس با کلیک بر روی GPIO_Output پایه مورد نظر خروجی و با انتخاب GPIO_Input پایه بصورت ورودی تعریف میشود. برای مثال در این آموزش بدلیل این که از برد Bluepill استفاده شده است و Led موجود بر روی برد به پایه ۲ وصل شده است. پایه شماره ۲ (PC13( میکروکنترلر را بعنوان خروجی و پایه شماره ۳ (PC14( را بعنوان ورودی تعریف میکنیم.
بهتر است تا برای هر پایه ای که استفاده میکنید یک Label انتخاب کنید. برای انتخاب Label بایستی بر روی پایه ای که استفاده نموده اید راست کلیک کنید و گزینه Eanter User Label را انتخاب کنید و سپس نام مورد نظر را وارد نمایید و Enter را بزنید. در این آموزش پایه شماره ۲ را با نام LED و پایه شماره ۳ را با نام Button مشخص میکنیم. از نوار ابزار سمت چپ وارد بخش GPIO شده و بر روی قسمتی که با نام Button مشخص شده است کلیک کنید.
در این قسمت میتوانید با استفاده از گزینه GPIO pull-up/pull-down وضعیت پایه را مشخص نمایید. در این آموزش ما وضعیت پایه را بر روی Pull-up تنظیم میکنیم. سپس بر روی قسمت مربوط به LED کلیک کنید. در این قسمت نیز میتوانید تنظیماتی از جمله سحل اولیه، وضعیت خروجی، ماکزیمم سرعت و … را مشخص نمایید. در این آموزش تنها سطح اولیه ولتاژ را بر روی High تنظیم میکنیم. زیرا پایه کاتد Led موحود بر روی برد به میکروکنترلر متصل شده است.
پس از انجام تنظیمات مورد نظر، وارد بخش Clock Configuration شده تا تنظیمات مربوط به فرکانس کاری هر بخش میکروکنترلر را انجام دهیم. در این آموزش قصد دارین تا Clock میکروکنترلر را بر روی ۷۲ مگاهرتز تنظیم کنیم. بنابراین بر روی بخش HCLK کلیک کرده و عدد ۷۲ را وارد میکینم و سپس Enter را میزنیم. نرم افزار بصورت خودکار فرکانس را بر روی ۷۲ مگاهرتز تنظیم میکند.
سپس بایستی وارد بخش Project Manager شده. ابتدا نام و آدرس مناسبی برای پروژه خود انتخاب کنید. و سپس گزینه Toolchain/ IDE را با توجه به کامپایلری که میخواهید استفاده نمایید تنظیم نمایید. در این آموزش ما قصد داریم تا از کامپایلر Keil ورژن ۵ استفاده کنیم. بنابراین این گزینه را بر روی MDK-ARM و Min Version را بر روی V5 تنظیم میکنیم.
وارد بخش Code Generator شده و بخش STM32Cube MCU package and embedded softwaer pack را بروی گزینه Copy only necessary library files تنظیم کنید. تا نرمافزار STM32CubeMX تنها کتابخانه های مورد نیاز بر نامه را به پوشه پروژه اضافه کند. این عمل باعث میشود تا حجم پروژه بسیار کاهش پیدا کند.سپس گزینه GENERATE CODE را از قسمت بالای نرم افزار انتخاب کنید تا پروژه ساخته شود.
مدت کوتاهی صبر کنید و پس از اتمام ساخت پروژه در پنجره باز شده Open Project را انتخاب کنید.
شروع کد نویسی در نرمافزار KEIL
نرم افزار KAIL برای برنامه نویسی میکروکنترلرهای stm32 انتخاب مناسبی است. پس از باز شدن نرم افزار KEIL، پنجره ای درسمت چپ برنامه با نام Project موجود است که فایل های مربوط به پروژه داخل آن موجود است. بر روی علامت مثبت کنار پوشه کلیک کنید. سپس داخل پوشه Application/User دو بار بر روی فایل main.c کلیک کنید تا این فایل باز شود. صفحه را به سمت پایین اسکرول کنید تا دستور while(1) را مشاهده کنید.
برای شروع کد نویسی ابتدا بایستی به این نکته توجه کنید. زمانی که با استفاده نرمافزار STM32CubeMX پروژه ساخته میشود. این نرم افزار داخل کد قسمت های مشخصی را برای کد نویسی مشخص میکند (مطابق تصویر زیر، میتوانید کد را در قسمت هایی بنویسید که با رنگ قرمز مشخص شده است). قسمت های قابل کدنویسی با حرف BEGIN شروع و با حرف END پایان میابند. شما بایستی کد را داخل قسمت های مشخص شده بنویسید تا اگر نیاز به تغیرات داخل نرمافزار STM32CubeMX بود پس از GENERATE دوباره پروژه کد های نوشته شده، حذف نشود. در صورتی که کد ها در جایی غیر از مکان های مشخص شده نوشته شود. بصورت خودکار پس از هر بار GENERATE حذف میشود.
تا به اینجای کار پیکربندی اولیه انجام شد. در ادامه توابع HAL_GPIO را بررسی میکنیم.
توابع HAL_GPIO
توابع مربوط به GPIO بصورت زیر میباشد.
۱٫HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init); ۲٫HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin); ۳٫HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin); ۴٫HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState); ۵٫HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
در ادامه تمامی توابع بصورت تک به تک توضیح داده شده است؛
HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
این تابع مربوط به پیکربندی پایههای میکروکنترلرهای stm32 است. بصورت کلی با این تابع کاری ندارید، زیرا تنظیمات مربوط به این تابع را داخل نرمافزار STM32CubeMX انجام میشود. این تابع دارای ۲ مقدار ورودی است، که عبارتند از:
GPIO_TypeDef *GPIOx: این قسمت برای انتخاب پورت است.
GPIO_InitTypeDef *GPIO_Init: ذر این قسمت بایستی استراکچر مربوط به GPIO را وارد کنید.
/*Configure GPIO pin : LED_Pin */ GPIO_InitStruct.Pin = LED_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);
برای مثال کد بالا برای پیکربندی پایه PC13 که با نام LED تعریف کرده بودیم است. کد زیر در فایل main.c تابع static void MX_GPIO_Init(void) است.
HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);
این تابع برای حذف کردن تنظیمات انجام شده بر روی پایه است. ورودی های این تابع بصورت زیر است؛
GPIO_TypeDef *GPIOx: این قسمت برای انتخاب پورت است.
uint32_t GPIO_Pin: در این قسمت بایستی شماره پایه مورد نظر را انتخاب کنید.
HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
زمانی که پایه بصورت ورودی تعریف شود. با استفاده از این تابع میتوانید. مقدار سطح منطقی پایه را خوانده و شرط قرار دهید. ورودی های این تابع نیز بصورت زیر است؛
GPIO_TypeDef *GPIOx: این قسمت برای انتخاب پورت است.
uint32_t GPIO_Pin: در این قسمت بایستی شماره پایه مورد نظر را انتخاب کنید.
// دستورات زیر بایستی قبل از تابع main نوشته شود. #include <stdbool.h> GPIO_PinState Key_State; bool Key_Last_State; // دستورات زیر بایستی داخل حلقه while(1) نوشته شود. Key_state = HAL_GPIO_ReadPin(Key_GPIO_Port,Key_Pin); if(Key_state == GPIO_PIN_RESET && Key_Last_State == false){ // در این قسمت میتوانید عملیاتی را که میخواهید بعد از فشردن کلید انجام شود را بنویسید. Key_Last_State = true; } else Key_Last_State = false;
برای مثال کد بالا برای خواندن کلید استفاده میشود؛ ابتدا دو متغیر برای وضعیت حال و وضعیت قبلی کلید تعریف شده است. سپس در ابتدا مقدار کلید خوانده میشود. درصورتی که کلید فشرده شده باشد. شرط برقرار شده و عملیات مورد نظر انجام میشود. سپس مقدار متغیری که به وضعیت قبلی کلید است، برابر ۱ میشود. در صورتی که کلید فشرده نشود و یا دست از روی کلید برداشته شود. مقدار متغیری که مربوط به وضعیت قبلی کلید است، برابر صفر میشود. این عمل debounce نام دارد. و باعث میشود تا با هر بار فشردن کلید، فقط یک بار عملیات داخل آن انجام شود.
HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
زمانی که پایه بصورت خروجی تعریف شود. با استفاده از این تابع میتوانید سطح منطقی پایه را تغیر دهید. این تابع دارای سه ورودی است. که به ترتیب عبارت از؛
GPIO_TypeDef *GPIOx: این قسمت برای انتخاب پورت است.
uint16_t GPIO_Pin: در این قسمت بایستی شماره پایه مورد نظر را انتخاب کنید.
GPIO_PinState PinState: در این قسمت بایستی سطح منطقی پایه مشخص شود. برای سطح منطقی پایه برابر صفر باشد، بایستی عبارت “GPIO_Pin_RESET” نوشته شود. برای این که سطح منطقی ۱ ، بایستی عبارت “GPIO_Pin_SET” نوشته شود.
// کد های زیر بایستی داخل حلقه while(1) نوشته شود. HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET); HAL_Delay(1000); HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET); HAL_Delay(1000);
در مثال بالا پایه PC13 که با نام LED تعریف کرده بودیم. ابتدا سطح پایه صفر و پس از گذشت یک ثانیه سطح آن یک میشود و دوباره بعد از مدت یک ثانیه این حلقه تکرار میشود. با توجه این نکته، که پایه کاتد LED موجود بر روی برد BluePill به میکروکنترلر متصل شده است. LED ابتدا روشن و پس از مدت یک ثانیه خواموش خواهد شد. سپس بعد از گذشت یک ثانیه باز این حلقه تکرار میشود.
HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
زمانی که پایه بصورت خروجی تعریف شود. هر زمان که این تابع داخل برنامه فراخوانی شود. سطح منطقی پایه Toggle میشود. برای مثال اگر سطح پایه صفر باشد، با فراخوانی این تابع سطح آن به یک تغیر خواهد کرد و بلعکس. این تابع دارای ۲ ورودی است. که به ترتیب عبارت از؛
GPIO_TypeDef *GPIOx: این قسمت برای انتخاب پورت است.
uint16_t GPIO_Pin: در این قسمت بایستی شماره پایه مورد نظر را انتخاب کنید.
// کد های زیر بایستی داخل حلقه while(1) نوشته شود. HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin); HAL_Delay(1000);
مثال بالا در عمل مثل مثال مربوط به تابع HAL_GPIO_WritePin است. با این تفاوت که در این برنامه از دستورات کمتری استفاده شده است. در هر حلقه وضعیت پایه تغییر کرده و پس از مدت یک ثانیه دوباره این عمل انجام می شود.
در ادامه مثالی برای ترکیب دستورات بالا مشاهده میکنید. با هر بار فشردن کلید وضعیت LED تغیر میکند.
// دستورات زیر بایستی قبل از تابع main نوشته شود. #include <stdbool.h> GPIO_PinState Key_State; bool Key_Last_State; // دستورات زیر بایستی داخل حلقه while(1) نوشته شود. Key_State = HAL_GPIO_ReadPin(Key_GPIO_Port,Key_Pin); if(Key_State == GPIO_PIN_RESET) { if(Key_Last_State == false) { HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin); Key_Last_State = true; } } else Key_Last_State = false; }
در اخر برای پروگرام برنامه بر روی میکروکنترلرهای stm32 از منوی Project گزینه ی Build Target را انتخاب کنید پس از اتمام کامپایل، از منوی Flash گزینه ی Download را انتخاب کنید. اگر با پیغام no target connected مواجه شدید ابتدا کلید reset روی برد را نگه داشته و گزینه ی Download را بزنید و سپس کلید reset را رها کنید. پس از دانلود شدن برنامه روی ای سی، بار دیگر کلید reset را فشار دهید. پس از آن برنامه اجرا خواهد شد.
لوازم مورد نیاز
چنانچه در مراحل راه اندازی میکروکنترلرهای stm32 با مشکل مواجه شدید، بدون هیچ نگرانی در انتهای همین پست، به صورت ثبت نظر سوالتان را مطرح کنید. من در سریعترین زمان ممکن پاسخ رفع مشکل شما را خواهم داد. همچنین اگر ایرادی در کدها و یا مراحل اجرایی وجود دارند میتوانید از همین طریق اطلاع رسانی کنید.
پروژه و دریافت بن ارسال رایگان
برای دریافت بن خرید از دانشجو کیت، کاربران بایستی با استفاده از وسایل این آموزش، پروژه را اجرا کرده و یا حتی مدار جدیدی تعریف کنید. سپس از اجرای کار فیلم گرفته و در شبکههای اجتماعی از جمله آپارات و اینستگرام، با هشتگهای دیجی_اسپارک ، دانشجوکیت ، digispark و daneshjookit منتشر کنند. سپس از طریق بخش نظرات در ادامه همین آموزش، جهت دریافت بن خرید ارسال رایگان به ارزش ۱۲۰۰۰ تومان از دانشجو کیت، لینک را زیر همین پست ارسال کنید.
در پایان نظرات و پیشنهادات خود را با ما درمیان بگذارید و با اشتراک گذاری این آموزش در شبکه های اجتماعی , از وبسایت دیجی اسپارک حمایت کنید.
سلام
خیلی روان توضیح دادید
مرسی
باسلام
از توجه شما سپاسگزارم مهندس.
برای برنامه نویسی کامپایل و دیباگینگ از خود برنامه شرکت به اسم cube ide هم میشه استفاده کرد برنامه قوی ای هست
شاید مهمترین ویژگی میکرو های st پشتیبانی خوبی باشه و utility های خیلی عالی cubemx هم که فوق العادس
سلام از توجه شما سپاسگزارم
بله در پست مربوط به معرفی میکرو کنترلر های Stm32 از این نرم افزار هم نامبرده شد.
سلام مهندس خسته نباشید
بنده از کیل و کیوب استفاده میکنم اما مشکلی که هست یک سری چیز هارو از کد های شما متوجه نمیشه …
یعنی وقتی میخوام bool رو تعریف کنم ارور میگیره که انگار توی زبان C تعریف نشده
خواستم با int تعریف کنم ولی بازم مشکل هست باز هم هیچی از GPIO_PinState Key_State نمیفهمه با اینکه ارور نمیگیره ولی توی خط های پایین به همه شون ارور میگیره و میگه براش قابل تشخیص نیست و تعریف نشده
با سلام از توجه شما سپاسگزارم
تغیراتی در قسمت کد های آموزش صورت گرفت لطفا بار دیگر این قسمت را بررسی نمایید.
میشه در خصوص تابع HAL_GPIO_LockPin هم توضیح بدید؟ و اینکه چطوری میشه از خروجی این تابع استفاده کرد؟
این تابع زمانی استفاده میشود که شما نیاز داشته باشید، تنظیمات پیکربندی پین های یک پورت را قفل کنید. تا با تغییر مقادیر رجیستر های پیکربندی تغییری حاصل نشود. برای استفاده از خروجی این تابع بایستی متغیری از نوع HAL_StatusTypeDef بسازید و ان را برابر با تابع قرار دهید.
چرا تو تنظیمات GPIO مقدار سرعت رو روی GPIO_SPEED_FREQ_LOW قرار دادید؟ فرکانس خروجی GPIO تو سرعت های مختلف چقدر هست؟ مگر مزیت میکروهای ST به AVR سرعت کاریشون نیست؟ چرا مقدار سرعت پین رو حالت LOW قرار گرفته؟
تنظیماتی که در این بخش مشاهده میکند. صرفا برای آموزش انجام شده است. و نیازی به بالا بردن سرعت GPIO ها نبوده. برای بررسی فرکانس GPIO ها در سرعت های مختلف بایستی دیتاشیت میکروکنترلر مورد نظر را بررسی نمایید.
چه حالتی ممکنه هست پیش بیاد که ما مجبور بشیم از تابع HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin); برای حذف تنظیمات GPIO استفاده کنیم؟ کاربردش دقیقا کجا هست؟
حالت های مختلفی ممکن است پیش بیاید که شما مجبور باشید از این دستور استفاده کنید تا تنظیمات پیکربندی پایه را به حالت پیشفرض بازگردانید. برای مثال ممکن است شما میکروکنترلری انتخاب کرده باشید، که دارای تعداد GPIO های کمی است. و مجبور باشید از چند پایه هم بعنوان ورودی و هم بعنوان خروجی استفاده نمایید.
من از پروگرامر ST-Link-V2 از نوع Clone استفاده میکنم. (همین هایی که شبیه فلش مموری هست)متاسفانه گاهی میکرو رو میشناسه و گاهی نمی شناسه. چند تا پروگرامر دیگه هم مثل همین خریدم بازم همین طوری بود. firmware مربوطه رو هم آپدیت کردم. یک بنده خدایی گفت قلق داره منتها بهم نگفت راه حلش رو. تجربه ای تو این زمینه دارید؟
ممکن است زمانی که فرکانس کاری پروگرامر بیشتر از ۱ مگاهرتز است. عملیات پروگرام دچار اختلال شود. فرکانس را کاهش دهید و مجددا بررسی فرمایید. همچنین توجه داشته باشید که در برخی از این مدل پروگرامر ها جای پایه های SWDIO و SWCLK برعکس چاپ شده است. و بایستی موقع پروگرام سیم های این پایه هارا جابجا متصل کنید تا میکروکنترلر توسط پروگرامر شناخته شود.
در انتهای فایل main.c که توسط Cube MX تولید شده یک عبارت #ifdef USE_FULL_ASSERT درج شده. کاربردش چیه؟
با سلام
این قسمت مربوط به بخش Debug است.
سلام ببخشید من وقتی که کد ها رو اضافه می کنم و کامپایل میکنم ارور میده.میشه بی زحمت بگین کدها ی مثال اخررو دقیقا در چه خطی از main.cاضافه می کنید که ارور نمیده.یا اگر میشه فایل خود برنامه نوشته شده توی کیل رو برام بفرستین.خیلی ممنونم.
با سلام
لطفا ارور دریافتی را از طریق بخش کامنت همین پست اعلام کنید تا مشکل بررسی و رفع شود.
سلام خسته نباشین من برای برنامه نویسی یه میکرو stm32f030k6t6 باید با کیل برنامه اش رو بنویسم که یه ال ای دی و یه بازر روشن شه نرم افزارcube mx رو نصب کردم ولی میکروم رو پیدا نکردم میشه بدون اون هم با کیل بنویسم برنامه اش رو و از پروگرمر hattel استفاده میکنم وقتم خیلی کمه ممکنه کمکم کنید
با سلام
نرم افزار CUBEMX برای انجام یکسری پیکربندی های اولیه در میکروکنترلر استفاده می شود، امکان پیکربندی میکروکنترلر بدون این نرم افزار وجود دارد، اما این کار بسیار دشوار است. همچنین برای پروگرام کردن میکروکنترلر های STM32 بایستی پروگرامر ST LINK را تهیه کنید. و پروگرامر هاتل تنها برای پروگرام کردن میکروکنترلر های AVR قابل استفاده است.
سلام. مگر پایه مثبت led نباید به میکروکنترلر وصل شه؟ چرا گفت شده پایه کاتد Led موحود بر روی برد به میکروکنترلر متصل شده
با سلام
شماتیک برد بلوپیل به این صورت است که پایه کاتد LED به میکروکنترلر متصل شده است. بنابراین برای روشن کردن LED بایستی مقدار ۰ بر روی پایه قرار بگیرد.
درود این خط ایراد نداره که برا من خطا میکیره
Key_State = HAL_GPIO_ReadPin(Key_GPIO_Port,Key_Pin);
با سلام
متن ارور را ارسال کنید.