در قسمت چهارم از آموزش STM32 با توابع LL، با واحد RCC آشنا شدیم و جزئیات و دلیل وجود کلاک در مدارات دیجیتال را بررسی کردیم، همچنین گفتیم که کلاک ورودی به میکروکنترلر چگونه در میکروکنترلر با استفاده از PLL افزایش و با استفاده از Prescaler کاهش مییابد. در ادامه مدار Reset که برای ریست کردن میکروکنترلر استفاده میشود را معرفی کردیم و گفتیم که با ریست کردن میکروکنترلر عملاً در برنامه چه اتفاقی خواهد افتاد و این عمل باعث چه چیزی خواهد شد. درنهایت هم یک برد آموزشی بسیار ساده اما کاربردی به اسم blue pill board را برای پیشبرد ادامهی آموزش به شما معرفی کردیم و حال میخواهیم در این قسمت شما را با GPIO-Output با توابع LL آشنا کنیم، با سیسوگ همراه باشید.
پس از گذشت چهار قسمت تازه میتوان گفت که از مقدمات عبور کردیم و قرار است که بهصورت جدی وارد فاز برنامهنویسی میکروکنترلر بشویم. پس با ما همراه باشید تا گام اول را به خوبی برداریم و نقشهی راه را برای ادامهی مسیر مشخص کنیم. همانطور که بیان شد چون این قسمت، اولین قسمتی است که بهطور جدی وارد فاز برنامهنویسی میکروکنترلر میشویم، میخواهیم از جنبههایی متفاوتی یک واحد جانبی را بررسی و تحلیل کنیم و یک سری نتایج را بهصورت مستدل بیان کنیم.
این تحلیلها بهگونهای ارائه خواهند شد که جامعیت داشته باشند و قابلیت تعمیم بهجاهای دیگر را نیز داشته باشند. درواقع هدف این است که ماهیگیری به شما آموخته شود تا به نقطهای برسید که نقشهی راه برایتان مشخص شود و اگر جایی نیاز بود که خودتان کاری را پیش ببرید، ادامهی مسیر برایتان هموار باشد.
اما در این قسمت قصد داریم چه مواردی را بررسی کنیم؟
اگر به خاطر داشته باشید در قسمت سوم یک کد برای GPIO نوشتیم و به شما قول دادیم که کد نوشتهشده را در قسمت مربوط به GPIO بهطور کامل بررسی و تحلیل کنیم.
پس مشخصاً در این قسمت قصد داریم که در رابطه با GPIO-Output با توابع LL صحبت کنیم.
اما آن بررسی و تحلیلهایی که گفتیم قرار است نقشهی راه را برای شما مشخص و ادامهی مسیر را هموار کند شامل چه چیزهایی میشود؟
ما در ابتدا کد GPIO با توابع LL را مینویسم و توضیح خواهیم داد که چگونه باید از این توابع در برنامه استفاده کرد. سپس همین کد GPIO را با استفاده از توابع HAL خواهیم نوشت و در هر دو حالت سرعت پین GPIO که خروجی کردیم را اندازهگیری و مقایسه میکنیم.
پس از مقایسه مشاهده خواهیم کرد که سرعت توابع LL بهطور چشمگیری بیشتر است. این تفاوت فاحش سرعت، چندین دلیل دارد که ما همهی این دلایل را بهطور کامل بررسی و تحلیل خواهیم کرد.
خب اکنون اجازه بدهید کمی در رابطه با خود GPIO و اینکه چه چیزی هست صحبت بکنیم.
GPIO-Output با توابع LL
بهطور خیلی ساده، وظیفهی اصلی واحد GPIO کنترل وضعیت پینهای میکروکنترلر است. ما با استفاده از رجیسترهای این واحد، میتوانیم ورودی یا خروجی بودن پین، مقدار و سرعت پین در حالت خروجی و … را مشخص کنیم. اما همانطور که میدانید قرار نیست که ما با استفاده از رجیسترها، وضعیت پینها را کنترل کنیم، بلکه با استفاده از توابع LL این کار را انجام خواهیم داد.
به کدی که در قسمت سوم نوشتیم دقت کنید:
1 2 3 4 | LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_0); LL_mDelay(500); LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_0); LL_mDelay(500); |
اولاً که این کد در حلقهی while برنامه نوشتهشده است، یعنی مداوم یک پین از میکروکنترلر 0 و 1 خواهد شد.
تابع LL_GPIO_SetOutputPin، برای High کردن پینی از میکروکنترلر که از قبل بهعنوان خروجی تنظیم شد (همان تنظیماتی که در نرمافزار STM32CubeMX انجام میدادیم درواقع پین را بهعنوان خروجی تنظیم میکرد) بهکار میرود.
بیایید به تعریف تابع برویم، ببینیم که در بدنهی تابع چه اعمالی انجامشده است که باعث میشود یک پین خروجی High شود.
به تعریف تابع توجه کنید:
1 2 3 4 | __STATIC_INLINE void LL_GPIO_SetOutputPin(GPIO_TypeDef *GPIOx, uint32_t PinMask) { WRITE_REG(GPIOx->BSRR, (PinMask >> GPIO_PIN_MASK_POS) & 0x0000FFFFU); } |
در تعریف تابع فقط عبارت زیر وجود دارد:
1 | WRITE_REG(GPIOx->BSRR, (PinMask >> GPIO_PIN_MASK_POS) & 0x0000FFFFU); |
حال باید به تعریف تابع WRITE_REG برویم، تا ببینیم که این تابع چه کاری انجام میدهد:
1 | #define WRITE_REG(REG, VAL) ((REG) = (VAL)) |
ورودی دوم، عبارتی شامل 0 و 1 منطقی است و ورودی اول یک رجیستر از GPIO است، یعنی رجیستر BSRR. پس برای High کردن یک پین میکروکنترلر، باید مقداری متناظر با همان پین در رجیستر BSRR نوشته شود.
این تابع بر اساس مستندات میکروکنترلر نوشتهشده است. در مستندات گفتهشده است که برای High کردن یک پین از میکروکنترلر باید در بیت متناظر با آن در رجیستر BSRR مقدار 1 منطقی قرار داده شود.
حال اگر شما در عبارت (PinMask >> GPIO_PIN_MASK_POS) & 0x0000FFFFU) که همان ورودی دوم تابع است بهجای PinMask یکی از مقادیری که در توضیحات تابع گفتهشده است را قرار بدهید، و عبارت بالا را محاسبه کنید میبینید که بیت متناظر با آن پین از میکروکنترلر که قرار است High شود مقدار 1 منطقی را دارد. ما در اینجا بهجای PinMask مقدار LL_GPIO_PIN_0 را قراردادیم.
توضیحات تابع کجاست؟
دو روش برای پیدا کردن توضیحات تابع وجود دارد، یک روش خواندن فایل Description of STM32F1 HAL and low-layer drivers – User manual، که هم توابع LL را توضیح میدهد و هم توابع HAL را. روش دیگر در نرمافزار است، قبل از تعریف هر تابع، در فایل مربوط به آن، توضیحات آن تابع نیز وجود دارد که میتوانید از این توضیحات استفاده بکنید.
مثلا در نرمافزار برای تابع LL_GPIO_SetOutputPin، قبل از تعریف تابع، توضیحات زیر آورده شده است:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | /** * @brief Set several pins to high level on dedicated gpio port. * @rmtoll BSRR BSy LL_GPIO_SetOutputPin * @param GPIOx GPIO Port * @param PinMask This parameter can be a combination of the following values: * @arg @ref LL_GPIO_PIN_0 * @arg @ref LL_GPIO_PIN_1 * @arg @ref LL_GPIO_PIN_2 * @arg @ref LL_GPIO_PIN_3 * @arg @ref LL_GPIO_PIN_4 * @arg @ref LL_GPIO_PIN_5 * @arg @ref LL_GPIO_PIN_6 * @arg @ref LL_GPIO_PIN_7 * @arg @ref LL_GPIO_PIN_8 * @arg @ref LL_GPIO_PIN_9 * @arg @ref LL_GPIO_PIN_10 * @arg @ref LL_GPIO_PIN_11 * @arg @ref LL_GPIO_PIN_12 * @arg @ref LL_GPIO_PIN_13 * @arg @ref LL_GPIO_PIN_14 * @arg @ref LL_GPIO_PIN_15 * @arg @ref LL_GPIO_PIN_ALL * @retval None */ __STATIC_INLINE void LL_GPIO_SetOutputPin(GPIO_TypeDef *GPIOx, uint32_t PinMask) { WRITE_REG(GPIOx->BSRR, (PinMask >> GPIO_PIN_MASK_POS) & 0x0000FFFFU); } |
همانطور که در بالا مشاهده میکنید ابتدا توضیحاتی در مورد عملکرد تابع آورده شده است و سپس پارامترهای ورودی را توضیح میدهد و میگوید که برای هر ورودی چه مقادیری میتوانند قرار بگیرند.
مثلاً برای اینکه PA0 مقدارش High شود باید عبارت LL_GPIO_PIN_0 بهعنوان دومین پارامتر در تابع قرار بگیرد.
البته شما تنها با خواندن توضیحات تابع نیز میتوانید یک واحد را راهاندازی کنید و نیازی به اینکه در تابع چه چیزی نوشتهشده است ندارید، اما بررسی تعریف و جزئیات تابع و همینطور ارتباطش با سختافزار و رجیسترها درک شمارا عمیقتر میکند.
در بعضیاوقات اصلاً شما اجازه و دسترسی به بدنهی تابع را ندارید و فقط میتوانید با توجه به توضیحات تابع از آن استفاده کنید، این مورد ازاینجهت گفته شد که فکر نکنید باید همیشه همهچیز تابع مشخص باشد و همیشه هم جزئیات تابع بررسی شود. اما خب در اینجا دسترسی به جزئیات تابع امکانپذیر است و شما در صورت نیاز میتوانید آنها را بررسی کنید. پیشنهاد میشود در ابتدای کار سعی کنید جزئیات توابع را به خوبی بررسی و تحلیل کنید و رابطهی توابع با سختافزار را پیدا کنید.
پس از تابع LL_GPIO_SetOutputPin به تابع LL_mDelay میرسیم که بهاندازهی عددی که در ورودیاش قرار میگیرد برحسب ms تأخیر ایجاد میکند. چون این تابع بر اساس systick timer نوشتهشده است در این قسمت جزئیات این تابع را بررسی نمیکنیم و فقط با نحوهی عملکردش که همان تأخیر به میزان عدد ورودی برحسب ms است، آشنا میشویم.
تابع دیگر، تابع GPIO_ResetOutputPin است که برای Low کردن پینی از میکروکنترلر که از قبل بهعنوان خروجی تنظیم شد بهکار میرود.
به بدنهی تابع توجه کنید:
1 2 3 4 | __STATIC_INLINE void LL_GPIO_ResetOutputPin(GPIO_TypeDef *GPIOx, uint32_t PinMask) { WRITE_REG(GPIOx->BRR, (PinMask >> GPIO_PIN_MASK_POS) & 0x0000FFFFU); } |
این تابع همان عملیات تابع LL_GPIO_SetOutputPin را انجام میدهد، اما بر روی رجیستر BRR. برای Low کردن پین میکروکنترلر باید مقداری متناظر با همان پین در رجیستر BRR قرار داده شود.
جزئیات این تابع به دلیل مشابهت با تابع LL_GPIO_SetOutputPin بررسی نمیشود.
پس تا اینجا نتیجه میگیریم که برای High کردن پین باید در رجیستر BSRR و برای Low کردن آن باید در رجیستر BRR مقدار 1 منطقی را در بیت متناظر با پین موردنظر نوشت.
اگر به خاطر داشته باشد در قسمت دوم گفتیم که سرعت توابع LL بسیار بیشتر از توابع HAL است و بررسی اینکه چرا سرعت توابع LL بیشتر است را به آینده موکول کردیم، اکنون همان آیندهای است که قولش را داده بودیم. پس با ما همراه باشید تا دلیل این امر را متوجه بشوید.
این بار به کد GPIO ای که با توابع HAL نوشتهشده است توجه کنید:
1 2 3 4 | HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); HAL_Delay(500); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); HAL_Delay(500); |
این کد دقیقاً عملکرد همان کدی را دارد که با توابع LL نوشتیم.
ابتدا تست را انجام میدهیم تا اختلاف سرعت توابع LL و HAL را ببینیم، سپس توابع HAL را نیز بررسی خواهیم کرد. اما قبل از تست، به سناریوی تست که در ادامه ذکر میگردد توجه کنید.
سناریوی تست به این صورت است که میخواهیم سرعت 0 و 1 شدن یک پین از میکروکنترلر را با استفاده از لاجیک آنالایزر رصد کنیم.
درواقع ما تابع Delay را به این دلیل که چشم قادر به دیدن 0 و 1 شدن پین میکروکنترلر بر روی LED باشد، بهکار بردیم. حال که قرار است با استفاده از لاجیک آنالایزر نتیجه را رصد کنیم دیگر نیازی به تابع Delay نیست.
و نکتهی دیگر اینکه هر سری که شرط حلقهی while چک میشود باید زمانی صرف شود. همین زمانی که صرف چک کردن شرط حلقهی while میشود، بر روی سناریوی تست اثر بد میگذارد. برای رفع این مشکل کدی که درون حلقهی while مینویسیم باید بهصورت زیر باشد:
1 2 3 4 5 6 7 8 9 | LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_0); LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_0); LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_0); LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_0); LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_0); LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_0); . . . |
درواقع ما با تکرار کد، اثر زمانِ بررسی شرط حلقهی while را کم میکنیم. ما در بالا فقط سه بار کد را تکرار کردیم، اما اگر خودتان خواستید تست را انجام بدهید باید تعداد تکرار را بسیار بیشتر باشد.
در هر دو حالت؛ برنامهی نوشتهشده را بر روی حافظهی Flash میکروکنترلر دانلود میکنیم و با استفاده از لاجیک آنالایزر سرعت پین میکروکنترلر را اندازه میگیریم.
ابتدا به تصاویر زیر دقت کنید:
همانطور که مشاهده میکنید، سرعت با توابع LL تقریباً 5.6 برابر بیشتر از توابع HAL است!
آیا این امر اتفاقی بوده است؟ مشخص است که خیر.
چندین عامل مختلف باعث شده است که سرعت تا این اندازه بیشتر شود، در ادامه همهی این عوامل را بررسی میکنیم.
بهطورکلی اگر بخواهیم تنها یک دلیل ارائه بدهیم، آن دلیل چیزی نیست بهجز نحوهی پیادهسازی توابع LL و HAL. اما خود این دلیل جزئیاتی دارد که باید خیلی دقیق بررسی شود تا مسئله به خوبی روشن شود.
اگر به برنامهی نوشتهشده با توابع LL توجه بکنید، میبینید که برای 0 و 1 کردن پین خروجی دو تابع LL_GPIO_SetOutputPin و LL_GPIO_ResetOutputPin بهکاررفته است و در این دو تابع از دو رجیستر BSRR و BRR استفادهشده است. اما در برنامهی نوشتهشده با توابع HAL همین کار را تنها با یک تابع به اسم HAL_GPIO_WritePin انجام داده است و در ابن تابع فقط از رجیستر BSRR استفادهشده است!
کار این دو رجیستر چیست؟ رجیستر BRR یک رجیستر 16 بیتی است که برای 0 کردن پینهای میکروکنترلر بهکار میرود. و رجیستر BSRR یک رجیستر 32 بیتی است که 16 بیت اول آن برای 1 کردن و 16 بیت دوم آن برای 0 کردن پینهای میکروکنترلر بهکار میرود.
درواقع ST گفته است که برای 1 کردن پینهای میکروکنترلر از 16 بیت اول رجیستر BSRR و برای 0 کردن پینهای میکروکنترلر از رجیستر BRR استفاده کنید، اما اگر به هر دلیلی نمیخواهید که از رجیستر BRR استفاده بکنید، هم 0 کردن و هم 1 کردن پینها با استفاده از رجیستر BSRR امکانپذیر است.
با توضیحات و عکسهای بالا نتیجه میگیریم که باوجود رجیستر BSRR، دیگر نیازی به رجیستر BRR نیست. بله این نتیجه درست است، اما به هزینهی اینکه سرعت را فدا کنیم. کاری که دقیقاً در توابع HAL انجامشده است.
ابتدا به پیادهسازی تابع HAL_GPIO_WritePin توجه کنید:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState) { /* Check the parameters */ assert_param(IS_GPIO_PIN(GPIO_Pin)); assert_param(IS_GPIO_PIN_ACTION(PinState)); if (PinState != GPIO_PIN_RESET) { GPIOx->BSRR = GPIO_Pin; } else { GPIOx->BSRR = (uint32_t)GPIO_Pin << 16U; } } |
در این تابع، ابتدا شرط نابرابری PinState با GPIO_PIN_RESET چک میشود. این شرط درواقع بررسی میکند که آیا حالت ورودی مدنظر، RESET است یا خیر. درصورتیکه PinState برابر با RESET نباشد به این معنی است که قصد 1 یا SET کردن پینها راداریم. پس مقدار واردشده در پارامتر GPIO_Pin، باید در 16 بیت اول رجیستر BSRR بنشیند. در غیر این صورت، PinState برابر با RESET است و درنتیجه قصد صفر یا RESET کردن پینها را داشتهایم. پس از دستور شیفت بیتی استفادهشده است، (GPIO_Pin << 16U) تا مقدار GPIO_Pin، در 16 بیت دوم رجیستر BSRR قرار بگیرد.
در اینجا همین استفاده از دستور شیفت، موجب صرف زمان بیشتر و کاهش سرعت این تابع HAL میشود.
عامل دیگر این اختلاف سرعت این است که توابع LL به شکل توابع معمولی پیادهسازی نشدهاند، بلکه این توابع بهصورت INLINE پیادهسازی شدهاند! طبق توضیحات زیر:
در زبان C توابع به دو صورت در برنامه بهکاربرده میشوند:
- روش اول این است که وقتی برنامه به تابع موردنظر رسید، برنامه آن تابع را فراخوانی میکند.
- روش دوم این است که قبل از کامپایل، بدنه یا کدی که درون تابع نوشتهشده است در محلی از برنامه که از تابع استفادهشده است، کپی میشود و دیگر در زمان اجرای برنامه هیچ تابعی فراخوانی نمیشود. به این نوع توابع، توابع INLINE میگویند.
سرعت توابع INLINE بیشتر از توابع معمولی است و اگر دقت کرده باشید در تعریف توابع LL از عبارت STATIC_INLINE_ استفادهشده است که نشان از INLINE بودن این توابع دارد.
پس عاملی که باعث اختلاف سرعت فاحش شدند:
- دستورات شرطی
- شیفت بیتی
- توابعی که بهصورت INLINE پیادهسازی شدند
البته عوامل تأثیرگذار دیگر مثل ساختارهای شیگرائی که در توابع HAL بهوفور و بیشتر از توابع LL یافت میشود نیز وجود دارد که بنا به اهمیت کمتر از عوامل ذکرشده به آنها پرداخته نشده است.
ما در این مقاله از جهات مختلفی به شرح مسائلهی GPIO-Output با توابع LL که ممکن است تابهحال برایتان پیشآمده باشد و جوابشان را نمیدانستید یا در آینده با این مسائله برخورد کنید، پرداختیم. در قسمتهای بعد سعی میشود تمرکز بر روی نکات دیگری گذاشته شود تا هر آن چیزی که برای کار کردن با میکروکنترلرها نیاز است پوشش داده شود. اما از آنجایی که سعی شده است اصول بهگونهای بیان شود که قابلتعمیم به سایر بخشها نیز باشد، انتظار میرود که پس از خواندن این مقالات خودتان تحلیل و تمرین کنید تا مهارتتان هرچه بیشتر شود. و اگر سوالی یا مشکلی داشتید با ما در میان بگذارید.
در قسمت ششم در رابطه با GPIO در حالت Input صحبت خواهم کرد.
سلام خیلی ممنون از مقاله فوق العاده خوبتون بسیار جامع و کامل بود و از مطالعه اش لذت بردم
بازم ممنون بابت تلاش و نوشتن این مطالب زیبا
بسیار خوشحالم که چندساله با آموزش های شما و سایت عالی تون آشنا شدم واقعا درجه یک هستید در هر ضمیمه ای واقعا آموزش هاتون به هیدن جم تمام عیار من لذت بردم و امیدوارم بقیه عزیزان نیز مانند بنده لذت برده باشند
فقط یک سوال کوچکی داشتم دلیل اینکه من از این توابع در میکروکنترلر stm32f401ccu6جوابی نمیگیرم چیست ممنون میشم پاسخ دهید.
سلام دوست عزیز
ممنونم برای همراهی شما یا ما
مساله ای که باید به اون دقت کنید اینه که سری های مختلف ممکنه کتابخانه ها و دستورات مقداری متفاوت باشند برای همین بهتره مثال های مروبط به آن خانواده رو بررسی کنید تا بهتر متوجه ربشه مشکل بشید
ببخشید توابع LL روی میکروکنترلر سری f4 کار نمیکنه دلیلش چیه ؟
کار میکنه ولی LL مخصوص خودش رو باید دانلود کنید.
اموزشتون بی نظیر من خیلی دوست دارم آموزش های که کمباین سایت شمام منبعشه فقط یک سوال من با این توابع در هر سری جواب گرفتم ولی تو میکروکنترلر stm32f401ccu6اصلا کار نمیکنه مشکلش چیه امکان داره پاسخ بدید
آیا کتابخانه مخصوص همین سری رو دانلود کردید ؟
خیلی آموزش هاتون بی نظیر سیسوگ واقعا یک سوپر سایت خفن و بی نظیر پر از محتوا و آموزش های تک که نظیرش نیست .
لطف دارید شما دوست عزیز
سلام
بسیار عالی
دست مریزادبه همت و روحیه پاسخگویت
خیلی آقائی
متن من ناقص ارسال شده شاید به خاطر طولانی بودن متن
بعد استفاده از توابع LL
بصورت رجستری پین روشن و خاموش کردم
; GPIOA->BSRR|=(1<BRR|=(1<<2)
حتی به جای شیفت از 0x4نیز استفاده کردم
فرکانس خروجی 1Mhzبود و زمان بالا و پایین بودن پین 0.5usبود
علت کند بودن دستورات رجستری به LLچیه
سلام
با تشکر از مقاله مفید و عالیتون ..ممنونم
من طبق فرمایش شما در قسمت سوم مقالتون طبق تصویر کلاک تنظیم کردم که 16Mhzهست
اول تست خودم با روشن و خاموش کردن پین pa2شروع کردم
;LL_GPIO_SetOutputPin(GPIOA,LL_GPIO_PIN_2)
;LL_GPIO_ResetOutputPin(GPIOA,LL_GPIO_PIN_2) که تقریبا 1200 بار این کد داخل حلقه while برنامه تکرار کردم
نتایج فرکانس خروجی پین 2.667Mhz…….on pin time 0.125us…….off pin time 0.25us
حالا در درون همین برنامه بدون تغییرات کلاک و برنامه به جای دستورات بالا دستورات زیر جایگزین کردم
;GPIOA->BSRR|=(1<BRR|=(1<BSRR|=0x4
;GPIOA->BRR|=0x4
نتایج همان بود
حالا سوال من این هست ایا چطور توابع LL از دستورات رجستری سریعتر هست و این اتفاق افتاد.
ممنون میشم راهنمایی کنید
خوب این به این دلیله که برنامه رجیستری رو اشتباه نوشتید
برای استفاده از BRR و BSRR نیاز نیست که چیزی رو OR کنید – خود این OR کردن سیکل ماشین اضافی میبره
اگر دیتاشیت قطعه رو مطالعه کنید به صراحت گفته این دو رجیستر فقط نوشتنی هستند و خواندنی نیستند و مشکل دقیقا همینجاست که شما دارید مقدارش رو میخونید و بعد مینویسید که در واقع نیازی به این کار نیست
ممنونم از پاسخ گوییتون
یعنی set & reset به صورت زیر بنویسم
GPIOA->BSRR=0x2;
GPIO->BRR=0x2;
درسته؟
بله درسته
خداقوت واقعا مفید و عالی بود
سپاس علی جان.
سلام روزتون بخیر
ضمن تشکر از زحماتی که برای تولید این محتوای جذاب و کاربردی انجام دادین
یک سوال داشتم از شما اینکه من با توجه به بررسی که از reference manual میکرو مورد استفادم داشتم STM32f429 رجیستری تحت عنوان BRR برای این میکرو نبود و من کد تستی که فرموده بودین رو هم با استفاده از کتابخانه HAL و هم با LL تست کردم و خروجی یکسانی داشتن و در هر دو کتابخانه برای ست و ریست کردن خروجی از رجیستر BSRR استفاده شده بود.
سوالی که برای من ایجاد شده بود این بود که میخواستم بدونم علت این مسئله احتمالا ورژن firmwareمورد استفاده شما بوده یا سری میکرویی که استفاده کردین متفاوت هست؟
سلام علی جان. سپاس از نظر مثبت شما. بله شما درست میفرمائید، من همین الان بررسی کردم، ظاهرا در میکروکنترلر F4 رجیستر BRR وجود ندارد و هر دو عمل ست و ریست با استفاده از رجیستر BSRR انجام میشود.
نه این رجیستر به صورت فیزیکی در میکروکنترلر موجود نیست و ربطی به ورژن فریمور ندارد.
البته حتی اگر رجیستر BRR هم وجود نداشته باشد، بنا به Inline بودن توابع LL و یک سری موارد دیگر، حتما سرعت توابع LL بالاتر است و نباید نتیجه یکسان باشد. احتمالا جایی اشتباه انجام دادهاید.
سلام
من توی راه اندازی logic analyser مشکلی دارم. برای گرفتن وضعیت یک پایه باید متغیر رو چی تعریف کنم؟ من چیزهایی مثل PORTA.2 یا GPIOA.2 رو امتحان کردم ولی نشد.
سلام دوست عزیز. اسم متغیر که مهم نیست، هر اسمی میتونید انتخاب کنید. موارد دیگه مثل فرکانس نمونه برداری و اینا رو بررسی کنید ببینید مشکل کجاست.
البته اگه دقیقتر توضیح بدید که کجا به مشکل خوردید بهتر میتونم کمکتون بکنم.
16u یعنی چی؟
چه فرقی با 16 می کنه؟
سعید جان، وقتی شما یک عدد صحیح رو بدون پسوند مینویسید دیفالت به صورت integer، و وقتی یک عدد اعشاری را بدون پسوند مینویسید دیفالت به صورت double در نظر گرفته میشود.
حال ما بنا به نیاز؛ که میتونه مدیریت حافظه، جلوگیری از تبدیلات ضمنی، بهینهسازی برنامه و … باشه میتونیم پسوندی به این اعداد بدهیم تا به آن صورت دیفالتی که توضیح دادم در نظر گرفته نشوند. مثلا در همینجا وقتی از حرف “U” استفاده میکنیم به معنای unsigned است.
سلام من الان ی کم میکروst رو بلدم اما مشکلی که دارم اینه که مثلا برای ساخت pwm تو یوتیوب فیلم هست مثل اون انجام میدم ولی مثلا در حالت one pulse فیلمی نیست من نمی تونم راش بندازم یعنی نمی دونم باید از چه مستنداتی از شرکت استفاده کنم لطفا راهنمایی کنید چطوری باید ی قسمت از میکرو رو راه بندازم بدون این که دید قبلی از اون واحد داشته باشم یعنی هیچی ندونم ازش اما ی فایلی که به تر تیب بگه باید چه کار کنم
سلام پارسای نازنینم.
بهترین منبع برای یادگیری هر میکروکنترلری، خواندن مستنداتی است که شرکت سازندهی آن میکروکنترلر ارائه میدهد.
هر میکروکنترلر دارای مستندات زیادی است، اما شما در وهلهی اول تنها به بعضی از آنها نیاز پیدا خواهید کرد.
مثلا در میکروکنترلرهای شرکت ST در وهلهی اول تنها به سه تا از آنها یعنی دیتاشیت، رفرنس منوال و دیسکریپشن توابع نیاز دارید.
در گام اول شما باید دیتاشیت را بخوانید تا با کلیات میکروکنترلر مثل مقادیر حافظه، انواع باسها، پریفرالها، پروتکلهای پشتیبانی شده، مشخصات الکتریکی و … آشنا شوید.
پس از اینکه یک ذهنیت و کلیتی از میکروکنترلر بدست آوردید باید فایل رفرنس منوال را بخوانید، در این فایل به صورت طبقهبندی شده هر قسمت شرح داده شده است و شما با خواندن این فایل متوجه خواهید شد که مثلا برای راهاندازی UART باید در رجیسترهای مربوط به این واحد چه مقادیری را به چه ترتیبی بنویسید و در این حین چه اتفاقاتی رخ خواهد داد.
خب شما تا الان با خواندن رفرنس منوال متوجه شدید که چگونه باید یک واحد را راهاندازی کنید، اما اینکه با چه ابزاری این کار را انجام بدهید هنوز مشخص نیست!
راههای غیر معقول زیادی وجود دارند که من در اینجا نام نمیبرم، اما سه راه معقول رجیستری، توابع LL و توابع HAL وجود دارند که شما میتوانید از این راهها استفاده کنید.
پیشنهاد من استفاده از توابع LL در ابتدای کار است، دلایلش را میتوانید در مقاله مربوطه بخوانید. شما با خواندن فایل رفرنس منوال و فایلی که توابع LL را توضیح داده است و همچنین انطباق این دو فایل باهم، به راحتی میتوانید قسمتهای مختلف یک میکروکنترلر را راهاندازی کنید.
خوب بود
ممنون
سپاس از شما دوست عزیز.
درود خوب بود ولی باید بیشتر میرفتی تو جزئیات برنامه نویسی باGpio
درود نوید نازنین. بله جزئیات بسیار بیشتری وجود داره که میشه به اونا پرداخت اما خب در وهلهی اول گفتن این نکات ضرورتی نداره و باعث شلوغی و سردرگمی میشه.
اما خب سعی میکنم در ویدئوهایی که به موازات این مجموعه آموزشی تدوین میکنم، نکات بیشتری را توضیح بدم.
خدا خیرتون بده اگ ویدئو های و مقالات بیشتری در مورد میکروARMبزارید ممنون میشم
حتما حتما نوید عزیز.
واقعا چرا من زودتر با سیسوگ آشنا نشدم 🙁
احساس میکنم زندگیم رو هدر دادم.
بسیار آموزنده بود.
سپاس.
شما لطف دارید محمد جان. هدر رفتن هم بخشی از زندگی است که همهی ما با تصمیمات اشتباه تجربهاش را داشتهایم، مهم این است که در وقت مناسب جلویش را بگیریم.
خیلی جالب و آموزنده بود.
منتظر قسمت بعدی هستیم.
خدا قوت … ممنون.
سپاس امیر نازنین.