میکروکنترلرهای STM32 که از معماری ARM Cortex M استفاده میکنند، اخیرا بسیار محبوب شدهاند و در پروژههای بسیاری از آنها استفاده میشود. با توجه به کارایی، هزینههای معقول و این محبوبیت، آیندهی درخشانی در انتظار این میکروهاست و احتمالا آنها را در کاربردهای مختلفی خواهیم دید. در جلسات گذشته، نحوهی پروگرم کردن این میکروکنترلر را با استفاده از Arduino IDE آموزش دادهایم. پروگرم کردن STM32 با استفاده از Arduino IDE بسیار ساده است چرا که این IDE کتابخانههای فراوانی را برای ارتباط با سنسورهای مختلف و انجام وظایف مرتبط با آنها به صورت آماده در خود دارد. بنابراین فقط کافی است که ما این کتابخانهها را به کدهایمان اضافه کرده و به راحتی از امکانات آنها استفاده کنیم. مزیت این فرآیند سرراست و ساده، این است که شما را درگیر پیچیدگیهای احتمالی شناخت دقیق و عمیق برنامهنویسی ARM نمیکند. اما بهرحال یادگیری این نوع پروگرم کردن نیز اجتنابناپذیر و بسیار مفید است. بنابراین در این مرحله قصد داریم وارد آموزش ARM programming شویم. با این روش، نه تنها قادر خواهیم بود که ساختار برنامههایی که مینویسیم را بهبود داده و بهینه سازیم، بلکه میتوانیم با حذف کتابخانههای غیرضروری، از مموری کمتری برای پروگرم کردن استفاده کنیم.
شرکت STMicroelectronics، ابزاری را به نام STM32Cube MX توسعه داده است که چهارچوب اولیهی کدها را با توجه به نوع پریفرالها و بورد STM32 مورد استفاده در هر پروژه تولید میکند. به این ترتیب نگرانی ما در مرحلهی اول نوشتن کد تا حدی مرتفع خواهد شد. این چهارچوب اولیهی داده شده را سپس میتوانیم وارد ابزار دیگری به نام Keil uVision کنیم و در آنجا ادیتهای لازم برای تکمیل برنامه را تا رسیدن به هدف مورد نظر انجام دهیم. در نهایت کد حاصل شده را با استفاده از ابزار دیگری از همین شرکت یعنی پروگرمر ST-Link، روی میکروکنترلر بارگذاری میکنیم.
در این آموزش، قصد داریم نحوهی استفاده از سه ابزار اول فوق را در قالب انجام یک پروژهی ساده (ارتباط LED و کلید فشاری با بورد میکروکنترلر Blue pill) STM32)) آموزش بدهیم. به این ترتیب که ابتدا با استفاده از STM32Cube MX کد اولیه را تولید میکنیم و سپس با استفاده از Keil uVision آن را ادیت کرده و در آخر با استفاده از پروگرم بر روی میکرو آپلود میکنیم.
قبل از شروع توضیح جزییات کار، بد نیست ابتدا قدری با ابزارهای STM32Cube MX و ST-Link پروگرمر آشنا شویم.
ST-LINK V2
ST-LINK/V2 یک پروگرمر و دیباگر تحت مدار (in-circuit) برای خانوادهی میکروکنترلرهای STM8 و STM32 است. یعنی با استفاده از آن، میتوانیم میکروهای این دو خانه از جمله STM32F103C8 را پروگرم کنیم. بر روی بورد آن، یک ماژول اینترفیس تک سیم (SWIM) و یک JTAG/ دیباگر سریال (SWD) نیز وجود دارند که میتوانند با میکروهای مذکور ارتباط برقرار کنند. از آنجا که میکروهای STM32 برای ارتباط با Atollic ،IAR ،Keil و TASKING از اینترفیس full-speel USP استفاده میکنند، بنابراین ST-Link ابزار مناسبی برای بارگذاری کد بر روی این میکروها محسوب میشود.
در تصویر فوق، دانگل ST-LINK V2 را میبینیم. این دانگل ازمحدودهی کامل اینترفیس دیباگ STM32 SWD، و اینترفیس سادهی 4-wire پشتیبانی میکند. پرسرعت است و پایداری خوبی دارد. در رنگهای مختلف در بازار وجود دارد و بدنهی آن از یک آلیاژ آلومینیومی ساخته شده است. در داخل آن یک LED آبی رنگ تعبیه شده است که وضعیت عملکرد آن را نشان میدهد. نام پایههای آن به صورت واضح همانطور که در تصویر فوق میبینیم بر روی بدنه درج شدهاند. به راحتی میتواند با Keil software ارتباط برقرار کند و از این طریق برنامهها را بر روی میکروکنترلر STM32 آپلود کند. در ادامهی آموزش، چگونگی این ارتباط را توضیح خواهیم داد. تصویر زیر، نمای نزدیک پایههای این تراشه را نشان داده است.
توجه: زمانی که برای اولین بار این پروگرمر را به کامپیوتر وصل میکنیم، باید درایور آن را نصب کنیم. درایورهای مختلف بر اساس سیستم عامل مورد استفاده را در این لینک میتوانید پیدا کنید.
STM32CubeMX
این ابزار در حقیقت بخشی از STMicroelectronics STMCube است. STMCube نرمافزاری برای کاهش هزینه، زمان و تلاش مورد نیاز برای توسعهی پروژه محسوب میشود و MX بخش گرافیکی آن است که به کاربر این امکان را میدهد که کد اولیهی هر پروژه را در یک محیط گرافیکی تولید کند. کد به دست آمده از این محیط را میتوان در ابزارهای مختلفی مانند keil uVision ،GCC ،IAR استفاده کرد. اگر STM32CubeMX را از قبل دانلود نکردهاید میتوانید از این لینک آن را دانلود کنید.
ویژگیهای STM32CubeMX
- مجهز به conflict solver برای Pin out
- دارای clock-tree setting helper
- دارای محاسبهگر مصرف توان
- دارای قابلیت تنظیم متناسب با پریفرالهای ارتباطی میکروکنترلرها مانند GPIOها، USART و …
- دارای تنظیمات USB ،TCP/IP و …
تجهیزات مورد نیاز برای انجام پروژه
تجهیزات سختافزاری
- بورد STM32F103C8 Blue Pill
- پروگرمر ST-Link V2
- کلید فشاری
- LED
- برد بورد
- سیم برد بوردی
تجهیزات نرمافزاری
- نرمافزار STM32CubeMX Code Generation Tool (لینک)
- نرمافزار Keil uVision 5 (لینک)
- درایورهای لازم برای ST-Link V2 (لینک)
نمودار مدار و اتصالات
در تصویر زیر مدار لازم برای اتصال LED به بورد میکروکنترلر را با استفاده از یک کلید فشاری میبینیم.
اتصال بین میکروکنترلر STM32F103C8 و پروگرمر ST-Link V2
در این قسمت مدار میکروکنترلر را داریم که به کمک پروگرمر و USB آن به کامپیوتر وصل میشود. به این ترتیب دیگر نیازی نیست که میکرو را به صورت جداگانه تغذیهرسانی کنیم، همین اتصال پاور آن را تامین خواهد کرد. جدول زیر اتصالات میان این دو ماژول را توضیح داده است.
LED و کلید فشاری
LED را برای نشان دادن خروجی میکرو در زمان فشرده شدن کلید استفاده میکنیم. پایهی آنود LED را به پایهی PC13 از میکرو و پایهی کاتد آن را به زمین مدار وصل میکنیم. کلید فشاری هم قرار است ورودی پایهی PA1 میکرو را تامین کند. از یک مقاومت پول آپ 10K هم در این اتصال استفاده میشود تا در صورت رها شدن کلید، پین به صورت بدون ورودی (float) رها نشود. بنابراین یک سر کلید فشاری به پایهی PA1 وصل میشود و سر دیگر آن به زمین. مقاومت پول آپ هم از یک سر به پین ۳.۳ ولت میکرو و از سر دیگر به PA1 متصل میشود.
ساخت برنامه و آپلود کردن آن بر روی STM32 با استفاده از Keil uVision و ST-Link
قدم اول: ابتدا تمام درایورهای لازم برای ST-Link V2 نصب کنید. ابزارهای STM32Cube MX و Keil uVision را نیز به همین شکل. تمام کتابخانههای لازم برای STM32F103C8 را نیز نصب کنید.
قدم دوم: STM32Cube MX را باز کنید.
قدم سوم: New Project را بزنید.
قدم چهارم: در قسمت search، نوع میکروکنترلری که میخواهیم استفاده کنیم (STM32F103C8) را جستجو و انتخاب کنید.
قدم پنجم: در این مرحله نقشهی پایههای این میکروکنترلر نمایش داده میشود. تنظیمات مربوط به پایهها را همین جا میتوانیم انجام دهیم. این تنظیمات را بر اساس نیازهای پروژه انجام میدهیم.
قدم ششم: اگر بر روی هرکدام از پایهها مستقیما کلیک کنید، میبینید که لیستی ظاهر میشود که از روی آن میتوانید تنظیمات دلخواه را برای آن پایه انتخاب کنید.
قدم هفتم: مثلا در این پروژه، ما پایهی PA1 را به عنوان GPIO INPUT، پایهی PC13 را به عنوان GPIO OUTPUT و SYS debug را به عنوان SERIAL WIRE انتخاب میکنیم. ضمن اینکه برای این پروژه، ما فقط SWCLK و SWDIO را برای ST-Link فعال میکنیم. پینهایی که انتخاب و تنظیم میشوند با رنگ سبز مشخص میشوند که در تصویر زیر هم میتوانید ببینید.
قدم هشتم: در بخش GPIO ،Configuration tab را باز کنید تا آن را برای پینهایی که تنظیماتشان را تغییر دادهایم مشخص کنیم.
قدم نهم: حالا در pin configuration box، میتوانیم برای پینهایی که استفاده میکنیم User Label تعیین کنیم. این label در واقع همان نامی است که به دلخواه کاربر برای هر پایه تعریف میشود.
قدم دهم: در این مرحله به مسیر Project >> Generate Code بروید.
قدم یازدهم: حالا پنجرهی مربوط به تنظیمات پروژه را میبینید که باز شده است. در آن میتوانید نام پروژه، محل ذخیره شدن آن و محیطی که میخواهید پروژه را در آن توسعه دهید را انتخاب کنید. ما از Keil استفاده میکنیم، پس کافی است در بخش IDE گزینهی MDK-ARMv5 را انتخاب کنیم.
قدم دوازدهم: در تب Copy only the necessary library files ،Code Generator را انتخاب کنید و OK را بزنید.
قدم سیزدهم: در این گام، پنجرهی مربوط به تولید کد را میبینید. اگر گزینهی Open Project را انتخاب کنید، کد پروژه به صورت اتوماتیک تولید شده و در Keil uvision نشان داده میشود.
قدم چهاردهم: میبینیم که ابزار Keil uVision باز شده و یک کد اولیه نیز برای پروژهی ما در آن تولید شده است. این کد شامل کتابخانههای مورد نیاز و تنظیماتی است که برای پینها مشخص کرده بودیم.
قدم پانزدهم: تنها کاری که الان باید انجام دهیم این است که برنامهی مربوط به کارهایی که باید در پروژه انجام شوند را بنویسیم. یعنی به LED که به پین PC13 متصل است بگوییم با فشرده یا آزاد شدن کلید فشاری (پین PA1) روشن یا خاموش شود. به این منظور main.c را باز میکنیم.
قدم شانزدهم: کد را در حلقهی (while(1 باید اضافه کنیم. در عکس زیر، قسمتی که هایلایت شده است همان بخشی است که کد را پشت سر هم اجرا میکند.
while (1) { if(HAL_GPIO_ReadPin(BUTN_GPIO_Port,BUTN_Pin)==0) //=> DETECTS Button is Pressed { HAL_GPIO_WritePin(LEDOUT_GPIO_Port,LEDOUT_Pin,1); //To make output high when button pressesd } else { HAL_GPIO_WritePin(LEDOUT_GPIO_Port,LEDOUT_Pin,0); //To make output Low when button de pressed } }
قدم هفدهم: بعد از اتمام کد، آیکون Options for Target را که در زیر تب debug قرار دارد باز کنید و از میان گزینهها ST-LINK Debugger را انتخاب کنید.
سپس Settings را بزنید و در ذیل تب Flash Download، تیک گزینهی Reset and Run را بزنید و بر روی ok کلیک کنید.
قدم هجدهم: Rebuild را بزنید تا تمام فایلهای لازم ساخته شوند.
قدم نوزدهم: بسیار خب، حالا میتوانید پروگرمر ST-LINK را با اتصالاتی که قبلتر گفتیم به کامپیوتر وصل کنید. پس از وصل کردن آن، کافیست گزینهی DOWNLOAD و یا کلید F8 را بزنید تا برنامه بر روی میکرو بارگذاری شود.
قدم بیستم: فرآیند بارگذاری شدن کد را میتوانید در پایین پنجرهی keil uVision ببینید.
گرفتن خروجی نهایی از میکروکنترلر STM32 که با Keil پروگرم شده است
برای تست کردن پروژه، کافیست که کلید را فشار دهید و ببینید که آیا LED روشن میشود یا خیر. همچنین با رها کردن کلید باید LED خاموش شود.
کد برنامه
اصلیترین بخشی که به برنامهی ساخته شدهی اولیه اضافه کردهایم را در این قسمت میبینید. این کد همانی است که گفتیم باید در حلقهی (While(1 در فایل main.c کدی که توسط STM32CubeMX ساخته شده است، اضافه شود.
برای مرور دوبارهی مراحل آن، میتوانید قدمهای ۱۵ تا ۱۷ بخش قبلی را دنبال کنید.
while (1) { if(HAL_GPIO_ReadPin(BUTN_GPIO_Port,BUTN_Pin)==0) //=> DETECTS Button is Pressed { HAL_GPIO_WritePin(LEDOUT_GPIO_Port,LEDOUT_Pin,1); //To make output high when button pressesd } else { HAL_GPIO_WritePin(LEDOUT_GPIO_Port,LEDOUT_Pin,0); //To make output Low when button de pressed } }
مراحل کامل تولید و بارگذاری کد بر روی STM32 در ویدئوی زیر نیز قابل مشاهده است. کد کامل فایل main.c که شامل قطعه کد بالا نیز هست را هم در ادامه میتوانید ببینید.
کد
/** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** ** This notice applies to any and all portions of this file * that are not between comment pairs USER CODE BEGIN and * USER CODE END. Other portions of this file, whether * inserted by the user or by software development tools * are owned by their respective copyright owners. * * COPYRIGHT(c) 2018 STMicroelectronics * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of STMicroelectronics nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "stm32f1xx_hal.h" /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); /* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ /* USER CODE END PFP */ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * * @retval None */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { if(HAL_GPIO_ReadPin(BUTN_GPIO_Port,BUTN_Pin)==0) //=> Button is Pressed { HAL_GPIO_WritePin(LEDOUT_GPIO_Port,LEDOUT_Pin,1); } else //=>Button is released { HAL_GPIO_WritePin(LEDOUT_GPIO_Port,LEDOUT_Pin,0); } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; /**Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = 16; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure the Systick interrupt time */ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); /**Configure the Systick */ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } /** Configure pins as * Analog * Input * Output * EVENT_OUT * EXTI */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(LEDOUT_GPIO_Port, LEDOUT_Pin, GPIO_PIN_RESET); /*Configure GPIO pin : LEDOUT_Pin */ GPIO_InitStruct.Pin = LEDOUT_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(LEDOUT_GPIO_Port, &GPIO_InitStruct); /*Configure GPIO pin : BUTN_Pin */ GPIO_InitStruct.Pin = BUTN_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(BUTN_GPIO_Port, &GPIO_InitStruct); } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @param file: The file name as string. * @param line: The line in file as a number. * @retval None */ void _Error_Handler(char *file, int line) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ while(1) { if(HAL_GPIO_ReadPin(BUTN_GPIO_Port,BUTN_Pin)==0) //=> DETECTS Button is Pressed { HAL_GPIO_WritePin(LEDOUT_GPIO_Port,LEDOUT_Pin,1); //To make output high when button pressesd } else { HAL_GPIO_WritePin(LEDOUT_GPIO_Port,LEDOUT_Pin,0); //To make output Low when button de pressed } } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
ویدئو
- منبع: ترجمه از سایت circuitdigest.com
در ادامه پیشنهاد میکنیم دیگر آموزشهای STM32 را نیز مطالعه کنید.
اگر این نوشته برایتان مفید بود لطفا کامنت بنویسید.