IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 基于STM32的简易RTOS分析-延时函数与空闲任务 -> 正文阅读

[嵌入式]基于STM32的简易RTOS分析-延时函数与空闲任务

????????之前的代码里为了实现LED灯闪烁效果,需要先将LED点亮然后延时一段时间后将其熄灭。在这段延时等待期间MCU一直在做无意义的等待计数,为了提高MCU机时的有效利用率,可以让MCU在延时的这段时间内执行其他任务。任务自身发起延时后放弃MCU使用权导致自身的运行发生阻塞,这种延时就叫做阻塞式延时。

????????RTOS一个基于优先级的抢占式内核,为了使高优先级的任务不至于一直独占MCU的使用权,需要其在合适的时机让出MCU的使用权,给其他任务使用MCU的机会。阻塞式延时RTOS提供的让高优先级任务主动放弃MCU使用权的方法之一。

? ? ? ? 在RTOS中会出现在某个时间内所有的任务都处于非就绪态的情况,这会导致系统处于无任务可运行的状况,为了防止这种状况的出现,RTOS需要提供一个最低优先级的任务,在没有其他任务可执行的时候去执行这个任务,这个最低优先级的任务就是空闲任务。

? ? ?一、空闲函数设计? ?

????????新增一个最低优先级的空闲任务,并配置其相关的任务栈和任务控制块。在进行RTOS初始化的时候,创建这个任务。

List taskDelayList;

#define TASK_IDLE_STACK_SIZE       128
UINT32 taskIdleStack[TASK_IDLE_STACK_SIZE];
TaskTcb taskIdleTcb;

/**********************************************************************************************
  * @brief 
  *       
  * @param  None
  * @retval None
  **********************************************************************************************/
void TaskIdle(void)
{    
    while(1)
    {
        LED_SetRed();
    }
}


/**********************************************************************************************
  * @brief 
  *       
  * @param  None
  * @retval None
  **********************************************************************************************/
void TaskScheduleInit(void)
{
    UINT16 i = 0;
    
    for(i = 0; i <= OS_TASK_MAX_PRIORITIES; i++)
    {
        ListInit(&taskTcbPtrPrioTbl[i]);
    }
    
    ListInit(&taskDelayList);
    
    BitMapInit(&taskPrioBitMap);

    TaskCreate(&taskIdleTcb, TaskIdle,taskIdleStack, TASK_IDLE_STACK_SIZE, OS_TASK_MAX_PRIORITIES, 0);
}

二、延时函数设计

????????为了方便增加和删除延时任务,增加一个延时任务的链表taskDelayList,将需要延时任务都挂载在这个链表下面,在系统Tick时遍历这个链表进行延时逻辑处理。在任务控制块里增加延时节点taskDelayNode和延时计数变量delayTicks。

typedef struct STRUCT_TASK_TCB
{
    UINT32 *stackPtr; /*< Points to the location of the last item placed on the tasks stack.  THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
    Node taskTcbNode;
    
    Node taskDelayNode;
    UINT32  delayTicks;/* Nbr ticks to delay task or, timeout waiting for event   */
    
    UINT8 priority; /*< The priority of the task.  0 is the highest priority. */
    UINT8 timeSliceSet;
    UINT8 timeSlice;
}TaskTcb,*TaskTcbPtr;

????????在任务创建函数里对延时相关变量进行初始化,延时任务链表taskDelayList已在TaskScheduleInit函数里初始化。


