راه اندازی وقفه خارجی در STM32

توسط | 7 اسفند, 1398 | STM32, میکروکنترلر | 4 دیدگاه ها

راه-اندازی-وقفه-خارجی-stm32

آموزش STM32 یوبرد

شروع بازی ST

آموزش های رایگان STM32

فیلم های آموزش STM32

آموزش خصوصی STM32

راه اندازی وقفه خارجی در STM32 به طور کلی شامل چهار بخش است. بخش اول، پیکربندی پایه های ورودی وقفۀ خارجی است. بخش دوم، پیکربندی واحد وقفۀ خارجی است. بخش سوم، تعیین اولویت وقفه و فعال کردن آن در واحد NVIC است. بخش چهارم نیز نوشتن کدهای روتین یا زیر روال وقفه است. در این نوشته به این چهار بخش راه اندازی وقفه در STM32 می پردازیم. در ادامه دو نمونه کد وقفه خارجی در STM32 را بررسی می کنیم. یک نمونه کد با استفاده از مقداردهی مستقیم به رجیسترها و یک نمونه کد با استفاده از توابع HAL. البته در نمونه کد رجیستری، تنها به رجیسترهای واحد وقفۀ خارجی، به طور مستقیم مقدار می دهیم. در این نمونه کد، پیکربندی پایه های ورودی وقفۀ خارجی را با توابع کتابخانۀ gpio.h انجام می دهیم. رجیسترهای NVIC مربوط به وقفه خارجی را نیز با توابع NVIC مقداردهی می کنیم. هر دو نمونه کد را در نرم افزار Keil نوشته ایم. نمونه کد HAL را نیز با استفاده از نرم افزار STM32CubeMX ایجاد کرده ایم. فایل های پروژۀ هر دو نمونه کد را در پیوست قرار داده ایم. عملکرد برنامه ای که خواهیم دید، به این صورت است که با فشردن کلیدهای متصل به پایه های PE2 و PE3 میکروکنترلر، LEDهای سبز و آبی تغییر وضعیت می دهند. برای راه اندازی وقفه خارجی STM32 در این نوشته، دو کلید را به پایه های مذکور متصل و سر دیگر آنها را به زمین وصل کرده ایم. میکروکنترلر مورد استفادۀ ما نیز STM32F107VC است که روی برد STM32F10xVxxx یوبرد قرار دارد. شما می توانید از میکروکنترلرهای STM32 دیگر نیز استفاده کنید.

نوشته های مرتبط در وبلاگ یوبرد:

آموزشهای یوبرد مرتبط با این نوشته:

اتصالات-راه-اندازی-وقفه-خارجی

تصویر 1 – اتصالات لازم برای راه اندازی وقفه خارجی میکروکنترلر STM32F107VC در این نوشته

نمونه کد رجیستری راه اندازی وقفه خارجی در STM32

در این بخش به نمونه کد رجیستری وقفه خارجی در STM32 می پردازیم. در نمونه کد راه اندازی رجیستری وقفه خارجی در STM32، ابتدا کتابخانه هایی را فراخوانی کرده ایم. سپس پایه های متصل به کلیدها و LEDهای برد را دیفاین کرده ایم. در تابع main، رجیسترهای CR و CFGR را مقدار داده و فرکانس کلاک سیستم را 8 مگاهرتز تنظیم کرده ایم. سپس با مقداردهی به رجیستر APB2ENR، کلاک AFIO را فعال کرده ایم. در ادامه، از بخش AFIO رجیستر MAPR را برای فعال کردن SWD و غیر فعال کردن JTAG در پروگرام کردن میکروکنترلر، مقدار داده ایم. با تابع gpio_config، پایه های متصل به کلیدهای روی برد توسعه را ورودی با پول آپ داخلی تنظیم کرده ایم. پایه های متصل به LEDها را نیز روی مد خروجی پوش پول قرار داده ایم. آند LEDهای روی برد به VDD و کاتد آنها به پایۀ میکروکنترلر وصل است. برای این که در لحظۀ اول خاموش باشند، سطح خروجی متصل به آنها را با تابع gpio_write یک کرده ایم. با مقداردهی به رجیستر IMR از رجیسترهای وقفۀ خارجی، وقفه های خارجی شمارۀ 2 و 3 را فعال کرده ایم. با یک کردن بیت های FTSR، نوع تحریک وقفۀ خارجی 2 و 3 را روی لبۀ پایین رونده تنظیم کرده ایم. با مقداردهی به رجیستر EXTICR[0] از بخش AFIO، پورت E را برای وقفۀ 2 و 3 در نظر گرفته ایم. بنابراین پایه های PE2 و PE3، به عنوان ورودی های وقفه های 2 و 3 در نظر گرفته می شوند. در ادامه با توابع NVIC، اولویت وقفه ها را تعیین و آنها را از بخش NVIC نیز فعال کرده ایم. برای اطلاعات بیشتر دربارۀ اولویت وقفه ها، به نوشتۀ «اولویت وقفه ها در STM32» مراجعه کنید.

