FreeRTOS中斷配置與臨界段

Cortex-M中斷

中斷是指計算機運行過程中,出現某些意外情況需主機干預時,機器能自動停止正在運行的程序并轉入處理新情況的程序(中斷服務程序),處理完畢后又返回原被暫停的程序繼續運行。Cortex-M內核的MCU提供了一個用于中斷管理的嵌套向量中斷控制器(NVIC)。
當多個中斷來臨的時候,處理器應響應哪一個中斷是由中斷的優先級來決定的,高優先級(優先級的編號小)的中斷首先得到響應,可以搶占低優先級的中斷。Cortex-M處理器有三個固定優先級和256個可編程優先級,最多有128個搶占等級,優先級配置寄存器是8位寬的,處理器還把優先級分為高低兩段:搶占優先級和亞優先級,但實際的優先級數量是由芯片廠商決定的,STM32選擇了4位作為優先級,只有16個優先級,FreeRTOS的中斷配置沒有處理亞優先級這種情況,所以全是搶占優先級,設置分組時候,選擇中斷優先級分組4,優先級分組配置在HAL_Init()中。
在這里插入圖片描述

FreeRTOS中斷配置宏

  1. configPRIO_BITS
    設置MCU使用幾位優先級,STM32使用的是4位

  2. configLIBRARY_LOWEST_INTERRUPT_PRIORITY
    設置最低優先級,STM32配置使用組4,都是搶占優先級,最低優先級為15
    在這里插入圖片描述

  3. configKERNEL_INTERRUPT_PRIORITY
    設置內核中斷優先級

  4. configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
    系統可管理的最大優先級
    在這里插入圖片描述
    優先級數低于5不歸FreeRTOS管理

  5. configMAX_SYSCALL_INTERRUPT_PRIORITY
    此宏設置好后,優先級低于此的中斷可以安全調用FreeRTOS的API函數,優先級高于此的中斷FreeRTOS是不能禁止的,中斷服務函數也不能調用FreeRTOS的API函數。
    在這里插入圖片描述
    由于高于configMAX_SYSCALL_INTERRUPT_PRIORITY的優先級不會被FreeRTOS內核屏蔽,因此對于那些實時性要求嚴格的任務就可以使用這些優先級。

FreeRTOS開關中斷

開關中斷函數為portENABLE_INTERRUPTS和portDISABLE_INTERRUPTS
當關閉中斷后,優先級低于configMAX_SYSCALL_INTERRUPT_PRIORITY(優先級數大于configMAX_SYSCALL_INTERRUPT_PRIORITY)的中斷將被屏蔽,高于configMAX_SYSCALL_INTERRUPT_PRIORITY(優先級數小于configMAX_SYSCALL_INTERRUPT_PRIORITY)的不會被屏蔽

臨界段代碼

臨界段代碼也叫臨界區,是指那些必須完整運行,不能被打斷的代碼段。FreeRTOS在進入臨界段代碼的時候需要關閉中斷,當處理完臨界段代碼以后再打開中斷。
FreeRTOS與臨界段代碼保護有關的函數有4個:taskENTER_CRITICAL、taskEXIT_CRITICAL、taskENTER_CRITICAL_FROM_ISR、taskEXIT_CRITICAL_FROM_ISR,前兩個是任務級別的臨界段代碼保護,后兩個是中斷級的臨界區保護。

中斷測試

start_task:創建另一個任務
interrupt_task:中斷測試實驗,任務中會調用FreeRTOS的關中斷函數portDISABLE_INTERRUPTS來將中斷關閉一段時間。

任務設置

//任務優先級
#define START_TASK_PRIO			1
//任務堆棧大小	
#define START_STK_SIZE 			256  
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define INTERRUPT_TASK_PRIO		2
//任務堆棧大小	
#define INTERRUPT_STK_SIZE 		256  
//任務句柄
TaskHandle_t INTERRUPTTask_Handler;
//任務函數
void interrupt_task(void *p_arg);

main函數

