当前位置:首页 > 单片机 > 单片机
[导读]一、上篇回顾上一篇文章中,我们完成了两个任务使用PendSV实现了互相切换的功能,下面我们接着其思路往下做。这次我们完成OS基本框架,即实现一个非抢占式(已经调度的进程执行完成,然后根据优先级调度等待的进程)的

一、上篇回顾

上一篇文章中,我们完成了两个任务使用PendSV实现了互相切换的功能,下面我们接着其思路往下做。这次我们完成OS基本框架,即实现一个非抢占式(已经调度的进程执行完成,然后根据优先级调度等待的进程)的任务调度系统,至于抢占式的,就留给大家思考了。上次代码中Task_Switch实现了两个任务的切换,代码如下:


voidTask_Switch(){if(g_OS_Tcb_CurP==&TCB_1)g_OS_Tcb_HighRdyP=&TCB_2;elseg_OS_Tcb_HighRdyP=&TCB_1;OSCtxSw();}


我们把要切换任务指针付给跟_OS_Tcb_HighRdyP,然后调用OSCtxSw触发PendSV异常,就实现了任务的切换。如果是多个任务,我们只需找出就绪任务中优先级最大的切换之即可。

二、添加任务调度功能

为了实现这一目标我们至少需要知道任务的状态和时间等数据。我们定义了一个任务状态枚举类型OS_TASK_STA,方便添加修改状态。在OS_TCB结构体中添加了两个成员TimeDly和State,TimeDly是为了实现OS_TimeDly,至于State与优先级一起是作为任务切换的依据。


typedefenumOS_TASK_STA{TASK_READY,TASK_DELAY,}OS_TASK_STA;typedefstructOS_TCB{OS_STK*StkAddr;OS_U32TimeDly;OS_TASK_STAState;}OS_TCB,*OS_TCBP;


说到任务切换,我们必须面对临界区的问题,在一些临界的代码两端不加临界区进去和退出代码,会出现许多意想不到的问题。以下地方需要特别注意,对关键的全局变量的写操作、对任务控制块的操作等。进入临界区和退出临界区需要关闭和开启中断,我们采用uCOS中的一部分代码:


PUBLICOS_CPU_SR_SavePUBLICOS_CPU_SR_RestoreOS_CPU_SR_SaveMRSR0,PRIMASKCPSIDIBXLROS_CPU_SR_RestoreMSRPRIMASK,R0BXLR


#defineOS_USE_CRITICALOS_U32cpu_sr;#defineOS_ENTER_CRITICAL(){cpu_sr=OS_CPU_SR_Save();}#defineOS_EXIT_CRITICAL(){OS_CPU_SR_Restore(cpu_sr);}#defineOS_PendSV_Trigger()OSCtxSw()

一个OS至少要有任务表,我们可以用数组,当然也可以用链表。为了简单,我们使用数组,使用数组下表作为优先级。当然,必要的地方一定要做数组越界检查。

#defineOS_TASK_MAX_NUM32OS_TCBPOS_TCB_TABLE[OS_TASK_MAX_NUM];

为了使OS更完整,我们定义几个全局变量,OS_TimeTick记录系统时间,g_Prio_Cur记录当前运行的任务优先级,g_Prio_HighRdy记录任务调度后就绪任务中的最高优先级。

OS_U32OS_TimeTick;OS_U8g_Prio_Cur;OS_U8g_Prio_HighRdy;

下面三个函数与PendSV一起实现了任务的调度功能。

OS_Task_Switch函数功能:找出已就绪最高优先级的任务,并将其TCB指针赋值给g_OS_Tcb_HighRdyP,将其优先级赋值g_Prio_HighRdy。注意其中使用了临界区。


voidOS_Task_Switch(void){OS_S32i;OS_TCBPtcb_p;OS_USE_CRITICALfor(i=0;iState==TASK_READY)break;}OS_ENTER_CRITICAL();g_OS_Tcb_HighRdyP=tcb_p;g_Prio_HighRdy=i;OS_EXIT_CRITICAL();}


