当前位置: 首页 > news >正文

电脑自带的做网站叫什么软件网站建设验收标准

电脑自带的做网站叫什么软件,网站建设验收标准,怎么做代刷网站教程,宁德市建设银行网站文章目录 一、任务调度器开启函数 vTaskStartScheduler()二、内核相关硬件初始化函数 xPortStartScheduler()三、启动第一个任务 prvStartFirstTask()四、中断服务函数 xPortPendSVHandler()五、空闲任务 一、任务调度器开启函数 vTaskStartScheduler() 这个函数的功能就是开启…

文章目录

  • 一、任务调度器开启函数 vTaskStartScheduler()
  • 二、内核相关硬件初始化函数 xPortStartScheduler()
  • 三、启动第一个任务 prvStartFirstTask()
  • 四、中断服务函数 xPortPendSVHandler()
  • 五、空闲任务


一、任务调度器开启函数 vTaskStartScheduler()

这个函数的功能就是开启任务调度器的,这个函数在文件 tasks.c中有定义,缩减后的函数代码如下:

void vTaskStartScheduler( void )
{BaseType_t xReturn;xReturn = xTaskCreate( prvIdleTask, (1)"IDLE", configMINIMAL_STACK_SIZE,( void * ) NULL,( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),&xIdleTaskHandle );#if ( configUSE_TIMERS == 1 ) //使用软件定时器使能{if( xReturn == pdPASS ){xReturn = xTimerCreateTimerTask(); (2)}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configUSE_TIMERS */if( xReturn == pdPASS ) //空闲任务和定时器任务创建成功。{portDISABLE_INTERRUPTS(); (3)#if ( configUSE_NEWLIB_REENTRANT == 1 ) //使能 NEWLIB{_impure_ptr = &( pxCurrentTCB->xNewLib_reent );}#endif /* configUSE_NEWLIB_REENTRANT */xNextTaskUnblockTime = portMAX_DELAY;xSchedulerRunning = pdTRUE; (4)xTickCount = ( TickType_t ) 0U;portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); (5)if( xPortStartScheduler() != pdFALSE ) (6){//如果调度器启动成功的话就不会运行到这里,函数不会有返回值的}else{//不会运行到这里,除非调用函数 xTaskEndScheduler()。}}else{//程序运行到这里只能说明一点,那就是系统内核没有启动成功,导致的原因是在创建//空闲任务或者定时器任务的时候没有足够的内存。configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );}//防止编译器报错,比如宏 INCLUDE_xTaskGetIdleTaskHandle 定义为 0 的话编译器就会提//示 xIdleTaskHandle 未使用。( void ) xIdleTaskHandle;
}

(1)、创建空闲任务,如果使用静态内存的话使用函数 xTaskCreateStatic()来创建空闲任务,优先级为 tskIDLE_PRIORITY,宏 tskIDLE_PRIORITY 为 0,也就是说空闲任务的优先级为最低。

(2)、如果使用软件定时器的话还需要通过函数xTimerCreateTimerTask()来创建定时器服务任务。定时器服务任务的具体创建过程是在函数 xTimerCreateTimerTask()中完成的。

(3)、关闭中断,在 SVC 中断服务函数 vPortSVCHandler()中会打开中断。

(4)、变量 xSchedulerRunning 设置为 pdTRUE,表示调度器开始运行。

(5)、当宏 configGENERATE_RUN_TIME_STATS 为 1 的时候说明使能时间统计功能,此时需要用户实现宏 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS,此宏用来配置一个定时器/计数器。

(6)、调用函数 xPortStartScheduler()来初始化跟调度器启动有关的硬件,比如滴答定时器、FPU 单元和 PendSV 中断等等。

二、内核相关硬件初始化函数 xPortStartScheduler()

FreeRTOS 系统时钟是由滴答定时器来提供的,而且任务切换也会用到 PendSV 中断,这些硬件的初始化由函数 xPortStartScheduler()来完成,缩减后的函数代码如下:

BaseType_t xPortStartScheduler( void )
{/******************************************************************//****************此处省略一大堆的条件编译代码**********************//*****************************************************************/portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; (1)portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; (2)vPortSetupTimerInterrupt(); (3)uxCriticalNesting = 0; (4)prvStartFirstTask(); (5)//代码正常执行的话是不会到这里的!return 0;
}

(1)、设置 PendSV 的中断优先级,为最低优先级。

(2)、设置滴答定时器的中断优先级,为最低优先级。

(3)、调用函数 vPortSetupTimerInterrupt()来设置滴答定时器的定时周期,并且使能滴答定时器的中断,函数比较简单,大家自行查阅分析。

(4)、初始化临界区嵌套计数器。

(5)、调用函数 prvStartFirstTask()开启第一个任务。

三、启动第一个任务 prvStartFirstTask()

经过上面的操作以后我们就可以启动第一个任务了,函数 prvStartFirstTask()用于启动第一个任务,这是一个汇编函数,函数源码如下:

__asm void prvStartFirstTask( void )
{PRESERVE8ldr r0, =0xE000ED08 ;R0=0XE000ED08 (1)ldr r0, [r0] ;取 R0 所保存的地址处的值赋给 R0 (2)ldr r0, [r0] ;获取 MSP 初始值 (3)msr msp, r0 ;复位 MSP (4)cpsie I ;使能中断(清除 PRIMASK) (5)cpsie f ;使能中断(清除 FAULTMASK) (6)dsb ;数据同步屏障 (7)isb ;指令同步屏障 (8)svc 0 ;触发 SVC 中断(异常) (9)nopnop
}

(1)、将 0XE000ED08 保存在寄存器 R0 中。一般来说向量表应该是从起始地址(0X00000000)开始存储的,不过,有些应用可能需要在运行时修改或重定义向量表,Cortex-M 处理器为此提供了一个叫做向量表重定位的特性。向量表重定位特性提供了一个名为向量表偏移寄存器(VTOR)的可编程寄存器。VTOR 寄存器的地址就是 0XE000ED08,通过这个寄存器可以重新定义向量表,比如在 STM32F103 的 ST 官方库中会通过函数 SystemInit()来设置 VTOR 寄存器,

代码如下:

SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; //VTOR=0x08000000+0X00

通过上面一行代码就将向量表开始地址重新定义到了0X08000000,向量表的起始地址存储的就是 MSP 初始值。

(2)、读取 R0 中存储的地址处的数据并将其保存在 R0 寄存器,也就是读取寄存器 VTOR中的值,并将其保存在 R0 寄存器中。这一行代码执行完就以后 R0 的值应该为 0X08000000。

(3)、读取 R0 中存储的地址处的数据并将其保存在 R0 寄存器,也就是读取地址 0X08000000处存储的数据,并将其保存在 R0 寄存器中。我们知道向量表的起始地址保存的就是主栈指针MSP 的初始值,这一行代码执行完以后寄存器 R0 就存储 MSP 的初始值。现在来看(1)、(2)、(3)这三步起始就是为了获取 MSP 的初始值而已!

(4)、复位 MSP,R0 中保存了 MSP 的初始值,将其赋值给 MSP 就相当于复位 MSP。

(5)和(6)、使能中断。

(7)和(8)、数据同步和指令同步屏障。

(9)、调用 SVC 指令触发 SVC 中断,SVC 也叫做请求管理调用,SVC 和 PendSV 异常对于OS 的设计来说非常重要。SVC 异常由 SVC 指令触发。在 FreeRTOS 中仅仅使用 SVC 异常来启动第一
个任务,后面的程序中就再也用不到 SVC 了。

四、中断服务函数 xPortPendSVHandler()

在函数 prvStartFirstTask()中通过调用 SVC 指令触发了 SVC 中断,而第一个任务的启动就是在 SVC 中断服务函数中完成的,SVC 中断服务函数应该为 SVC_Handler(),但是
FreeRTOSConfig.h 中通过#define 的方式重新定义为了 xPortPendSVHandler(),如下:

#define xPortPendSVHandler PendSV_Handler

函数 vPortSVCHandler()在文件 port.c 中定义,这个函数也是用汇编写的,函数源码如下:

__asm void vPortSVCHandler( void )
{PRESERVE8ldr r3, =pxCurrentTCB ;R3=pxCurrentTCB 的地址 (1)ldr r1, [r3] ;取 R3 所保存的地址处的值赋给 R1 (2)ldr r0, [r1] ;取 R1 所保存的地址处的值赋给 R0 (3)ldmia r0!, {r4-r11, r14} ;出栈 ,R4~R11 和 R14 (4)msr psp, r0 ;进程栈指针 PSP 设置为任务的堆栈 (5)isb ;指令同步屏障mov r0, #0 ;R0=0 (6)msr basepri, r0 ;寄存器 basepri=0,开启中断 (7)orr r14, #0xd ; (8)bx r14 (9)
}

(1)、获取 pxCurrentTCB 指针的存储地址,pxCurrentTCB 是一个指向 TCB_t 的指针,这个指针永远指向正在运行的任务。这里先获取这个指针存储的地址,比如我现在的代码测试出来这个指针是存放在 0X20000044,如下图所示。
在这里插入图片描述
(2)、取 R3 所保存的地址处的值赋给 R1。通过这一步就获取到了当前任务的任务控制块的存储地址。比如当前我的程序中这个地址就为 0X20000EE8,如下图所示:
在这里插入图片描述
(3)、取 R3 所保存的地址处的值赋给 R0,我们知道任务控制块的第一个字段就是任务堆栈的栈顶指针 pxTopOfStack 所指向的位置,所以读取任务控制块所在的首地址(0X20000EE8)得到
的就是栈顶指针所指向的地址,当前我的程序中这个栈顶指针(pxTopOfStack)所指向的地址为0X20000E98,如下图所示
在这里插入图片描述
可以看出(1)、(2)和(3)的目的就是获取要切换到的这个任务的任务栈顶指针,因为任务所对应的寄存器值,也就是现场都保存在任务的任务堆栈中,所以需要获取栈顶指针来恢复这些寄存器值!

