【FreeRTOS】详细讲解FreeRTOS中任务管理并通过示例讲述其用法

news2024/11/17 19:38:32

任务状态

  在FreeRTOS中一个任务经创建后会有多个状态,通常可分为以下几种状态:

  • 就绪态:新创建的任务一般处于就绪态。处于就绪态的任务表明其已经存在于就绪列表中,其已经具备所有的任务执行需要条件,只等待调度器调度运行
  • 运行态:运行态,表明该任务正在占用处理器执行任务。调度器永远都只会从就绪列表中选取优先级最高任务运行
  • 挂起态:处于挂起态的任务一般都是长时间不允许运行的任务,此时CUP不会处理该任务的任何信息;
  • 阻塞态:任务处于阻塞态,说明该任务不在就绪列表中,其正在等待某个时序或者是某个外部中断。通常任务挂起任务延时任务等待信号量都属于阻塞。

  既然如此,各个状态间转换关系又是怎么的呢?

  • 创建任务—>就绪态1:任务经过创建函数(xTaskCreate/xTaskCreateStatic)后可以直接进入就绪态
  • 就绪态—>运行态2:任务发生切换时,调度器总从就绪列表中选取优先级最高的任务进入运行态开始运行
  • 运行态—>就绪态3:当有更高优先级任务被创建或恢复后,调度器就会将新任务变成运行态,而原来的任务就会变成阻塞状态,直到新任务执行完毕后原任务才会继续运行;看到这大家有没有觉得这玩意有点像中断呢?🤣🤣🤣
  • 运行态—>阻塞态4:当正在执行的任务发生阻塞(挂起、延时、读取信号量等)时,该任务就会变成阻塞态,并且任务还会从就绪列表中删除,最后调度器会从就绪列表中执行当前优先级最高的任务
  • 阻塞态—>就绪态5:当阻塞任务恢复(任务恢复、延时超时、读取信号量超时等)后,该任务会变成就绪态,并且重新加入到就绪列表,此时调度器仍然执行就绪列表中优先级最高的任务
  • 就绪态—>挂起态6:无论任务处于哪个状态一旦调用API(vTaskSuspend)任务都会切换到挂起状态,挂起任务不会获得CPU使用权,更不会参与调度器的调度 ,挂起后调度器仍然调度就绪列表中优先级最高的任务运行
  • 阻塞态—>挂起态7:与6相同;
  • 运行态—>挂起态8:与6相同;
  • 挂起态—>就绪态9:处于挂起态的任务经任务恢复vTaskResume)后,任务会切换到就绪态,此时调度器仍然调度就序列表中优先级最高的任务运行

任务函数

启动任务调度器
函数原型

void vTaskStartScheduler(void);

函数参数

函数说明
  函数vTaskStartScheduler是FreeRTOS中一个非常重要的函数,无论是什么样的FreeRTOS程序都需要使用vTaskStartScheduler函数启动调度器,该函数就像一个总开关,只有将其打开才能够使得FreeRTOS正常工作。

静态任务创建
函数原型

TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
                                const char * const pcName, 
                                const uint32_t ulStackDepth,
                                void * const pvParameters,
                                UBaseType_t uxPriority,
                                StackType_t * const puxStackBuffer,
                                StaticTask_t * const pxTaskBuffer );
    

参数解析

  • TaskFunction_t pxTaskCode:设置创建任务所需执行的任务函数;
  • const char * const pcName:设置任务名字;
  • const uint32_t ulStackDepth:设置任务栈长度;
  • void * const pvParameters:传递给任务的参数;
  • UBaseType_t uxPriority:设置任务优先级;
  • StackType_t * const puxStackBuffer:设置任务堆栈;
  • StaticTask_t * const pxTaskBuffer:任务控制块;

函数说明
  静态创建任务函数xTaskCreateStatic,含有七个参数、一个返回值(表示任务是否创建成功)。需要注意的是使用其创建任务时需要传入任务栈

动态任务创建
函数原型

    BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
                            const char * const pcName,
                            const configSTACK_DEPTH_TYPE usStackDepth,
                            void * const pvParameters,
                            UBaseType_t uxPriority,
                            TaskHandle_t * const pxCreatedTask);