int main(void)
{HAL_Init();                     //初始化HAL庫   Stm32_Clock_Init(360,25,2,8);   //設置時鐘,180Mhzdelay_init(180);                //初始化延時函數LED_Init();                     //初始化LED uart_init(115200);              //初始化串口TIM3_Init(10000-1,9000-1); 		//初始化定時器3,定時周期1STIM5_Init(10000-1,9000-1); 		//初始化定時器5,定時周期1S//創建開始任務xTaskCreate((TaskFunction_t )start_task,            //任務函數(const char*    )"start_task",          //任務名稱(uint16_t       )START_STK_SIZE,        //任務堆棧大小(void*          )NULL,                  //傳遞給任務函數的參數(UBaseType_t    )START_TASK_PRIO,       //任務優先級(TaskHandle_t*  )&StartTask_Handler);   //任務句柄              vTaskStartScheduler();          //開啟任務調度
}

任務函數

//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL();           //進入臨界區//創建中斷測試任務xTaskCreate((TaskFunction_t )interrupt_task,  			//任務函數(const char*    )"interrupt_task", 			//任務名稱(uint16_t       )INTERRUPT_STK_SIZE,		//任務堆棧大小(void*          )NULL,						//傳遞給任務函數的參數(UBaseType_t    )INTERRUPT_TASK_PRIO,		//任務優先級(TaskHandle_t*  )&INTERRUPTTask_Handler); 	//任務句柄vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL();            //退出臨界區
}//中斷測試任務函數 
void interrupt_task(void *pvParameters)
{static u32 total_num=0;while(1){total_num+=1;if(total_num==5) {printf("關閉中斷.............\r\n");portDISABLE_INTERRUPTS();			//關閉中斷delay_xms(5000);					//延時5sprintf("打開中斷.............\r\n");	//打開中斷portENABLE_INTERRUPTS();}LED0=~LED0;vTaskDelay(1000);}
}   

中斷初始化

TIM_HandleTypeDef TIM3_Handler;	//定時器3句柄
TIM_HandleTypeDef TIM5_Handler;	//定時器5句柄//通用定時器3中斷初始化
//arr:自動重裝值。
//psc:時鐘預分頻數
//定時器溢出時間計算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定時器工作頻率,單位:Mhz
//這里使用的是定時器3!(定時器3掛在APB1上,時鐘為HCLK/2)
void TIM3_Init(u16 arr,u16 psc)
{TIM3_Handler.Instance = TIM3;TIM3_Handler.Init.Period = arr;TIM3_Handler.Init.Prescaler = psc;TIM3_Handler.Init.CounterMode = TIM_COUNTERMODE_UP;TIM3_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;HAL_TIM_Base_Init(&TIM3_Handler);
}//通用定時器5中斷初始化
//arr:自動重裝值(TIM2,TIM5是32位的!!)
//psc:時鐘預分頻數
void TIM5_Init(u32 arr,u16 psc)
{TIM5_Handler.Instance = TIM3;TIM5_Handler.Init.Period = arr;TIM5_Handler.Init.Prescaler = psc;TIM5_Handler.Init.CounterMode = TIM_COUNTERMODE_UP;TIM5_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;HAL_TIM_Base_Init(&TIM5_Handler);
}//定時器底冊驅動,開啟時鐘,設置中斷優先級
//此函數會被HAL_TIM_Base_Init()函數調用
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM3){__HAL_RCC_TIM3_CLK_ENABLE();HAL_NVIC_EnableIRQ(TIM3_IRQn);HAL_NVIC_SetPriority(TIM3_IRQn,4,0);HAL_TIM_Base_Start_IT(&TIM3_Handler);	//開啟定時器并更新中斷,以后每次更新中斷,都會調用TIM3_IRQHandler}else if(htim->Instance == TIM5){__HAL_RCC_TIM5_CLK_ENABLE();HAL_NVIC_EnableIRQ(TIM5_IRQn);HAL_NVIC_SetPriority(TIM5_IRQn,5,0);HAL_TIM_Base_Start_IT(&TIM5_Handler);	//開啟定時器并更新中斷,以后每次更新中斷,都會調用TIM3_IRQHandler}
}
//定時器3中斷服務函數
void TIM3_IRQHandler(void)
{HAL_TIM_IRQHandler(&TIM3_Handler);
}//定時器5中斷服務函數
void TIM5_IRQHandler(void)
{HAL_TIM_IRQHandler(&TIM5_Handler);
}//回調函數,定時器中斷服務函數調用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM3){printf("TIM3輸出.....\r\n");}else if(htim->Instance == TIM5){printf("TIM5輸出.....\r\n");}
}

