FreeRTOS中断配置与临界段
Cortex-M中斷
中斷是指計(jì)算機(jī)運(yùn)行過(guò)程中,出現(xiàn)某些意外情況需主機(jī)干預(yù)時(shí),機(jī)器能自動(dòng)停止正在運(yùn)行的程序并轉(zhuǎn)入處理新情況的程序(中斷服務(wù)程序),處理完畢后又返回原被暫停的程序繼續(xù)運(yùn)行。Cortex-M內(nèi)核的MCU提供了一個(gè)用于中斷管理的嵌套向量中斷控制器(NVIC)。
當(dāng)多個(gè)中斷來(lái)臨的時(shí)候,處理器應(yīng)響應(yīng)哪一個(gè)中斷是由中斷的優(yōu)先級(jí)來(lái)決定的,高優(yōu)先級(jí)(優(yōu)先級(jí)的編號(hào)小)的中斷首先得到響應(yīng),可以搶占低優(yōu)先級(jí)的中斷。Cortex-M處理器有三個(gè)固定優(yōu)先級(jí)和256個(gè)可編程優(yōu)先級(jí),最多有128個(gè)搶占等級(jí),優(yōu)先級(jí)配置寄存器是8位寬的,處理器還把優(yōu)先級(jí)分為高低兩段:搶占優(yōu)先級(jí)和亞優(yōu)先級(jí),但實(shí)際的優(yōu)先級(jí)數(shù)量是由芯片廠商決定的,STM32選擇了4位作為優(yōu)先級(jí),只有16個(gè)優(yōu)先級(jí),FreeRTOS的中斷配置沒(méi)有處理亞優(yōu)先級(jí)這種情況,所以全是搶占優(yōu)先級(jí),設(shè)置分組時(shí)候,選擇中斷優(yōu)先級(jí)分組4,優(yōu)先級(jí)分組配置在HAL_Init()中。
FreeRTOS中斷配置宏
configPRIO_BITS
設(shè)置MCU使用幾位優(yōu)先級(jí),STM32使用的是4位
configLIBRARY_LOWEST_INTERRUPT_PRIORITY
設(shè)置最低優(yōu)先級(jí),STM32配置使用組4,都是搶占優(yōu)先級(jí),最低優(yōu)先級(jí)為15
configKERNEL_INTERRUPT_PRIORITY
設(shè)置內(nèi)核中斷優(yōu)先級(jí)
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
系統(tǒng)可管理的最大優(yōu)先級(jí)
優(yōu)先級(jí)數(shù)低于5不歸FreeRTOS管理
configMAX_SYSCALL_INTERRUPT_PRIORITY
此宏設(shè)置好后,優(yōu)先級(jí)低于此的中斷可以安全調(diào)用FreeRTOS的API函數(shù),優(yōu)先級(jí)高于此的中斷FreeRTOS是不能禁止的,中斷服務(wù)函數(shù)也不能調(diào)用FreeRTOS的API函數(shù)。
由于高于configMAX_SYSCALL_INTERRUPT_PRIORITY的優(yōu)先級(jí)不會(huì)被FreeRTOS內(nèi)核屏蔽,因此對(duì)于那些實(shí)時(shí)性要求嚴(yán)格的任務(wù)就可以使用這些優(yōu)先級(jí)。
FreeRTOS開(kāi)關(guān)中斷
開(kāi)關(guān)中斷函數(shù)為portENABLE_INTERRUPTS和portDISABLE_INTERRUPTS
當(dāng)關(guān)閉中斷后,優(yōu)先級(jí)低于configMAX_SYSCALL_INTERRUPT_PRIORITY(優(yōu)先級(jí)數(shù)大于configMAX_SYSCALL_INTERRUPT_PRIORITY)的中斷將被屏蔽,高于configMAX_SYSCALL_INTERRUPT_PRIORITY(優(yōu)先級(jí)數(shù)小于configMAX_SYSCALL_INTERRUPT_PRIORITY)的不會(huì)被屏蔽
臨界段代碼
臨界段代碼也叫臨界區(qū),是指那些必須完整運(yùn)行,不能被打斷的代碼段。FreeRTOS在進(jìn)入臨界段代碼的時(shí)候需要關(guān)閉中斷,當(dāng)處理完臨界段代碼以后再打開(kāi)中斷。
FreeRTOS與臨界段代碼保護(hù)有關(guān)的函數(shù)有4個(gè):taskENTER_CRITICAL、taskEXIT_CRITICAL、taskENTER_CRITICAL_FROM_ISR、taskEXIT_CRITICAL_FROM_ISR,前兩個(gè)是任務(wù)級(jí)別的臨界段代碼保護(hù),后兩個(gè)是中斷級(jí)的臨界區(qū)保護(hù)。
中斷測(cè)試
start_task:創(chuàng)建另一個(gè)任務(wù)
interrupt_task:中斷測(cè)試實(shí)驗(yàn),任務(wù)中會(huì)調(diào)用FreeRTOS的關(guān)中斷函數(shù)portDISABLE_INTERRUPTS來(lái)將中斷關(guān)閉一段時(shí)間。
任務(wù)設(shè)置
//任務(wù)優(yōu)先級(jí) #define START_TASK_PRIO 1 //任務(wù)堆棧大小 #define START_STK_SIZE 256 //任務(wù)句柄 TaskHandle_t StartTask_Handler; //任務(wù)函數(shù) void start_task(void *pvParameters);//任務(wù)優(yōu)先級(jí) #define INTERRUPT_TASK_PRIO 2 //任務(wù)堆棧大小 #define INTERRUPT_STK_SIZE 256 //任務(wù)句柄 TaskHandle_t INTERRUPTTask_Handler; //任務(wù)函數(shù) void interrupt_task(void *p_arg);main函數(shù)
int main(void) {HAL_Init(); //初始化HAL庫(kù) Stm32_Clock_Init(360,25,2,8); //設(shè)置時(shí)鐘,180Mhzdelay_init(180); //初始化延時(shí)函數(shù)LED_Init(); //初始化LED uart_init(115200); //初始化串口TIM3_Init(10000-1,9000-1); //初始化定時(shí)器3,定時(shí)周期1STIM5_Init(10000-1,9000-1); //初始化定時(shí)器5,定時(shí)周期1S//創(chuàng)建開(kāi)始任務(wù)xTaskCreate((TaskFunction_t )start_task, //任務(wù)函數(shù)(const char* )"start_task", //任務(wù)名稱(uint16_t )START_STK_SIZE, //任務(wù)堆棧大小(void* )NULL, //傳遞給任務(wù)函數(shù)的參數(shù)(UBaseType_t )START_TASK_PRIO, //任務(wù)優(yōu)先級(jí)(TaskHandle_t* )&StartTask_Handler); //任務(wù)句柄 vTaskStartScheduler(); //開(kāi)啟任務(wù)調(diào)度 }任務(wù)函數(shù)
//開(kāi)始任務(wù)任務(wù)函數(shù) void start_task(void *pvParameters) {taskENTER_CRITICAL(); //進(jìn)入臨界區(qū)//創(chuàng)建中斷測(cè)試任務(wù)xTaskCreate((TaskFunction_t )interrupt_task, //任務(wù)函數(shù)(const char* )"interrupt_task", //任務(wù)名稱(uint16_t )INTERRUPT_STK_SIZE, //任務(wù)堆棧大小(void* )NULL, //傳遞給任務(wù)函數(shù)的參數(shù)(UBaseType_t )INTERRUPT_TASK_PRIO, //任務(wù)優(yōu)先級(jí)(TaskHandle_t* )&INTERRUPTTask_Handler); //任務(wù)句柄vTaskDelete(StartTask_Handler); //刪除開(kāi)始任務(wù)taskEXIT_CRITICAL(); //退出臨界區(qū) }//中斷測(cè)試任務(wù)函數(shù) void interrupt_task(void *pvParameters) {static u32 total_num=0;while(1){total_num+=1;if(total_num==5) {printf("關(guān)閉中斷.............\r\n");portDISABLE_INTERRUPTS(); //關(guān)閉中斷delay_xms(5000); //延時(shí)5sprintf("打開(kāi)中斷.............\r\n"); //打開(kāi)中斷portENABLE_INTERRUPTS();}LED0=~LED0;vTaskDelay(1000);} }中斷初始化
TIM_HandleTypeDef TIM3_Handler; //定時(shí)器3句柄 TIM_HandleTypeDef TIM5_Handler; //定時(shí)器5句柄//通用定時(shí)器3中斷初始化 //arr:自動(dòng)重裝值。 //psc:時(shí)鐘預(yù)分頻數(shù) //定時(shí)器溢出時(shí)間計(jì)算方法:Tout=((arr+1)*(psc+1))/Ft us. //Ft=定時(shí)器工作頻率,單位:Mhz //這里使用的是定時(shí)器3!(定時(shí)器3掛在APB1上,時(shí)鐘為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); }//通用定時(shí)器5中斷初始化 //arr:自動(dòng)重裝值(TIM2,TIM5是32位的!!) //psc:時(shí)鐘預(yù)分頻數(shù) 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); }//定時(shí)器底冊(cè)驅(qū)動(dòng),開(kāi)啟時(shí)鐘,設(shè)置中斷優(yōu)先級(jí) //此函數(shù)會(huì)被HAL_TIM_Base_Init()函數(shù)調(diào)用 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); //開(kāi)啟定時(shí)器并更新中斷,以后每次更新中斷,都會(huì)調(diào)用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); //開(kāi)啟定時(shí)器并更新中斷,以后每次更新中斷,都會(huì)調(diào)用TIM3_IRQHandler} } //定時(shí)器3中斷服務(wù)函數(shù) void TIM3_IRQHandler(void) {HAL_TIM_IRQHandler(&TIM3_Handler); }//定時(shí)器5中斷服務(wù)函數(shù) void TIM5_IRQHandler(void) {HAL_TIM_IRQHandler(&TIM5_Handler); }//回調(diào)函數(shù),定時(shí)器中斷服務(wù)函數(shù)調(diào)用 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {if(htim->Instance == TIM3){printf("TIM3輸出.....\r\n");}else if(htim->Instance == TIM5){printf("TIM5輸出.....\r\n");} }運(yùn)行結(jié)果
一開(kāi)始沒(méi)有關(guān)閉中斷,所以TIM3和TIM5都正常運(yùn)行,當(dāng)interrupt_task運(yùn)行5次之后,此時(shí)由于TIM5的中斷優(yōu)先級(jí)為5,等于configMAX_SYSCALL_INTERRUPT_PRIORITY,因此TIM5會(huì)被關(guān)閉。但是,TIM3的中斷優(yōu)先級(jí)高于configMAX_SYSCALL_INTERRUPT_PRIORITY,不會(huì)被關(guān)閉,所以TIM3正常運(yùn)行,中斷運(yùn)行5s后調(diào)用函數(shù)portENABLE_INTERRUPTS重新打開(kāi)中斷,重新打開(kāi)中斷后TIM5恢復(fù)運(yùn)行。
總結(jié)
以上是生活随笔為你收集整理的FreeRTOS中断配置与临界段的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: FreeRTOS任务挂起和恢复
- 下一篇: FreeRTOS的列表和列表项