参数解析

  • TaskFunction_t pxTaskCode:设置创建任务所需执行的任务函数;
  • const char * const pcName:设置任务名字;
  • const configSTACK_DEPTH_TYPE usStackDepth:设置任务栈大小;
  • void * const pvParameters:传递任务函数参数;
  • UBaseType_t uxPriority:设置任务优先级;
  • TaskHandle_t * const pxCreatedTask:保存任务控制块;

函数说明
  动态创建任务函数,共含有六个参数、一个返回值(返回值也表示任务是否创建成功),与静态创建任务不同之处是该函数不用传入任务栈,其任务栈使用动态方式创建。

单任务挂起
函数原型

void vTaskSuspend( TaskHandle_t xTaskToSuspend );

参数解析

  • TaskHandle_t xTaskToSuspend:任务的控制权柄;

函数说明
  通过该函数可以使得某任务进入挂起状态,等待下次任务恢复才有可能继续运行。

多任务挂起
函数原型

void vTaskSuspendAll( void );

参数解析

函数说明
  通过函数vTaskSuspendAll能够使得所有的任务都进入挂起状态,看起来将所有任务都挂起了,实际上仅仅锁住调度器也就是挂起任务调度器)。使用该函数虽然锁住了调度器,但系统中断依旧可以正常使用

单任务恢复
函数原型

void vTaskResume( TaskHandle_t xTaskToResume );

参数解析

  • TaskHandle_t xTaskToSuspend:任务的控制权柄;

函数说明
  通过函数vTaskResume可以使由挂起函数vTaskSuspend挂起的任务重新恢复。
  无论同一任务在挂起时候调用过多少次vTaskSuspend()函数,也只需调用一次vTaskResume()函数即可将任务恢复运行;当然,无论调用多少次vTaskResume()函数,也只有在任务是挂起态的时候才进行恢复

多任务恢复
函数原型

BaseType_t xTaskResumeAll( void );

参数解析

  • 返回值:类型为BaseType_t,用于表示恢复任务是否成功;

函数说明
  通过函数xTaskResumeAll可以使得所有被挂起的任务都恢复。
  调度器恢复可以调用xTaskResumeAll()函数,调用多少次的 vTaskSuspendAll()就要调用多少次xTaskResumeAll()进行恢复

在中断中恢复任务
函数原型

BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume );

参数解析

  • TaskHandle_t xTaskToResume:任务控制权柄;
  • 返回值:类型为BaseType_t,用于表示任务恢复是否成功;

函数说明
  函数xTaskResumeFromISR是在中断中恢复被挂起任务。
  使用该函数时必须将INCLUDE_vTaskSuspend INCLUDE_vTaskResumeFromISR 都定义为 1 才有效。但任务还没有处于挂起态的时候,调用xTaskResumeFromISR()函数是没有任何意义的

任务删除
函数原型

void vTaskDelete( TaskHandle_t xTaskToDelete );

参数解析

  • TaskHandle_t xTaskToDelete:任务的控制句柄;

函数说明
  使用函数vTaskDelete()前需要将INCLUDE_vTaskDelete定义为 1;被删除任务可以从所有就绪、阻塞、挂起和事件列表中删除
  通过函数vTaskDelete()可以删除某个任务;当删除自身时,传入参数NULL,但自己的内存并没有得到释放

任务相对延时
函数原型

void vTaskDelay( const TickType_t xTicksToDelay );

参数解析

  • const TickType_t xTicksToDelay:延时时间,单位为系统节拍时间 (tick);

函数说明
  使用vTaskDelay()函数前,必须把INCLUDE_vTaskDelay 定义为 1。
  函数vTaskDelay()相对地阻塞延时,调用该函数后,任务将进入阻塞状态,并且让出 CPU 资源。延时时长由形参 xTicksToDelay 决定,单位为系统节拍周期, 比如系统的时钟节拍周期为 1ms,那么调用vTaskDelay(10)的延时时间则为10ms,那么经过从调用vTaskDelay()相对的10ms后任务会解除阻塞,因此,函数vTaskDelay()不适用于周期性执行任务的场合,并且其他任务与中断也会影响该函数正常工作

任务绝对延时
函数原型

BaseType_t xTaskDelayUntil( TickType_t *pxPreviousWakeTime, 
							const TickType_t xTimeIncrement );

