当前位置: 首页> 汽车> 时评 > 优化seo技术_webqq网页版_网站站长_广告点击一次多少钱

优化seo技术_webqq网页版_网站站长_广告点击一次多少钱

时间:2025/8/23 15:30:35来源:https://blog.csdn.net/2301_77061352/article/details/143163648 浏览次数: 0次
优化seo技术_webqq网页版_网站站长_广告点击一次多少钱

前言

先讲讲RTOS。

RTOS有两种大类型,分别是事件触发系统和时间触发系统。

事件触发系统由中断驱动,通常采用中断线程化等技术,适用于响应速度要求高的场景,例如传感器数据采集,但是当大量事情一次性发生时,计算机会面临大问题。

(一般的中断是CPU放下一切全力去做一件事情,中断线程化就是把事情放线程里,等中断触发这个线程,然后让这个线程跟其他线程并行执行)

时间触发系统的任务调度基于定时器中断,适用于周期性任务和确定性要求高的场景,如控制系统。它的内部有一个时钟,每隔一定时间间隔就会触发一次时间中断,每次时钟中断时,调度器决定是否需要切换任务。

不过现在的RTOS往往会结合这两种类型,比如FreeRTOS就属于时间触发系统和时间触发系统的结合。

在第十节的最后,我们得到了这些架构图,这就是Sparrow的蓝图:

img

sparrow的运行

现在让我们来看看Sparrow的设计,因为它并不是一个完整的RTOS内核,现在还是时间触发系统的部分占主要成分:

当Sparrow运行起来后,调度器负责选择并且切换任务,结合笔者前面的arm架构的文章可知:

1.调度器的组成有SVC、Systick、PendSV三个中断,它们都属于arm cortex m3架构的硬件资源。

2.SVC:负责当MCU复位后启动第一个任务,此时属于特权级线程模式,确保os的启动成功。

  1. Systick: 定时触发,触发Systick中断,Systick中断会根据当前时钟检查是否需要把某些任务加入就绪列表,在那之后,会触发PendSV中断。
  2. PendSV中断:保存当前任务状态,然后选择最高优先级的任务进行切换。它是整个调度器的精髓所在。

任务对象

我们得到的任务对象的蓝图如下,对于arm架构和rtos架构大家可能有点陌生,所以笔者啰嗦一点,任务对象让我们直接开始写代码,在代码中结合框图理解:

img

添加图片注释,不超过 140 字(可选)

Sparrow是动态创建任务,对于任务栈和任务控制块(TCB_t),我们都要分配内存。xTaskCreat是用户与RTOS的接口,我们可以得到TCB_t的各项参数并赋值,现在还没有就绪列表,所以笔者注释了几行代码。

(usStackDepth - (uint32_t)1)是为了获取栈顶的地址,我们分配内存会得到内存的第一个地址,所以加上栈的大小后要减1才是栈顶。举例:申请500,起始地址为1,那就是1–500这部分空间,1+500 -1得到的值才是500这个栈顶。

& (~…是字节对齐。

xTaskCreat完成了:

1.获得用户设置的参数,例如优先级,栈的大小等等,然后初始化任务控制块。

2.为任务栈和任务控制块开辟内存

3.初始化任务栈,获得任务栈的栈顶参数

void xTaskCreate( TaskFunction_t pxTaskCode,const uint16_t usStackDepth,void * const pvParameters,//it can be used to debuguint32_t uxPriority,TaskHandle_t * const self )
{uint32_t *topStack =NULL;TCB_t *NewTcb = (TCB_t *)heap_malloc(sizeof(TCB_t *));*self = ( TCB_t *) NewTcb;//TcbTaskTable[uxPriority] = NewTcb;NewTcb->uxPriority = uxPriority;NewTcb->pxStack = ( uint32_t *) heap_malloc( ( ( ( size_t ) usStackDepth ) * sizeof( uint32_t * ) ) );topStack =  NewTcb->pxStack + (usStackDepth - (uint32_t)1) ;topStack = ( uint32_t *) (((uint32_t)topStack) & (~((uint32_t) aligment_byte)));NewTcb->pxTopOfStack = pxPortInitialiseStack(topStack,pxTaskCode,pvParameters,self);pxCurrentTCB = NewTcb;//ReadyBitTable |= (1 << uxPriority);
}

pxPortInitialiseStack函数负责初始化任务栈,任务栈是保存寄存器的地方,让我们先看看arm cm3手册:

img

笔者在stack_register结构体中已经添加了这些寄存器,让我们边写代码,边听笔者慢慢讲解::

在32位架构下,一个指针大小为一个字,即32位,一个寄存器大小也为一个字。

pxTopOfStack-=16,因为一开始它是指向栈顶的,这是为了容纳stack_register结构体,把这个地址赋值给stack_register结构体,现在结构体的起始地址就是结构体中的第一个寄存器。

然后设置xPSR寄存器:xPSR的24位被置1,表示这是Thumb指令状态,实际上cm3架构只支持Thumb指令状态。

设置PC寄存器:pxCode是任务函数的地址,在arm架构中,分为arm指令集状态和Thumb指令集状态,你可以使用这两种指令集,区别是,Thumb指令集寄存器最低位是0,cm3下都是Thumb指令集,所以,为了预防未定义问题,必须把任务的地址最低位进行清0。

设置LR寄存器:LR寄存器是用于存储任务调用返回地址的专用寄存器,当一个函数被调用时,返回地址会被保存到 LR 寄存器中,以便在函数执行完毕后能够正确返回到调用该函数的下一条指令。但是,rtos中通常任务是不会返回的,所以这里的pvParameters其实是一个笔者用来调试的参数,观察栈有没有被破坏。读者可以把它改成自己的调试函数的地址。

设置r0:self也是一个笔者用来调试的参数,当任务执行后,r0的值会被马上更改,主要是用来判断任务栈是否创建成功。

(*self)->self_stack = Stack:设置任务对象的栈对象,这一操作是为了方便调试时找到一个线程的栈地址。

uint32_t * pxPortInitialiseStack( uint32_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters ,TaskHandle_t * const self)
{pxTopOfStack -= 16;Stack_register *Stack = (Stack_register *)pxTopOfStack;Stack->xPSR = 0x01000000UL;Stack->PC = ( ( uint32_t ) pxCode ) & ( ( uint32_t ) 0xfffffffeUL );Stack->LR = ( uint32_t ) pvParameters;Stack->r0 = ( uint32_t ) self;(*self)->self_stack = Stack;return pxTopOfStack;
}

总结

笔者先给出Sparrow的框图,根据框图一步步完成了任务的创建以及初始化部分。任务对象的创建已经完成了,下一节笔者将会带领大家完成调度器对象的创建,同时使用SVC中断启动第一个任务!

关键字:优化seo技术_webqq网页版_网站站长_广告点击一次多少钱

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: