FreeRTOS总结
前言
在使用二值信号量的时候会遇到很常见的一个问题——优先级翻转,优先级翻转在可剥夺
内核中是非常常见的,在实时系统中不允许出现这种现象,这样会破坏任务的预期顺序,可能
会导致严重的后果。
提示:以下是本篇文章正文内容,下面案例可供参考
一、浅浅了解优先级翻转
例如:三个不同优先级的任务——低任务、中任务、高任务
创建二值信号量,然后释放一次信号量。
低任务获取信号量,长时间不释放,占住了高任务的资源。
高任务获取信号量,但是此时信号量被低任务占用着,高任务只能等待。但是等待过程中,中任务是一直运行的。出现了优先级反转。
二、模拟 优先级翻转实验
1.代码
**注意:**低优先级和高优先级均要获取二值信号,并且低优先级要长时间获取信号量,模拟占取高优先级的二值信号量。
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "lcd.h"
#include "key.h"
#include "beep.h"
#include "malloc.h"
#include "string.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/************************************************
ALIENTEK ¾«Ó¢STM32F103¿ª·¢°å FreeRTOSʵÑé14-3
FreeRTOSÓÅÏȼ¶·×ªÊµÑé-¿âº¯Êý°æ±¾
¼¼ÊõÖ§³Ö£ºwww.openedv.com
ÌÔ±¦µêÆÌ£ºhttp://eboard.taobao.com
¹Øע΢ÐŹ«ÖÚƽ̨΢Ðźţº"ÕýµãÔ×Ó"£¬Ãâ·Ñ»ñÈ¡STM32×ÊÁÏ¡£
¹ãÖÝÊÐÐÇÒíµç×ӿƼ¼ÓÐÏÞ¹«Ë¾
×÷ÕߣºÕýµãÔ×Ó @ALIENTEK
************************************************/
//ÈÎÎñÓÅÏȼ¶
#define START_TASK_PRIO 1
//ÈÎÎñ¶ÑÕ»´óС
#define START_STK_SIZE 256
//ÈÎÎñ¾ä±ú
TaskHandle_t StartTask_Handler;
//ÈÎÎñº¯Êý
void start_task(void *pvParameters);
//ÈÎÎñÓÅÏȼ¶
#define LOW_TASK_PRIO 2
//ÈÎÎñ¶ÑÕ»´óС
#define LOW_STK_SIZE 256
//ÈÎÎñ¾ä±ú
TaskHandle_t LowTask_Handler;
//ÈÎÎñº¯Êý
void low_task(void *pvParameters);
//ÈÎÎñÓÅÏȼ¶
#define MIDDLE_TASK_PRIO 3
//ÈÎÎñ¶ÑÕ»´óС
#define MIDDLE_STK_SIZE 256
//ÈÎÎñ¾ä±ú
TaskHandle_t MiddleTask_Handler;
//ÈÎÎñº¯Êý
void middle_task(void *pvParameters);
//ÈÎÎñÓÅÏȼ¶
#define HIGH_TASK_PRIO 4
//ÈÎÎñ¶ÑÕ»´óС
#define HIGH_STK_SIZE 256
//ÈÎÎñ¾ä±ú
TaskHandle_t HighTask_Handler;
//ÈÎÎñº¯Êý
void high_task(void *pvParameters);
//¶þÖµÐźÅÁ¿¾ä±ú
SemaphoreHandle_t BinarySemaphore; //¶þÖµÐźÅÁ¿
//LCDË¢ÆÁʱʹÓõÄÑÕÉ«
int lcd_discolor[14]={ WHITE, BLACK, BLUE, BRED,
GRED, GBLUE, RED, MAGENTA,
GREEN, CYAN, YELLOW,BROWN,
BRRED, GRAY };
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//ÉèÖÃϵͳÖжÏÓÅÏȼ¶·Ö×é4
delay_init(); //ÑÓʱº¯Êý³õʼ»¯
uart_init(115200); //³õʼ»¯´®¿Ú
LED_Init(); //³õʼ»¯LED
KEY_Init(); //³õʼ»¯°´¼ü
BEEP_Init(); //³õʼ»¯·äÃùÆ÷
LCD_Init(); //³õʼ»¯LCD
my_mem_init(SRAMIN); //³õʼ»¯ÄÚ²¿ÄÚ´æ³Ø
POINT_COLOR = RED;
LCD_ShowString(30,10,200,16,16,"ATK STM32F103/407");
LCD_ShowString(30,30,200,16,16,"FreeRTOS Examp 14-3");
LCD_ShowString(30,50,200,16,16,"Priority Overturn");
LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,90,200,16,16,"2016/11/25");
//´´½¨¿ªÊ¼ÈÎÎñ
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(); //½øÈëÁÙ½çÇø
//´´½¨¶þÖµÐźÅÁ¿
BinarySemaphore=xSemaphoreCreateBinary();
//¶þÖµÐźÅÁ¿´´½¨³É¹¦ÒÔºóÒªÏÈÊÍ·ÅÒ»ÏÂ
if(BinarySemaphore!=NULL)xSemaphoreGive(BinarySemaphore);
//´´½¨¸ßÓÅÏȼ¶ÈÎÎñ
xTaskCreate((TaskFunction_t )high_task,
(const char* )"high_task",
(uint16_t )HIGH_STK_SIZE,
(void* )NULL,
(UBaseType_t )HIGH_TASK_PRIO,
(TaskHandle_t* )&HighTask_Handler);
//´´½¨ÖеÈÓÅÏȼ¶ÈÎÎñ
xTaskCreate((TaskFunction_t )middle_task,
(const char* )"middle_task",
(uint16_t )MIDDLE_STK_SIZE,
(void* )NULL,
(UBaseType_t )MIDDLE_TASK_PRIO,
(TaskHandle_t* )&MiddleTask_Handler);
//´´½¨µÍÓÅÏȼ¶ÈÎÎñ
xTaskCreate((TaskFunction_t )low_task,
(const char* )"low_task",
(uint16_t )LOW_STK_SIZE,
(void* )NULL,
(UBaseType_t )LOW_TASK_PRIO,
(TaskHandle_t* )&LowTask_Handler);
vTaskDelete(StartTask_Handler); //ɾ³ý¿ªÊ¼ÈÎÎñ
taskEXIT_CRITICAL(); //Í˳öÁÙ½çÇø
}
//¸ßÓÅÏȼ¶ÈÎÎñµÄÈÎÎñº¯Êý
void high_task(void *pvParameters)
{
u8 num;
POINT_COLOR = BLACK;
LCD_DrawRectangle(5,110,115,314); //»Ò»¸ö¾ØÐÎ
LCD_DrawLine(5,130,115,130); //»Ïß
POINT_COLOR = BLUE;
LCD_ShowString(6,111,110,16,16,"High Task");
while(1)
{
vTaskDelay(500); //ÑÓʱ500ms£¬Ò²¾ÍÊÇ500¸öʱÖÓ½ÚÅÄ
num++;
printf("high task Pend Sem\r\n");
xSemaphoreTake(BinarySemaphore,portMAX_DELAY); //»ñÈ¡¶þÖµÐźÅÁ¿
printf("high task Running!\r\n");
LCD_Fill(6,131,114,313,lcd_discolor[num%14]); //Ìî³äÇøÓò
LED1=!LED1;
xSemaphoreGive(BinarySemaphore); //ÊÍ·ÅÐźÅÁ¿
vTaskDelay(500); //ÑÓʱ500ms£¬Ò²¾ÍÊÇ500¸öʱÖÓ½ÚÅÄ
}
}
//ÖеÈÓÅÏȼ¶ÈÎÎñµÄÈÎÎñº¯Êý
void middle_task(void *pvParameters)
{
u8 num;
POINT_COLOR = BLACK;
LCD_DrawRectangle(125,110,234,314); //»Ò»¸ö¾ØÐÎ
LCD_DrawLine(125,130,234,130); //»Ïß
POINT_COLOR = BLUE;
LCD_ShowString(126,111,110,16,16,"Middle Task");
while(1)
{
num++;
printf("middle task Running!\r\n");
LCD_Fill(126,131,233,313,lcd_discolor[13-num%14]); //Ìî³äÇøÓò
LED0=!LED0;
vTaskDelay(1000); //ÑÓʱ1s£¬Ò²¾ÍÊÇ1000¸öʱÖÓ½ÚÅÄ
}
}
//µÍÓÅÏȼ¶ÈÎÎñµÄÈÎÎñº¯Êý
void low_task(void *pvParameters)
{
static u32 times;
while(1)
{
xSemaphoreTake(BinarySemaphore,portMAX_DELAY); //»ñÈ¡¶þÖµÐźÅÁ¿
printf("low task Running!\r\n");
for(times=0;times<5000000;times++) //Ä£ÄâµÍÓÅÏȼ¶ÈÎÎñÕ¼ÓöþÖµÐźÅÁ¿
{
taskYIELD(); //·¢ÆðÈÎÎñµ÷¶È
}
xSemaphoreGive(BinarySemaphore); //ÊͷŶþÖµÐźÅÁ¿
vTaskDelay(1000); //ÑÓʱ1s£¬Ò²¾ÍÊÇ1000¸öʱÖÓ½ÚÅÄ
}
}
总结
今天就大概了解了什么是优先级翻转的现象。
当一个低优先级任务和一个高优先级任务同时使用同一个信号量,而系统中还有其他中等优先级任务时。如果低优先级任务获得了信号量,那么高优先级的任务就会处于等待状态,但是,中等优先级的任务可以打断低优先级任务而先于高优先级任务运行(此时高优先级的任务在等待信号量,所以不能运行),这是就出现了优先级翻转的现象。
那如何解决这个问题呢?下篇的博客会告诉你。
继续加油!