OS_TimeDly至当前任务为延时状态,并将延时时间赋值给当前TCB的TimeDly成员,并调用OS_Task_Switch函数,然后触发PendSV进行上下文切换。OS_Task_Switch找到就绪状态中优先级最高的,并将其赋值相关全局变量,作为上下文切换的依据。


voidOS_TimeDly(OS_U32ticks){OS_USE_CRITICALOS_ENTER_CRITICAL();g_OS_Tcb_CurP->State=TASK_DELAY;g_OS_Tcb_CurP->TimeDly=ticks;OS_EXIT_CRITICAL();OS_Task_Switch();OS_PendSV_Trigger();}


SysTick_Handler实现系统计时,并遍历任务表,任务若是延时状态,就令其延时值减一,若减完后为零,就将其置为就绪状态。


voidSysTick_Handler(void){OS_TCBPtcb_p;OS_S32i;OS_USE_CRITICALOS_ENTER_CRITICAL();++OS_TimeTick;for(i=0;iState==TASK_DELAY){--tcb_p->TimeDly;if(tcb_p->TimeDly==0)tcb_p->State=TASK_READY;}}OS_EXIT_CRITICAL();}


当所有任务都没就绪怎么办?这时就需要空闲任务了,我们把它设为优先级最低的任务。WFE指令为休眠指令,当来中断时,退出休眠,然后看看有没有已就绪的任务,有则调度之,否则继续休眠,这样可以减小功耗哦。


voidOS_Task_Idle(void){while(1){asm("WFE");OS_Task_Switch();OS_PendSV_Trigger();}}


当一个任务只运行一次时(例如下面main.c的task1),结束时就会调用OS_Task_End函数,此函数会调用OS_Task_Delete函数从任务表中删除当前的任务,然后调度任务。


voidOS_Task_Delete(OS_U8prio){if(prio>=OS_TASK_MAX_NUM)return;OS_TCB_TABLE[prio]=0;}voidOS_Task_End(void){printf("TaskofPrio%dEndn",g_Prio_Cur);OS_Task_Delete(g_Prio_Cur);OS_Task_Switch();OS_PendSV_Trigger();}


三、OS实战

下是完整的main.c代码:


