خدایا با نام تو و برای تو سلام و عرض ادب خدمت دوستان همراه، مهدی حسن زاده آملی هستم با جلسه دوم آموزش کاملا رجیستری stm32f10x درخدمت شما هستم. در مطالب جلسهی اول موضوع بحث ما درمورد شیوه استفاده از پورتهای ورودی-خروجی در مد خروجی بود که در این پست میخواهم درمورد مد ورودی و حالتهای اینتراپت و معمولی صحبت کنیم. خب، برای ورودی کردن یک پین، اول باید منطق ورودی بودن یک پین رو مشخص کنیم که طبق گفتههای جلسه قبل ما نیاز داریم تا بیتهای رجیستر CRL-H را طبق نیاز تغییر دهیم تا بتوانیم از پین مورد نظر به منظور ورودی بهره ببریم.
این کد برای clearکردن پین صفرم استفاده میشود.
این کد هم ورودی کردن پین مورد نظر را انجام میدهد (floating).
این کد برای clear کردن پین صفرم استفاده میشود.
این کد هم ورودی کردن پین مورد نظر را انجام میدهد (PULL-DOWN).
برای پول داون کردن نیز از این کد استفاده میکنیم.
این کد برای clear کردن پین صفرم استفاده میشود.
این کد هم ورودی کردن پین مورد نظر را انجام میدهد (PULL-DOWN)
برای پول آپ کردن نیز از این کد استفاده میکنیم. حال که تنظیمات پین مورد نظرمون را درست انجام دادیم ، میرویم سروقت استفاده از پین موردنظر. رجیستر مورد استفاده برای خواندن مقدار در حالت ورودی GPIOX-IDR است که شیوهی استفاده این رجیستر به این حالت است:
در حالت عادی رجیستر IDR به صورت 0x0000000000000000 است که با & کردن 0x0000000000000001 مشخص میکنیم که این بیت یک شده است (یعنی ANDبیتی) خب من یه کد ساده مینویسم که نشون بدم پین موردنظرم یک شده یا نه و اگر یک شد led را روشن کنه در غیر این صورت خاموش کنه
این از پین ورودی اما یه زمانی لازمه ما از یک پین به صورت اینتراپت استفاده کنیم تا بتوانیم بر اثر تحریک خارجی عملیات درحال اجرای CPU را متوقف نکنیم.
نام اینتراپت مورد استفاده رو در قسمت هدر میکرو خواهیم یافت. خب دوستان اینو تا یادم نرفته بگم که اینتراپت چیکار میکنه ،مطمئنم میدونید اما گفتنش بد نیست! زمانی که اینتراپت خارجی و یا اینتراپت داخلی (پریفرالها) اتفاق بیافته برنامه ای که CPU درحال اجراش بود رو رها میکنه و برنامه ای که در تابع مخصوص اینتراپت نوشته شده رو اجرا میکنه و بعد از اتمام کدهای تابع اینتراپت CPUب رمیگرده و برنامه قبلی خودش رو ادامه میده. تابع اینتراپت برای اینتراپت خارجی به زیر تعریف میشود: (نام هر تابع اینتراپت در داخل فایل startup قرار دارد)
ما در stm32f10x به تعداد 15 اینتراپت خارجی دراختیار داریم که در اکثر پایههای میکرو قابل دسترسی هستند. نکته مهم: در این سری میکرو برای اینتراپتهای خارجی 0 تا 4 هرکدام تابعهای وقفه جداگانه در اختیار ما است اما از اینتراپت خارجی 5 تا 9 فقط یک تابع وقفه و از اینتراپتهای 10تا 15 هم یک تابع وقفه در اختیار داریم. به طور مثال اگر بخواهیم همزمان از اینتراپت خارجی 5 و 8 و 9 استفاده کنیم به صورت زیر عمل خواهیم کرد:
توضیحات رجیسترهای بالا رو جلوتر خواهم گفت، اما شیوهی نوشتن تابع وقفه رو باهم یاد بگیریم:


خب این چیزی که از هر عکس بالا مشخصه AFIO_EXTICRX هر کدام چهار پین را برای هر پورت مشخص میکند. طریقه کد نویسی هم به صورت زیر است:
X شماره رجیستر AFIO_EXTICRx است. خب کد بالا به این معناست که از داخل رجیستر EXTICR1 پین شماره 0 از پورت A، که این (AFIO_EXTICR1_EXTI0_PA) جمله به صورت define در داخل هدر میکرو وجود دارد. اما از نظر بیتی جمله AFIO_EXTICR1_EXTI0_PA به صورت زیر نوشته میشود:
اگر بخواهیم پورت C را برای اینتراپت 7 تنظیم کنیم به صورت زیر عمل میکنیم (طبق تصویر AFIO_EXTICR2):
حال میرویم سر وقت رجیسترهای مختص اینتراپت خارجی:
این رجیستر برای به این منظور استفاده میشود که در هر پایهای اینتراپت بخواهیم داشته باشیم اون پایه رو فعال کنیم.