参数解析

  • TickType_t *pxPreviousWakeTime:指针,指向一个变量,该变量保存任务最后一次解除阻塞的的时刻。第一次使用时,该变量必须初始化为当前时间,之后这个变量会在vTaskDelayUntil()函数内自动更新。
  • const TickType_t xTimeIncrement:周 期 循 环 时 间 。 当 时 间 等 于(*pxPreviousWakeTime + xTimeIncrement)时,任务解除阻塞。如果不改变参数 xTimeIncrement 的值,调用该函数的任务会按照固定频率执行。
  • 返回值:数据类型为BaseType_t,用于检验任务是否实际延迟的值。

函数说明
  在实际使用过程中,一般使用vTaskDelayUntil函数,但是它的实现本质上还是依靠函数xTaskDelayUntil实现。函数重声明如下:

/*
 * vTaskDelayUntil() is the older version of xTaskDelayUntil() and does not
 * return a value.
 */
#define vTaskDelayUntil( pxPreviousWakeTime, xTimeIncrement )                   \
    do {                                                                        \
        ( void ) xTaskDelayUntil( ( pxPreviousWakeTime ), ( xTimeIncrement ) ); \
    } while( 0 )

  使用函数vTaskDelayUntil前,必须把INCLUDE_vTaskDelayUntil 定义为 1。
  函数vTaskDelayUntil()延时是绝对性的。
  功能上看,函数vTaskDelayUntil() 与函数vTaskDelay () 都是用来实现任务的周期性延时。但vTaskDelay ()的延时是相对的,是不确定的,它的延时是
vTaskDelay ()调用完毕后开始计算**的。并且 vTaskDelay ()延时时间到了之后,如果有高优先级的任务或者中断正在执行,被延时阻塞的任务并不会马上解除阻塞,所有每次执行任务的周期并不完全确定。vTaskDelayUntil()延时是绝对的,适用于周期性执行的任务。当(*pxPreviousWakeTime +xTimeIncrement)时间到达后,vTaskDelayUntil()函数立刻返回,如果此任务是最高优先级的,则任务会立马解除阻塞


示例

示例1
  利用FreeRTOS的空闲任务计时实现LED1、LED2灯闪烁。

  • 步骤一:创建两个FreeRTOS的任务,其优先级都设置为1;
  • 步骤二:完成两个FreeRTOS任务的函数体,每次执行一次任务后就使用函数vTaskSuspend将任务挂起;
  • 步骤三:完成空闲任务函数函数体,每执行一个函数就将计数值加 1 。当空闲任务执行次数到达指定次数时,就使用函数vTaskResume恢复函数。
void task1(void);
void task2(void);

unsigned int count[2] = {0,0};

/*****************************************
* 函数功能:freertos工作函数
* 函数参数:无
* 函数返回值:无
*****************************************/
void freertosWork(void)
{
	/*创建任务两个LED灯闪烁任务*/
	//存储创建任务的返回值
	BaseType_t xReturn[2] ;
	
	//动态创建任务1
	xReturn[0] = xTaskCreate(
				(TaskFunction_t )task1,//任务入口函数
				(const char *)"task1",//任务名字
				(uint16_t)512,//任务栈大小
				(void*)NULL,//任务入口参数
				1,//任务优先级  优先级越高,任务优先选越高
				&xHandleTsak[0]//任务控制块
				);
	
	//动态创建任务2
	xReturn[1] = xTaskCreate(
				(TaskFunction_t )task2,//任务入口函数
				(const char *)"task2",//任务名字
				(uint16_t)512,//任务栈大小
				(void*)NULL,//任务入口参数
				1,//任务优先级  优先级越高,任务优先选越高
				&xHandleTsak[1]//任务控制块
				);					
		
	//创建成功 
	if (pdPASS == xReturn[0] == xReturn[1])
		//启动任务,开启调度 
		vTaskStartScheduler(); 
	//创建失败
	else
		//点亮LED6
		changeLedStateByLocation(LED6,ON);
	return 0;
}

/*****************************************
* 函数功能:freertos的任务1
* 函数参数:无
* 函数返回值:无
*****************************************/
void task1(void)
{
	while(1)
	{
		//LED1反转状态
		rollbackLedByLocation(LED1);
		//挂起任务
		vTaskSuspend(xHandleTsak[0]);
	}
}

