09_FreeRTOS任务调度器

2023-05-16

目录

开启任务调度器vTaskStartScheduler函数

xPortStartScheduler开启任务调度器函数

启动第一个任务

prvStartFirstTask开启第一个任务函数

vPortSVCHandler  SVC中断服务函数

出栈/压栈汇编指令详解


开启任务调度器vTaskStartScheduler函数

作用:用于启动任务调度器,任务调度器启动后, FreeRTOS 便会开始进行任务调度 

该函数内部实现,如下步骤:

1.创建空闲任务

2.如果使能软件定时器,则创建定时器任务

3.关闭中断,防止调度器开启之前或过程中,受中断干扰,会在运行第一个任务时打开中断

4.初始化全局变量,并将任务调度器的运行标志设置为已运行

5.初始化任务运行时间统计功能的时基定时器

6.调用函数xPortStartScheduler()

void vTaskStartScheduler( void )
{
BaseType_t xReturn;

	/* Add the idle task at the lowest priority. */
	/*静态任务创建*/
	#if( configSUPPORT_STATIC_ALLOCATION == 1 )
	{
		/*
		StaticTask_t *pxIdleTaskTCBBuffer = NULL;
		StackType_t *pxIdleTaskStackBuffer = NULL;
		uint32_t ulIdleTaskStackSize;

		/* The Idle task is created using user provided RAM - obtain the
		address of the RAM then create the idle task. */
		vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
		xIdleTaskHandle = xTaskCreateStatic(	prvIdleTask,
												"IDLE",
												ulIdleTaskStackSize,
												( void * ) NULL,
												( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
												pxIdleTaskStackBuffer,
												pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */

		if( xIdleTaskHandle != NULL )
		{
			xReturn = pdPASS;
		}
		else
		{
			xReturn = pdFAIL;
		}*/
	}

	#else
	/*动态任务创建*/
	{
		/* The Idle task is being created using dynamically allocated RAM. */
		
		/*创建空闲任务*/
		xReturn = xTaskCreate(	prvIdleTask,
								"IDLE", configMINIMAL_STACK_SIZE,
								( void * ) NULL,
								( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
								&xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
	}
	#endif /* configSUPPORT_STATIC_ALLOCATION */

	/*判断宏是否使能软件定时器*/
	#if ( configUSE_TIMERS == 1 )
	{
		/*空闲任务创建成功*/
		if( xReturn == pdPASS )
		{
			/*创建定时器任务*/
			xReturn = xTimerCreateTimerTask();
		}
		else
		{
			/*未实现*/
			mtCOVERAGE_TEST_MARKER();
		}
	}
	#endif /* configUSE_TIMERS */

	/*判断定时器任务是否创建成功*/
	if( xReturn == pdPASS )
	{
		/* Interrupts are turned off here, to ensure a tick does not occur
		before or during the call to xPortStartScheduler().  The stacks of
		the created tasks contain a status word with interrupts switched on
		so interrupts will automatically get re-enabled when the first task
		starts to run. */
		
		/*关中断*/
		portDISABLE_INTERRUPTS();

		#if ( configUSE_NEWLIB_REENTRANT == 1 )
		{
			/* Switch Newlib's _impure_ptr variable to point to the _reent
			structure specific to the task that will run first. */
			_impure_ptr = &( pxCurrentTCB->xNewLib_reent );
		}
		#endif /* configUSE_NEWLIB_REENTRANT */

		/*初始化全局变量*/
		/*初始化下一个任务阻塞超时时间,因为时开启调度器没有任务运行,
		也就是没有阻塞时间所以直接赋值为最大*/
		xNextTaskUnblockTime = portMAX_DELAY;
		/*任务调度器正在运行*/
		xSchedulerRunning = pdTRUE;
		/*系统节拍*/
		xTickCount = ( TickType_t ) 0U;

		/* If configGENERATE_RUN_TIME_STATS is defined then the following
		macro must be defined to configure the timer/counter used to generate
		the run time counter time base. */
		
		/*统计任务运行时间未实现*/
		portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();

		/* Setting up the timer tick is hardware specific and thus in the
		portable interface. */
		/*启动任务调度器,与硬件架构相关的配置部分,以及开启第一个任务*/
		/*运行这个函数时不会返回直接跳读第一个任务去执行*/
		if( xPortStartScheduler() != pdFALSE )
		{
			/* Should not reach here as if the scheduler is running the
			function will not return. */
		}
		else
		{
			/* Should only reach here if a task calls xTaskEndScheduler(). */
		}
	}
	else
	{
		/* This line will only be reached if the kernel could not be started,
		because there was not enough FreeRTOS heap to create the idle task
		or the timer task. */
		configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );
	}

	/* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0,
	meaning xIdleTaskHandle is not used anywhere else. */
	( void ) xIdleTaskHandle;
}
/*-----------------------------------------------------------*/

xPortStartScheduler开启任务调度器函数

作用:该函数用于完成启动任务调度器中与硬件架构相关的配置部分,以及启动第一个任务

该函数内部实现,如下:

1.检测用户在FreeRTOSConfig.h文件中对中断的相关配置是否有误

2.配置PendSV和SysTick的中断优先级为最低优先级

3.调用函数vPortSetupTimerlnterrupt()配置SysTick

4.初始化临界区嵌套计数器为0

5.调用函数prvEnableVFP()使能FPU6(M3没有)、调用函数prvStartFirstTask()启动第一个任务

BaseType_t xPortStartScheduler( void )
{
	/*检测用户在FreeRTOSConfig.h文件中对中断的相关配置是否有误*/
	#if( configASSERT_DEFINED == 1 )
	{
		volatile uint32_t ulOriginalPriority;
		volatile uint8_t * const pucFirstUserPriorityRegister = ( uint8_t * ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
		volatile uint8_t ucMaxPriorityValue;

		/* Determine the maximum priority from which ISR safe FreeRTOS API
		functions can be called.  ISR safe functions are those that end in
		"FromISR".  FreeRTOS maintains separate thread and ISR API functions to
		ensure interrupt entry is as fast and simple as possible. 

		Save the interrupt priority value that is about to be clobbered. */
		ulOriginalPriority = *pucFirstUserPriorityRegister;

		/* Determine the number of priority bits available.  First write to all
		possible bits. */
		*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;

		/* Calculate the maximum acceptable priority group value for the number
		of bits read back. */
		ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
		while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
		{
			ulMaxPRIGROUPValue--;
			ucMaxPriorityValue <<= ( uint8_t ) 0x01;
		}

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

		/* Restore the clobbered interrupt priority register to its original
		value. */
		*pucFirstUserPriorityRegister = ulOriginalPriority;
	}
	#endif /* conifgASSERT_DEFINED */

	/* Make PendSV and SysTick the lowest priority interrupts. */
	/*配置PendSV和SysTick的中断优先级为最低优先级*/
	portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
	portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;

	/* Start the timer that generates the tick ISR.  Interrupts are disabled
	here already. */
	
	/*初始化滴答定时器*/
	vPortSetupTimerInterrupt();

	/* Initialise the critical nesting count ready for the first task. */
	
	/*初始化临界区嵌套计数器为0*/
	uxCriticalNesting = 0;

	/* Start the first task. */
	/*启动第一个任务*/
	prvStartFirstTask();

	/* Should not get here! */
	return 0;
}

启动第一个任务

假设我们要启动的第一个任务是任务A,那么就需要将任务A的寄存器值加载到CPU寄存器中,任务A的寄存器值,在一开始创建任务时就保存在任务堆栈里边!

注意:

1.中断产生时,硬件自动将xPSR, PC(R15), LR(R14), R12, R3-R0保存和恢复;而R4~R11需要手动保存和恢复

2.进入中断后硬件会强制使用MSP指针,此时LR(R14)的值将会被自动被更新为特殊的EXC_RETURN

prvStartFirstTask开启第一个任务函数

prvStartFirstTask开启第一个任务函数

用于初始化启动第一个任务前的环境,主要是重新设置MSP指针,并使能全局中断

1.什么是MSP指针?

程序在运行过程中需要一定的栈空间来保存局部变量等一些信息当有信息保存到栈中时,MCU会自动更新SP(R13)指针, ARM Cortex-M内核提供了两个栈空间:

主堆栈指针(MSP):它由OS内核、异常服务例程以及所有需要特权访问的应用程序代码来使用。

进程堆栈指针(PSP):用于常规的应用程序代码(不处于异常服务例程中时)。

在FreeRTOS中,中断使用MSP (主堆栈) ,中断以外使用PSP (进程堆栈)

__asm void prvStartFirstTask( void )
{
	/*1首先是使用了 PRESERVE8,进行 8 字节对齐,这是因为,
	栈在任何时候都是需要 4 字节对齐的,而在调用入口得8字节对齐,
	在进行C编程的时候,编译器会自动完成的对齐的操作,而对于汇编,
	就需要开发者手动进行对齐。*/
	
	/*8字节对齐*/
	PRESERVE8

	/* Use the NVIC offset register to locate the stack. */
	
	/*向量表开始寄存器地址*/
	ldr r0, =0xE000ED08
	/* 获取向量表的值*/
	ldr r0, [r0]
	/*获取MSP的初始值(栈底指针)*/
	ldr r0, [r0]

	/* Set the msp back to the start of the stack. */
	/*初始化MSP*/
	msr msp, r0
	/* Globally enable interrupts. */
	
	/*使能全局中断*/
	cpsie i
	cpsie f
	dsb
	isb
	/* Call SVC to start the first task. */
	
	/*触发svc中断启动第一个任务*/
	svc 0
	nop
	nop
}

vPortSVCHandler  SVC中断服务函数

注意:SVC中断只在启动第一次任务时会调用一次,以后均不调用

当使能了全局中断,并且手动触发SVC中断后,就会进入到SVC的中断服务函数中

1.通过 pxCurrentTCB 获取优先级最高的就绪态任务的任务栈地址,优先级最高的就绪态任务是系统将要运行的任务。

2.通过任务的栈顶指针,将任务栈中的内容出栈到CPU寄存器中,任务栈中的内容在调用任务创建函数的时候,已初始化,然后设置 PSP 指针。

3.通过往 BASEPRI 寄存器中写 0,允许中断。

4. R14是链接寄存器LR,在ISR中(此刻我们在SVC的ISR中) ,它记录了异常返回值EXC_RETURN而EXC_RETURN只有6个合法的值(M4、M7),如下表所示:

__asm void vPortSVCHandler( void )
{
	/*首先是使用了 PRESERVE8,进行 8 字节对齐,这是因为,
	栈在任何时候都是需要 4 字节对齐的,而在调用入口得8字节对齐,
	在进行C编程的时候,编译器会自动完成的对齐的操作,而对于汇编,
	就需要开发者手动进行对齐。*/

	/*8字节对齐*/	
	PRESERVE8

	/*获取当前任务优先级最高的任务地址*/
	ldr	r3, =pxCurrentTCB	/* Restore the context. */
	/*通过任务地址获取首成员地址*/
	ldr r1, [r3]			/* Use pxCurrentTCBConst to get the pxCurrentTCB address. */
	/*通过首成员获取首成员值*/	
	ldr r0, [r1]			/* The first item in pxCurrentTCB is the task top of stack. */
	/*出栈,把任务控制块里的变量赋值到CPU的R4-R11*/
	ldmia r0!, {r4-r11}		/* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */
	/*设置PSP为任务栈指针此时R0地址是R11,把R0地址赋值给PSP,
	为的是退出中断时由硬件恢复其他寄存器*/
	msr psp, r0				/* Restore the task stack pointer. */
	isb
	
	/*basepri等于0的时候使能所有中断*/
	mov r0, #0
	msr	basepri, r0

	/*使用 PSP 指针,并跳转到任务函数*/	
	orr r14, #0xd
/*最后通过 r14指令,跳转到任务的任务函数中执行*/
	bx r14
}

出栈/压栈汇编指令详解

1.出栈(恢复现场),方向:从下往上(低地址往高地址):假设r0地址为0x04汇编指令示例:

/*任务栈r0地址由低到高,将r0存储地址里面的内容手动加载到CPU寄存器r4、r5、r6*/

Idmia r0!, {r4-r6}

r0地址(0x04)内容加载到r4,加载完后地址需要加4此时地址r0= r0+4 = 0x08

R0地址(0x08)内容加载到r5,加载完后地址需要加4此时地址r0=r0+4 = 0x0C

R0地址(0x0C)内容加载到r6,加载完后地址需要加4此时地址r0=r0+4 = 0x10

 

2.压栈(保存现场),方向:从上往下(高地址往低地址):假设r0地址为0x10汇编指令示例:

/*r0的存储地址由高到低递减,将r4、r5、r6里的内容存储到r0的任务栈里面。*/

stmdb r0!, {r4-r6}}

地址: r0=r0-4 = 0x0C,将r6的内容(寄存器值)存放到r0所指向地址(0x0C)

地址: r0=r0-4 = 0x08,将r5的内容(寄存器值)存放到r0所指向地址(0x08)

地址: r0=r0-4 = 0x04,将r4的内容(寄存器值)存放到r0所指向地址(0x08)

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

09_FreeRTOS任务调度器 的相关文章

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

    文章目录 前言 介绍 系统框架 原项目地址 本项目开发开源地址 硬件PCB 软件功能 详细内容 硬件外壳制作 WS2812级联及控制 MAX30102血氧传感器 0 96OLED FreeRTOS 效果视频 总结 前言 在好几年前 我好像就
  • 【FreeRtos学习笔记】STM32 CubeMx——Timers(定时器)

    目录 1 软件定时器 2 示例程序 2 1 例程功能 2 2 步骤 2 3 实验结果 2 4 函数讲解 1 软件定时器 定时器是MCU常用的外设 我们在学习各种单片机时必然会学习它的硬件定时器 但是 MCU自带的硬件定时器资源是有限的 而且
  • FreeRTOS内核配置说明---FreeRTOS Kernel V10.2.1

    FreeRTOS内核是高度可定制的 使用配置文件FreeRTOSConfig h进行定制 每个FreeRTOS应用都必须包含这个头文件 用户根据实际应用来裁剪定制FreeRTOS内核 这个配置文件是针对用户程序的 而非内核 因此配置文件一般
  • STM32CubeMX+FreeRTOS学习笔记(一)

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

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

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

    一 软件定时器介绍 freeRTOS软件定时器的时基是基于系统时钟节拍实现的 可以创建很多个 在硬件定时器资源不充足的情况下非常有用 软件定时器一般用作周期性地执行函数 在创建软件定时器时指定软件定时器的回调函数 在回调函数中实现相应的功能
  • 【FreeRTOS】队列的使用

    作者主页 凉开水白菜 作者简介 共同学习 互相监督 热于分享 多加讨论 一起进步 专栏资料 https pan baidu com s 1nc1rfyLiMyw6ZhxiZ1Cumg pwd free 点赞 收藏 再看 养成习惯 订阅的粉丝
  • stm32f103zet6移植标准库的sdio驱动

    sdio移植 st官网给的标准库有给一个用于st出的评估板的sdio外设实现 但一是文件结构有点复杂 二是相比于国内正点原子和野火的板子也有点不同 因此还是需要移植下才能使用 当然也可以直接使用正点原子或野火提供的实例 但为了熟悉下sdio
  • FreeRTOS之软件定时器

    FreeRTOS之软件定时器 声明 本人按照正点原子的FreeRTOS例程进行学习的 欢迎各位大佬指责和批评 谢谢 include sys h include delay h include usart h include led h in
  • FreeRTOS笔记(一)简介

    这个笔记主要依据韦东山freertos快速入门系列记录 感谢韦东山老师的总结 什么是实时操作系统 操作系统是一个控制程序 负责协调分配计算资源和内存资源给不同的应用程序使用 并防止系统出现故障 操作系统通过一个调度算法和内存管理算法尽可能把
  • [FreeRTOS入门学习笔记]定时器

    定时器的使用步骤 1 定义一个handle xTimerCreate创建 2 启动定时器 在Task1中调用 通过队列通知守护任务来执行定时器任务 要再config头文件中定义守护任务相关配置 虽然定时器是在task1中启动 但是定时器的任
  • FreeRTOS轻量级同步--任务通知

    1 简介 在FreeRTOS的配置参数中的configUSE TASK NOTIFICATIONS宏打开 一般RTOS会默认打开 如图1所示 图1 notify宏开关 RTOS在创建任务时 会创建一个32位的通知值ulNotifiedVal
  • 单片机通信数据延迟问题排查

    1 问题说明 笔者在最近的项目中 发现系统的响应延迟较高 经过排查 排除了单片机运行卡死的问题 2 原因分析 具体排查过程这里就不细致说明了 直接给出排查后原因 任务执行周期规划不合理 导致freertos队列发送接收到的命令有延迟 为了便
  • FreeRTOS临界段

    1 临界段 在访问共享资源时不希望被其他任务或者中断打断的代码 这段要执行的代码称为临界段代码 2 设置临界段的目的 保护共享资源 例如 全局变量 公共函数 不可重入函数 函数里面使用 了一些静态全局变量 malloc 等 保护外设的实时性
  • 13-FreeRTOS任务创建与删除

    任务创建和删除API函数位于文件task c中 需要包含task h头文件 task h里面包函数任务的类型函数 例如 对xTaskCreate的调用 通过指针方式 返回一个TaskHandle t 变量 然后可将该变量用vTaskDele
  • FreeRTOS之系统配置

    1 FreeRTOS的系统配置文件为FreeRTOSConfig h 在此配置文件中可以完成FreeRTOS的裁剪和配置 在官方的demo中 每个工程都有一个该文件 2 先说一下 INCLUDE 开始的宏 使用 INCLUDE 开头的宏用来
  • 如何更改 FreeRTOS 中任务的最大可用堆大小?

    我通过以下方式在任务中创建元素列表 l dllist pvPortMalloc sizeof dllist dlllist 有 32 字节大 我的嵌入式系统有 60kB SRAM 所以我希望系统可以轻松处理我的 200 个元素列表 我发现在
  • FreeRTOS 匈牙利表示法 [重复]

    这个问题在这里已经有答案了 我是 RTOS 和 C 编程的新手 而且我仍在习惯 C 的良好实践 因此 我打开了一个使用 FreeRTOS 的项目 我注意到操作系统文件使用匈牙利表示法 我知道一点符号 但面临一些新的 标准 FreeRTOS
  • 小型 ARM 微控制器的 RTOS 内核之间的可量化差异 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 有许多不同的 RTOS 可用于微控制器 我专门寻找支持 ARM Cortex M 处理器的 RTOS 另外 我对闭源解决方案不感兴趣 试图从网站

随机推荐

  • python vstack

    Python numpy函数hstack vstack stack dstack vsplit concatenate 感觉numpy hstack 和numpy column stack 函数略有相似 xff0c numpy vstack
  • Linux下VNC Server的配置

    1 xff09 安装vnc server xff1a rpm ivh tigervnc server 1 1 0 5 el6 x86 64 rpm 2 修改配置文件 xff0c 1 表示第1号桌面 xff0c 对应端口号5901 2 表示2
  • WIN10_GTX1650_深度学习环境搭建

    这篇博客总结的非常好 xff0c 但安装过程中可能会碰到一些问题 在这记录 xff0c 分享一下解决方案 https blog csdn net weixin 45755980 article details 105397874 Tenso
  • Linux面试必备20个常用命令

    文章目录 第一章 什么是linux第二章 linux的基础命令1 pwd 命令2 ls 命令3 cd 命令4 man 命令5 grep 命令6 find 命令7 chmod 命令8 ps 命令9 kill 命令10 tail 命令11 ne
  • Python爬虫实战(一):翻页爬取数据存入SqlServer

    目录 前言爬取目标准备工作代码分析1 设置翻页2 获取代理ip3 发送请求4 获取详情页地址5 提取详情信息6 存入数据库7 循环实现翻页8 启动 前言 x1f525 x1f525 本文已收录于Python爬虫实战100例专栏 xff1a
  • 已解决error: subprocess-exited-with-error

    已解决 xff08 pip安装第三方模块lxml模块报错 xff09 Building wheels for collected packages lxml Building wheel for lxml setup py error er
  • 已解决此处缺少‘,‘, ‘]‘字符, 实际上是一个 ‘EOF‘

    已解决Python解析JSON xff0c 抛出此处缺少 39 39 39 字符 实际上是一个 39 EOF 异常的解决方法 xff0c 亲测有效 文章目录 报错问题报错原因解决方法千人全栈VIP答疑群联系博主帮忙解决报错 报错问题 粉丝群
  • 已解决E: Unable to locate package ros-kinetic-desktop-full

    已解决Ubuntu安装ros xff0c 抛出异常E Unable to locate package ros kinetic desktop full的正确解决方法 xff0c 亲测有效 xff0c 文末附上Ubuntu系统对应ros系统
  • 数组元素交叉排列的算法题(a1 a2 a3 .. an b1 b2 b3 .. bn -->a 1 b1, a2 b2, a3 b3, .. an bn ) 概论思想(perfect shuffle 算法)

    perfect shuffle 算法 今天又发现一个关于完美洗牌的算法 这个比较简单一些 xff0c 由 microsoft的Peiyush Jain提出 原论文 xff1a A Simple In Place Algorithm for
  • Linux操作系统之命令

    Linux操作系统指令有很多 xff0c 这里就先介绍一些最最基础的吧 首先就是将操作界面显示 xff1a Ctrl 43 alt 43 t 显示当前目录内容 xff1a ls ls l xff1a 将目录内容使用列表显示 ls a xff
  • [操作系统]学习操作系统的经典书籍

    http blog chinaunix net u1 43966 showart 396940 html 介绍了一些操作系统学习的经典书籍 xff0c 包括理论上的 具体操作系统的 Abraham Silberschatz的两本书 xff1
  • 原创:史上最全最通俗易懂的,索引最左前缀匹配原则(认真脸)

    索引最左前缀匹配原则 对于最左前缀匹配原则居然没有百度百科 xff0c 实在是让我感觉不可思议 最左前缀匹配原则 xff0c 用几句话来概述就是 xff1a 顾名思义 xff0c 就是最左优先 xff0c 在创建多列索引时 xff0c 要根
  • MATLAB从文件读取数据

    一 从filename文件读取数据 1 readtable函数 语法 xff1a t 61 readtable xff08 filename xff09 支持的扩展名 xff1a txt csv xls xlsm xlsx xlsm xlt
  • 前端进阶之TS总结

    知识点 高频面试题TS装饰器axios二次封装 1 高频面试题 1 1 类型推论 amp 可赋值性 什么是类型推论 xff1f TypeScript 会在没有明确的指定类型的时候推测出一个类型 xff0c 这就是类型推论如果定义的时候没有赋
  • 岁月清浅,邀你入梦

    这世间本应美好 xff0c 怎无奈痛苦缠身 xff0c 卿心亦真 xff0c 免世人之苦 xff0c 乐自身之本 卿之容 xff0c 多沉醉 xff0c 于心赞 xff0c 日夜思 淡若微风的陪伴 xff0c 奈何情深缘浅 只相识 xff0
  • 记一次解BUG的心得感受

    今天遇到 了 一个 STP的问题 xff0c 从测试 现象 来看与之前一个FR的验证过程中表现出来的特征很相似 这种相似性将我引入了一种歧途 xff1a 怀疑原来的修改有问题 假设你知道第N次修改有潜在的case无法验证 那么这种潜在的风险
  • 02_Keil5报错 error: #5: cannot open source input file “XXX.h”: No such file or directory解决方法

    Keil5 error 5 cannot open source input file led h No such file or directory 是找不到包含文件 解决办法1 包含文件可以解决 解决办法2 如果包含了还是报 5找不到文
  • 05_FreeRTOS中断管理

    目录 什么是中断 中断相关寄存器 源码实验 什么是中断 简介 让CPU打断正常运行的程序 转而去处理紧急的事件 程序 就叫中断 举例 上课可以比做CPU正常运行的程序 上厕所可以比做中断程序 中断执行机制 可简单概括为三步 中断请求 外设产
  • 07_FreeRTOS任务调度器的挂起和恢复

    任务调度器的挂起和恢复 挂起任务调度器 调用此函数不需要关闭中断 使用格式示例 1 与临界区不一样的是 挂起任务调度器 未关闭中断 2 它仅仅是防止 xff1b 任务之间的资源争夺 中断照样可以直接响应 3 挂起调度器的方式 适合于临界区位
  • 09_FreeRTOS任务调度器

    目录 开启任务调度器vTaskStartScheduler函数 xPortStartScheduler开启任务调度器函数 启动第一个任务 prvStartFirstTask开启第一个任务函数 vPortSVCHandler SVC中断服务函