FreeRTOS-空闲任务、低功耗源码分析

2023-05-16

FreeRTOS在启动任务调度时会自动创建一个空闲任务,空闲任务主要在系统没有其它任务或任务都处于挂起状态时执行,它被系统设置为最低优先级,不会去抢占其它高优先级的任务,从而既能保证系统总有至少一个任务可以运行又不干扰到其它任务。空闲任务里面可以执行一些辅助操作,比如任务删除自身时由于无法立马释放掉自己的内存,这时可以做个标记,在空闲任务里面去删除。还有个非常重要的功能就是实现低功耗,进入空闲任务一般意味着系统当前没事做了,此时如果关闭某些外设或时钟就能达到降低功率的效果。
从启动任务调度器的代码中可以看到系统创建了一个空闲任务:

void vTaskStartScheduler( void )
{
BaseType_t xReturn;

/* 静态创建空闲任务 */
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
{
	.....
	/* 静态内存方式创建空闲任务 */
	xIdleTaskHandle = xTaskCreateStatic(	prvIdleTask,
											configIDLE_TASK_NAME,
											ulIdleTaskStackSize,
											( void * ) NULL, 
											portPRIVILEGE_BIT,
											pxIdleTaskStackBuffer,
											pxIdleTaskTCBBuffer ); 

	.....
}
#else
{
	//动态方式创建空闲任务
	xReturn = xTaskCreate(	prvIdleTask,
							configIDLE_TASK_NAME,
							configMINIMAL_STACK_SIZE,
							( void * ) NULL,
							portPRIVILEGE_BIT, 
							&xIdleTaskHandle ); 
}
#endif

其中空闲任务的函数指针 prvIdleTask 是一个宏定义:

#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
static portTASK_FUNCTION( prvIdleTask, pvParameters )

可以看出 portTASK_FUNCTION 的形参为 prvIdleTask ,所以最终 portTASK_FUNCTION 就是空闲任务 prvIdleTask,这里分析一下 portTASK_FUNCTION 这个函数的源码:

static portTASK_FUNCTION( prvIdleTask, pvParameters )
{
	( void ) pvParameters;//防止报错

	portTASK_CALLS_SECURE_FUNCTIONS();

	for( ;; )
	{
		/* 进入空闲任务后会不停的查看是否有任务需要删除,在这个函数内进行删除 */
		prvCheckTasksWaitingTermination();

		#if ( configUSE_PREEMPTION == 0 )
		{
			/* 如果没有使用抢占,会不停的强制一次任务切换查看是否有其他任务需要执行
			   使用了抢占的话就不需要这一步了,因为有高优先级任务就绪后会自动抢占 */
			taskYIELD();
		}
		#endif

		/* 如果使能了抢占并使能时间片调度的话执行这个分支 */
		#if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
		{
			/* 查看除了空闲任务以外同等优先级下有没有任务等待执行,有的话将时间片剩余的时间让给同优先级的就绪任务 */
			if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 )
			{
				taskYIELD();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		#endif 

		/* 定义了这个宏的话当进入空闲任务时就会执行下面这个钩子函数 */
		#if ( configUSE_IDLE_HOOK == 1 )
		{
			/* 这个钩子函数由用户自己定义使用,可做一些低功耗处理,但是一般建议使用 tickless 来做低功耗操作 */
			extern void vApplicationIdleHook( void );
			
			vApplicationIdleHook();
		}
		#endif 

		/* 当使能这个宏时就使能低功耗 tickless 模式 */
		#if ( configUSE_TICKLESS_IDLE != 0 )
		{
		TickType_t xExpectedIdleTime;

			/* 获取下一个任务的解锁时间(即进入低功耗模式的时长) */
			xExpectedIdleTime = prvGetExpectedIdleTime();

			/* 下一个任务的解锁时间必须大于用户定义的最小空闲休眠时间阈值,否则不休眠 */
			if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
			{
				/* 挂起任务调度器 */
				vTaskSuspendAll();
				{
					configASSERT( xNextTaskUnblockTime >= xTickCount );
					/* 重新采集一次时间值,这次的时间值可以使用 */
					xExpectedIdleTime = prvGetExpectedIdleTime();

					configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( xExpectedIdleTime );

					/* 下一个任务的解锁时间必须大于用户定义的最小空闲休眠时间阈值,否则不休眠 */
					if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
					{
						traceLOW_POWER_IDLE_BEGIN();
						/* 进入Tickless模式 */
						portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
						traceLOW_POWER_IDLE_END();
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}
				/* 恢复任务调度器 */
				( void ) xTaskResumeAll();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		#endif
	}
}

查看是否有任务需要删除,内存未释放的,使用这个函数 prvCheckTasksWaitingTermination 实现:

static void prvCheckTasksWaitingTermination( void )
{

	#if ( INCLUDE_vTaskDelete == 1 )
	{
		TCB_t *pxTCB;

		/* 有等待删除的任务 */
		while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )
		{
			/* 进入临界区 */
			taskENTER_CRITICAL();
			{
				/* 获取等待删除列表的任务 */
				pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
				/* 将任务从状态列表中删除 */
				( void ) uxListRemove( &( pxTCB->xStateListItem ) );
				/* 当前任务数量减一 */
				--uxCurrentNumberOfTasks;
				/* 等待删除任务减一 */
				--uxDeletedTasksWaitingCleanUp;
			}
			/* 退出临界区 */
			taskEXIT_CRITICAL();

			/* 释放任务控制块内存 */
			prvDeleteTCB( pxTCB );
		}
	}
	#endif 
}

这两个函数都比较简单,其中还可以看到 configUSE_IDLE_HOOK 这个宏的实现,可以做到当进入空闲任务时执行用户定义的回调函数,用户可以自行在里面做降低功耗的处理。接下来分析一下系统自带的 tickless 低功耗模式的处理,什么时候进入低功耗、退出低功耗,有两种方式,一种是延时触发一个指定时间的定时器中断,当延时时间到了后触发中断返回正常状态,还有就是外设中断的触发也会导致系统退出低功耗。在第一种方式下我们需要指定一个定时时间,这个时间可以定义为下一个任务的解锁时间,一旦下一个要运行的任务时间片到了后就退出低功耗去执行对应的任务,如何获取下一个任务的解锁时间,使用的是 prvGetExpectedIdleTime,源码分析如下:

#if ( configUSE_TICKLESS_IDLE != 0 )

	static TickType_t prvGetExpectedIdleTime( void )
	{
	TickType_t xReturn;
	UBaseType_t uxHigherPriorityReadyTasks = pdFALSE;

		/* 寻找下一个运行任务使用通用方法(软件方式,C语言实现,效率低,不限制最大优先级数目) */
		#if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
		{
			if( uxTopReadyPriority > tskIDLE_PRIORITY )
			{
				/* 当前有就绪任务 */
				uxHigherPriorityReadyTasks = pdTRUE;
			}
		}
		/* 寻找下一个运行任务使用特殊方法(硬件方式,硬件实现,效率高,限制最大优先级数目) */
		#else
		{
			const UBaseType_t uxLeastSignificantBit = ( UBaseType_t ) 0x01;

			if( uxTopReadyPriority > uxLeastSignificantBit )
			{
				/* 当前有就绪任务 */
				uxHigherPriorityReadyTasks = pdTRUE;
			}
		}
		#endif

		if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY )
		{
			xReturn = 0;
		}
		else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 )
		{
			xReturn = 0;
		}
		else if( uxHigherPriorityReadyTasks != pdFALSE )
		{
			xReturn = 0;
		}
		else
		{
			/* 下一个任务的解锁时间减去当前时间 */
			xReturn = xNextTaskUnblockTime - xTickCount;
		}

		return xReturn;
	}

#endif

获取到下一个任务的解锁时间后,就可以去重置 systick 定时器中断的重载值,在下一个任务需要执行的时候退出低功耗模式,使用函数 vPortSuppressTicksAndSleep 来实现,源码分析如下:

#if( configUSE_TICKLESS_IDLE == 1 )

	__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
	{
	uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
	TickType_t xModifiableIdleTime;

		/* 确保systick定时器的重载值没有溢出,也就是不能超过滴答定时器最大计数值 */
		if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
		{
			/* xMaximumPossibleSuppressedTicks 会在  vPortSetupTimerInterrupt中被重新赋值 */
			xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
		}

		/* 停止系统滴答定时器 */
		portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;

		/* 根据 xExpectedIdleTime 计算滴答定时器的重载值 */
		ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
		if( ulReloadValue > ulStoppedTimerCompensation )
		{
			/* ulStoppedTimerCompensation 在 vPortSetupTimerInterrupt() 中被重新赋值 */
			ulReloadValue -= ulStoppedTimerCompensation;
		}

		/* 进入临界区(关闭中断) */
		/* __disable_irq 用于设置PRIMASK,在执行WFI前设置寄存器PRIMASK的话处理器可以由中断唤醒但不会处理这些中断,
		   退出低功耗模式后通过清除寄存器PRIMASK来使ISR得到执行 */
		__disable_irq();
		__dsb( portSY_FULL_READ_WRITE );
		__isb( portSY_FULL_READ_WRITE );

		/* 确认是否可以进入低功耗模式,检查是否还有就绪任务来决定能不能进入低功耗模式 */
		if( eTaskConfirmSleepModeStatus() == eAbortSleep )
		{
			/* 不能进入低功耗模式,重启滴答定时器 */
			portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
			portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
			portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;

			/* 使能中断 */
			__enable_irq();
		}
		else
		{
			/* 可以进入低功耗模式,设置滴答定时器的重载值 */
			portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
			portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
			portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;

			xModifiableIdleTime = xExpectedIdleTime;
			/* 在进入低功耗模式之前可能有一些其他的事情要处理,
			   比如降低系统时钟、关闭外设时钟等都在这个宏里面
			   实现(configPRE_SLEEP_PROCESSING),需用户自己定义 */
			configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
			if( xModifiableIdleTime > 0 )
			{
				__dsb( portSY_FULL_READ_WRITE );
				/* 使用wfi指令进入睡眠模式 */
				__wfi();
				__isb( portSY_FULL_READ_WRITE );
			}

			/* 执行到这里说明已经退出低功耗模式,用户自己定义这个宏的实现,执行前面对应的退出操作 */
			configPOST_SLEEP_PROCESSING( xExpectedIdleTime );

			/* 使能中断 */
			__enable_irq();
			__dsb( portSY_FULL_READ_WRITE );
			__isb( portSY_FULL_READ_WRITE );

			/* 失能中断 */
			__disable_irq();
			__dsb( portSY_FULL_READ_WRITE );
			__isb( portSY_FULL_READ_WRITE );
			
			portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );

			/* 判断导致退出低功耗模式是由外部中断引起的还是滴答定时器计时时间到引起的 */
			if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
			{
				uint32_t ulCalculatedLoadValue;

				/* 休眠定时时间到了,复位重载值 */
				ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );

				if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
				{
					ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
				}

				portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;

				ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
			}
			/* 外部中断唤醒的,需要进行时间补偿 */
			else
			{
				/* 获取补偿值 */
				ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
				
				/* 将补偿值转换为节拍值 */
				ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;

				portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
			}

			/* 重启滴答定时器,滴答定时器的重载值设置为正常值 */
			portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
			portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
			/* 补偿系统时钟, ulCompleteTickPeriods 是要补充的值*/
			vTaskStepTick( ulCompleteTickPeriods );
			portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
			
			/* 使能中断 */
			__enable_irq();
		}
	}