運行結果

在這里插入圖片描述
一開始沒有關閉中斷,所以TIM3和TIM5都正常運行,當interrupt_task運行5次之后,此時由于TIM5的中斷優先級為5,等于configMAX_SYSCALL_INTERRUPT_PRIORITY,因此TIM5會被關閉。但是,TIM3的中斷優先級高于configMAX_SYSCALL_INTERRUPT_PRIORITY,不會被關閉,所以TIM3正常運行,中斷運行5s后調用函數portENABLE_INTERRUPTS重新打開中斷,重新打開中斷后TIM5恢復運行。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/379751.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/379751.shtml
英文地址,請注明出處:http://en.pswp.cn/news/379751.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

vector向量容器

一、vector向量容器 簡介: Vector向量容器可以簡單的理解為一個數組,它的下標也是從0開始的,使用時可以不用確定大小,但是它可以對于元素的插入和刪除,可以進行動態調整所占用的內存空間,它里面有很多系統…

netsh(二)

netsh 來自微軟的網絡管理看家法寶很多時候,我們可能需要在不同的網絡中工作,一遍又一遍地重復修改IP地址是一件比較麻煩的事。另外,系統崩潰了,重新配置網卡等相關參數也比較煩人(尤其是無線網卡)。事實上…

java uuid靜態方法_Java UUID getLeastSignificantBits()方法與示例

java uuid靜態方法UUID類getLeastSignificantBits()方法 (UUID Class getLeastSignificantBits() method) getLeastSignificantBits() method is available in java.util package. getLeastSignificantBits()方法在java.util包中可用。 getLeastSignificantBits() method is us…

Google C2Dm相關文章

Android C2DM學習——云端推送:http://blog.csdn.net/ichliebephone/article/details/6591071 Android C2DM學習——客戶端代碼開發:http://blog.csdn.net/ichliebephone/article/details/6626864 Android C2DM學習——服務器端代碼開發:http…

FreeRTOS的列表和列表項