پروگرام کردن STM32 با JTAG و SWD و بوت لودر

#include "stm32f10x.h"
#include "Libs/delay.h"
#include "Libs/gpio.h"

#define left_key					pe_2
#define right_key					pe_3
#define green_led					pa_8
#define blue_led					pd_0


int main (void)
{
	RCC->CR |= (1<<0);// HSI on
	while((RCC->CR & (1<<1)) != (1<<1));// Wait for HSI ready
	RCC->CFGR &= ~((1<<1)|(1<<0));// Select HSI as System clock
	
	RCC->APB2ENR |= RCC_APB2ENR_AFIOEN ;
	AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_JTAGDISABLE ;
	
	gpio_config(left_key, input_pull_up, 2);
	gpio_config(right_key, input_pull_up, 2);
	gpio_config(green_led, output_push_pull, 2);
	gpio_config(blue_led, output_push_pull, 2);
	
	gpio_write(green_led, 1);
	gpio_write(blue_led, 1);
	
	EXTI->IMR = (1<<3)|(1<<2);
	EXTI->FTSR= (1<<3)|(1<<2);
	AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI3_PE | AFIO_EXTICR1_EXTI2_PE;
	
	NVIC_SetPriority(EXTI2_IRQn,NVIC_EncodePriority(0, 3, 0));
	NVIC_EnableIRQ(EXTI2_IRQn);
	NVIC_SetPriority(EXTI3_IRQn,NVIC_EncodePriority(0, 4, 0));
	NVIC_EnableIRQ(EXTI3_IRQn);
	
	while(1)
	{
		
	}
}

عملکرد-برنامه-راه-اندازی-وقفه-خارجی

تصویر 2 – عملکرد نمونه کد راه اندازی وقفه در STM32

کدهای روتین وقفه

برای هر یک از وقفه های شمارۀ 2 و 3، یک روتین وقفه وجود دارد. در روتین وقفۀ شمارۀ 2، ابتدا سطح پایۀ متصل به کلید سمت چپ را بررسی می کنیم. در صورتی که وقفۀ شمارۀ 2 اتفاق بیفتد و سطح پایۀ PE2 صفر شود، کدهای درون if اجرا می شوند. ابتدا یک تأخیر 300 میلی ثانیه ای ایجاد کرده ایم. به این شکل به پدیدۀ Bounce حاصل از فشرده شدن کلید، غلبه می کنیم. این کار در واقع یک Debounce نرم افزاری است. روش های دیگری نیز برای دیبانس وجود دارد. ما از روش ایجاد تأخیر استفاده کرده ایم. در ادامه یک حلقۀ while بدون دستور قرار داده ایم. در این صورت با هر بار فشردن کلید و رها کردن آن، LED تنها یک بار تغییر وضعیت دهد. سپس با تابع gpio_write، سطح پایۀ متصل به LED را تغییر می دهیم. در این قسمت با تابع gpio_read، سطح پایه را می خوانیم و مقدار خوانده شده را not می کنیم. مقدار حاصل را در ورودی دوم تابع gpio_write قرار می دهیم و به این ترتیب، سطح پایۀ PA8 تغییر می کند. در انتهای روتین وقفه نیز بیت دوم رجیستر PR را با یک کردن آن پاک می کنیم. در این صورت، برای دفعۀ بعد نیز با فشردن کلید سمت چپ، وقفه اتفاق می افتد. کدهای درون روتین وقفۀ شمارۀ 3 نیز مانند کدهای روتین وقفۀ شمارۀ 2 است. تفاوت آن در این است که پایۀ ورودی، PE3 است و در آن LED آبی رنگ تغییر وضعیت می دهد. بیت مربوط به رجیستر PR نیز، بیت شمارۀ 3 است. به این ترتیب نمونه کد راه اندازی وقفه خارجی در STM32 به پایان می رسد. در ادامه به نمونه کد وقفه خارجی STM32 با توابع HAL می پردازیم.