#endif

其中对系统时钟进行补偿的函数也比较简单:

void vTaskStepTick( const TickType_t xTicksToJump )
{
	configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );
	xTickCount += xTicksToJump;
	traceINCREASE_TICK_COUNT( xTicksToJump );
}

上面展示出来的代码只是使用 WFI 指令进入了睡眠模式,如果想降低功耗,就必须在进入和退出时做关闭相应时钟的操作,从代码中可以看出进入和退出调用了这个两个接口 configPRE_SLEEP_PROCESSING 和 configPOST_SLEEP_PROCESSING,他们是需要用户自行去实现的宏,定义在 FreeRTOSConfig.h 示例如下:

extern void PreSleepProcessing(uint32_t ulExpectedIdleTime);
extern void PostSleepProcessing(uint32_t ulExpectedIdleTime);


//进入低功耗模式前要做的处理
#define configPRE_SLEEP_PROCESSING	PreSleepProcessing

//退出低功耗模式后要做的处理
#define configPOST_SLEEP_PROCESSING	PostSleepProcessing

之后在相应的应用代码中实现这两个接口即可:

/* 低功耗处理函数 */
void PreSleepProcessing(uint32_t ulExpectedIdleTime)
{	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, DISABLE);
}

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

FreeRTOS-空闲任务、低功耗源码分析 的相关文章

  • Windows11安装Detectron2(附详细操作指南)

    Windows11安装Detectron2 0 简介 Detectron2 是 Facebook AI Research 的下一代目标检测库 xff0c 可提供最先进的检测和分割算法 它是 Detectron 和 maskrcnn benc
  • 四轴飞行器F450+Futaba 14SG+好盈电调油门行程校准

    F450 43 Futaba 14SG油门行程校准 装机前忘了进行油门校准 xff0c 装好后进行校准一开始老出现电机接收不到油门信号的提示音 因为Futaba 14SG也是新入手的控 xff0c 有些模式和操作不熟悉 xff0c 为此花了
  • NTKO控件安装:“不能装载文档控件,请在检查浏览器的选项中检查浏览器的安全设置”问题

    上礼拜手欠把OFFICE文档控件 NTKO给卸载了 xff0c 结果这周通知基金结题网上填写报告 本以为就装个控件 xff0c 没想到各种问题 xff0c 几经尝试终于解决 xff0c 总结如下 xff1a 1 问题 xff1a 不能装载文
  • Arduino - 串口操作函数与示例代码大全

    Arduino 串口操作函数与示例代码大全 本文总结了Arduino常用串口操作函数 xff0c 函数说明部分来源于Arduino 官网串口使用指南 xff0c 示例与实验部分为自编 本文是对Arduino串口操作函数的较全面总结 xff0
  • vs2010 出错:error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏

    LNK1123 转换到 COFF期间失败 文件无效或损坏 的解决方法 一 错误描述 之前写的程序隔段时间使用VS2010再次运行时出现如下错误 xff1a LINK fatal error LNK1123 转换到 COFF 期间失败 文件无
  • OpenCV—基本矩阵操作与示例

    OpenCV的基本矩阵操作与示例 OpenCV中的矩阵操作非常重要 xff0c 本文总结了矩阵的创建 初始化以及基本矩阵操作 xff0c 给出了示例代码 xff0c 主要内容包括 xff1a 创建与初始化 矩阵加减法 矩阵乘法 矩阵转置 矩
  • ubuntu16.04下利用ROS启动LPMS-CURS、CURS2等型号IMU;用imu控制turtlesim--教程

    文章目录 IMU型号及协议第一步 下载安装 LPsensor library第二步 设置ROS和carkin工作空间第三步 下载编译LPMS IMU的ROS驱动第四步 启动IMU xff08 可能也会遇到问题 xff09 遇到的问题1 ub
  • PixHawk飞控和Mission Planner地面站安装调试

    PixHawk飞控和Mission Planner地面站安装调试 PixHawk是著名飞控厂商3DR推出的新一代独立 开源 高效的飞行控制器 xff0c 前身为APM飞控 xff0c 不仅提供了丰富的外设模块和可靠的飞行体验 xff0c 有
  • 飞越650四轴无人机安装全程详解(多图)

    飞越650四轴无人机安装全程详解 xff08 多图 xff09 本文根据自己的安装实际过程 xff0c 总结了开箱后一个比较合理的650四轴无人机安装顺序 xff0c 以及各个步骤的注意事项 xff0c 主要内容包括 xff1a 系统基本配
  • DIY一个基于树莓派和Python的无人机视觉跟踪系统

    DIY 一个基于树莓派和Python的无人机视觉跟踪系统 无人机通过图传将航拍到的图像存储并实时传送回地面站几乎已经是标配 如果想来点高级的 在无人机上直接处理拍摄的图像并实现自动控制要怎么实现呢 xff1f 其实视觉跟踪已经在一些高端的消
  • windows环境下的Anaconda安装与OpenCV机器视觉环境搭建

    windows环境下的Anaconda安装与OpenCV机器视觉环境搭建 本文介绍win7和win10系统下通过Anaconda配置基于python语言的机器视觉编程环境 xff08 博主测试了两个系统下的安装基本相同 xff09 xff0
  • OpenCV—轮廓操作一站式详解:查找/筛选/绘制/形状描述与重心标注(C++版)

    OpenCV 轮廓操作一站式详解 xff1a 查找 筛选 绘制 形状描述与重心标注 C 43 43 版 轮廓 是定义或限定形状或对象的边或线 xff0c 是机器视觉中的常用的概念 xff0c 多用于目标检测 识别 等任务 关于OpenCV轮
  • 正太分布函数和反函数 标量值函数 (借鉴)

    标准正态分布函数 CREATE function dbo normcdf 64 p decimal 28 18 AS begin
  • 离散时间傅里叶变换(一)

    一 非周期信号的表示 xff1a 离散时间博里叶变换 1 1 离散时间傅里叶变换的导出 1 离散时间傅里叶变换对 要清楚推导过程 X ejw 称为离散时间傅里叶变换 xff0c 这一对式子就是离散时间傅里叶变换对 上式称为综合公式 xff0
  • HuskyLens摄像头系列 | 写给小学生看的视觉PID巡线算法

    Hello xff0c 大家好 xff0c 光天化日之下我又来撸狗了 距离上次撸狗已经过去了个把月时间了 xff0c 那么这次又有什么新惊喜呢 xff1f 先来看一下本期的演示视频吧 https www bilibili com video
  • 时空行为检测数据集 JHMDB & UCF101_24 详解

    文章目录 0 前言1 JHMDB1 1 基本情况1 2 数据准备以及标签详解 2 UDF101 242 1 基本情况2 2 数据准备与标签详解 3 数据集可视化代码 0 前言 现在常用的时空行为检测数据集只有AVA JHMDB UCF101
  • Lock与RLock的区别

    目录 往期推荐介绍区别一区别二 往期推荐 Python多线程的使用 Python线程池的使用 Python多线程的安全问题 B站同名 有温度的算法 已经上线 想观看视频讲解的同学 点击此处直达B站 介绍 在上节中为大家说明了线程访问临界资源
  • ROS 小技巧 - OpenCV4 与 CV_Bridge 配合使用

    1 现象 ROS默认的Python版本是3 3 xff0c 但我系统安装的是OpenCV4 5 如果直接在pkg中使用cv bridge和opencv4 5就会有问题 会有一些undefined reference问题 参考资料 xff1a
  • 【做题系统】后端设计

    目录 一 设计思路 1 项目背景 2 技术栈选择 二 系统设计 1 系统结构图 2 项目结构 3 数据建模 4 数据流图 5 主要流程图 三 问题及解决办法 1 实现安全登录 访问 2 数据库中的信息安全问题 3 Mybatis plus如
  • C/C++字符串查找函数

    C C 43 43 string库 xff08 string h xff09 提供了几个字符串查找函数 xff0c 如下 xff1a memchr在指定内存里定位给定字符strchr在指定字符串里定位给定字符strcspn返回在字符串str