void TaskCreate(TaskTcb *pTcb, FunPtr pTaskFun, UINT32* pTaskStack, UINT32 stackSize, UINT8 taskPrio, UINT8 timeSlice)
{
    UINT32  *pStack;
    UINT32 cnt;
    
    for(cnt = 0; cnt < stackSize*sizeof(UINT32);cnt++)/* Fill the stack with a known value to assist debugging. */
    {
        *((UINT8*)pTaskStack + cnt) = OS_STACK_FILL_BYTE;
    }
    
    pStack      = &pTaskStack[stackSize];/* Get top address of stack, because grows from high memory to low*/
    pStack      = (UINT32 *)((UINT32)(pStack) & 0xFFFFFFF8u);/* AAPCS(ARM application procedure all standard) Align the stack to 8bytes */

    /*Registers stacked as if auto-saved on exception*/
    *(--pStack) = (UINT32)0x01000000uL;                /*xPSR bit24 thumb state bit*/
    *(--pStack) = (UINT32)pTaskFun;                    /*Entry Point(PC)*/
    *(--pStack) = (UINT32)0x12121212uL;                /*R14 (LR)*/
    *(--pStack) = (UINT32)0x12121212uL;                /* R12*/
    *(--pStack) = (UINT32)0x03030303uL;                /* R3*/
    *(--pStack) = (UINT32)0x02020202uL;                /* R2*/
    *(--pStack) = (UINT32)0x01010101uL;                /* R1*/
    *(--pStack) = (UINT32)0x00000000u;                 /* R0*/

    /*Remaining registers saved on process stack*/
    *(--pStack) = (UINT32)0x11111111uL;                /* R11*/
    *(--pStack) = (UINT32)0x10101010uL;                /* R10*/
    *(--pStack) = (UINT32)0x09090909uL;                /* R9*/
    *(--pStack) = (UINT32)0x08080808uL;                /* R8*/
    *(--pStack) = (UINT32)0x07070707uL;                /* R7*/
    *(--pStack) = (UINT32)0x06060606uL;                /* R6*/
    *(--pStack) = (UINT32)0x05050505uL;                /* R5*/
    *(--pStack) = (UINT32)0x04040404uL;                /* R4*/

  
    pTcb->stackPtr = pStack;
    
    pTcb->priority = taskPrio;

    pTcb->delayTicks = 0;

    if(timeSlice != 0)
        pTcb->timeSliceSet = timeSlice;
    else
        pTcb->timeSliceSet = OS_TASK_DEFAULT_TIME_SLICE;
    pTcb->timeSlice = pTcb->timeSliceSet;

    NodeInit(&pTcb->taskDelayNode, pTcb);
    NodeInit(&pTcb->taskTcbNode, pTcb);
    ListInsertAtTail(&taskTcbPtrPrioTbl[taskPrio], &pTcb->taskTcbNode);
    BitMapSetBit(&taskPrioBitMap, taskPrio);
}

????????在延时函数里设置需要延时的Tick数量,将需要延时的任务加入链表taskDelayList,并将当前任务从任务优先级调度链表里删除,随后进行任务调度将当前任务阻塞,去运行其他就绪的最高优先级任务。

/**********************************************************************************************
  * @brief 
  *       
  * @param  None
  * @retval None
  **********************************************************************************************/
void TaskDelay(UINT32 ticks)
{
    pOsCurTcb->delayTicks = ticks;
    ListInsertAtTail(&taskDelayList, &(pOsCurTcb->taskDelayNode));
    ListRemoveNode(&taskTcbPtrPrioTbl[pOsCurTcb->priority], &(pOsCurTcb->taskTcbNode));
    
    if(taskTcbPtrPrioTbl[pOsCurTcb->priority].nodeCount == 0)
    {
        BitMapDelBit(&taskPrioBitMap, pOsCurTcb->priority);
    }
    
    TaskSchedule();
}

????????在SysTick中断里对延时任务链表循环处理,若有任务延时结束则将其唤醒并加入任务优先级调度链表。

/**********************************************************************************************
  * @brief 
  *       
  * @param  None
  * @retval None
  **********************************************************************************************/