void EXTI2_IRQHandler(void)
{
	if(gpio_read(left_key) == 0)
	{
		delay_ms(300);
		while(gpio_read(left_key) == 0);
		gpio_write(green_led, !gpio_read(green_led));
	}
	
	EXTI->PR |= (1<<2);
}

void EXTI3_IRQHandler(void)
{
	if (gpio_read(right_key) == 0)
	{
		delay_ms(300);
		while(gpio_read(right_key) == 0);
		gpio_write(blue_led, !gpio_read(blue_led));
	}
	
	EXTI->PR |= (1<<3);
}

ویدئوی 1 – نتیجۀ راه اندازی وقفه خارجی در میکروکنترلرهای ARM STM32

راه اندازی وقفه خارجی در STM32 با HAL

در این بخش نمونه کد HAL وقفه خارجی در STM32 را بررسی می کنیم. ابتدا به تنظیمات وقفه خارجی در STM32CubeMX می پردازیم. مطابق تصویر، برای PE2 و PE3، حالت وقفۀ خارجی را انتخاب می کنیم (1). در تنظیمات GPIO، مد آنها را روی وقفۀ خارجی با نوع تحریک لبۀ پایین رونده قرار می دهیم. پول آپ داخلی آنها را نیز فعال می کنیم. لیبل این پایه ها را هم LEFT_KEY و RIGH_KEY قرار می دهیم (2). پایه های PA8 و PD0 را که به ترتیب به LEDهای سبز و آبی متصل است، روی مد خروجی پوش پول قرار می دهیم. سطح آنها را نیز High می کنیم تا در ابتدا LEDها خاموش باشند. لیبل این پایه ها را نیز GREEN_LED و BLUE_LED تعیین می کنیم (3).

پیکربندی-پایه-وقفه-خارجی

تصویر 3 – تنظیمات پایه های ورودی وقفۀ خارجی در STM32CubeMX

برای راه اندازی وقفه خارجی STM32 با توابع HAL نیز باید تنظیمات NVIC را انجام دهیم. در بخش NVIC چهار بیت را به Preempt priority و صفر بیت را به Sub priority اختصاص می دهیم (1). برای اطلاع از این موضوع، نوشتۀ «اولویت وقفه ها در STM32» را مطالعه کنید. در جدول مربوط به NVIC، تیک وقفه های خارجی 2 و 3 را فعال می کنیم. در جلوی آنها، می توانیم Preempt priority و Sub priority را تعیین کنیم. اولویت Preempt وقفۀ 2 را 3 و اولویت Preempt وقفۀ 3 را 4 تنظیم می کنیم (2). در برنامۀ ایجاد شده توسط STM32CubeMX کافی است در فایل stm32f1xx_it.c، کدهای تغییر وضعیت LEDها را در روتین وقفه های شمارۀ 2 و 3، بنویسیم. برای این کار از توابع HAL_GPIO استفاده می کنیم. در انتهای روتین وقفه نیز تابع HAL_GPIO_EXTI_IRQHandler را قرار می دهیم. در این صورت، دفعۀ بعد نیز با فشردن کلیدها وقفه اتفاق می افتد. عملکرد این نمونه کد مشابه نمونه کد رجیستری است.

void EXTI2_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI2_IRQn 0 */
	
	if(HAL_GPIO_ReadPin(LEFT_KEY_GPIO_Port, LEFT_KEY_Pin) == 0)
	{
		HAL_Delay(300);
		while(HAL_GPIO_ReadPin(LEFT_KEY_GPIO_Port, LEFT_KEY_Pin) == 0);
		HAL_GPIO_WritePin(GREEN_LED_GPIO_Port, GREEN_LED_Pin, 
		!HAL_GPIO_ReadPin(GREEN_LED_GPIO_Port, GREEN_LED_Pin));
	}
	
  /* USER CODE END EXTI2_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);
  /* USER CODE BEGIN EXTI2_IRQn 1 */
	
  /* USER CODE END EXTI2_IRQn 1 */
}

/**
  * @brief This function handles EXTI line3 interrupt.
  */
void EXTI3_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI3_IRQn 0 */
	
	if(HAL_GPIO_ReadPin(RIGHT_KEY_GPIO_Port, RIGHT_KEY_Pin) == 0)
	{
		HAL_Delay(300);
		while(HAL_GPIO_ReadPin(RIGHT_KEY_GPIO_Port, RIGHT_KEY_Pin) == 0);
		HAL_GPIO_WritePin(BLUE_LED_GPIO_Port, BLUE_LED_Pin, 
		!HAL_GPIO_ReadPin(BLUE_LED_GPIO_Port, BLUE_LED_Pin));
	}
	
  /* USER CODE END EXTI3_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);
  /* USER CODE BEGIN EXTI3_IRQn 1 */

  /* USER CODE END EXTI3_IRQn 1 */
}