/*****************************************
* 函数功能:freertos的任务2
* 函数参数:无
* 函数返回值:无
*****************************************/
void task2(void)
{
	while(1)
	{
		//LED2状态反转
		rollbackLedByLocation(LED2);
		//挂起任务
		vTaskSuspend(xHandleTsak[1]);
	}
}

/*****************************************
* 函数功能:freertos的空闲任务
* 函数参数:无
* 函数返回值:无
*****************************************/
void vApplicationIdleHook (void)
{
		++count[0];		
		if(count[0] % 900000 == 0)
			//恢复任务1
			vTaskResume(xHandleTsak[1]);
		if(count[0] % 1000000 == 0)
			//恢复任务0
			vTaskResume(xHandleTsak[0]);
		if(count[0] % 500000 == 0)
			rollbackLedByLocation(LED8);
}

结果
  其结果为LED1、LED2根据空闲任务执行次数来切换LED1与LED2的状态;

示例2
  利用FreeRTOS的空闲任务计时实现LED1、LED2、LED3轮换灯闪烁。

  • 步骤一:创建三个FreeRTOS的任务,其优先级都设置为1;
  • 完成三个FreeRTOS任务的函数体,每次执行一次任务后就使用函数vTaskDelayUntil将任务周期性阻塞,切换各个任务;
void task1(void);
void task2(void);
void task3(void);

unsigned int count[2] = {0,0};

/*****************************************
* 函数功能:freertos工作函数
* 函数参数:无
* 函数返回值:无
*****************************************/
void freertosWork(void)
{
	/*创建任务两个LED灯闪烁任务*/
	//存储创建任务的返回值
	BaseType_t xReturn[2] ;
	
	//动态创建任务1
	xReturn[0] = xTaskCreate(
				(TaskFunction_t )task1,//任务入口函数
				(const char *)"task1",//任务名字
				(uint16_t)512,//任务栈大小
				(void*)NULL,//任务入口参数
				1,//任务优先级  优先级越高,任务优先选越高
				&xHandleTsak[0]//任务控制块
				);
	
	//动态创建任务2
	xReturn[1] = xTaskCreate(
				(TaskFunction_t )task2,//任务入口函数
				(const char *)"task2",//任务名字
				(uint16_t)512,//任务栈大小
				(void*)NULL,//任务入口参数
				1,//任务优先级  优先级越高,任务优先选越高
				&xHandleTsak[1]//任务控制块
				);					
	
	//动态创建任务3
	xReturn[2] = xTaskCreate(
				(TaskFunction_t )task3,//任务入口函数
				(const char *)"task3",//任务名字
				(uint16_t)512,//任务栈大小
				(void*)NULL,//任务入口参数
				1,//任务优先级  优先级越高,任务优先选越高
				&xHandleTsak[2]//任务控制块
				);		
	//创建成功 
	if (pdPASS == xReturn[0] == xReturn[1] == xReturn[2])
		//启动任务,开启调度 
		vTaskStartScheduler(); 
	//创建失败
	else
		//点亮LED6
		changeLedStateByLocation(LED6,ON);
	return 0;
}

/*****************************************
* 函数功能:freertos的任务1
* 函数参数:无
* 函数返回值:无
*****************************************/
void task1(void)
{
	//保存上次任务执行的时间,调用后会再次刷新时间
	static portTickType PreviousWakeTime;
	const volatile TickType_t xDelay900ms = pdMS_TO_TICKS( 900UL );
	//获取当前时间
	PreviousWakeTime = xTaskGetTickCount();
	while(1)
	{
		//LED1反转状态
		rollbackLedByLocation(LED1);
		vTaskDelayUntil( &PreviousWakeTime,xDelay900ms );
	}
}

/*****************************************
* 函数功能:freertos的任务2
* 函数参数:无
* 函数返回值:无
*****************************************/
void task2(void)
{

	//保存上次任务执行的时间,调用后会再次刷新时间
	static portTickType PreviousWakeTime;
	const volatile TickType_t xDelay1400ms = pdMS_TO_TICKS( 1400UL );
	//获取当前时间
	PreviousWakeTime = xTaskGetTickCount();
	while(1)
	{
		//LED2状态反转
		rollbackLedByLocation(LED2);	
		vTaskDelayUntil( &PreviousWakeTime,xDelay1400ms );
	}
}