#include"stdio.h"#include"stm32f4xx.h"#defineOS_EXCEPT_STK_SIZE1024#defineTASK_1_STK_SIZE128#defineTASK_2_STK_SIZE128#defineTASK_3_STK_SIZE128#defineTASK_IDLE_STK_SIZE1024#defineOS_TASK_MAX_NUM32#defineOS_TICKS_PER_SECOND1000#defineOS_USE_CRITICALOS_U32cpu_sr;#defineOS_ENTER_CRITICAL(){cpu_sr=OS_CPU_SR_Save();}#defineOS_EXIT_CRITICAL(){OS_CPU_SR_Restore(cpu_sr);}#defineOS_PendSV_Trigger()OSCtxSw()typedefsignedcharOS_S8;typedefsignedshortOS_S16;typedefsignedintOS_S32;typedefunsignedcharOS_U8;typedefunsignedshortOS_U16;typedefunsignedintOS_U32;typedefunsignedintOS_STK;typedefvoid(*OS_TASK)(void);typedefenumOS_TASK_STA{TASK_READY,TASK_DELAY,}OS_TASK_STA;typedefstructOS_TCB{OS_STK*StkAddr;OS_U32TimeDly;OS_U8State;}OS_TCB,*OS_TCBP;OS_TCBPOS_TCB_TABLE[OS_TASK_MAX_NUM];OS_TCBPg_OS_Tcb_CurP;OS_TCBPg_OS_Tcb_HighRdyP;OS_U32OS_TimeTick;OS_U8g_Prio_Cur;OS_U8g_Prio_HighRdy;staticOS_STKOS_CPU_ExceptStk[OS_EXCEPT_STK_SIZE];OS_STK*g_OS_CPU_ExceptStkBase;staticOS_TCBTCB_1;staticOS_TCBTCB_2;staticOS_TCBTCB_3;staticOS_TCBTCB_IDLE;staticOS_STKTASK_1_STK[TASK_1_STK_SIZE];staticOS_STKTASK_2_STK[TASK_2_STK_SIZE];staticOS_STKTASK_3_STK[TASK_3_STK_SIZE];staticOS_STKTASK_IDLE_STK[TASK_IDLE_STK_SIZE];externOS_U32SystemCoreClock;externvoidOSStart_Asm(void);externvoidOSCtxSw(void);externOS_U32OS_CPU_SR_Save(void);externvoidOS_CPU_SR_Restore(OS_U32);voidtask_1(void);voidtask_2(void);voidtask_3(void);voidOS_Task_Idle(void);voidOS_TimeDly(OS_U32);voidOS_Task_Switch(void);voidOS_Task_Create(OS_TCB*,OS_TASK,OS_STK*,OS_U8);voidOS_Task_Delete(OS_U8);voidOS_Task_End(void);voidOS_Init(void);voidOS_Start(void);voidtask_1(void){printf("[%d]Task1Runing!!!n",OS_TimeTick);OS_Task_Create(&TCB_2,task_2,&TASK_2_STK[TASK_2_STK_SIZE-1],5);OS_Task_Create(&TCB_3,task_3,&TASK_3_STK[TASK_3_STK_SIZE-1],7);}voidtask_2(void){while(1){printf("[%d]Task2Runing!!!n",OS_TimeTick);OS_TimeDly(1000);}}voidtask_3(void){while(1){printf("[%d]Task3Runing!!!n",OS_TimeTick);OS_TimeDly(1500);}}voidOS_Task_Idle(void){while(1){asm("WFE");OS_Task_Switch();OS_PendSV_Trigger();}}voidOS_TimeDly(OS_U32ticks){OS_USE_CRITICALOS_ENTER_CRITICAL();g_OS_Tcb_CurP->State=TASK_DELAY;g_OS_Tcb_CurP->TimeDly=ticks;OS_EXIT_CRITICAL();OS_Task_Switch();OS_PendSV_Trigger();}voidOS_Task_Switch(void){OS_S32i;OS_TCBPtcb_p;OS_USE_CRITICALfor(i=0;iState==TASK_READY)break;}OS_ENTER_CRITICAL();g_OS_Tcb_HighRdyP=tcb_p;g_Prio_HighRdy=i;OS_EXIT_CRITICAL();}voidOS_Task_Delete(OS_U8prio){if(prio>=OS_TASK_MAX_NUM)return;OS_TCB_TABLE[prio]=0;}voidOS_Task_End(void){printf("TaskofPrio%dEndn",g_Prio_Cur);OS_Task_Delete(g_Prio_Cur);OS_Task_Switch();OS_PendSV_Trigger();}voidOS_Task_Create(OS_TCB*tcb,OS_TASKtask,OS_STK*stk,OS_U8prio){OS_USE_CRITICALOS_STK*p_stk;if(prio>=OS_TASK_MAX_NUM)return;OS_ENTER_CRITICAL();p_stk=stk;p_stk=(OS_STK*)((OS_STK)(p_stk)&0xFFFFFFF8u);*(--p_stk)=(OS_STK)0x01000000uL;//xPSR*(--p_stk)=(OS_STK)task;//EntryPoint*(--p_stk)=(OS_STK)OS_Task_End;//R14(LR)*(--p_stk)=(OS_STK)0x12121212uL;//R12*(--p_stk)=(OS_STK)0x03030303uL;//R3*(--p_stk)=(OS_STK)0x02020202uL;//R2*(--p_stk)=(OS_STK)0x01010101uL;//R1*(--p_stk)=(OS_STK)0x00000000u;//R0*(--p_stk)=(OS_STK)0x11111111uL;//R11*(--p_stk)=(OS_STK)0x10101010uL;//R10*(--p_stk)=(OS_STK)0x09090909uL;//R9*(--p_stk)=(OS_STK)0x08080808uL;//R8*(--p_stk)=(OS_STK)0x07070707uL;//R7*(--p_stk)=(OS_STK)0x06060606uL;//R6*(--p_stk)=(OS_STK)0x05050505uL;//R5*(--p_stk)=(OS_STK)0x04040404uL;//R4tcb->StkAddr=p_stk;tcb->TimeDly=0;tcb->State=TASK_READY;OS_TCB_TABLE[prio]=tcb;OS_EXIT_CRITICAL();}voidSysTick_Handler(void){OS_TCBPtcb_p;OS_S32i;OS_USE_CRITICALOS_ENTER_CRITICAL();++OS_TimeTick;for(i=0;iState==TASK_DELAY){--tcb_p->TimeDly;if(tcb_p->TimeDly==0)tcb_p->State=TASK_READY;}}OS_EXIT_CRITICAL();}voidOS_Init(void){inti;g_OS_CPU_ExceptStkBase=OS_CPU_ExceptStk+OS_EXCEPT_STK_SIZE-1;asm("CPSIDI");for(i=0;i

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

