قسمت نهم: وقفه خارجی (EXTI)

0
775
وقفه خارجی (EXTI)
وقفه خارجی (EXTI)

در قسمت هشتم آموزش میکروکنترلر STM8 سیستم کلاک میکروکنترلر را آموزش دادیم. در این قسمت از آموزش میکروکنترلر STM8 قصد دارد وقفه خارجی را توضیح‌دهیم. با ما همراه باشید.

وقفه خارجی یکی‌از ویژگی‌های اضافه‌شده به GPIOها در حالت ورودی است. که باعث می‌شود میکروکنترلر روال فرآیندهایش را متوقف‌کند و به تغییرات اعمالی در پین‌های ورودی توسط eventها یا triggerها پاسخ فوری بدهد. دربسیاری‌از موارد استفاده‌از وقفه خارجی سودمند است. به‌عنوان‌مثال، دکمه اضطراری موجود روی تردمیل را درنظر بگیرید. شما با سرعت زیاد درحال دویدن هستید که ناگهان مچ پایتان درد می‌گیرد. مطمئناً شما در این‌حالت میخواهید بلافاصله متوقف‌شوید، به‌جای کاهش سرعت به‌صورت مرحله‌به‌مرحله، می‌توانید دکمه اضطراری را بزنید تا تردمیل سریعاً متوقف‌شود. دکمه اضطراری تمام فرآیندهای دیگر را متوقف می‌کندو بلافاصله به CPU تردمیل دستور می‌دهد تا سرعت را سریع‌تر از حد‌امکان تغییر‌دهد. درواقع اولویت آن بالاتر از سایر فرآیندها می‌باشد.

اکثر میکروکنترلرهای ۸بیتی، پین‌های وقفه خارجی کمی دارند و دارای محدودیت هستند، اما چنین محدودیتی برای میکروکنترلر‌های STM8 وجود ندارد. در STM8، تقریباً تمامی پین‌های GPIO دارای قابلیت وقفه خارجی با ورودی اشمیت تریگر هستند. علاوه‌بر این، کنترل‌کننده وقفه برای تعیین اولویت وقفه‌ها وجود دارد.

شماتیک
شماتیک

 

اتصالات سخت افزاری

اتصالات سخت افزاری وقفه خارجی میکروکنترلر STM8
اتصالات سخت افزاری وقفه خارجی میکروکنترلر STM8

 

نمونه کد وقفه خارجی

همان LED ای که درمثال GPIO استفاده‌کردیم را در اینجا نیز مجدداً استفاده می‌کنیم، اما اینبار از سوئیچ به‌عنوان وقفه خارجی استفاده می‌کنیم. اکنون باید ببینیم که چگونه باید وقفه خارجی را پیکربندی و کدگذاری کرد. این کد با تمام چیزهایی که قبلاً دیده‌اید متفاوت‌است و نیاز٬به توجه بیشتری دارد. چون برخلاف کامپایلرهای دیگر شما باید گام‌های خاصی را بردارید. در دیگر کامپایلرها، تنها چیزی‌که انجام میدادیم این بود که تابع وقفه را ایجاد کنیم و آدرس بردار وقفه را به کامپایلر بدهیم. دراینجا علاوه‌بر این کار مراحل دیگری را نیز باید انجام‌دهیم.

جدول بردار وقفه برای STM8S003 در زیر نشان ‌داده‌شده‌است:

جدول بردار وقفه STM8S003
جدول بردار وقفه STM8S003

 

این جدول را می‌توانید در دیتاشیت آی‌سی نیز پیدا کنید. این جدول برای هر آی‌سی متفاوت است پس مطمئن‌شوید که دیتاشیت آی‌سی مورد‌نظر خود را دریافت کرده‌اید. از آنجاکه ما قصد‌داریم سوئیچ را به PB5 وصل‌کنیم پس باید از IRQ4 ، وقفه خارجی PORTB یا EXTI1 استفاده‌کنیم. تمام وقفه‌های خارجی روی پین‌های GPIOB در این آدرس قرار‌گرفته‌است.

 

main.c

#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

/* 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.h
stm8s_it.h

 

stm8s_it.c

stm8s_it.c
stm8s_it.c

 

کد شما باید به‌صورت بالا نوشته‌شده باشد.

توضیح

اکثر قسمت‌های کد همانند کدهای قبلی هستند، بنابراین از توضیح آن‌ها می‌گذریم. بااین‌حال، چیزی جدید وجود دارد:

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” باشد. همچنین باید بخش‌زیر را درنظر داشته‌باشید:

//@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;
//}

 

باید نام فانکشنی را که قصد داریم هنگام وقوع وقفه‌ای خاص اعمال شود به کامپایلر بدهیم. برای این کار دو قسمت وجود دارد. آدرس بردار وقفه و نام تابع. به‌همین‌دلیل خط زیر را در برنامه می‌نویسیم.

{0x82, (interrupt_handler_t)EXTI3_IRQHandler}, /* irq4 */

 

در این قسمت راجع‌به وقفه خارجی صحبت‌کردیم. در قسمت دهم آموزش میکروکنترلر STM8 قصد داریم، برنامه‌ای بااستفاده‌از بیپر (Beeper) را آموزش دهیم.

با ما همراه باشید.

 

 

 

منبع:‌سیسوگ

مطلب قبلیآموزش میکروکنترلر STM32 قسمت هشتم: مثال عملی رابط سریال UART
مطلب بعدیآموزش میکروکنترلر STM32 قسمت نهم: وقفه رابط سریال

پاسخ دهید

لطفا نظر خود را وارد کنید!
لطفا نام خود را در اینجا وارد کنید