در قسمت ششم از آموزش STM32 با توابع LL، در رابطه با GPIO در حالت ورودی صحبت کردیم. نحوهی کار به این صورت بود که مقدار رجیستری که مربوط به پینهای میکروکنترلر در حالت ورودی بود را میخواندیم و پس از آن، متناسب با آن مقدار، متغییری را افزایش و بر روی سون سگمنت نشان میدادیم.
در این قسمت میخواهیم در رابطه با Interrupt یا وقفه صحبت کنیم.
ابتدا در مورد اینکه Interrupt چیست صحبت میکنیم، سپس توضیح میدهیم که در میکروکنترلرهای STM32، وقفهها به چه صورتی عمل میکنند و به چه نحوی در میکروکنترلر جاسازی شدهاند و در نهایت این واحد را به صورت عملی راهاندازی خواهیم کرد.
Interrupt
همانطور که از واژهی Interrupt مشخص است، در روند یا انجام کاری، وقفه ایجاد میکند. در دیجیتال و مشخصا در میکروکنترلرها نیز، Interrupt به همین معناست و در روند کار CPU وقفه ایجاد میکند.
زمانی که CPU در حال انجام کار و روال عادی خود است با وقوع وقفه، CPU برای مدتی روال عادی که در حال اجرای آن بود را متوقف کرده و زیر روال مربوط به وقفهای که اتفاق افتاد را اجرا میکند. (البته توضیحات بالا به صورت کلی بیان شده است، جزئیات این کار را در ادامه به صورت دقیقتر بررسی میکنیم)
اجازه بدهید با یک تشبیه وقفه را تشریح بکنم، تا هم مفهموش را بهتر متوجه شوید و هم کاربرد وجود وقفه را لمس کنید.
فرض کنید در خانه نشستید و در حال انجام کارهایتان هستید، در عین حال منتظر دوستتان هستید که میخواهد پیش شما بیاید. یک راه این است که چشم از پنجره برندارید، و منتظر بمانید تا دوستتان بیاید و وقتی رسید در را بر روی او باز کنید، راه دیگر این است که با خیال راحت کارهایتان را انجام بدهید و هر موقع صدای زنگ خانه را شنیدید در را بر روی دوستتان باز کنید. در اینجا زنگ خانه نقش وقفه را دارد و با به صدا در آمدن زنگ، وقفهای به شما میرسد که باید کار در حال انجام را برای مدتی رها کنید و به وقفه رسیده شده، رسیدگی کنید.
در میکروکنترلر هم همچین اتفاقی رخ میدهد، و با وقوع وقفه، کار در حال انجام رها شده و به وقفه رسیده شده، رسیدگی میشود. فکر میکنم با توضیحات بالا به خوبی متوجه شده باشید که ذات وقفه چیست و چرا باید وجود داشته باشد.
خب تا الان کلیات وقفه را بررسی کردیم و با دلیل وجود و کاربرد وقفه یا همان Interrupt آشنا شدیم. اکنون میخواهیم ساختار Interrupt را به صورت دقیقتر در پردازندههای Cortex-M، و مشخصا در میکروکنترلرهای STM32 بررسی کنیم.
وقفه یا Interrupt در میکروکنترلرهای STM32 سری F1
ما در میکروکنترلرهای STM32 انواع وقفهها را داریم، مثل وقفههای خارجی، وقفهی تایمر، وقفهی مبدل آنالوگ به دیجیتال (ADC)، وقفههای پروتکلها و ارتباطات مثل پروتکل UART و تعداد زیادی وقفه دیگر وجود دارد که مربوط به مدیریت سختافزار درون خود میکروکنترلر میشود.
وقفههای این دسته از میکروکنترلرها دارای یک سری قابلیت ویژه هستند که در ادامه، این قابلیتهای ویژه را با هم بررسی میکنیم.
NVIC (Nested vectored interrupt controller )
NVIC به معنای کنترلکننده بردار وقفههای تو در تو. در میکروکنترلرهای ARM برخلاف میکروکنترلرهای AVR، وقفهها دارای اولویت هستند. اجازه بدهید کمی بیشتر در رابطه با وقفههای تو در تو صحبت کنیم تا موضوع به خوبی تفهیم شود.
در میکروکنترلرهای AVR نحوهی کار به این صورت است که اگر وقفهای رخ بدهد، تابع سرویسدهنده مربوط به این وقفه اجرا میشود، حال اگر در حین اجرای این تابع، وقفهی دومی رخ بدهد هیچ اتفاقی نمیافتد، در واقع موقعی به وقفهی دوم رسیدگی میشود که کدهای درون تابع سرویسدهنده به وقفهی اول به طور کامل اجرا شده باشند.
در میکروکنترلرهای ARM هم روند کار مانند AVR است اما با یک تفاوت بسیار مهم و اساسی. فرض کنید وقفهی اول رخ داده است و میکروکنترلر در حال رسیدگی به این وقفه است، در همین حین وقفهی دومی رخ میدهد، اکنون میکروکنترلر بر اساس شرایطی تصمیم میگیرد که به وقفهی دوم پاسخ بدهد، یا رسیدگی به همان وقفهی اول را ادامه بدهد.
این شرایط چیست؟
در میکروکنترلرهای ARM هر وقفه دارای یک اولویت است و واحد NVIC با توجه به این اولویتها به وقفهها رسیدگی میکند. پس زمانی که وقفهی اول در حال انجام است اگر وقفهی دومی رخ بدهد، تنها در صورتی به وقفهی دوم رسیدگی میشود که اولویت بالاتری داشته باشد، در غیر این صورت آن را نادیده میگیرد تا عملیات مربوط به وقفهی اول به پایان برسد.
حال فرض کنیم که عملیات مربوط به وقفهی اول در حال اجرا است و وقفهی دومی که اولویت بالاتری دارد رخ میدهد، چه اتفاقی میافتد؟ عملیات مربوط به وقفهی اول که در حال اجرا بود برای مدتی رها میشود و به وقفهی دوم رسیدگی میشود. پس از اینکه عملیات مربوط به وقفهی دوم به صورت کامل انجام گرفت، به ادامهی عملیات مربوط به وقفهی اول رسیدگی خواهد شد.
برای اینکه مفاهیم توضیح داده شده در بالا را به خوبی متوجه بشوید، به تصویر زیر دقت بکنید.
در میکروکنترلرهای سری F1 ما میتوانیم 16 اولویت وقفه تعیین کنیم. تنظیم این اولویتها با استفاده از 4 بیت که در مجموع شامل 16 حالت مختلف را شامل میشود، صورت میگیرد.
همانطور که گفتیم تعداد وقفهها بسیار زیاد است و پرداختن به تمامی این وقفهها در یک مقاله ممکن نیست، پس در این مقاله فقط به وقفههای خارجی میپردازیم و سایر وقفهها را در قسمتهای مربوطه توضیح خواهیم داد.
External interrupt
در میکروکنترلرهای سری F1 در مجموع 16 وقفه خارجی بر روی پینهای GPIO وجود دارد.
ابتدا به تصویر زیر که جانمایی و چگونگی این وقفهها را نشان میدهد توجه کنید:
همانطور که از تصویر بالا مشخص است هر شماره از خط یا لاین وقفه خارجی با استفاده از یک مالتی پلکسر به چندین پین از GPIO با همان شماره متصل است.
از تصویر بالا میتوان استنتاج کرد که اگر به عنوان مثال وقفهای بر روی لاین شماره 1 یا همان EXTI1 رخ داد، این وقفه مربوط به یکی از پینهای PA1 تا PG1 میشود. اینکه دقیقا کدام یک از این پینها عامل وقفه بوده است را ما خودمان از قبل تعیین کردیم. ما در یک رجیستر تعیین میکنیم که خروجی مالتی پلکسر کدام یک از ورودیها باشد.
به این نکته دقت کنید که ما به صورت همزمان نمیتوانیم دو پین هم شماره از دو پورت مختلف مثل PA1 و PB1 را به عنوان وقفه خارجی تعریف کنیم، دلیلش هم در دل تصویر و توضیحات بالا نهفته است، اگر دلیل این موضوع را متوجه نشدید دوباره برگردید تصویر بالا را ببینید و توضیحات را یک بار دیگر به دقت بخوانید.
ISR (Interrupt service routine)
زمانی که یک وقفه رخ میدهد، زمان رسیدگی به آن وقفه فرا میرسد. حال سوال اینجاست که چگونه و به چه نحوی باید به این وقفه رسیدگی شود و اصلا ما از کجا میتوانیم متوجه بشویم که وقفه رخ داده است.
برای شرح دقیق اینکه هنگام وقوع وقفه دقیقا چه اتفاقاتی رخ میدهد، باید وارد جزئیات پردازنده Cortex-M3 بشویم. ذکر این جزئیات از حوصله این مقاله خارج است و به علاوه میتواند باعث سردرگمی شما شود. اما نگران نباشید من در ادامه به صورت خیلی مختصر و ساده و البته به طوری که قابل فهم باشد این موضوع را به شما توضیح خواهم داد.
اینکه چگونه باید متوجه بشویم که وقفه رخ داده است بسیار ساده است. با بررسی بیت متناظر با هر وقفه در رجیستر Pending register متوجه خواهیم شده که وقفه رخ داده است یا خیر.
اما موضوع اصلی اینجاست که وقتی متوجه شدیم که وقفه رخ داده است چگونه باید به آن رسیدگی کنیم. وظیفه رسیدگی به وقفه با ISR میباشد. ISR یا ترجمه آن، “روال سرویس وقفه” در زمان وقوع وقفه به صورت سختافزاری فعال میشود و کدهایی که ما نیاز داریم در زمان وقفه اجرا شود را اجرا میکند. دقت کنید که فعال شدن ISR به صورت سختافزاری میباشد و اصلا نیازی نیست که به صورت نرمافزاری کاری انجام بدهیم. فقط باید کدهایی که میخواهیم در زمان فعال شدن ISR اجرا شود را درون تابع مربوط به آن بنویسیم.
پس نتیجه میگیریم که هنگام وقوع یک وقفه خودکار و به صورت سختافزاری ISR مربوط به آن وقفه فعال میشود و ما باید کدهایمان را در قسمت مشخص شده در درون یک تابع بنویسیم تا در زمان وقوع وقفه اجرا شوند. اینکه محل نوشتن این کدها در کجای برنامه و در درون چه تابعی باشد را در ادامه، زمانی که وارد نرمافزار Keil و محیط برنامهنویسی شدیم به شما خواهم گفت.
همانطور که گفتیم ما در مجموع 16 وقفه خارجی که بر روی پینهای GPIO جانمایی شدهاند، داریم. آیا هر کدام از این وقفههای خارجی، ISR مربوط به خودشان را دارند؟ خیر، ممکن است چندین وقفه خارجی، همگی با هم فقط یک ISR داشته باشند.
در میکروکنترلرهای سری F1 که پردازنده آنها Cortex-M3 است، وقفههای خارجی شماره 0 تا 4 هر کدام به صورت جداگانه یک ISR دارند، وقفههای شماره 5 تا 9 همگی یک ISR و وقفههای شماره 10 تا 15 هم همگی یک ISR دارند.
تا اینجا به خوبی با مفاهیم اولیه آشنا شدیم و جزئیات مربوط به وقفهها را به خوبی میدانیم، اکنون وقت آن است که وارد نرمافزار بشویم و تمامی این مفاهیم را به صورت عملی پیادهسازی بکنیم.
ما قصد داریم که وقفه خارجی را بر روی پین PA1 فعال و این پین را به یک کلید خارجی متصل بکنیم. حال اگر این کلید 5 بار فشرده شد، یک LED بر روی پین PA0 روشن و اگر 5 بار دیگر فشرده شد همین LED خاموش شود.
البته یک مدار خارجی که در زیر مشاهده میکنید بر روی پین PA1 قرار میدهیم تا دیبانس (اگر در مورد دیبانس نمیدانید در انتهای همین مقاله کامنت بگذارید) کلید از بین برود و با هر بار فشردن کلید تنها یک بار وقفه رخ بدهد.
کلاک و دیباگ را مانند قسمتهای گذشته تنظیم میکنیم. پین PA0 را بر روی GPIO_Output و پین PA1 را بر روی GPIO_EXTI1 قرار میدهیم:
وقفه را نیز بر روی لبهی پایین رونده با اولویت 0 تعریف میکنیم:
پس از انجام مراحل بالا از پروژه خروجی میگیریم و وارد محیط برنامهنویسی میشویم.
ما ابتدا یک متغیر تعریف میکنیم و با وقوع وقفه این متغیر را یک واحد افزایش میدهیم. چگونه باید با وقوع وقفه متغیر را یک واحد افزایش داد؟ همانطور که قبلا گفتیم با وقوع وقفه، ISR مربوط به آن وقفه فعال میشود. پس از فعال شدن ISR، تابعی فراخوانی میشود و هر کدی درون آن تابع باشد اجرا میشود. حال ما باید این تابع را پیدا کنیم و کدمان که همان افزایش متغیر است را درون این تابع بنویسیم.
توابع مربوط به وقفهها درون فایل stm32f1xx_it.c وجود دارند، ما باید به این فایل برویم و تابع مربوط به وقفهی خارجی که بر روی پین PA1 رخ میدهد را پیدا کنیم. اسم تابع مربوط به این وقفه EXTI1_IRQHandler است. ما باید طبق کد زیر، درون تابع متغیر را افزایش بدهیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | void EXTI1_IRQHandler(void) { /* USER CODE BEGIN EXTI1_IRQn 0 */ /* USER CODE END EXTI1_IRQn 0 */ if (LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_1) != RESET) { LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_1); /* USER CODE BEGIN LL_EXTI_LINE_1 */ i++; /* USER CODE END LL_EXTI_LINE_1 */ } /* USER CODE BEGIN EXTI1_IRQn 1 */ /* USER CODE END EXTI1_IRQn 1 */ } |
درون تابع و در کد بالا، ما با یک شرط چک کردیم که وقفهای بر روی لاین 1 یا همان پین PA1 اتفاق افتاده است یا نه، و اگر وقفه اتفاق افتاد، ابتدا بیت مربوط به این وقفه را پاک کن و سپس به متغیر i، یک واحد اضافه کن. از این به بعد هر موقع وقفهای بر روی پین PA1 رخ داد؛ ISR به صورت خودکار فعال و تایع EXTI1_IRQHandler فراخوانی میشود و متغیر یک واحد افزایش مییابد.
در اینجا ممکن است بپرسید که دلیل گذاشتن شرط و همچنین پاک کردن بیت مربوط به وقفه چیست!
خب همانطور که گفتیم بعضی از وقفهها همگی با هم تنها یک ISR و یک تابع دارند و ما باید حتما درون تابع، با استفاده از شرط بررسی کنیم که کدام یک از وقفهها رخ داده است تا دستورات هر وقفه متناظر با همان وقفه اجرا بشوند.
بیت مربوط به وقفه را هم به این دلیل پاک میکنیم که با هر بار فراخوانی تابع، مدهای درون شرط وقفهای که رخ نداده است، اجرا نشود.
شاید توضیحات بالا کمی برایتان گنگ باشد، اجازه بدهید با یک مثال این موضوع را برای شما بیشتر توضیح بدهم.
همانطور که میدانید وقفههای خارجی شماره 5 تا 9 همگی با هم یک ISR و یک تابع دارند. پس هر کدام از وقفههای 5 تا 9 رخ بدهد، تنها یک تابع فراخوانی میشود. حال فرض کنید ما میخواهیم اگر وقفه شماره 5 رخ داد، متغیر A و اگر وقفه شماره 6 رخ داد، متغیر B یک واحد افزایش پیدا کند. اگر درون تابع، بدون هیچ شرطی متغیر A و B را افزایش بدهیم، با هر کدام از وقفههای شماره 5 و 6 هم متغیر A افزایش پیدا میکند و هم متغیر B. این عملکرد مدنظر ما نیست و هیچ کنترلی روی وقفهها هم نداریم، پس با این تفاسیر وجود شرط الزامی است.
اکنون در نظر بگیرید که ما برای هر وقفه درون تابع از یک شرط استفاده کردیم، اما بیتهای مربوط به وقفه را پاک نکردیم، چه اتفاقی رخ میدهد؟
فرض کنید وقفه شماره 5 رخ میدهد و تابع فراخوانی میشود و درون شرط مربوط به این وقفه، فقط متغیر A یک واحد افزایش پیدا میکند و بیت مربوط به این وقفه را پاک نمیکنیم.
در دفعه بعد فرض کنید وقفه شماره 6 رخ میدهد و تابع فراخوانی میشود، چه اتفاقی رخ میدهد؟ چون درون شرط مربوط به وقفه شماره 5، بیت مربوط به وقفه را پاک نکردیم، شرط مربوط به وقفه 5 همچنان برقرار است و با وجود اینکه فقط وقفه شماره 6 رخ داده است متغیر A دوباره افزایش پیدا میکند که مطلوب ما نیست. پس الزامی است که درون هر شرط بیت مربوط به وقفه را پاک کنیم.
حال درون main برنامه و در حلقه while باید کد زیر را قرار بدهیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 | if (i > 5 && State == 0) { LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_0); i = 0; State = 1; } if (i > 5 && State == 1) { LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_0); i = 0; State = 0; } |
خب همانطور که گفتیم درون فایل stm32f1xx_it.c و در تابع EXTI1_IRQHandler مشخص کردیم که با هر بار وقوع وقفه، متغیر i یک واحد افزایش پیدا کند. درون main برنامه هم که در بالا مشاهده میکنید کارهای کنترلی بر روی متغیر i که منجر به خاموش و روشن شدن LED میشود را انجام میدهیم.
تا ابنجا هر آن چیزی که در رابطه با وقفه خارجی نیاز بود را مفصلا شرح دادم. سایر وقفهها را نیز در قسمتهای مربوطه به صورت کامل توضیح خواهم داد.
در قسمت هشتم در رابطه با UART-Transmit صحبت خواهیم کرد.
برای دوستانی کار نمیکنه باید عرض کنم که در فایل main بالای تابع main عبارت ;int i = 0 و ;int State
و همچنین در فایل stm32f1xx_it.h زیر مکان اینکلود کتابخانه ها عبارت ;extern int i رو اضافه کنید
سلام مهندس اگه میشه یه توضیحی در مورد دیبانس هم بدید ممنون میشم
سلام دوست عزیز میتونید در این بخش درباره دیبانسینگ مطالعه کنید https://sisoog.com/what-is-switch-debouncing
همچنین میتونید سوال خودتون رو داخل فروم سیسوگ یعنی ask.sisoog.com مطرح کنید
استاد سلام
مهندس جون بیزحمت این یه دونه رو خودت یه بار اجرا . خروجی نمیده . خیلی هم باهاش کلنجار رفتم نشد که نشد . کامنت های اقا ضا و پاسخت هم دیدم ولی نمیشه که نمیشه .
سلام دوست عزیز
آیا پروژه رو از گیت هاب برداشتید و کار نکرد ؟
مشکلی که من به شخصه با توابع SPL و LL دارم اینه که منابع براشون کمه. به عنوان مثال اگر با توابع HAL بخوام یه LCD پروگرام کنم خیلی راحت درایور نوشته شدس پیدا میشه تو نت. ولی برای SPL و LL باید حتما خودت بنویسی که زمان زیادی میگیره ازت.
خوب spl که منسوخ شده ولی من سعی میکنم با چیزی که راحتم کار کنم و از hal به دلیل پیچیدگی بالایی که داره استفاده نمی کنم و معمولا درایوری که نیست رو بنویسم
سلام.
من خواستم کد رو تست کنم اما وقتی درون فایل stm32f1xx_it.c توی تابع EXTI0_IRQHandler میخوام متغیرم رو بهش اضافه کنم اما نمیشناستش. چیکار باید بکنم؟
سلام دوست عزیز. اگر متغیری رو به صورت گلوبال توی فایل main.c تعریف کردین باید توی فایل stm32f1xx_it.c با دستور extern توی این فایل بهش دسترسی بدین( و ترجیحا از نوع volatile تعریفیش کنین) مثلا توی کد همین پروژه از int i = 0; توی فایل main.c و extern int i; توی فایل stm32f1xx_it.c استفاده شده. میتونین از لینکی که آخر مقاله به گیت هاب ارجاع دادیم، به فایل پروژه هم دسترسی داشته باشین.
بسیار شیوا و جامع توضیح دادین
لایک
سپاس مسعود جان. خوشحالم که این مقاله مورد توجه شما قرار گرفته است.
سلام
تشکر از آموزش خوب. من برای اینکه بهتر بتونم کار کنم بلوپیل تهیه کردم اما کاش فقط یه آموزش ریزی هم درباره CH32f103 در سایت موجود بود. متاسفانه تراشه من از این نوع هست و به سختی تونستم فقط یه بار برنامه روش بریزم. منابع مفید و کافی ای نیست(اغلب به زبان چینی هست) علی رغم اینکه اخیراً تو بازار ایران بلو پیل با همین تراشه به خاطر قیمت مناسبش داره بیشتر میشه.
به زور تونستم فقط به Keil اضافهاش کنم…
سلام محمدرضا جان. والا پیشنهاد من اینه که چون در حال آموزش هم هستید کلا میکروکنترلرتون رو عوض کنید و یه دونه ST بخرید که حداقل اگه برنامهتون کار نکرد خیالتون از بابت سختافزار راحت باشه.
اما اگه میخواهید با همین میکروکنترلر کار کنید، زئوس تو مقالهای که در ادامه میفرستم، یه سری توضیحات داده که شاید به کارتون بیاد و مشکلتون رو حل کنه.
https://sisoog.com/2021/02/%d8%a7%d8%b2-%da%af%d8%b1%d8%a7%d9%86%db%8c-%d9%85%db%8c%da%a9%d8%b1%d9%88%da%a9%d9%86%d8%aa%d8%b1%d9%84%d8%b1-stm32-%d8%aa%d8%a7-%d9%85%db%8c%da%a9%d8%b1%d9%88%da%a9%d9%86%d8%aa%d8%b1%d9%84%d8%b1/
متشکرم کامین عزیز، اتفاقا اون مطلب رو هم خوندم.
خوشبختانه تونستم برنامه های مختلف رو روش بریزم و تست کنم(از ابتدا آموزشهای شما رو دوره کردم و کلی تغییر ایجاد کردم) اگر لازم هست من فایلی که باید به کیل اضافه بشه رو براتون بفرستم چون سخت پیدا شد.
فقط یه مسئله ای هست. یک مثال در بخش آموزش GPIO زده بودین(یک شمارنده با فشار دادن کلید)، من اون رو تغییر دادم و 2 کلید گذاشتم که اعداد کم و زیاد بشه و اونجا متوجه شدم یه اشکالی وجود داره.
برای خواندن پین فرمودین باید کل پورت رو بخونیم و با عدد مثلا 1<<0 & کنیم و … من این کار را برای پین 0 A و B میتونم انجام بدم ولی وقتی میخوام مثلا PB5 رو بهش کلید وصل کنم، فشردن کلید رو تشخصی نمیده!!!
5<<1 رو میزنم برای این پین. بارها هم چک کردم همه چی رو ولی فشردن این کلید توسط میکرو تشخیص داده نمیشه، نمیدونم مشکل از منه یا میکرو.
(البته میدونم روش بهتر استفاده از اینتراپت هست ولی جهت تمرین بیشتر این کار رو کردم.)
سپاس محمدرضا جان. به نظرم این فایل رو همینجا آپلود کنید تا اگه یه نفر دیگه هم این مشکل براش به وجود اومد بتونه استفاده بکنه.
در رابطه با سوال دومتون هم فکر کنم جای 1 و 5 را تو شیفت دادن جابهجا نوشتید (البته اینجا تو قسمت کامنتها، علامت شیفت به چپ و راست و اینا یکم چپه میشه و نمیدونم دقیق تو کدتون چی نوشتید) اما شما جای 1 و 5 را در کدتون جابهجا کنید احتمالا درست میشه. اگه درست نشد رو یه پایه دیگه تست کنید و نهایتا اگه دیگه درست نشد، کدتون را بفرستید تا بررسیش کنم.
مرسی
– نمیتونم آپلود کنم اینجا، این لینک دانلود کنید.
(فایل Keil.WCH32F1xx_DFP.1.0.1.pack اصل کاری هست و باید به کیل اضافه بشه)
https://1drv.ms/u/s!AoEbEnXq2rMDg-xdu3FDbLycfY-U0Q?e=nFN9ql
اگر وقت کنم سعی میکنم یه توضیحاتی بعدا بنویسم و ارسال کنم.
– توی کامنت << رو جابجا مینویسه. نفهمیدم مشکل چی بود که دیشب درست نبود اما الان رفع شد خوشبختانه!
سپاس از شما. همین لینک دانلود خوبه و کفایت میکنه.
مرسی این آموزش یکی از بهترین آموزش های سیسوگ هست. لطفا ادامش بدید 🙂
سپاس جاوید نازنین، شما لطف دارید. نگران نباشید این مجموعه شاید یکم زمان ببره اما سعی میشه تا حد قابل قبول سرفصلهاش کامل بشه. والا من همیشه سعی میکنم که هفتهای یه مقاله از این مجموعه منتشر بکنم، اما خب آخرش نمیشه و همون دو هفته یه بار میشه، عمده دلیلش هم اینه که خودم حساسیت زیادی به خرج میدم تا مقالات کیفیت خوبی داشته باشن.
سلام
خیلی آموزش هاتون خوبه، واقعا با حوصله نوشته شده، منتها مشکلی که هست فاصله انتشار پست هاتون بسیار زیاده. این سری آموزش تا به جایی برسه که برای خواننده کاربردی باشه باید حداقلا 15 تا پست منتشر شده باشه و این یعنی 1سال دیگه؟
کاش اگر آموزش ها آماده هست همرو منتشر کنین تا کسی که میخواد یاد بگیره بشینه پاش و کامل بخونه
تیکه تیکه و با این فاصله به درد الان کسی نمیخوره مگر اونکه همون یک سال دیگه که کامل شده بخواد شروع کنه.
تشکر
سلام دوست عزیزم. اول از همه ممنونم که با حمایت معنویتان من را حمایت میکنید تا ادامه این مسیر را با انرژیتر پیش بروم.
دوم اینکه سعی من بر این بوده است که حداقل هفتهای یک پست منتشر بشود، اما خب اگر بعضی اوقات خلاف این چیزی که میگویم پیش میرود، دلیلش مشغلههای زیاد است که در حال حاضر دارم چند کار مختلف و متفاوت را باهم پیش میبرم و واقعا تمرکز ذهنی برای نوشتن نمیماند، اما یکم فرصت بدهید حتما زمان را مدیریت میکنم تا شما هم بتوانید به نحو احسنت از این سری مقالات استفاده بکنید.
و در آخر هم یک خبر خوب بدهم، آن هم اینکه ویدئوهای این مجموعه آموزشی در حال ساخت هستند و تا الان چند قسمتی ساخته شده است که احتمالا در هفته بعد ویرایش و منتشرشان میکنم.
موفق و پیروز باشید.
ویدیو هم خیلی عالیه، ایشالا موفق باشین و ممنون بابت زحماتتون.
من نمیدونم چرا هر چی تو اینترنت میگردم هیچ آموزشی برای LL پیدا نمیکنم، فقط داکیومنت خود ST هست که HAl و LL رو توش گفته ولی فقط معرفی تمام توابع هست. برای F4 حدود 2100 صفحه است. ولی اصلا کاربردی نیست.
برای HAL خیلی زیاده ولی LL نیست، من حتی UART راه انداختم نتونستم پیدا کنم.
خود سایت ST هم هر چی میزاره برای HAL میزاره، شما مرجعی دارین برای LL معرفی کنین ممنون میشم.
سپاس از شما رضای نازنین.
من خودمم تو گوگل و یوتیوب اینا سرچ کردم هیچ آموزشی ندیدم، میشه گفت همین آموزشی که ما در حال ساختش هستیم اولین آموزش در این زمینه است.
راهی که خودم رفتم را بهتون میگم شاید به کارتون بیاد، من اون اوایل ابتدا با توابع HAL کار میکردم، از حق نگذریم ساختارمندی این کتابخونه بسیار عالی هستش اما یه مشکلی که وجود داره اینه که شما رو بسیار زیاد از سطح سختافزار دور میکنه که به نظر من مناسب یه مهندس الکترونیک حداقل در وهلهی اول نیست.
بعد این رفتم سراغ رجیستری، جوری که همه رجیسترها را هم خودم از ابتدا آدرسدهی میکردم و براشون استراکت مینوشتم و اینا و سپس بهشون مقدار میدادم که وقت خیلی زیادی رو ازم میگرفت.
بعدترش با همین رجیستری ادامه دادم اما خب از ماکروها و فایلهای از قبل تعریف شده CMSIS استفاده میکردم تا کارم سریعتر پیش برود. در نهایت هم اومدم سراغ توابع LL و کلا دیگه با این توابع کار میکنم. اگه بخوام این توابع رو توصیف کنم میگم که جمع همه خوبان رو یکجا با هم داره.
مرجع من که برای نوشتن این مقالات استفاده میکنم در واقع داکیومنتای ST و تجربهای که در کار با انواع توابع دارم هست، امیدوارم این توضیحات من به کارتون بیاد. موفق و پیروز باشید.
ممنون از توضیحات
اتفاقا سوال من هم بود که مرجع برای LL از کجا گیر بیاریم. من حتی کامنت ها رو هم با دقت میام میخونم که یاد بگیرم.
اما خب با سرچ در گوگل چیزی برای LL پیدا نکردم مثل دوستمون. البته نه اینکه آموزش شما کافی نباشه، اتفاقاً خیلی هم خوبه. ولی اگر مرجعی هست ممنون میشیم یه لینک دانلود بزارید.
ایشالا وقت بشه، خودم که یاد گرفتم بتونم به انگلیسی هم در بازنشرش کمک کنم.
یه دونهاید. ?
محمدرضا جان هیچ منبع شسته رفتهای برای آموزش LL نیست یا حداقل من ندیدم. تنها چیزی که ازش هست، همون فایلی هست که توابع LL و HAL را با هم توضیح داده.
خب مثلا شما برای اینکه بدونید چرا توابع LL سرعت بالایی دارن باید با مفهوم توابع inline آشنا باشید که برمیگرده به زبان C یا برای اینکه بدونید در چه مواقعی نباید از LL استفاده کنیم، باید با عملکرد انواع حافظهها در میکروکنترلر آشنا باشید.
در کل اینو میخوام بگم که نمیشه یه منبع خاصی براش معرفی کرد، همه چیز به هم پیوستس.
من هم سعی میکنم تا جای ممکن و تا جایی که وقت اجازه بده براتون آموزش بزارم و هر سوالی بود در این رابطه بپرسید جواب میدم.
مثل همیشه عالی بود. ممنون
خواهش میکنم دوست عزیز. سپاس از نظر مثبتتان.