/*****************************************
* 函数功能:freertos的任务3
* 函数参数:无
* 函数返回值:无
*****************************************/
void task3(void)
{
	
	//保存上次任务执行的时间,调用后会再次刷新时间
	static portTickType PreviousWakeTime;
	const volatile TickType_t xDelay2000ms = pdMS_TO_TICKS( 2000UL );
	//获取当前时间
	PreviousWakeTime = xTaskGetTickCount();
	while(1)
	{
		//LED2状态反转
		rollbackLedByLocation(LED3);	
		vTaskDelayUntil( &PreviousWakeTime,xDelay2000ms );
	}
}

结果
  FreeRTOS创建的三个任务,分别以900ms、1400ms、2000ms的时间间隔轮流执行,视觉上就是LED1、LED2、LED3轮流闪烁。


小编这里还有一篇关于定时器的文章,也欢迎各位点击观看😉😉😉【FreeRTOS】详细讲解FreeRTOS的软件定时器及通过示例讲述其用法

最后 ,也欢迎大家留言或私信交流,大家共同进步!😁😁😁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/184243.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

社科院杜兰大学金融管理硕士项目——美丽的风景,在你前行的路上

一个人的强大源于内心的坚定,内心强大的人,是平和的、自信的、乐观的。在工作中也是奋发图强、积极向上的,就像选择来社科院与杜兰大学金融管理硕士充电,为职场发展注入能量,为未来发展奠定基础。近些年来,…

Centos7离线安装MySQL

使用tar.gz文件安装MySQL 1、下载MySQL离线包 下载地址:https://downloads.mysql.com/archives/community/ 根据需要下载对应版本tar.gz文件,下载完成后上传到服务器 2、解压tar.gz文件 tar -zxvf mysql-5.7.37-linux-glibc2.12-x86_64.tar.gz等待解…

【计算机网络】TCP/UDP协议

传输层协议 负责数据能够从发送端传输接收端,这篇文章主要介绍TCP和UDP协议 UDP协议 学习UDP协议需要掌握,UDP协议如何做到封装和解包的,如何做到向上交付的(分用问题) UDP协议格式 封装:添加定长报头 解包&…

用Python掌握QQ群聊天记录数据分析

当你打开QQ群时,你是否想过如何用Python提取里面的数据呢?随着社交媒体的兴起,QQ群成为了人们交流的重要平台,而提取这些数据可以帮助我们了解用户喜好和行为。那么,如何使用Python提取QQ群数据呢? 这里做了一套脚本用于提取QQ群的消息并进行一些简单的处理。 其中包括…

IB、AP、A-LEVEL,哪种最适合自己呢?

刚开始了解新加坡留学的家长和学生,一定看到这些就觉得头大吧。当下国际学校里的课程可以说五花八门,在选择之前一定要弄清楚这些名词背后的含义…… IB是什么 IB(International Baccalaureate)全称为国际预科证书课程&#xff0c…

Linux下rabbitmq的集群搭建

1 修改 3 台机器的主机名称 在三台服务器分别执行 hostnamectl set-hostname master hostnamectl set-hostname node01 hostnamectl set-hostname node022 配置各个节点的 hosts 文件 vim /etc/hosts 192.168.5.6 master 192.168.5.7 node01 192.168.5.8 node023 确保各个节…

【工具】苏格拉底式诘问法解决工作问题

目录一、什么是苏格拉底式诘问法二、苏格拉底式诘问法的细分三、在实际工作中运用苏格拉底式诘问法解决问题一、什么是苏格拉底式诘问法 苏格拉底式诘问法(Socratic Elenchus)是苏格拉底式提问的一种,也叫做"诘问法"。它是由古希腊…

OpenCV-PyQT项目实战(2)QtDesigner 和 PyUIC 快速入门

欢迎关注『OpenCV-PyQT项目实战 Youcans』系列,持续更新中 OpenCV-PyQT项目实战(1)安装与环境配置 OpenCV-PyQT项目实战(2)QtDesigner 和 PyUIC 快速入门 OpenCV-PyQT项目实战(3)信号与槽机制 …