اولویت-وقفه-تنظیمات-nvic

تصویر 4 – تنظیمات وقفه خارجی در بخش NVIC در STM32CubeMX

نتایج راه اندازی وقفه خارجی در STM32

  1. راه اندازی وقفه خارجی میکروکنترلرهای STM32 شامل چهار بخش پیکربندی ورودی ها، پیکربندی پایه ها در واحد GPIO، تنظیمات وقفه در NVIC و نوشتن روتین وقفه است.
  2. در راه اندازی وقفه خارجی در STM32F1باید به رجیسترهای IMR و FTSR از واحد وقفۀ خارجی و رجیسترهای EXTICR از واحد AFIO مقدار داد. دیگر رجیسترهایی که مقداردهی می شوند، رجیسترهای مربوط به پیکربندی پایه ها در واحد GPIO و رجیسترهای واحد NVIC هستند.
  3. رجیسترهای EXTICR تعیین کنندۀ پورت GPIOای است که پایۀ ورودی وقفۀ خارجی در آن قرار می گیرد.
  4. با توجه به پدیدۀ Bounce حاصل از خاصیت فنری کلیدها و دکمه ها، برای عملکرد صحیح برنامه، باید به روش هایی، Debounce را انجام داد.
  5. در انتهای روتین وقفۀ خارجی، برای این که وقفه برای دفعۀ بعد بتواند اتفاق بیفتد، باید بیت متناظر با وقفۀ حاضر را در رجیستر PR پاک کرد.
  6. پیکربندی وقفه خارجی میکروکنترلرهای STM32 در نرم افزار STM32CubeMX با چند تیک انجام می شود. به طوری که تنها نوشتن کدهای روتین وقفه باقی می ماند.

رضا اسدی

رضا اسدی

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

سفارش پروژه میکروکنترلر یوبرد

زیرساخت مطمئن صنعت

جدیدترین تاپیک های STM32

راه-اندازی-dac-stm32

راه اندازی DAC در STM32

راه اندازی DAC در STM32، ویژگی های DAC در میکروکنترلرهای STM32F1، بلوک دیاگرام DAC در STM32، اتصالات راه اندازی DAC در میکروکنترلر STM32F107VC، نمونه کد رجیستری راه اندازی واحد DAC در میکروکنترلرهای STM32F1، ساخت موج سینوسی با STM32، راه اندازی مبدل دیجیتال به آنالوگ STM32 با توابع HAL

راه-اندازی-usart-stm32

راه اندازی UART در STM32، رجیستری و HAL

راه اندازی UART در STM32، اتصالات و نرم افزار مورد نیاز، نمونه کد USART در STM32 به صورت رجیستری، نمونه کد رجیستری USART با وقفۀ دریافت، نمونه کد HAL برای راه اندازی USART در STM32، نمونه کد HAL با وقفۀ دریافت، نحوه محاسبه Baud rate در USART میکروکنترلرهای STM32F1

برنامه-نویسی-میکروکنترلر-ویژوال-استودیو

برنامه نویسی میکروکنترلرها با ویژوال استودیو

نصب VisualGDB روی ویژوال استودیو، ساخت پروژه برای برنامه نویسی میکروکنترلرها با ویژوال استودیو، ساخت پروژه برای STM32 در ویژوال استودیو، کدنویسی STM32 در ویژوال استودیو، ساخت پروژه برای AVR در ویژوال استودیو، ساخت پروژه برای LPC در ویژوال استودیو، ساخت پروژۀ آردوینو در ویژوال استودیو

راه-اندازی-adc-stm32

راه اندازی ADC در STM32، رجیستری و HAL

راه اندازی ADC در STM32، استفاده از پیکربندی Independent، کانال تکی، تبدیل Discontinuous و کانال Regular، اتصالات لازم برای راه اندازی واحد ADC در STM32، نمونه کد رجیستری، نمونه کد ADC میکروکنترلر STM32 با HAL، خواندن از چند کانال ADC با توابع HAL، توابع HAL راه اندازی ADC