随机推荐

  • ssh命令-manpage

    SSH Section User Commands 1 Index Return to Main Contents BSD mandoc NAME ssh OpenSSH SSH 客户端 远程登录程序 总览 SYNOPSIS ssh l l
  • 一小时做出Java实战项目——飞翔的小鸟

    学姐又来啦 xff0c 今日分享一个Java实战项目 飞翔的小鸟 相信大家都玩过这个游戏 xff0c 这个游戏陪伴了我们整整一个童年 xff0c 是我们青春的回忆 飞翔的小鸟 xff0c 游戏中玩家只需通过点击方向键操纵让小鸟避开绿色管道等
  • 搭建本地仓库源

    一 如何搭建仓库源 之前讲了定制ISO的方法 xff1a 使用chroot定制系统 xff0c 但有时候我们想自定义的安装包不在上游的仓库源中 xff0c 在我们本地应该怎么办呢 xff1f 如果我们将deb包拷贝到iso目录再安装有点过于
  • 节点操作案例

    1 下拉菜单 xff08 仿微博 xff09 lt DOCTYPE html gt lt html lang 61 34 en 34 gt lt head gt lt meta charset 61 34 UTF 8 34 gt lt me
  • document获取对象的三种三方法

    Document对象中有几个常用的方法 xff0c 我们在Dom简介中提到过 说到获取JavaScript对象的方法 xff0c 最常用的可能就是getElementById了 xff0c 它是Document中最常用的获取对象的方式之一
  • 程序员,最关键的跨越是什么?做到了月薪可能翻上几番~

    黑马程序员视频库 播妞微信号 xff1a boniu236 传智播客旗下互联网资讯 学习资源免费分享平台 作为一名程序员 xff0c 最关键的跨越是什么 xff1f 从普通程序员进阶为熟练开发者 xff0c 从熟练开发者跃升到技术专家或架构
  • 黑马程序员:3分钟带你读懂C/C++学习路线

    随着互联网及互联网 43 深入蓬勃的发展 xff0c 经过40余年的时间洗礼 xff0c C C 43 43 俨然已成为一门贵族语言 xff0c 出色的性能使之成为高级语言中的性能王者 而在今天 xff0c 它又扮演着什么样重要的角色呢 x
  • 数据归一化

    原文链接 xff1a 从公式出发 xff1a 什么是模型收敛的有效方法 xff1f 大家好 xff0c 我是泰哥 数据归一化在模型收敛中起着至关重要的作用 xff0c 从经典机器学习到深度学习的数据归一化方法是如何一步步演变的呢 xff1f
  • 【Python面试】 说说Python变量、函数、类的命名规则?

    最近公众号新增加了一个栏目 xff0c 就是每天给大家解答一道Python常见的面试题 xff0c 反正每天不贪多 xff0c 一天一题 xff0c 正好合适 xff0c 只希望这个面试栏目 xff0c 给那些正在准备面试的同学 xff0c
  • ​LeetCode刷题实战46:全排列

    算法的重要性 xff0c 我就不多说了吧 xff0c 想去大厂 xff0c 就必须要经过基础知识和业务逻辑面试 43 算法面试 所以 xff0c 为了提高大家的算法能力 xff0c 这个公众号后续每天带大家做一道算法题 xff0c 题目就从
  • Android硬件访问服务-Service

    Android有四大组件 xff1a 一 Activity 二 Service 三 Broadcast Receiver 四 Content Provider Service是Android中一个类 xff0c 它是Android四大组件之
  • android6.0第三方APP获得设备节点的访问权限

    之前使用android4 4的系统进行开发时 system app xff08 系统自带APP xff09 目录下的 app 可以直接访问 dev 目录下的设备节点 xff0c Android 5 0 以后 xff0c 因为采取了 SEAn
  • U-boot取消或修改启动延时bootdelay

    在我们的实际项目中都希望uboot尽量能够快速启动 xff0c 这就涉及到uboot的裁剪工作 xff0c 由于裁剪的工作量和内容比较多 xff0c 这里暂不描述 但是uboot有个启动延时bootdelay xff0c 在我们进入linu
  • uboot启动分析第一阶段(start.S)

    前面分析了启动脚本 Makefile mkconfig xff0c 接下来就是uboot的start S这个启动代码了 xff0c 下面是本章的平台介绍 xff1a 单板 xff1a 迅为4412开发板 Exynos 4412 SDRAM
  • Android使用串口(基于android-serialport-api)

    运行平台 xff1a CPU xff1a 全志V40 Android版本 xff1a 6 0 1 关于安卓设备上使用串口 xff0c 谷歌官方在github上有提供代码实例 xff0c 里面有JNI的代码和串口API的java文件 xff0
  • FreeRTOS-启动任务调度器源码分析

    本章基于FreeRTOS的启动任务调度器源码分析 xff0c 后续将会上传其它我对FreeRTOS的源码分析过程及理解 xff0c 首先来认识一下任务调度器 任务调度器 xff1a 任务调度器主要用于实现任务的切换 xff0c 任务并不是我
  • FreeRTOS-任务创建源码分析

    任务创建是FreeRTOS系统启动的第一个步骤 xff0c 前面在启动调度器的时候先创建了空闲任务 xff0c 然后再由调度器跳到任务里面去执行 任务创建函数里面做了很多的工作 xff0c 先会为任务堆栈和任务控制块分配内存并初始化它们 x
  • FreeRTOS-任务通知源码分析

    任务通知可用来代替信号量 消息队列 事件标志位 xff0c 而且使用任务通知的形式效率会更高 xff0c 它不需要像信号量那样创建队列和操作队列 xff0c 任务通知的存储变量来自任务控制块中 xff0c 当宏 configUSE TASK
  • Anaconda出现Collecting package metadata (current_repodata.json): failed错误

    安装包时出现这个错误 xff0c 个人怀疑是梯子使用出错 网上很多教程是换源等均没有解决问题 最后解决方法 xff1a 1 卸载clash for Windows xff08 不确定这一步是不是必须的 xff09 2 直接删除C Users
  • FreeRTOS-空闲任务、低功耗源码分析

    FreeRTOS在启动任务调度时会自动创建一个空闲任务 xff0c 空闲任务主要在系统没有其它任务或任务都处于挂起状态时执行 xff0c 它被系统设置为最低优先级 xff0c 不会去抢占其它高优先级的任务 xff0c 从而既能保证系统总有至