سیسوگ در قسمت هشتم آموزش میکروکنترلر STM8 سیستم کلاک میکروکنترلر را آموزش داد. در این قسمت از آموزش میکروکنترلر STM8 قصد دارد وقفه خارجی را توضیح دهد. با سیسوگ همراه باشید.
وقفه خارجی یکی از ویژگی های اضافه شده به GPIO ها در حالت ورودی است. که باعث میشود میکروکنترلر روال فرآیندهایش را متوقف کند و به تغییرات اعمالی در پینهای ورودی توسط event ها یا trigger ها پاسخ فوری بدهد. در بسیاری از موارد استفاده از وقفه خارجی سودمند است. به عنوان مثال، دکمه اضطراری موجود روی تردمیل را در نظر بگیرید. شما با سرعت زیاد در حال دویدن هستید که ناگهان مچ پایتان درد میگیرد. مطمئناً شما در این حالت میخواهید بلافاصله متوقف شوید، به جای کاهش سرعت به صورت مرحله به مرحله، میتوانید دکمه اضطراری را بزنید تا تردمیل سریعاً متوقف شود. دکمه اضطراری تمام فرآیندهای دیگر را متوقف میکند و بلافاصله به CPU تردمیل دستور میدهد تا سرعت را سریعتر از حد امکان تغییر دهد. در واقع اولویت آن بالاتر از سایر فرآیندها میباشد.
اکثر میکروکنترلرهای 8 بیتی، پینهای وقفه خارجی کمی دارند و دارای محدودیت هستند، اما چنین محدودیتی برای میکروکنترلرهای STM8 وجود ندارد. در STM8، تقریباً تمامی پینهای GPIO دارای قابلیت وقفه خارجی با ورودی اشمیت تریگر هستند. علاوه بر این، کنترل کننده وقفه برای تعیین اولویت وقفهها وجود دارد.
وقفه خارجی میکروکنترلر STM8
اتصالات سخت افزاری
اتصالات سخت افزاری وقفه خارجی میکروکنترلر STM8
نمونه کد وقفه خارجی
همان LED ای که در مثال GPIO استفاده کردیم را در اینجا نیز مجدداً استفاده میکنیم، اما این بار از سوئیچ به عنوان وقفه خارجی استفاده میکنیم. اکنون باید ببینیم که چگونه باید وقفه خارجی را پیکربندی و کدگذاری کرد. این کد با تمام چیزهایی که قبلاً دیده اید متفاوت است و نیاز به توجه بیشتری دارد. چون بر خلاف کامپایلرهای دیگر شما باید گامهای خاصی را بردارید. در دیگر کامپایلرها، تنها چیزی که انجام میدادیم این بود که تابع وقفه را ایجاد کنیم و آدرس بردار وقفه را به کامپایلر بدهیم. در اینجا علاوه بر این کار مراحل دیگری را نیز باید انجام دهیم.
جدول بردار وقفه برای STM8S003 در زیر نشان داده شده است:
این جدول را میتوانید در دیتاشیت آی سی نیز پیدا کنید. این جدول برای هر آی سی متفاوت است پس مطمئن شوید که دیتاشیت آی سی مورد نظر خود را دریافت کردهاید. از آنجا که ما قصد داریم سوئیچ را به PB5 وصل کنیم پس باید از IRQ4 ، وقفه خارجی PORTB یا EXTI1 استفاده کنیم. تمام وقفههای خارجی روی پینهای GPIOB در این آدرس قرار گرفته است.
main.c
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | #include "stm8s.h" bool state = FALSE; int j; void GPIO_setup(void); void EXTI_setup(void); void clock_setup(void); void EXTI1_IRQHandler(void) { GPIO_WriteReverse(GPIOD, GPIO_PIN_3); } void main(void) { GPIO_setup(); EXTI_setup(); clock_setup(); GPIO_WriteReverse(GPIOD, GPIO_PIN_3); do { }while (TRUE); } void GPIO_setup(void) { GPIO_DeInit(GPIOB); GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_IN_PU_IT); GPIO_DeInit(GPIOD); GPIO_Init(GPIOD, GPIO_PIN_3, GPIO_MODE_OUT_PP_LOW_FAST); } void EXTI_setup(void) { ITC_DeInit(); ITC_SetSoftwarePriority(ITC_IRQ_PORTB, ITC_PRIORITYLEVEL_0); EXTI_DeInit(); EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOB, EXTI_SENSITIVITY_FALL_ONLY); EXTI_SetTLISensitivity(EXTI_TLISENSITIVITY_FALL_ONLY); enableInterrupts(); } void clock_setup(void) { CLK_DeInit(); CLK_HSECmd(DISABLE); CLK_LSICmd(DISABLE); CLK_HSICmd(ENABLE); while(CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == FALSE); CLK_ClockSwitchCmd(ENABLE); CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1); CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI, DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART1, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, DISABLE); } |
stm8_interrupt_vector.c
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | /* BASIC INTERRUPT VECTOR TABLE FOR STM8 devices * Copyright (c) 2007 STMicroelectronics */ typedef void @far (*interrupt_handler_t)(void); struct interrupt_vector { unsigned char interrupt_instruction; interrupt_handler_t interrupt_handler; }; @far @interrupt void NonHandledInterrupt (void) { /* in order to detect unexpected events during development, it is recommended to set a breakpoint on the following instruction */ return; } extern void _stext(); /* startup routine */ extern void EXTI1_IRQHandler(void); struct interrupt_vector const _vectab[] = { {0x82, (interrupt_handler_t)_stext}, /* reset */ {0x82, NonHandledInterrupt}, /* trap */ {0x82, NonHandledInterrupt}, /* irq0 */ {0x82, NonHandledInterrupt}, /* irq1 */ {0x82, NonHandledInterrupt}, /* irq2 */ {0x82, NonHandledInterrupt}, /* irq3 */ {0x82, (interrupt_handler_t)EXTI1_IRQHandler}, /* irq4 */ {0x82, NonHandledInterrupt}, /* irq5 */ {0x82, NonHandledInterrupt}, /* irq6 */ {0x82, NonHandledInterrupt}, /* irq7 */ {0x82, NonHandledInterrupt}, /* irq8 */ {0x82, NonHandledInterrupt}, /* irq9 */ {0x82, NonHandledInterrupt}, /* irq10 */ {0x82, NonHandledInterrupt}, /* irq11 */ {0x82, NonHandledInterrupt}, /* irq12 */ {0x82, NonHandledInterrupt}, /* irq13 */ {0x82, NonHandledInterrupt}, /* irq14 */ {0x82, NonHandledInterrupt}, /* irq15 */ {0x82, NonHandledInterrupt}, /* irq16 */ {0x82, NonHandledInterrupt}, /* irq17 */ {0x82, NonHandledInterrupt}, /* irq18 */ {0x82, NonHandledInterrupt}, /* irq19 */ {0x82, NonHandledInterrupt}, /* irq20 */ {0x82, NonHandledInterrupt}, /* irq21 */ {0x82, NonHandledInterrupt}, /* irq22 */ {0x82, NonHandledInterrupt}, /* irq23 */ {0x82, NonHandledInterrupt}, /* irq24 */ {0x82, NonHandledInterrupt}, /* irq25 */ {0x82, NonHandledInterrupt}, /* irq26 */ {0x82, NonHandledInterrupt}, /* irq27 */ {0x82, NonHandledInterrupt}, /* irq28 */ {0x82, NonHandledInterrupt}, /* irq29 */ }; |
حالا قسمتهای بالای فایلهای stm8s_it.h و stm8s_it.c را چک کنید.
stm8s_it.h
stm8s_it.c
کد شما باید به صورت بالا نوشته شده باشد.
توضیح
اکثر قسمتهای کد همانند کدهای قبلی هستند، بنابراین از توضیح آنها میگذریم. با این حال، چیزی جدید وجود دارد:
1 2 3 4 5 6 7 8 9 10 11 | void EXTI_setup(void) { ITC_DeInit(); ITC_SetSoftwarePriority(ITC_IRQ_PORTB, ITC_PRIORITYLEVEL_0); EXTI_DeInit(); EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOD, EXTI_SENSITIVITY_FALL_ONLY); EXTI_SetTLISensitivity(EXTI_TLISENSITIVITY_FALL_ONLY); enableInterrupts(); } |
این قسمت از کد جایی است که وقفه خارجی را تنظیم میکنیم. دو خط اول، کنترل کننده وقفه را پیکربندی میکند و اولویتها را در زمان شروع تعیین میکند. این قسمت اجباری نیست مگر اینکه شما قصد داشته باشید برای وقفههای کد خود اولویت قرار دهید. سپس وقفههای خارجی را روی پینهای PORTD پیکربندی میکنیم. هم چنین تنظیم میکنیم که وقفه با لبه فعال شود.
حال وقت آن رسیده تا فایل stm8_interrupt_vector.c را توضیح دهیم. قسمت بالای این فایل باید شامل خط #include “stm8s_it.h” باشد. همچنین باید بخش زیر را در نظر داشته باشید:
1 2 3 4 5 6 7 | //@far @interrupt void NonHandledInterrupt (void) //{ /* in order to detect unexpected events during development, it is recommended to set a breakpoint on the following instruction */ // return; //} |
باید نام فانکشنی را که قصد داریم هنگام وقوع وقفهای خاص اعمال شود به کامپایلر بدهیم. برای این کار دو قسمت وجود دارد. آدرس بردار وقفه و نام تابع. به همین دلیل خط زیر را در برنامه مینویسیم.
1 | {0x82, (interrupt_handler_t)EXTI3_IRQHandler}, /* irq4 */ |
در این قسمت راجب وقفه خارجی صحبت کردیم. در قسمت دهم آموزش میکروکنترلر STM8 سیسوگ قصد دارد، برنامه ای با استفاده از بیپر (Beeper) را آموزش دهد. با سیسوگ همراه باشید.
مطالب مرتبط
- قسمت اول − میکروکنترلر STM8 چیست و از کجا آمده است؟
- قسمت دوم − معرفی بردهای Discovery میکروکنترلر STM8
- قسمت سوم − کامپایلر و پروگرامر
- قسمت چهارم − STM8CubeMX
- قسمت پنجم − آماده سازی ابزارهای نرمافزاری برای STM8
- قسمت ششم − چگونه برنامه خود را روی STM8 آپلود کنیم؟
- قسمت هفتم − LED چشمکزن
- قسمت هشتم − کلاک سیستم (CLK)
- قسمت دهم − Beeper
- قسمت یازدهم − LCD کاراکتری
- قسمت دوازدهم − مبدل آنالوگ به دیجیتال (ADC)
- قسمت سیزدهم − تایمر نگهبان آنالوگ (AWD)
- قسمت چهادهم − تایمر نگهبان (IWDG)
- قسمت پانزدهم − تایمر نگهبان محدوده ای (WWDG)
- قسمت شانزدهم− اصول اولیه تایمرها
- قسمت هفدهم− تایمر 2
- قسمت هجدهم −تایمر 4
- قسمت نوزدهم −PWM
- قسمت بیستم − PWM تایمر 1
- قسمت بیست و یکم − بررسی اجمالی ارتباطات
- قسمت بیست و دوم − رابط سریال (UART)
- قسمت بیست و سوم − رابط کاربری سریال (SPI)
- قسمت بیست و چهارم − رابط I2C
- دوره رایگان آموزش میکروکنترلر STM8 – سیسوگ
باسلام و عرض وقت بخیر و تشکر
سوالی از محضرتون داشتم اونم اینکه من بعد از BUILD کردن برنامه به یه اروری میخورم که میگه symbol f_NonHandledInterrupt multiply defined (Debug\stm8s_it.o) به این معنی که یک تابع با اسم مذکور رو چندبار تعریف کردم ولی خب درست بم گرا نمیده که بدونم دقیقا کجا اضافه تعریف شده
ممنون میشم اکر راهنماییم کنین
سلام دوست عزیز
خوب دقیقا برداشتتون درسته به سادگی جستجوی تابع توی کد میتونید ببینید این تابع کجاها تعریف شده
سلام وقت بخیر
برای دو تا کلید که به دوتا از پین های پورت A و B میکرو Stm8s وصل کردم اینتراپت تعریف کردم. تنظیمات مربوط به رجیستری GPIO و EXTI رو به طور کامل نوشتم . برنامه اینتراپت هم یک Blink ساده است.
با زدن دکمه ها اینتراپ ها کار میکنه و ال ای دی ها روشن و خاموش میشن ولی به محض اتمام برنامه اینتراپت ، میکرو ریست میکنه!منظور اینکه اینتراپت اجرا میشه ولی میکرو ریست میکنه. ممنون میشم راهنمایی کنید.
این مساله میتونه به دلیل کم بودن استک اینتراپت باشه و این که بعد از تمام شدن اینتراپت cpu نتونه مسیر برگشت به برنامه اصلی رو پیدا کنه
سلام این کتابخانه stm8s_it. را از کجا اوردید و کارش چیه توی spl نبود برنامه بدون اینها کامپایل میشه بدون خطا ولی وقفه جواب نداد
اینو خودتون ایجاد میکیند
فکر میکنیم سمپلش رو بتونید توی مثال های خود کتابخانه پیدا کنید.
کارش هم اینه که روال وقفه رو توش تعریف میکنید – وجودش الذامی نیست و میتونید روال های مروبط به وقفه رو توی فایل مین هم تعریف کنید.
سلام وقت بخیر
بنده تمام موارد رو اجرا کردم و یک کد کوچیک با led و اینتراپت نوشتم که وقتی اینتراپت میخوره ال ای دی روشن بشه و داخل وایل اگر فلگ داخل اینتراپت یک شده بود ، کمی صبر کنه و خاموش کنه. اما مشکل اینجاست که به محض اینتراپت خوردن ، ال ای دی سریع روشن میشه (اینتراپت اجرا میشه) و میکرو ریست میکنه!! (ابتدای کد یک تعدادی چشمک زن گذاشتم و مطمئن هستم میکرو ریست میشه.) لازم به ذکره که تایمر ،adc و gpio عادی رو راه انداختم بدون مشکل اما اینتراپت خیلی اذیت میکنه. (البته در این کد خبری از تایمر و adc نیست)
سلام دوست عزیز
با توجه به صحبت اتون تفکری که پشت کدنویسی شما بوده به نظر درست میاد و احتمالا قسمتی از کد به خوبی نوشته نشده.
لطف کنین کدتون را بذارید تا بیشتر بتونم کمکتون کنم.
سلام منم به همین مشکل برخورد کردم. چطوری میشه رفعش کرد؟
آیا واچ داگ فعال نیست ؟ یکی از احتمال های اینه که واچ داگ فعال باشه
برنامه نویسی اصولی میگه شما نباید برنامه تان رو در وقفه متوقف کنید یکی از دلایل میتونه این باشه
دلیل دوم میتونه پر شدن استک باشه (استک مروبط به اینتراپت) دلیل دیگه میتونه پاک نکردن فلگ اینتراپت باشه
با سلام
با ارور : ?ASlink-Warning-Undefined Global ‘_EXTI_SetTLISensitivity’ referenced by module ‘main’
make: *** [makefile:56: main] Error 1
“make all” terminated with exit code 2. Build might be incomplete.
مواجه میشوم
22:07:32 **** Incremental Build of configuration Default for project STM8 ****
make all
sdcc -c -IStdPeriphLib/inc -DUSE_STDPERIPH_DRIVER -mstm8 -Ddouble=float –std-c99 –nolospre –opt-code-size –out-fmt-ihx –debug -obin/StdPeriphLib/src/ StdPeriphLib/src/stm8s_clk.c
sdcc -c -IStdPeriphLib/inc -DUSE_STDPERIPH_DRIVER -mstm8 -Ddouble=float –std-c99 –nolospre –opt-code-size –out-fmt-ihx –debug -obin/StdPeriphLib/src/ StdPeriphLib/src/stm8s_gpio.c
sdcc -IStdPeriphLib/inc -DUSE_STDPERIPH_DRIVER -mstm8 -Ddouble=float –std-c99 –nolospre –opt-code-size –out-fmt-ihx –debug main.c -o bin/ bin/StdPeriphLib/src/stm8s_gpio.rel bin/StdPeriphLib/src/stm8s_clk.rel
?ASlink-Warning-Undefined Global ‘_ITC_DeInit’ referenced by module ‘main’
?ASlink-Warning-Undefined Global ‘_EXTI_SetExtIntSensitivity’ referenced by module ‘main’
?ASlink-Warning-Undefined Global ‘_EXTI_DeInit’ referenced by module ‘main’
?ASlink-Warning-Undefined Global ‘_ITC_SetSoftwarePriority’ referenced by module ‘main’
?ASlink-Warning-Undefined Global ‘_EXTI_SetTLISensitivity’ referenced by module ‘main’
make: *** [makefile:56: main] Error 1
“make all” terminated with exit code 2. Build might be incomplete.
22:07:33 Build Failed. 1 errors, 0 warnings. (took 1s.535ms)
سلام دوست عزیز
خطاهایی که مواجه شدید به این معنی است که از توابعی استفاده کردید که توی فایل های پروژه تعریفی برای اون وجود نداره ؛ الان داره میگه که مثلا ‘_ITC_DeInit’ تایعی رو که توی مین برنامه مورد استفاده قرار دادید ؛ هیچ کجا دیفاین نشده و هیچ تعریفی براش پیدا نمیکنه
خیلی ببخشید مطالب سایتتون مفت نمی ارزه.همش یا کپی پیسته یا ترجمه
بعضی مطالبی که میذارین اصلا تست شده هم نسیتن ناقص کپی شدن فقط باعث سردرگمی ادم میشن
با تشکر
ممنون از نظر شما
این اولین نظر به این تندی در حدود یکسال کاری سیسوگ هست 🙂
و به جرات میتونم بگم شاید دو مطلب در کل سایت داریم که قسمتهایی از اون کپی شدند که دقیقا هم اشاره شده
خیلی از محتواهای ایجاده شده هم عملی تست شده اند و اکثر آموزش میکروکنترلر STM8 دقیقا تست شده که میتونید حتی نمونه بردهای تست شده را هم در زیر برخی از پست ها ببنید
بسیاری از مطالب وب سایت هیچ نمونه حتی خارجی ندارند و خیلی از اونها هم دقیقا ایجاد شده اند
اگر قسمتی اش به نظرتون دچار اشکال هست و اگر نظری دارید در مورد قسمتی اش که میتونه بهتر کنه اموزش را ممنون میشم بگید تا ما سعی کنیم تصحیح کنیم
این آموزشتون واقعا ترجمه ناقص و ایراد داری هستش، لطفا اصلاحش کنید
منبع اصلی تصاویر و آموزش هم لینک زیر هستش
http://embedded-lab.com/blog/starting-stm8-microcontrollers/10/
همین لینک که به عنوان منبع ذکر شده 😐 انتهای مطلب رو اگر ببینید
بررسی میکنیم
ممنون برای پیگیری موضوع
عذرخواهی میکنم بابت لحن تندم
منبع رو ندیده بودم
متشکرم
خواهش میکنم 😐