این رجیستر برای این منظور استفاده میشود تا پین اینتراپت خارجی ما در لبه بالا رونده عکس العمل ازخودش نشان دهد.
این خط برای clear کردن لبه پایین رونده استفاده میشود.
این خط برای فعال کردن لبه بالا رونده استفاده میشود.
این رجیستر برای این منظور استفاده میشود تا پین اینتراپت خارجی ما در لبه پایین رونده عکس العمل ازخودش نشان دهد.
این خط برای clear کردن لبه بالا رونده استفاده میشود.
این خط برای فعال کردن لبه پایین رونده استفاده میشود.
این رجیستر تشخیص میدهد که وقفه در کدام پایه اتفاق افتاده است که در تابع وقفه استفاده میشود.
بعد از تشخیص باید با یک کردن در این رجیستر عمل clear به صورت نرم افزاری صورت بگیرد تا اینتراپتهای بعدی را هم تشخیص دهیم برای پایه موردنظر.
نکته همیشگی: برای استفاده از هر پریفرالی حتما باید کلاک اون پریفرال رو فعال کنید واِلله برنامه شما اصلا عمل نمیکنه.
نکته: برای استفاده از اینتراپت خارجی باید حتما پین مورد نظرمون را اول ورودی کنیم.
امیدوارم موفق باشید.
حالت input-floating:
در این حالت پین ما با هر نویز و یا ولتاژ خواسته و یا ناخواسته تحریک میشود و تغییر حالت میدهد که برای جلو گیری از این اتفاق ناخوشآیند از مقاومتهای پول خارجی استفاده میکنیم و رجیستر CRL-H ما هم در این حالت، عدد 4 را به خود اتخاذ میکند.1 | GPIOA-> CRL &= ~ 0x0000000F; |
1 | GPIOA-> CRL &= ~ 0x00000004; |
حالت INPUT-PULL-DOWN:
در این حالت پین موردنظر با اعمال ولتاژ مثلا 3.3 ولت تحریک میشود و این پین در حالت عادی صفر است. خب برای تنظیم این حالت میبینیم که دیتاشیت به ما میگه بیت CNF1 را برابر یک قرار میدهیم و همچنین رجیستر ODR را هم صفر میکنیم تا خروجی به حالت PULL Down قرار بگیرد.1 | GPIOA-> CRL &= ~ 0x0000000F; |
1 | GPIOA-> CRL &= ~ 0x00000008; |
1 | GPIOA->ODR |= ~(1<<0); |
1 | GPIOA->ODR |= (0<<0); |
حالت INPUT-PULL-UP:
در این حالت پین موردنظر ما با اعمال صفر ولت تحریک میشود و این پین هم در حالت عادی برابر VCC است. در این حالت هم طبق دیتاشیت و عکس بالا CNF1 را هم یک قرار میدهیم اما رجیستر ODR را برای پین مورد نظر یک میکنیم.1 | GPIOA-> CRL &= ~ 0x0000000F; |
1 | GPIOA-> CRL &= ~ 0x00000008; |
1 | GPIOA->ODR |= (1<<0); |
در حالت PULL-DOWN
1 2 3 4 5 | If(GPIOA->IDR & (1<<0)) { کدی که میخواهیم بعد از فشردن کلید اجرا شود } |
در حالت PULL-UP
1 2 3 4 5 | If(! (GPIOA->IDR & (1<<0))) { کدی که میخواهیم بعد از فشردن کلید اجرا شود } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <stm32f10x.h> int main (void) { RCC -> APB2ENR |= (1<<2); GPIOA -> CRL &= ~(0x000000FF) ; GPIOA -> CRL |= (0x00000038); GPIOA -> ODR |=(1<<0); while(1) { if( !(GPIOA -> IDR & (1<<0))) { GPIOA -> BSRR |= (1<<1); while(!(GPIOA -> IDR & (1<<0))); } else{ GPIOA -> BRR |= (1<<1); } } |
interrupt:
در فعال سازی اینتراپت چند پارامتر و پیکربندیای رو باید انجام بدیم.فعالساز اینتراپت مورد (پین و یا پریفرال) نظر به صورت سراسری:
1 | NVIC_EnableIRQ(نام اینتراپت مورد استفاده ); |
1 2 3 4 | Void EXTI0_IRQHandler (void) { } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | Void EXTI9-5_Handler (void) { If(EXTI -> PR & (1UL << 5)) { //your code EXTI -> PR |= (1UL << 5); } If(EXTI -> PR & (1UL << 8)) { //your code EXTI -> PR |= (1UL << 8); } If(EXTI -> PR & (1UL << 9)) { //your code EXTI -> PR |= (1UL << 9);//clear interrupt flag } } |
تنظیمات AFIO:
خب با این رجیستر میتونیم مشخص کنیم که وقفه 0 در چه پورتی (A یا B یا …) قرار بگیرد. در قسمت تنظیمات AFIO ما چهار رجیستر داریم که این رجیسترها عبارتند از:External interrupt configuration register 1 (AFIO_EXTICR1)
External interrupt configuration register 2 (AFIO_EXTICR2)
External interrupt configuration register 3 (AFIO_EXTICR3)
External interrupt configuration register 4 (AFIO_EXTICR4)
1 | AFIO -> EXTICR[x-1] |= AFIO_EXTICR1_EXTI0_PA; |
1 | AFIO -> EXTICR[1-1] |= (0x0 << 0); |
1 | AFIO -> EXTICR[2-1] |= (0x2 << 12); |
Interrupt mask register (EXTI_IMR):
1 2 | EXTI -> IMR |= (1UL << 0);// for pin 0 interrupt EXTI -> IMR |= EXTI_IMR_M0; // for pin 0 interrupt |
Rising trigger selection register (EXTI_RTSR):
1 | EXTI -> FTSR &=~ EXTI_FTSR_TR0; |
1 | EXTI -> RTSR |= EXTI_RTSR_TR0; |
Falling trigger selection register (EXTI_FTSR):
1 | EXTI -> RTSR &=~ EXTI_RTSR_TR0; |
1 | EXTI -> FTSR |= EXTI_FTSR_TR0; |
Pending register (EXTI_PR):
1 2 3 4 5 | If(EXTI -> PR & (1UL << 5)) { //your code EXTI -> PR |= (1UL << 5); } |
1 | EXTI -> PR |= (1UL << 5); //clear |
1 | RCC -> APB2ENR |= RCC_APB2ENR_AFIOEN; |
سلام
خیلی ممنون از مطالب مفید و اموزنده تون
ایشالله که بقیه اموزش رو هم قرار بدین
من سعی کردم کد وقفه رو برای پایه های A0 و A1 بنویسم که برای بقیه به اشتراک میگذارم:
#include
void EXTI0_IRQHandler (void)
{
EXTI-> PR=0x00000001; // 1<BSRR|=(1<<1);
int i;
for(int i=0;iBRR|=(1< APB2ENR |= (1< CRL &= ~(0x000000FF) ; //Clear PinA0 and PinA1
GPIOA -> CRL |= (0x00000038); //Enable PinA0 as input and PinA1 as output
GPIOA -> ODR |=(1<ODR |= (1< APB2ENR |= RCC_APB2ENR_AFIOEN; //Enable clock for interrupt (AFIO EN) 1< EXTICR[0] |= AFIO_EXTICR1_EXTI0_PA; //AFIO -> EXTICR[0] |= (0x0 < IMR |= 1 < RTSR |= 1 << 0;
//——————————————-
NVIC_EnableIRQ(EXTI0_IRQn);
//——————————————-
while(1)
{
}
return 0;
}
سلام ممنون از شما دوست عزیز
سلام.خسته نباشید و خدا قوت
سوال بنده این هست که منظور از ul در کنار عددی که داخل شماره بیت رجیستر قرار میگیره چیه؟ایا unsighnd large منظورش هست؟یا اینکه اون عدد در اون رجیستر اگر بیشتر از یک باشه به سمت چپ شیفت پیدا میکنه؟
سلام این عبارت یه کامپایلر میگه که نوع این عدد unsigned long باشه.
چرا ادامه ندادید ؟
ادامه پیدا میکنه دوست عزیز 🙂
سلام مهدی هستم نویسنده پست :متاسفانه درگیر خدمت سربازی و …بودم
بزودی ادامه خواهم داد مطمئن باشید
ببخشید بابت تاخیر
آقا مهدی ما هم منتظر ادامه مطلب هستیم
لطفا ادامه بدین . و اینکه نمی شه این فایل هارو به صورت پی دی اف بشه دانلود کرد چون همیشه که اینترنت در دسترس نیست اگه بشه خیلی خوب می شه 🙂 ممنون
سلام چرا پستهای مربوط به اموزش التیوم رو برداشتین؟تازه قسمت 7مونده بود و ادامه دار بود.لطفا این اموزش رو ادامه بدین خیلی پیگیر بودم
سلام دوست عزیز
پست های مربوط به اموزش التیوم از روی سایت پاک نشده . شما میتونین آنها را اینجا پیدا کنین
https://sisoog.com/?s=%D8%A2%D9%85%D9%88%D8%B2%D8%B4+%D8%A2%D9%84%D8%AA%DB%8C%D9%88%D9%85+%D8%AF%DB%8C%D8%B2%D8%A7%DB%8C%D9%86%D8%B1&post_type=post
برای رفاه حال دوستان به زودی دسته آموزش آلتیوم دیزاینر در قسمت آموزشها اضافه میشه.
ممنون از همراهی شما