بسیاری از ما با میکروکنترلرهای محبوب و مشهوری مانند آردوینو، ESP8266، رزبریپای، NoduMCU ،8051 و … و بوردهای توسعه دهندهی آنها آشنا هستیم. در این میان، معمولا ( نه به طور قطع) آردوینو انتخاب اول بیشتر افراد محسوب میشود. اما اگر قدری در کارها و پروژههای تخصصی و پیچیدهتر ورود پیدا کنیم، خواهیم دید که بوردهای آردوینو با محدودیتهای مهمی مواجه هستند؛ از جمله در مواردی مانند قیمت، قابلیت انطباق، پایداری، سرعت و … . همینجاست که نیاز به استفاده از پلتفرمهای میکروکنترلری دقیقتر و قویتر مانند PIC ،STM یا Renesas و … را احساس خواهیم کرد.
تا امروز، آموزشهای فراوانی را برای میکروکنترلرهای PIC ، میکروکنتلرهای AVR و بوردهای آردوینو ارائه دادهایم که حتی به افراد مبتدی هم کمک میکنند که قدم به قدم با این میکروکنترلرها آشنا شده و کار با آنها را یاد بگیرند. در مورد میکروکنترلر STM32 نیز به همین ترتیب بوده است. در این جلسه هم قصد داریم با پرداختن به بورد STM32 Nucleo64 و آموزش نحوهی کارکردن با آن، این مجموعه آموزشها را کاملتر کنیم. این آموزش و آموزشهای بعدی پیرامون این بورد به نحوی هستند که حتی افراد مبتدی نیز میتوانند با خیال راحت و قدم به قدم همراه با ما پیش بیایند. در حقیقت یکی از مزیتهای بورد Nucleo64 این است که در کنار قیمت پایین و مناسبی که دارد، هم پاسخگوی نیازهای افراد و پروژههای حرفهای است و هم افراد تازهکار و کسانی که در قالب پروژههای ابتدایی و سرگرم کننده قصد ورود به این حوزه را دارند.
لازم به ذکر است که در این ویدئو نحوهی پروگرم کردن میکروهای STM32 با پلتفرم ARM Mbed نیز توضیح داده میشود. ولی ما در این آموزش قصد داریم برای پروگرم کردن از پلتفرم دیگری به نام TrueSTUDIO استفاده کنیم.
نکته: بورد STM32 Nucleo64 ورژنهای مختلفی دارد. ورژنی که ما در اینجا از آن استفاده میکنیم NUCLEO-F030R8 است. اصلیترین دلیلی که برای انتخاب این نسخه داشتهایم قیمت پایین آن است. چنانچه شما نسخههای دیگری را هم استفاده کنیم، اصلا جای نگرانی نیست و اغلب مطالب گفته شده برای تمام نسخهها یکسان هستند.
انتخاب و دانلود پلتفرمهای لازم برای استفاده از بورد Nucleo64
برای شروع کار با هر میکروکنترلری، اولین چیزی که نیاز داریم یک IDE است. مثلا برای بوردهای آردوینو ما Arduino IDE را داریم، برای AVRها Atmel Studio، برای PIC میکروکنترلرها MP Lab را و … . به همین ترتیب برای پروگرم کردن و دیباگ کردن بوردهای STM32 Nucleo64 نیز به یک IDE نیاز داریم. خانوادهی میکروهای STM32 میکروکنترلرهای ۳۲ بیتی هستند که از IDEهای زیر پشتیبانی میکنند.
- IAR Embedded Workbench® for ARM® (EWARM).
- MDK-ARM Keil
- TrueSTUDIO
- System Workbench for STM32
در اینجا ما برای نوشتن، کامپایل کردن و دیباگ کردن کدها از TrueSTUDIO استفاده میکنیم؛ به دو علت: اولا که استفاده و دانلود آن رایگان است و دوما اینکه در بسیاری از مقاصد تجاری نیز از همین IDE استفاده میشود و نیاز به لایسنسهای بخصوصی ندارد.
از STM32CubeMX نیز برای تسهیل فرآیند پروگرم کردن استفاده میکنیم. با استفاده از این نرمافزار، میتوان چارچوب اولیه کد برای یک میکروی STM32 را با در نظر گرفتن پریفرالهای آن در هر پروژه تولید کرد.
برای آنکه فایل کد (hex.) را بر روی میکرو بارگذاری کنیم نیز، هم میتوان از ابزاری به نام STM32 ST-LINK Utility استفاده نمود و هم از خود TrueSTUDIO. که ما در اینجا گزینه دوم را انتخاب میکنیم. این نرمافزار دارای یک مود debug است که در آن میتوان فایل hex را بر روی میکروکنترلر بارگذاری نمود.
دانلود و نصب هر دوی این ابزارها (TrueSTUDIO و STM32CubeMX) بسیار ساده است و کافی است از لینکهای زیر آنها را دانلود و سپس بر روی لپتاپ خود نصب کنید.
نمودار مدار و اتصالات سختافزاری
پیش از آنکه وارد بخش نرمافزاری و کدنویسی شویم، بهتر است ابتدا مدار پروژه را رو به راه کنیم. کاری که قرار است در این پروژه انجام دهیم، این است که یک LED را با استفاده از کلید فشاری کنترل کنیم. اگر ویدئویی که در قسمت قبلی لینک دادیم را دیده باشید و یا خودتان از قبل اطلاعات داشته باشید، میدانید که میکروی STM32 دارای دو سری پینهای کانکتور در دو طرف خود است که به آنها ST Morpho پین گفته میشود. ما LED و کلید فشاری را باید به این پینها متصل کنیم. این کار را مانند تصویر زیر انجام میدهیم.
همانطور که میبینید اتصالات این پروژه بسیار ساده هستند، کافیست LED را به پین PA5 از پورت A وصل کنیم و کلید فشاری را به پین PC13 از پورت C. (سر دیگر هر دو به زمین متصل است)
پس از برقراری اتصالات، ست آپ مدار ما چیزی شبیه شکل زیر خواهد بود.
یک راه دیگر هم این است که از LED و کلید فشاریای که در داخل خود بورد میکروکنترلر تعبیه شدهاند استفاده کنیم. این دو نیز همانطور که در نقشه پینها مشخص شده است به همان پینها متصل هستند. این که ما از LED و کلید خارجی استفاده کردهایم، فقط به علت تمرین و یادگرفتن اتصالات است و گرنه استفاده از LED و کلید داخلی نیز هیچ مشکلی ایجاد نخواهد کرد. تصویر زیر میتواند به شما کمک کند که متوجه شوید هرکدام از morpho پینها به چیزی متصل هستند.
نحوهی کار با نرمافزار STM32CubeMX
قدم اول: پس از نصب و باز کردن نرمافزار، access board selector را باز کنید و از آنجا بورد میکروکنترلر STM32 را انتخاب کنید.
قدم دوم: حالا نام بوردتان مثلا NUCLEO-F030R8 را جستجو کنید و مانند تصویر زیر پس از پیدا شدن آن را انتخاب کنید. (دقت کنید که اگر از ورژن متفاوتی استفاده میکنید نام همان نسخه را جستجو و انتخاب کنید) این نرمافزار از تمام بوردهای STM32 که توسط شرکت ST Microelectronics تولید شدهاند پشتیبانی میکند.
قدم سوم: مانند تصویر زیر، بر روی گزینهی yes کلیک کنید. با این کار تمام پریفرالها در مود اولیه ی خود مقداردهی اولیه میشوند (initialize). در مراحل بعدی، متناسب با پروژهای که داریم، مود هر کدام را که لازم باشد تغییر خواهیم داد.
پس از آن صفحهای مانند تصویر زیر ظاهر خواهد شد که رنگهای سبز در آن نمایانگر این هستند که این پینها در مود اولیه ی خود مقداردهی شدهاند.
قدم چهارم: در این مرحله کاربر میتواند تنظیمات مدنظر را از گروههای مختلفی که وجود دارند انتخاب کند. خب، پروژهی ما این است که با استفاده از یک کلید فشاری یک LED روشن و خاموش شونده تولید کنیم، پس باید پین LED را به عنوان خروجی و پین کلید را به عنوان ورودی تنظیم کنیم.
به این منظور، هر پین دلخواهی را میتوانید انتخاب کنید. مثلا ما در اینجا PA5 را انتخاب کردهایم و تنظیمات آن را در حالت GPIO OUTPUT قرار میدهیم.
PC13 را نیز به همین ترتیب به عنوان GPIO INPUT تنظیم میکنیم تا وضعیت کلید را در هر لحظه بخواند.
به جای این کار، میتوانیم به pinout and configuration tab برویم و تنظیمات ورودی یا خروجی بودن پینها را در آنجا نیز مشخص کنیم.
قدم پنجم: در این مرحله، میتوانیم فرکانس دلخواه برای میکرو و پینهای آن را انتخاب کنیم. این کار را با توجه به اسیلاتورهای داخلی و خارجی هر پروژه انجام میدهیم. حالت پیشفرض این است که از یک کریستال اسیلاتور 8MHz به عنوان اسیلاتور داخلی استفاده میشود که با استفاده از PLL میتوان آن را به 48MHz نیز ارتقا داد. بنابراین معمولا میکروهای STM32 در حالت پیشفرض دارای فرکانس 48MHZ هستند.
قدم ششم: در این مرحله به project manager میرویم و برای پروژهمان یک نام انتخاب میکنیم. همچنین مسیر ذخیره شدن فایلهای آن و نیز IDE که میخواهیم برای دیباگ آن استفاده کنیم را نیز تعیین میکنیم. از آنجایی که قرار شد ما از TrueSTUDIO به عنوان IDE استفاده کنیم، پس مانند تصویر زیر همان را از لیست انتخاب میکنیم.
قدم هفتم: بر روی گزینهی Generate Code که در تصویر زیر با دایرهی قرمزی دور آن نشان داده شده است، کلیک میکنیم.
قدم هشتم: در صفحهای که مانند تصویر زیر ظاهر میشود، بر روی open project کلیک میکنیم. فقط نکتهی مهمی که وجود دارد این است که قبل از انجام دادن این قدم حتما باید TrueSTUDIO را نصب کرده باشید.
پروگرم کردن بورد STM32 Nucleo64 با استفاده از TrueSTUDIO
پس از طی کردن مراحل قبلی، چارچوب اولیهی پروژه یا کد شما به صورت خودکار در TrueSTUDIO باز خواهد شد. اگر TrueSTUDIO از شما در مورد محل ذخیرهی فایل ها سوال کرد، یا آن را بر اساس دلخواه خود تعیین کنید و یا آنکه با همان مسیری که به صورت پیشفرض وجود دارد جلو بروید.
وقتی پنجرهی زیر را دیدید، بر روی آن گزینهای که در تصویر زیر دور آن دایره قرمز کشیده شده است (در گوشهی بالا سمت راست) کلیک کنید.
در این لحظه خواهید دید که کد در TrueSTUDIO IDE باز میشود. در سمت چپ پنجره، زیر فولدر src، میتوانیم سایر فایلهای تولید شده برای پروژه را نیز ببینیم. مثلا فایل c. را. تمام این فایلها را STM32Cube متناسب با نیاز پروژه ما برایمان ساخته است. کاری که ما در اینجا باید انجام دهیم این است که برنامه مورد نظرمان را در فایل main.c وارد کنیم. اگر این فایل را باز کنیم، میبینیم که CubeMX، حتی در این فایل نیز یک سری مقدمات اولیه را برای ما نوشته است و ما تنها باید آن را تا حدی ادیت کنیم. کد کاملی که ما برای این پروژه باید در فایل main.c وارد کنیم در انتهای جلسه برایتان قرار داده شده است.
نوشتن برنامهی کنترل LED با استفاده از کلید فشاری برای STM32 Nucleo64
از آنجا که بخش اصلی کد و درایورهای مربوطه توسط STM32CubeMX در فایل main.c قرار داده شدهاند، تنها کاری که ما باید در اینجا انجام دهیم این است که پین LED را به صورت خروجی و پین کلید را به صورت ورودی تعریف کنیم. همانطور که گفتیم، کد کامل این بخش را در انتهای جلسه در دسترس خواهید داشت و در ادامه بخشهای مهم آن را با هم مرور میکنیم.
برای نوشتن برنامهای که در آن LED براساس وضعیت کلید روشن و خاموش شود، ابتدا پینهای LED و کلید را تعریف میکنیم. به این منظور، پین ۵ از پورت A را برای LED اختصاص میدهیم.
#define LED_PORT GPIOA #define LED_PIN GPIO_PIN_5
و پین ۱۳ام پورت C را نیز به کلید.
#define SW_PORT GPIOC #define SW_PIN GPIO_PIN_13
در تابع main، یک بار تمام پریفرالهای مورد استفاده را مقداردهی اولیه میکنیم.
/* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART2_Init();
سپس پین مربوط به کلید را میخوانیم و بر اساس وضعیت آن، با یک جملهی شرطی (if)، تعیین میکنیم که LED باید تغییر وضعیت بدهد یا خیر.
While (1) { /* USER CODE END WHILE */ If (!HAL_GPIO_ReadPin(SW_PORT, SW_PIN)) { HAL_GPIO_TogglePin(SW_PORT, LED_PIN); HAL_Delay(200); } /* USER CODE BEGIN 3 */ }
اگر به تابع (HAL_GPIO_ReadPin(SW_PORT, SW_PIN دقت کنیم، میبینیم که دو آرگومان ورودی دارد، یکی آدرس پین و دیگری آدرس پورتی که کلید به آن متصل است. این پین در تنظیمات STM32CubeMX به عنوان ورودی تعیین شده است.
دیباگ کردن کد و آپلود آن بر روی میکروکنترلر STM32 با استفاده از TrueSTUDIO
با استفاده از کابل پروگرمر، بورد را به کامپیوتر متصل کنید. به محض اینکه آن را وصل کنید، درایورهای لازم برای بورد به صورت خودکار شروع به دانلود شدن خواهند کرد. اگر دوست داشتید میتوانید این درایورها را در device manager چک کنید.
حالا بر روی آیکون debug که درتصویر زیر با دایره قرمز مشخص شده است، کلیک کنید. به این ترتیب برنامه شروع به کامپایل شدن کرده و وارد debug mode میشود.
زمانی که در این مود قرار میگیریم، کد به صورت خودکار بر روی بورد آپلود خواهد شد. برای اجرای آن باید بر روی Resume کلیک کنید و یا F8 را بزنید. (مانند تصویر زیر)
و در آخر، به مرحلهی تست کردن پروژه میرسیم. براساس کدی که نوشتهایم، هر زمان که کلید فشار داده شود، وضعیت LED باید تغییر کند، یعنی اگر روشن است خاموش شود و اگر خاموش است روشن شود. این عملکرد را میتوانید در ویدئوی زیر به طور کامل ببینید.
بعد از تست کردن و اطمینان از صحت عملکرد، میتوانیم گزینهی terminate را بزنیم تا اجرای برنامه تمام شود. این آیکون در تصویر زیر با دایره قرمز مشخص شده است.
کد
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * <h2><center>© Copyright (c) 2020 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define LED_PORT GPIOA #define LED_PIN GPIO_PIN_5 #define SW_PORT GPIOC #define SW_PIN GPIO_PIN_13 /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ UART_HandleTypeDef huart2; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART2_UART_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ 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(); MX_USART2_UART_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ if (!HAL_GPIO_ReadPin(SW_PORT, SW_PIN)) { HAL_GPIO_TogglePin(LED_PORT, LED_PIN); HAL_Delay(200); } /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12; RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { Error_Handler(); } } /** * @brief USART2 Initialization Function * @param None * @retval None */ static void MX_USART2_UART_Init(void) { /* USER CODE BEGIN USART2_Init 0 */ /* USER CODE END USART2_Init 0 */ /* USER CODE BEGIN USART2_Init 1 */ /* USER CODE END USART2_Init 1 */ huart2.Instance = USART2; huart2.Init.BaudRate = 38400; huart2.Init.WordLength = UART_WORDLENGTH_8B; huart2.Init.StopBits = UART_STOPBITS_1; huart2.Init.Parity = UART_PARITY_NONE; huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Init.OverSampling = UART_OVERSAMPLING_16; huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart2) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN USART2_Init 2 */ /* USER CODE END USART2_Init 2 */ } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET); /*Configure GPIO pin : PC13 */ GPIO_InitStruct.Pin = GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /*Configure GPIO pin : LD2_Pin */ GPIO_InitStruct.Pin = LD2_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct); } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ /* 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(char *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 را نیز مطالعه کنید.
اگر این نوشته برایتان مفید بود لطفا کامنت بنویسید.