【Java】final的关键字和final的四种用法

final定义 final翻译成中文的意思是 “最终” , 它是java当中的一个关键字,使用final修饰的对象不允许修改或替换其原始值或定义。 假如当final修饰一个类的时候,是不能被其他类继承的。 final的四种用法 修饰类修饰方法修饰变量修饰参数 1.…

Oracle 里的优化器

对于关系型数据库而言,优化器是最核心的部分。主要是因为优化器负责解析SQL。而大家都是通过SQL来访问存储在数据库中的数据。故此,优化器的好坏直接决定该关系型数据库的强弱。 同时,想要做好SQL优化,就必须深入了解优化器。这是…

源表的基础知识

浅谈“源表”的定义、功能及应用 源表与传统电源的区别 源表速度更快; 源表电流、电压分辨率更高; 源表是四象限,可以正电压(源表提供给外部)负电流(外部灌入源表)或者负电压、正电流。 传统电…

3.组件的基本用法

目录 1 创建组件 1.1 用函数创建组件 1.2 使用类创建组件 2 项目上组件的使用方式 3 事件处理 3.1 事件绑定 3.1.1 类组件绑定事件 3.1.2 函数组件绑定事件 3.2 事件对象 4 组件状态 4.1 初始化状态 4.2 获取状态 4.3 设置状态 4.3.1 箭头函数 4.…

win10下Elasticsearch安装配置完整教程

一、在安装Elasticsearch引擎之前,必须安装ES需要的软件环境,安装Java JDK和配置JAVA_HOME环境变量 二.安装ElasticSearch服务,下载和安装es包 https://www.elastic.co/downloads/past-releases Elasticsearch 8.6.1 | Elastic 安装成功之…

数据结构 第五章 数组和广义表

还是会想你:点击收听 1 基本知识点 1、数组可以看作是下标和值的偶对的集合(具有相同类型的数据元素) 注意:数组是同类型值的集合?**错误**2、数组的存储方式:以行为主序(一行存储完成之后继续存储下一行)、以列为主序(一列存储…

【C++修行之路】C++入门之深剖变量

🍿本文主题:C语法中的变量 🎈更多内容:C较C的改进 💕我的主页:蓝色学者 文章目录前言概念什么是变量变量名变量类型为什么要有不同数据类型各自数据类型的本质结语前言 大家好久不见,今天是我…

22.1.29打卡 2023牛客寒假算法基础集训营1 ACDHKLM

2023牛客寒假算法基础集训营1_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ 网上高质量题解太多了, 我这就作为打卡日报随便写写 A 四个变量 a b记录两队得分 c d记录两队最多还能获得的得分 简单模拟 /* ⣿⣿⣿⣿⣿⣿⡷⣯⢿⣿⣷⣻⢯⣿⡽⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿…

Ruoyi-Cloud框架学习-【02 Redis安装搭建+Ruoyi下载+Nacos数据库配置】

Redis服务端与客户端的安装与搭建 参考该博文 https://joycez.blog.csdn.net/article/details/128776284?spm1001.2014.3001.5502 安装文件 链接:https://pan.baidu.com/s/1v19C9Dhh-ZkNQ8l1RVGQkA 提取码:6mim Ruoyi-Cloud下载以及数据库配置 1、前…

MySQL主从复制的数据同步延迟(二)

1、介绍 主从复制环境在单机应用的时候没有问题,但是在实际的生产环境中,会存在 复制延迟 的问题 查看从库同步状态 在从库中执行 show slave status\G : mysql> show slave status\G *************************** 1. row **************…

Matlab论文插图绘制模板第73期—带等高线的光影曲面图

在之前的文章中,分享了Matlab曲面图的绘制模板: 光影曲面图: 带等高线的曲面图: 进一步,再来看一下带等高线的光影曲面图的绘制模板。 先来看一下成品效果: 特别提示:Matlab论文插图绘制模板系…

make <board_name>_defconfigmake menuconfig

1.make <board_name>_defconfig (1)在uboot的顶层目录的Makefile中查找目标&#xff08;defconfig无法查到&#xff09;&#xff0c;检索config&#xff0c;找到目标config和目标%config 因为我们的目标为<board_name>_defconfig&#xff0c;所以需要看的是有通配…