列表和列表項 列表 列表是FreeRTOS中的一個數據結構,概念上和鏈表有點類型,是一個循環雙向鏈表,列表被用來跟蹤FreeRTOS中的任務。列表的類型是List_T,具體定義如下: typedef struct xLIST {listFIRST_LIST_INTEGRI…

string基本字符系列容器

二、string基本字符系列容器 簡介:C語言只提供了一個char類型來處理字符,而對于字符串,只能通過字符串數組來處理,顯得十分不方便。CSTL提供了string基本字符系列容器來處理字符串,可以把string理解為字符串類&#x…

正則表達式(一)

正則表達式概述 1.1什么是正則表達式? 正則表達式(Regular Expression)起源于人類神經系統的早期研究。神經生理學家Warren McCulloch和Walter Pitts研究出一種使用數學方式描述神經網絡的方法。1956年,數學家Stephen Kleene發表了一篇標題為“神經…

42.有“舍”才有“得”

大干世界,萬種誘惑,什么都想要,會累死你,該放就放,該舍就舍。人必須先有所舍,才能有所得,舍如同種子撒播出去,轉了一圈,又帶了一大群子子孫孫回來。“舍”永遠在“得”的…

Java StringBuilder codePointCount()方法與示例

StringBuilder類codePointCount()方法 (StringBuilder Class codePointCount() method) codePointCount() method is available in java.lang package. codePointCount()方法在java.lang包中可用。 codePointCount() method is used to count the number of Unicode code point…

FreeRTOS時間管理

在使用FreeRTOS的過程中,我們通常會在一個任務函數中使用延時函數對這個任務延時,當執行延時函數的時候就會進行任務切換,并且此任務就會進入阻塞太,直到延時完成,任務重新進入就緒態。延時函數舒屬于FreeRTOS的時間管…

set和multiset集合容器

三、①set集合容器 簡介&#xff1a;set集合的目的就是為了快速檢索。set集合容器實現了紅黑樹的平衡二叉檢索樹的數據結構。set集合里面不允許有重復的元素出現&#xff1b;使用set容器前&#xff0c;需要在程序的頭文件中聲明 #include < set >。 函數方法總結&#…

javascript獲取select的值全解

獲取顯示的漢字 document.getElementById("bigclass").options[window.document.getElementById("bigclass").selectedIndex].text 獲取數據庫中的id window.document.getElementById("bigclass").value 獲取select組分配的索引id window.docume…

Java File類void deleteOnExit()方法(帶示例)

文件類void deleteOnExit() (File Class void deleteOnExit()) This method is available in package java.io.File.deleteOnExit(). 軟件包java.io.File.deleteOnExit()中提供了此方法。 This method is used to delete the file or directory when the virtual machine termi…

FreeRTOS隊列

在實際應用中&#xff0c;我們會遇到一個任務或者中斷服務需要和另一個任務進行消息傳遞&#xff0c;FreeRTOS提供了隊列的機制來完成任務與任務、任務與中斷之間的消息傳遞。 0x01 隊列簡介 隊列是為了任務與任務、任務與中斷之間的通信而準備的&#xff0c;可以在任務與任務…

括號配對問題(C)

描述 現在&#xff0c;有一行括號序列&#xff0c;請你檢查這行括號是否配對。 輸入 第一行輸入一個數N&#xff08;0<N<100&#xff09;,表示有N組測試數據。后面的N行輸入多組輸入數據&#xff0c;每組輸入數據都是一個字符串S(S的長度小于10000&#xff0c;且S不是空串…

劇情介紹:“阿甘正傳”

阿甘是個智商只有75的低能兒。在學校里為了躲避別的孩子的欺侮&#xff0c;聽從一個朋友珍妮的話而開始“跑”。他跑著躲避別人的捉弄。在中學時&#xff0c;他為了躲避別人而跑進了一所學校的橄欖球場&#xff0c;就這樣跑進了大學。阿甘被破格錄取&#xff0c;并成了橄欖球巨…

java 方法 示例_Java集合syncedList()方法與示例

java 方法 示例集合類syncList()方法 (Collections Class synchronizedList() method) synchronizedList() method is available in java.util package. syncList()方法在java.util包中可用。 synchronizedList() method is used to return the synchronized view of the given…

FreeRTOS信號量---二值信號量

信號量可以用來進行資源管理和任務同步&#xff0c;FreeRTOS中信號量又分為二值信號量、計算型信號量、互斥信號量和遞歸互斥信號量。 0x01 二值信號量 二值信號量其實就是一個只有一個隊列項的隊列&#xff0c;這個特殊的隊列要么是滿的&#xff0c;要么是空的&#xff0c;任…

Linux 上 rpm包管理工具的基本使用

查詢是否安裝某個包&#xff1a;rpm -q 包名查詢所有已安裝的包&#xff1a;rpm -q a查詢未安裝包的文件信息&#xff1a;rpm -qilp 未安裝的包安裝包&#xff1a;rpm -i 包測試安裝包&#xff1a;rpm -i test 包刪除包&#xff1a;rpm -e 包名測試刪除包&#xff1a;rpm -e te…

ios 內存使用陷阱

在iphone開發過程中&#xff0c;代碼中的內存泄露我們很容易用內存檢測工具leaks 檢測出來&#xff0c;并一一改之&#xff0c;但有些是因為ios 的缺陷和用法上的錯誤&#xff0c;leaks 檢測工具并不能檢測出來&#xff0c;你只會看到大量的內存被使用&#xff0c;最后收到didR…