(4)、R4~R11,R14 这些寄存器出栈。这里使用了指令 LDMIA,LDMIA 指令是多加载/存储指令,不过这里使用的是具有回写的多加载/存储访问指令,用法如下:

LDMIA Rn! , {reg list}

表示从 Rn 指定的存储器位置读取多个字,地址在每次读取后增加(IA),Rn 在传输完成以后写回。对于 STM32 来说地址一次增加 4 字节,比如如下代码:

LDR R0, =0X800
LDMIA R0!, {R2~R4}

上面两行代码就是将 0X800 地址的数据赋值给寄存器 R2,0X804 地址的数据赋值给寄存器 R3,0X8008 地址的数据赋值给 R4 寄存器,然后,重点来了!此时 R0 为 800A!通过这一步我们就从任务堆栈中将 R4~R11 这几个寄存器的值给恢复了。这里有朋友就要问了,R0~R3,R12,PC,xPSR 这些寄存器怎么没有恢复?这是因为这些寄存器会在退出中断的时候 MCU 自动出栈(恢复)的,而 R4~R11 需要由用户手动出栈。这个我们在分析 PendSV 中断服务函数的时候会讲到。到这步以后我们来看一下堆栈的栈顶指针指到哪
里了?如下图所示:
在这里插入图片描述
从上图可以看出恢复 R4~R11 和 R14 以后堆栈的栈顶指针应该指向地址 0X20000EB8,也就是保存寄存器 R0 值的存储地址。退出中断服务函数以后进程栈指针 PSP 应该从这个地址开始恢复其他的寄存器值。

(5)、设置进程栈指针 PSP,PSP=R0=0X20000EB8,如下图所示:
在这里插入图片描述
(6)、设置寄存器 R0 为 0。

(7)、设置寄存器 BASEPRI 为 R0,也就是 0,打开中断!

(8)、R14 寄存器的值与 0X0D 进行或运算,得到的结果就是 R14 寄存器的新值。表示退出异常以后 CPU 进入线程模式并且使用进程栈!

(9)、执行此行代码以后硬件自动恢复寄存器 R0~R3、R12、LR、PC 和 xPSR 的值,堆栈使用进程栈 PSP,然后执行寄存器 PC 中保存的任务函数。至此,FreeRTOS 的任务调度器正式开始运行!

五、空闲任务

在前面讲解函数 vTaskStartScheduler()说过,此函数会创建一个名为“IDLE”的任务,这个任务叫做空闲任务。顾名思义,空闲任务就是空闲的时候运行的任务,也就是系统中其他的任务由于各种原因不能运行的时候空闲任务就在运行。空闲任务是 FreeRTOS 系统自动创建的,不需要用户手动创建。任务调度器启动以后就必须有一个任务运行!但是空闲任务不仅仅是为了满足任务调度器启动以后至少有一个任务运行而创建的,空闲任务中还会去做一些其他
的事情,如下:
1、判断系统是否有任务删除,如果有的话就在空闲任务中释放被删除任务的任务堆栈和任务控制块的内存。

2、运行用户设置的空闲任务钩子函数。

3、判断是否开启低功耗 tickless 模式,如果开启的话还需要做相应的处理空闲任务的任务优先级是最低的,为 0,任务函数为 prvIdleTask()。

http://www.yayakq.cn/news/658860/

相关文章:

  • 北京网站建设 云智互联erp管理系统有哪些牌子
  • 深圳网站建设深圳网站建设定做
  • 一键建站公司南宁建站平台
  • 网站建设吴中区简述从网站规划的角度常见的网站模式
  • 杭州小型网站建设服务东莞网站建设如何做
  • 网站整站下载带数据库后台的方法怎么可以做自己的网站
  • 郑州 网站制作广州越秀区天气预报
  • 后台网站如何建设宿迁网站建设价格
  • 校园二手交易网站要怎么做呀石家庄企业招聘信息网
  • 微信网站建设模板建站收费标准
  • 网站如何调用百度地图电子商务的建站流程
  • 传播网站建设杭州公司名称大全
  • 怎样查询网站的备案号设计包装
  • 苏州建设网站价格ui包括哪几个方面
  • 找外包公司做个网站多少钱网站开发前台实训
  • 微网站制作工具三水建设网站
  • 创新能力建设资金网站h5页面怎么制作报名页面
  • 做移动网站点击软件免费创建个人博客网站
  • title 网站建设手机搭建网站
  • 网站定制开发要多少钱drupal wordpress 比例
  • 网站建设氺金手指排名14wordpress返利插件
  • 网站建设公司效果钙网logo设计
  • app的后台和网站的后台差别哈尔滨企业自助建站
  • php网站案例外汇网站模版
  • 网站各个阶段推广上海公共招聘网首页
  • 俄文淘宝网站建设重庆软装设计公司官网
  • 廊坊网站短链接生成器官方
  • 昆明哪个公司做网站建设最好江西人才招聘网官网
  • 宿迁网站建设介绍公司公司注册查询网
  • 广西柳州网站制作公司wordpress最新版新建页面选择模板