在嵌入式开发中,STM32的时钟系统因其灵活性和复杂性成为开发者关注的焦点。然而,看似简单的时钟配置背后,隐藏着诸多易被忽视的陷阱,轻则导致系统不稳定,重则引发硬件损坏。本文从时钟源选择、PLL配置、总线时钟分配等关键环...

关键字: STM32 时钟系统

在嵌入式系统开发中,STM32系列微控制器的内部温度传感器因其低成本、高集成度特性,广泛应用于设备自检、环境监测等场景。然而,受芯片工艺差异和电源噪声影响,其原始数据存在±1.5℃的固有误差。本文从硬件配置、校准算法、软...

关键字: STM32 温度传感器

在能源效率与智能化需求双重驱动下,AC-DC转换器的数字控制技术正经历从传统模拟方案向全数字架构的深刻变革。基于STM32微控制器的PFM(脉冲频率调制)+PWM(脉冲宽度调制)混合调制策略,结合动态电压调整(Dynam...

关键字: AC-DC STM32

当前智能家居产品需求不断增长 ,在这一背景下 ,对现有浇花装置缺陷进行了改进 ,设计出基于STM32单片机的全 自动家用浇花机器人。该设计主要由机械结构和控制系统构成 ,机械结构通过麦克纳姆轮底盘与喷洒装置的结合实现机器...

关键字: STM32 麦克纳姆轮 安全可靠 通过性强

用c++编程似乎是让你的Arduino项目起步的障碍吗?您想要一种更直观的微控制器编程方式吗?那你需要了解一下Visuino!这个图形化编程平台将复杂电子项目的创建变成了拖动和连接块的简单任务。在本文中,我们将带您完成使...

关键字: Visuino Arduino ESP32 STM32

基于STM32与LoRa技术的无线传感网络凭借其低功耗、广覆盖、抗干扰等特性,成为环境监测、工业自动化等场景的核心解决方案。然而,如何在复杂电磁环境中实现高效休眠调度与动态信道优化,成为提升网络能效与可靠性的关键挑战。本...

关键字: STM32 LoRa

在实时控制系统、高速通信协议处理及高精度数据采集等对时间敏感的应用场景中,中断响应延迟的优化直接决定了系统的可靠性与性能上限。STM32系列微控制器凭借其灵活的嵌套向量中断控制器(NVIC)、多通道直接内存访问(DMA)...

关键字: STM32 DMA

数字电源技术向高功率密度、高效率与高动态响应方向加速演进,STM32微控制器凭借其基于DSP库的算法加速能力与对LLC谐振变换器的精准控制架构,成为优化电源动态性能的核心平台。相较于传统模拟控制或通用型数字控制器,STM...

关键字: STM32 数字电源

STM32微控制器凭借其针对电机控制场景的深度优化,成为高精度、高可靠性驱动系统的核心选择。相较于通用型MCU,STM32在电机控制领域的核心优势集中体现在FOC(磁场定向控制)算法的硬件加速引擎与PWM死区时间的动态补...

关键字: STM32 电机控制

无线充电技术加速渗透消费电子与汽车电子领域,基于Qi协议的无线充电发射端开发成为智能设备能量补给的核心课题。传统模拟控制方案存在响应滞后、参数调整困难等问题,而基于STM32的数字PID控制结合FOD(Foreign O...

关键字: STM32 无线充电
关闭