void SysTick_Handler(void)
{
    NodePtr pHeadNode;
    TaskTcbPtr pTaskTcb;

    pHeadNode = taskDelayList.pHeadNode;

    for(UINT16 i = 0; i < taskDelayList.nodeCount; i++)
    {
        pTaskTcb = (TaskTcbPtr)(pHeadNode->pOwner);

        if(pTaskTcb->delayTicks)
        {
            pTaskTcb->delayTicks--;
            
            if(pTaskTcb->delayTicks == 0)
            {
                ListRemoveNode(&taskDelayList, pHeadNode);
                ListInsertAtTail(&taskTcbPtrPrioTbl[pTaskTcb->priority], &(pTaskTcb->taskTcbNode));
                BitMapSetBit(&taskPrioBitMap, pTaskTcb->priority);
            }
        }
        pHeadNode = pHeadNode->next;
    }

    
    if(pOsCurTcb->timeSlice)
        pOsCurTcb->timeSlice--;

    if(taskTcbPtrPrioTbl[pOsCurTcb->priority].nodeCount > 1)
    {
        if(pOsCurTcb->timeSlice == 0)
        {
            pHeadNode = ListPopHead(&taskTcbPtrPrioTbl[pOsCurTcb->priority]);
            ListInsertAtTail(&taskTcbPtrPrioTbl[pOsCurTcb->priority],pHeadNode);
            pTaskTcb = (TaskTcbPtr)(taskTcbPtrPrioTbl[pOsCurTcb->priority].pHeadNode->pOwner);
            pTaskTcb->timeSlice = pTaskTcb->timeSliceSet;
        }
    }
    
    TaskSchedule();
}

????????之前的链表节点删除函数ListRemoveNode逻辑上未考虑删除头节点的情况,这里完善一下

 /**********************************************************************************************
  * @brief 
  *       
  * @param  None
  * @retval None
  **********************************************************************************************/
void ListRemoveNode(ListPtr pList, NodePtr pNode)
{
    if(pList->pHeadNode == pNode)
    {
        pList->pHeadNode = pNode->next;
    }

    pNode->prev->next = pNode->next;
    pNode->next->prev = pNode->prev;
    
    //NodeInit(pNode,pNode->pOwner);
    
    pList->nodeCount--;

    if(pList->nodeCount == 0)
        pList->pHeadNode = NULL;
}

三、仿真验证

? ? ? ? 创建两个优先级不同的任务,若高优先级的任务未进入延时阻塞状态则低优先级的任务就不会运行,同时当所有的任务都进入阻塞状态后,系统就会运行空闲任务。

/**********************************************************************************************
  * @brief StartTask
  *       
  * @param  None
  * @retval None
  **********************************************************************************************/
void StartTask(void)
{
    while(1)
    {
        LED_SetGreen();
        TaskDelay(1500);
        LED_ResetGreen();
        TaskDelay(1500);
    }
}

/**********************************************************************************************
  * @brief SecondTask
  *       
  * @param  None
  * @retval None
  **********************************************************************************************/
void SecondTask(void)
{
  static UINT16 ticks;
    while(1)
    {  
        LED_SetBlue();
        TaskDelay(2500);
        LED_ResetBlue();
        TaskDelay(2500);   
    }
}

????????在main函数里创建StartTask任务优先级设置为0,创建SecondTask任务优先级设置为1。

int main()
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
    LED_GPIO_Config();
    SysTickRateInit();
    TaskScheduleInit();
    
    TaskCreate(&StartTaskTcb, StartTask, StartTaskStack, START_TASK_SIZE,0,2);
    TaskCreate(&SecondTaskTcb, SecondTask, SecondTaskStack, SECOND_TASK_SIZE,1,3);
     
    OsTaskStart();

     return 0;
}

????????StartTask任务调用TaskDelay函数后进入阻塞状态,系统进行任务调度后会运行SecondTask任务。

????????StartTask阻塞后系统运行Second任务,注意此次调度是由TaskDelay函数引起的,并未进过SysTick进行调度,所以StartTask此时delayTicks仍是1500

? ? ? ? 当两个任务都进入阻塞状态后系统运行空闲任务。

?????????在SysTick中断里对延时任务进行处理

????????StartTask延时结束继续运行?

?

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-07-17 16:39:38  更:2022-07-17 16:42:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 13:48:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码