4 دیدگاه ها

  1. سلام. نوشتید که توی روتین وقفه در میکروکنترلرها نباید از کدهای زیادی استفاده کرد؟ دلیلش چیه؟ و منظورتون از زیاد دقیقا چقدر هست؟

    پاسخ
    • سلام. منظور از طولانی نشدن، استفاده نکردن از کدهای طولانی و سنگینه. یعنی بهتره که توی روتین وقفه ها از کدهای خیلی سبک مثل مقداردهی متغیرها و عملیات های ساده ریاضی استفاده بشه. به دلیل اینکه می خواهیم تا جایی که امکان داره کد ما Real Time باشه. اگر کدهای ما توی روتین وقفه توی پروژه های سنگین و از لحاظ زمانی خیلی طولانی باشه، پروژه از حالت Real Time خودش خارج میشه. فرض کنید توی وقفه یه delay گذاشته باشید. در این صورت نباید انتظار داشته باشید کدتون Real time باشه. چون هر وقت وقفه اتفاق میفته، اون delay هم اجرا میشه و باعث تاخیر در روند اجرای برنامه میشه. برای Real Time بودن پروژه باید تا جایی که ممکنه delay نداشته باشیم. برای حذف delay و دلیل حذف delay از پروژه های میکروکنترلری، نوشتۀ «آموزش روش حذف کتابخانۀ delay از پروژه های میکروکنترلری» رو مطالعه کنید.

      پاسخ
  2. سلام استاد
    من دوره ی مقدماتی میکروی شما رو تهیه کردم اما چون از تاریخ تهیه تا دیدن دوره ها بدلیل مشغله های کاری و زندگی بیش از یکسال میگذره پشتیبانیم تو دوره فکر کنم تمام شده.
    تو دوره اشاره ای به اینکه دقیقا تفاوت رخداد event با interrupt چیه نشده و مثالی با Event زده نشده ، میشه در مورد تفاوت این دو توضیحی بفرمایید؟ مچکرم

    پاسخ
    • سلام. وقت بخیر. ممنون از ثبت نظرتون. Event معمولاً به وقایع نرم افزاری بر میگرده، اما event سخت افزاری هم داریم. event نرم افزاری برمیگرده به سطح اپلیکیشن کد. مثل flagهایی که تعریف می کنیم و با واقعه ای، مقدارشون تغییر می کنه و جایی از برنامه، با تغییر flag، روند خاصی اجرا میشه. event توی OSها کامل پیاده شده و استفاده میشه. مثلاً توی OS ها موضوعی داریم به اسم Queue و Semaphore که یه سری بافرهایی هستن که داده ها رو میتونیم توشون ذخیره کنیم.  و میتونیم تعریف کنیم که تحت وقوع یه اتفاقی (مثل پر شدن بافر)، یه Task شروع به کار کنه. یعنی Task توی حالت Block باشه، تا زمانی که توی Queue یه چیزی قرار بگیره. اینجا این واقعه ای که باعث میشه Task شروع به کار کنه، پر شدن Queueه. این واقعه همون eventه. واقعه در سطح اپلیکیشن.

      اما توی میکروکنترلرها Event سخت افزاری هم وجود داره. که تفاوتش با وقفه اینه که روتین یا اجرای کد (Code execution) نداره. وقتی یه Event به وجود میاد، از یه واحد داخلی به یه واحد داخلی دیگه، فقط سیگنالی ارسال میشه و توی واحد داخلی دوم، یه کاری انجام میشه. مثلاً وقتی Event اتفاق میفته، میکروکنترلر از Sleep بیرون میاد. یا با Event یه واحد داخلی، ADC تبدیلش رو شروع میکنه. یا وقتی اتفاق افتاد، تایمر شروع به کار میکنه. این موارد Event سخت افزاری هستن.

      پاسخ

یک دیدگاه بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دیگر آموزش های یوبرد

آموزش FreeRTOS یوبرد

زمان واقعی در میکروکنترلر و پردازنده های کوچک با FreeRTOS

آموزش طراحی PCB و نویز یوبرد

تجسم دنیای الکترونیک

آموزش زبان C و MISRA-C یوبرد

گام نخست دنیای میکروکنترلر

آموزش لحیم کاری و IPC-A-610 یوبرد

ساخت دنیای الکترونیک

آموزش آردوینو یوبرد

جادۀ آسفالت میکروکنترلر

آموزش ماژول های SIM800 یوبرد

تلفن همراه صنعت

آموزش زبان ++C و ++MISRA-C یوبرد

لمس شی گرایی در میکروکنترلرها

آموزش میکروکنترلرهای AVR یوبرد

شاهکار 8 بیتی Atmel

آموزش میکروکنترلرهای LPC یوبرد

یادگار فیلیپس

آموزش های شاخص

ضبط پیام صوتی

زمان هر پیام صوتی 4 دقیقه است