FreeRtos源码分析之启动任务调度vTaskStartScheduler(二)

2023-05-16

一、概述

FreeRtos在创建任务之后,需要启动任务调度器才能使任务正常有序的运行。任务调度器的开启依赖于底层硬件,对于CortexM3内核而言,任务调度器需要用到中断和滴答定时器。FreeRtos在对中断优先级、空闲任务等进行初始化之后,会开启滴答定时器的中断,这样每隔1毫秒系统就会进入滴答定时器中断,FreeRtos会在这个中断中进行诸如记录系统运行时间、查找下一个就绪态任务等操作。换句话说,滴答定时器就是FreeRtos的心脏。
FreeRtos任务调度需要用到CortexM3和汇编知识,可以结合CorteM3权威指南进行学习。

二、FreeRtos任务调度开启流程

FreeRtos调用vTaskStartScheduler函数开启任务调度,流程如下:

  • [1]初始化空闲任务
  • [2]创建定时器管理任务
  • [3]中断初始化
  • [4]滴答定时器初始化
  • [5]调用vPortStartFirstTask函数出发svc中断
  • [6]在SVC中断函数vPortSVCHandler中启动第一个任务

2.1、空闲任务

  1. 当没有其它任务运行时,FreeRtos会自动运行空闲任务。空闲任务的优先级默认为0,在所有的任务中优先级最低。即使有和空闲任务相同优先级的任务被创建,系统依然会优先运行非空闲任务的其它任务。
    空闲任务会回收调用vTaskDelete(NULL)删除自己任务的内存,避免内存泄漏。
  2. 空闲任务会不停的监测是否有新的任务处于就绪状态,如果有则进行任务切换
  3. 空闲任务可以用于实现系统的低功耗,其原理是在系统空闲时间进入硬件低功耗模式。

空闲任务的功能总结如下:

  • 回收已删除任务的内存;
  • 检查是否需要进行任务切换
  • 调用vApplicationIdleHook函数,执行用户自定义代码
  • 可以用于实现系统的低功耗功能

空闲任务源码:

static portTASK_FUNCTION( prvIdleTask, pvParameters )
{
    /* 防止编译警告. */
    ( void ) pvParameters;

    /** 空闲任务,在任务调度器启动时自动创建. **/

    /*如果具有安全上下文的任务删除了自己,在这种情况下,空闲任务负责删除任务的安全上下文(如果有). */
    portALLOCATE_SECURE_CONTEXT( configMINIMAL_SECURE_STACK_SIZE );

    for( ; ; )
    {
        /* 如果有任务删除了自己,空闲任务负责释放被删除任务的TCB和内存。 */
        prvCheckTasksWaitingTermination();

        #if ( configUSE_PREEMPTION == 0 )
            {
              /*如果没有使用抢占式调度器,只要有可用的其它任务就进行任务切换*/
                taskYIELD();
            }
        #endif /* configUSE_PREEMPTION */

        #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
            {
                /* 如果使用抢占式调度的任务具有相同的优先级,那么它们将会按照时间片进行调度。
                 * 如果有任务和空闲任务具有相同的优先级,空闲任务应该在时间片耗尽之前进行调度。
                 * 由于我们只是从列表中读取内容,因此此处不需要关键区域,偶尔出现的错误值也无关紧要。 
                 * 如果处于空闲优先级的就绪列表包含多个任务,则准备执行非空闲任务以外的任务。*/
                if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 )//如果就绪列表中的任务数量大于1则执行任务切换
                {
                    taskYIELD();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
        #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */

        #if ( configUSE_IDLE_HOOK == 1 )
            {
                extern void vApplicationIdleHook( void );

                /* 调用用户自定义的钩子函数。这个函数禁止调用可能阻塞的函数。 */
                vApplicationIdleHook();
            }
        #endif /* configUSE_IDLE_HOOK */

        /* configUSE_TICKLESS_IDLE表示是否开启低功耗模式,为0表示关闭,非0表示打开. */
        #if ( configUSE_TICKLESS_IDLE != 0 )
            {
               //此处省略低功耗部分代码
            }
        #endif /* configUSE_TICKLESS_IDLE */
    }
}

2.2、定时器任务

定时器任务也在任务调度开始前创建,其优先级为2,略高于空闲任务,主要用来对FreeRtos软件定时器进行管理。

2.4、中断初始化中断

CortexM3和CortexM4的每一个外部中断都有一个对应的优先级寄存器,每个寄存器占用8位,但是最少允许使用最高3位。 4 个相临的优先级寄存器拼成一个 32 位寄存器,分别是抢占优先级和响应(亚)优先级。这些寄存器可以按照字节、字或者半字访问。 如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LiMR8DQb-1611110514033)(en-resource://database/588:1)]

stm32f4xx系列芯片使用高4位用来配置优先级,优先级取值范围为0-15。低4位始终为0,用户无法修改,FreeRtos使用这个特性来检验优先级中断寄存器的可用位数。
FreeRtos中断初始化流程:

  • [1]读取地址为0xE000E400优先级寄存器的值;
  • [2]将0xFF写入该优先级寄存器;
  • [3]读取该优先级寄存器地址的内容;
  • [4]判断读取到的值有多少位为1从而确定实际可用的优先级位数;
  • [5]使用读出来的值和stm32f4芯片实际的可用优先级进行比较,避免出错;
  • [6]恢复0xE000E400优先级寄存器访问之前的值;
  • [7]将PendSV和SysTick的优先级设为最低;
  • [8]初始化SysTick定时器
    源码:
    #if ( configASSERT_DEFINED == 1 )
        {
            volatile uint32_t ulOriginalPriority;
            //计算后得到的值为0xE000E400,表示外部中断优先级寄存器的地址
            volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
            volatile uint8_t ucMaxPriorityValue;

            /*  保存即将被破坏的优先级值,后面会修改寄存器的值. */
            ulOriginalPriority = *pucFirstUserPriorityRegister;

            /* 确定有多少优先级位可用,不可用的位始终为0,通过将寄存器所有位置1,再读取寄存器的值来确定. */
            *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;

            /* Read the value back to see how many bits stuck. */
            ucMaxPriorityValue = *pucFirstUserPriorityRegister;

            /* Use the same mask on the maximum system call priority. */
            ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;

            /* 根据读回来的值确定最大优先级组的值 ,比如读出来的值是0xf0,那么表示最高4位用来表示优先级*/
            ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;

            while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
            {
                ulMaxPRIGROUPValue--;
                ucMaxPriorityValue <<= ( uint8_t ) 0x01;
            }

            #ifdef __NVIC_PRIO_BITS
                {
                     /*检查CMIS配置的优先级位数是否和实际得到的硬件优先级位数是否相同*/
                     /*stm32f4使用了高4位作为可配置的优先级位*/
                    configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
                }
            #endif

            #ifdef configPRIO_BITS
                {
                    /* Check the FreeRTOS configuration that defines the number of
                     * priority bits matches the number of priority bits actually queried
                     * from the hardware. */
                    configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
                }
            #endif

            /* Shift the priority group value back to its position within the AIRCR
             * register. */
            ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
            ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;

            /* 将中断寄存器的值复原*/
            *pucFirstUserPriorityRegister = ulOriginalPriority;
        }
    #endif /* conifgASSERT_DEFINED */

    /* 使 PendSV and SysTick 的优先级最低. */
    portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
    portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;

    /* 初始化SysTick定时器. 此时中断已经被关闭. */
    vPortSetupTimerInterrupt();

2.4、初始化SysTick定时器

CortexM3和CortexM4都具有SysTick定时器,它被捆绑在 NVIC中,用于产生SYSTICK异常(异常号: 15)。
SysTick定时器有四个寄存器,相关定义如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nmJQEjMw-1611110514035)(en-resource://database/590:1)]

SysTick定时器重装载数值寄存器的初始值计算公式:

t=reload*(1/clock)

计数值为:

reload = clock*t-1

减一是因为计数值从0开始。比如stm32f407的系统时钟是168MHz,如果我们希望FreeRtos的时钟节拍设置为1ms,那么得到reload的值为168000000*(1/1000)-1
FreeRtos对SysTick初始化的源码如下:

__weak void vPortSetupTimerInterrupt( void )
{
    /* Stop and clear the SysTick. */
    portNVIC_SYSTICK_CTRL_REG = 0UL;//复位SysTick控制寄存器
    portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;//清零当前数值寄存器

    /* Configure SysTick to interrupt at the requested rate. */
    portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;//设置重装载数值寄存器值
    //使用内部时钟、SysTick倒数至0时产生中断、使能SysTick
    portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
}

FreeRtos将SysTick的中断函数重新定义:

#define xPortSysTickHandler SysTick_Handler

当中断开启之后,系统会每隔一个时钟节拍执行一次xPortSysTickHandler函数。

2.5、启动第一个任务

FreeRtos任务的启动和切换依赖于SVC(系统服务调用)和 PendSV(可悬起系统调用),它们多用于在操作系统之上的软件开发中。 SVC 用于产生系统函数的调用请求。例如,操作系统不让用户程序直接访问硬件,而是通过提供一些系统服务函数,用户程序使用 SVC 发出对系统服务函数的呼叫请求,以这种方法调用它们来间接访问硬件。
SVC异常是必须立即得到响应的, PendSV 则不同,它是可以像普通的中断一样被悬起的。 OS 可以利用它“缓期执行” 一个异常——直到其它重要的任务完成后才执行动作。 悬起 PendSV 的方法是: 手工往 NVIC 的 PendSV 悬起寄存器中写 1。 悬起后, 如果优先级不够高,则将缓期等待执行。PendSV 的典型使用场合是在上下文切换时(在不同任务之间切换)。

vPortSVCHandler:
	/* Get the location of the current TCB. */
	ldr	r3, =pxCurrentTCB//将pxCurrentTCB放入R3寄存器中
	ldr r1, [r3]             //将pxCurrentTCB的内容(*pxCurrentTCB)放入R1寄存器,这个值是pxCurrentTCB结构体的第一个元素pxTopOfStack
	ldr r0, [r1]             //将pxCurrentTCB结构体的第一个元素pxTopOfStack存储的内容放到R0中
	/* Pop the core registers. */
	ldmia r0!, {r4-r11, r14}  //出栈,从R4-R11,R14中一次性读出9个寄存器的数据
	msr psp, r0         
	isb                //指令同步隔离。它会清洗流水线,以保证所有它前面的指令都执行完毕之后,才执行它后面的指令。
	mov r0, #0        //将立即数0传送到R0寄存器
	msr	basepri, r0/*将basepri寄存器所有位写0使能中断*/
	bx r14           //跳转指令

/*-----------------------------------------------------------*/

vPortStartFirstTask
	/* Use the NVIC offset register to locate the stack. */
	ldr r0, =0xE000ED08/*向量表偏移量寄存器(VTOR)*/
	ldr r0, [r0]  //将r0存储地址(0xE000ED08)的内容放入r0
	ldr r0, [r0]  
	/* Set the msp back to the start of the stack. */
	msr msp, r0
	/* Clear the bit that indicates the FPU is in use in case the FPU was used
	before the scheduler was started - which would otherwise result in the
	unnecessary leaving of space in the SVC stack for lazy saving of FPU
	registers. */
	mov r0, #0
	msr control, r0
	/* Call SVC to start the first task. */
	cpsie i //开中断
	cpsie f  //开异常
	dsb
	isb
	svc 0   //触发SVC中断

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRtos源码分析之启动任务调度vTaskStartScheduler(二) 的相关文章

  • 心跳跟随的心形灯(STM32(HAL)+WS2812+MAX30102)

    文章目录 前言 介绍 系统框架 原项目地址 本项目开发开源地址 硬件PCB 软件功能 详细内容 硬件外壳制作 WS2812级联及控制 MAX30102血氧传感器 0 96OLED FreeRTOS 效果视频 总结 前言 在好几年前 我好像就
  • FreeRTOS快速上手

    FreeRTOS使用 一 源码下载和移植文件提取 1 1 源码下载 在网站https sourceforge net projects freertos 可以找到freertos最新的源码 1 2 移植文件提取 根据第一步 我们会得到一个f
  • FreeRTOS config开始的宏

    FreeRTOSConfig h系统配置文件中可以自定义 FreeRTOS h中定义默认值 configAPPLICATION ALLOCATED HEAP 默认情况下FreeRTOS的堆内存是由编译器来分配的 将宏configAPPLIC
  • STM32CubeMX+FreeRTOS学习笔记(一)

    嵌入式实时操作系统FreeRTOS 基本概述 在嵌入式领域当中 实时操作系统的应用越来越广泛了 目前嵌入式操作系统种类很多 例如 Clinux C OS II C OS III FreeRTOS RT Thread等等 这篇文章所记录的就是
  • FreeRTOS记录(七、FreeRTOS信号量、事件标志组、邮箱和消息队列、任务通知的关系)

    我们在前面单独介绍过FreeRTOS的任务通知和消息队列 但是在FreeRTOS中任务间的通讯还有信号量 邮箱 事件组标志等可以使用 这篇文章就这些成员与消息队列和任务通知的关系进行说明分析 增加邮箱部分 任务通知发送消息 Demo 202
  • FreeRTOS 软件定时器的使用

    FreeRTOS中加入了软件定时器这个功能组件 是一个可选的 不属于freeRTOS内核的功能 由定时器服务任务 其实就是一个定时器任务 来提供 软件定时器是当设定一个定时时间 当达到设定的时间之后就会执行指定的功能函数 而这个功能函数就叫
  • FreeRTOS软件定时器创建、复位、开始和停止(备忘)

    目录 一 简介 1 1 开发环境 1 2 摘要 二 STM32CubeIDE配置 三 创建定时器 3 1 头文件声明 3 2 工程文件定义 3 3 创建定时器 3 4 开启 复位 和关闭定时器 四 定时器回调函数 一 简介 1 1 开发环境
  • FreeRTOS学习笔记 6 - 互斥量

    目录 1 创建 2 获取 3 释放 4 测试 FreeRTOS不支持调度方式的设置 所以下面2个宏定义可以随意设置值 define RTOS IPC FLAG FIFO 0x00 define RTOS IPC FLAG PRIO 0x01
  • 一文教你学会keil软件仿真

    仿真在我们调试代码中是非常重要的 通过仿真 我们可以快速定位到错误代码 或者错误逻辑的地方 这里我就以上一篇博客为例 教大家如何软件仿真 软件仿真不需要单片机 直接通过keil软件进行代码调试 一 打开工具 二 选择软件仿真 三 开始仿真
  • FreeRTOS学习笔记(3、信号量、互斥量的使用)

    FreeRTOS学习笔记 3 信号量 互斥量的使用 前言 往期学习笔记链接 学习工程 信号量 semaphore 两种信号量的对比 信号量的使用 1 创建信号量 2 give 3 take 4 删除信号量 使用计数型信号量实现同步功能 使用
  • FreeRTOS系列

    1 RTOS简介 RTOS全称为 Real Time Operation System 即实时操作系统 RTOS强调的是实时性 又分为硬实时和软实时 硬实时要求在规定的时间内必须完成操作 不允许超时 而软实时里对处理过程超时的要求则没有很严
  • 【FreeRTOS】队列的使用

    作者主页 凉开水白菜 作者简介 共同学习 互相监督 热于分享 多加讨论 一起进步 专栏资料 https pan baidu com s 1nc1rfyLiMyw6ZhxiZ1Cumg pwd free 点赞 收藏 再看 养成习惯 订阅的粉丝
  • FreeRTOS ------- 任务(task)

    在学习RTOS的时候 个人觉得带着问题去学习 会了解到更多 1 什么是任务 在FreeRTOS中 每个执行线程都被称为 任务 每个任务都是在自己权限范围内的一个小程序 其具有程序入口每个任务都是在自己权限范围内的一个小程序 其具有程序入口通
  • freeRTOS手册 第六章 . 中断管理

    如果我对本翻译内容享有所有权 允许任何人复制使用本文章 不会收取任何费用 如有平台向你收取费用与本人无任何关系 第六章 中断管理 章节介绍和范围 事件 嵌入式实时系统必需对环境中的事件做出响应 比如 外部网络设备收到一个发送给TCP IP栈
  • FreeRTOS+CubeMX系列第一篇——初识FreeRTOS

    文章目录 一 关于FreeRTOS 二 FreeRTOS的特点 三 如何在CubeMX上配置FreeRTOS 四 FreeRTOS文档资料 五 同系列博客 一 关于FreeRTOS 1 什么是FreeRTOS FreeRTOS是一个迷你的实
  • freeRTOS使用uxTaskGetStackHighWaterMark函数查看任务堆栈空间的使用情况

    摘要 每个任务都有自己的堆栈 堆栈的总大小在创建任务的时候就确定了 此函数用于检查任务从创建好到现在的历史剩余最小值 这个值越小说明任务堆栈溢出的可能性就越大 FreeRTOS 把这个历史剩余最小值叫做 高水位线 此函数相对来说会多耗费一点
  • FreeRTOS:中断配置

    目录 一 Cortex M 中断 1 1中断简介 1 2中断管理简介 1 3优先级分组定义 1 4优先级设置 1 5用于中断屏蔽的特殊寄存器 1 5 1PRIMASK 和 FAULTMASK 寄存器 1 5 2BASEPRI 寄存器 二 F
  • FreeRTOS临界段和开关中断

    http blog sina com cn s blog 98ee3a930102wg5u html 本章教程为大家讲解两个重要的概念 FreeRTOS的临界段和开关中断 本章教程配套的例子含Cortex M3内核的STM32F103和Co
  • FreeRTOS学习(三)开关中断

    声明及感谢 跟随正点原子资料学习 在此作为学习的记录和总结 环境 keil stm32f103 背景知识 Cotex M3的NVIC最多支持240个IRQ 中断请求 1个不可屏蔽 NMI 1个Systick 滴答定时器 Cortex M处理
  • FreeRTOS 匈牙利表示法 [重复]

    这个问题在这里已经有答案了 我是 RTOS 和 C 编程的新手 而且我仍在习惯 C 的良好实践 因此 我打开了一个使用 FreeRTOS 的项目 我注意到操作系统文件使用匈牙利表示法 我知道一点符号 但面临一些新的 标准 FreeRTOS

随机推荐

  • STM32CubeMX基于HAL库点亮LED灯

    开发环境 xff1a Windows 软件 xff1a 1 STM32CubeMX 6 3 0 2 MDK 5 14 一 cubeMX的基本配置 1 选择MCU 2 配置时钟 查看电路图 xff0c 8MHz的高速外部晶振接到 OSCIN
  • 一起DIY四轴飞行器(三)添加实时操作系统--freeRTOS

    开发环境 xff1a Windows 软件 xff1a 1 STM32CubeMX 6 3 0 2 MDK 5 14 一 初识freeRTOS系统 1 什么是FreeRTOS xff1f Free 即免费的 xff0c RTOS 全称是 R
  • ESP8266 初次使用

    一 工具 1 ESP8266 01S 淘宝上搜索ESP8266 01S 引脚说明 xff1a 2 USB转串口 给设备供电3 3V xff08 官方说不要用USB转串口的3 3V xff0c 需要单独供电 xff09 xff0c USB转串
  • ubuntu安装boost

    ubuntu安装boost 系统 Ubuntu 18 04 boost中 xff0c 用到了别的函数库 xff0c 所以为了使用boost中相应的功能 xff0c 需要先安装系统中可能缺失的库 1 卸载已经安装的boost 删除 usr l
  • 简单的状态机图

    一 什么是状态机 xff1f 做产品的时候 xff0c 我们总能遇到一些比较复杂的逻辑问题 比如状态的转换 xff0c 字段状态的确认 xff0c 权限的控制 xff0c 状态的对应 而普通的流程图 xff0c 或时序图 xff0c 更侧重
  • js-对象转基本类型

    起因是收到朋友发的一道题 xff0c 如下 xff1a span class token comment 请在问号处填写你的答案 使下方等式成立 span span class token keyword let span a span c
  • 局域网内wakeonlan远程唤醒其它计算机

    背景 xff1a 需要管理多台计算机 xff0c 所有计算机在一个局域网内 xff0c 并且有的安装了Windows系统 xff0c 有的安装了Linux系统 我们想远程关闭和启动所有计算机 关闭计算机直接通过网络发生操作系统关机命令即可实
  • D3D中的三种Buffer

    在D3D中 针对视窗有三种Buffer 它们分别是 Color Buffer Depth Buffer和Stencil Buffer Color Buffer在D3D中又称为Render Target 意思是最后着色的目标Buffer 就是
  • 创建镜像(更新与构建镜像)

    创建镜像 有时从Docker镜像仓库中下载的镜像不能满足我们的要求 xff0c 此时可以基于这个镜像 xff08 基础镜像 xff09 封装一个自 己的镜像 两种方式 xff1a 更新镜像 xff1a 使用docker commit命令构建
  • (十)CMake链接已有的动态库

    使用一个已经存在的动态库 xff0c 需要用到CMake中两个命令 xff0c 分别是 xff1a link directoriestarget link libraries 下面先介绍以下两个命令的格式及其含义 xff0c 最后是一个使用
  • ROS入门21讲笔记(四)自定义话题消息类型和使用

    除了ROS内置消息外 xff0c 我们还能自定义消息 这一次我们不再与海龟较劲 xff0c 而是自定义一个订阅消息类型 xff0c 让订阅者和发布者通过这个结构进行数据通信 一 如何自定义话题消息 xff1f 话题消息是以 msg结尾的文件
  • ROS入门21讲笔记(七)自定义消息消息类型和使用

    这一节主要是学习如何自定义一个服务类型并使用它 一 如何自定义服务消息 xff1f 服务数据是以 srv结尾的文件 xff0c 是一个用于描述ROS服务信息简单文本文件 xff0c 用于生成不同语言消息的源代码 srv文件存放在packag
  • ROS入门21讲笔记(十二)常用可视化工具

    一 QT类可视化工具 1 1 rqt console rqt console 为显示和过滤ROS信息提供了一个GUI插件 1 2 rqt plot rqt plot使用不同的绘图后端提供数值可视化功能 1 3 rqt Image view
  • (二)CMake 使用头文件

    一 include directories 该命令用于增加一个编译头文件 其基本语法是 xff1a include directories span class token punctuation span span class token
  • cargo 宏展开遇到的问题

    最近学习rust xff0c 看到宏展开命令 span class token comment 单独文件 span rustc Z unstable options pretty span class token operator 61 s
  • 工程师笔记|常见的嵌入式软件工程师面试题

    Q xff1a 什么是ISR xff1f A xff1a ISR 是指中断服务程序 这些是存储在特定内存地址的函数 xff0c 当发生某种类型的中断时会调用这些函数 Cortex M 处理器系列具有管理中断执行的 NVIC Q xff1a
  • 计算机中的速率、带宽、时延、利用率解读

    计算机网络的性能一般是指它的几个重要的性能指标 但除了这些重要的性能指标外 xff0c 还有一些非性能特征 xff08 nonperformance characteristics xff09 也对计算机网络的性能有很大的影响 那么 xff
  • 手把手教你写链表,小学生看了都说好~

    摘要 xff1a 明明我们在之前已经接触了数组 xff0c 感到数组已经是万能的数据存储位置了 但是 xff0c 如果我们一直在使用比较复杂的数据 xff08 也就是比较多的数据时 xff09 xff0c 肯定会感到很反感 因为对于数组这种
  • 15-JavaScript高级程序设计-创建对象

    一 创建对象 创建单个对象 xff1a Object构造函数 new Object 对象字面量 xff08 参见8 Object amp Array xff09 创建多个对象 xff1a 以下7种方式 1 工厂模式 span class t
  • FreeRtos源码分析之启动任务调度vTaskStartScheduler(二)

    一 概述 FreeRtos在创建任务之后 xff0c 需要启动任务调度器才能使任务正常有序的运行 任务调度器的开启依赖于底层硬件 xff0c 对于CortexM3内核而言 xff0c 任务调度器需要用到中断和滴答定时器 FreeRtos在对