FreeRTOS学习笔记

2023-05-16


										FreeRTOS学习历程

总结:
	关键词:动态创建 静态创建 任务级 中断级
	一个任务至少有一个	do
   					 {	
						vtaskDelay(10);
   					 }while(1);	//不然程序容易卡死在一个任务中出不来,让CPU有运行空闲任务的机会。
0.0FreeRTOSv9.0移植

0.1任务相关API函数(*打开相应的宏)
	*uxTaskPriorityGet("任务句柄");		//获取任务优先级
	*vTaskPrioritySet("任务句柄","任务优先级");	//改变某一个任务的优先级
	*uxTaskGetSystemState("任务状态","任务状态数组大小","系统中的运行时间");//获取任务中所有任务的状态
	*uxTaskGetNumberOfTasks();//获取任务个数
	*xTaskGetCurrentTaskHandle();//获取当前任务句柄
	*xTaskGetHandle("任务名字");//根据任务名字获取任务句柄
	*uxTaskGetStackHighWaterMark("任务句柄");//任务堆栈历史剩余最小值
	eTaskGetState("任务句柄");//任务的运行状态(0运行 1就绪 ....)
	xTaskGetTickCount();//获取滴答定时器时钟节拍值
	相对重要API函数:
	vTaskList("定义缓冲区"); //获取所有运行任务的名字 状态(B阻塞 R就绪 S挂起 D删除) 任务优先级 任务堆栈剩余大小 任务运行编号
	
	vTaskGetRunTimeStats:
		打开相应的宏:
		configGENERATE_RUN_TIME_STATS			1
		configUSE_STATS_FORMATTING_FUNCTIONS	1
		之后需要自实现两个宏定义:
		#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()  	ConfigureTimeForRunTimeStats()//定时器3提供时间统计的时基
		
		#define portGET_RUN_TIME_COUNTER_VALUE()			FreeRTOSRunTimeTicks	//获取时间统计时间值 
		vTaskGetRunTimeStats("定义缓冲区");//获取所有运行任务的名字 运行时间 占运行总时间的百分比
1.任务的动态创建:
	遇到错误:(	char i=0;//必须要赋值初始值不然为随机数 )
	动态创建任务API:
	//任务创建配置参数
	#define START_TASK_PRIO 	1 //优先级
	#define START_STK_SIZE		120  //任务堆栈大小
	void start_tast( void * pvParameters );	//任务函数
	TaskHandle_t StartTask_Handler;//任务句柄

	xTaskCreate((TaskFunction_t ) start_tast,  		//任务
				 (char *					) "start_tast", 	//名字
				 (uint16_t				) START_STK_SIZE, //任务堆栈
				 (void *					) NULL,   				//参数
				 (UBaseType_t			) START_TASK_PRIO,//任务优先级
				 (TaskHandle_t *	) &StartTask_Handler);//	任务句柄
	
	vTaskStartScheduler();          //开启任务调度
	vTaskDelete(StartTask_Handler);			//删除自身也可以食用NULL或者是任务句柄
2.任务的静态创建:
	遇到错误:()
	重要宏和函数:
	configSUPPORT_STATIC_ALLOCATION	1//静态内存
	//为空闲任务和定时器任务的任务堆栈和任务控制块分配内存
	//空闲任务
	static StaticTask_t IdleTaskTCB;//任务控制块
	static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];//任务堆栈  堆栈大小
	//定时任务
	static StaticTask_t TimerTaskTCB;//任务控制块
	static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH];//任务堆栈  
	
	//空闲任务所需内存
	void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, 
									   StackType_t **ppxIdleTaskStackBuffer, 
									   uint32_t *pulIdleTaskStackSize)
	//定时器任务所需内存
	void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, 
										StackType_t **ppxTimerTaskStackBuffer, 
										uint32_t *pulTimerTaskStackSize)
	
	//静态创建API	
	//任务创建配置参数
	#define START_STK_SIZE 			128
	#define START_TASK_PRIO 		1
	StackType_t StartTaskStack[START_STK_SIZE];
	StaticTask_t StartTaskTCB;
	TaskHandle_t StartTask_Handler;
	void start_task( void * pvParameters );
	
		StartTask_Handler=xTaskCreateStatic((	TaskFunction_t) start_task,
	(char *					) "start_task",	
	(uint32_t				) START_STK_SIZE,
	(void *					) NULL,
	(UBaseType_t		) START_TASK_PRIO,
	(StackType_t *	) StartTaskStack,
	(StaticTask_t *	) &StartTaskTCB );
	
	vTaskStartScheduler();          				//开启任务调度
	vTaskDelete(StartTask_Handler);			//删除自身也可以食用NULL或者是任务句柄
3.任务的挂起和恢复:
	遇到错误:()
	临界区:(临界区代码一定要精简,临界区会关闭中断,导致优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断得不到及时响应)
	任务级临界代码保护:
	taskENTER_CRITICAL();	//进入临界区
	taskEXIT_CRITICAL();            //退出临界区
	任务:
	vTaskSuspend("任务句柄");			//挂起任务
	vTaskResume("任务句柄");			//恢复任务
4.开关中断:
	遇到错误:(任务中如果使用到延时函数要使用delay_xms();因为其他延时中带有中断,关闭中断之后可能一调用延时立马就把中断给打开。所以看不到效果 )
	需要设置FreeRTOS的PendSV  SysTick中断优先级
	临界区:(临界区代码一定要精简,临界区会关闭中断,导致优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断得不到及时响应)
	中断级临界代码保护:
	x = taskENTER_CRITICAL_FROM_ISR()//进入
	taskEXIT_CRITICAL_FROM_ISR( x )//退出
	中断:
	portDISABLE_INTERRUPTS();			//关闭中断
	portENABLE_INTERRUPTS();			//打开中断
5.列表和列表项:
	遇到错误:(在末尾添加列表项,遍历没搞完全清楚)
	重要宏和函数:
	configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1开启列表完整性检查
	//创建结构体列表和列表项
	List_t ListText; 
	ListItem_t ListItem1;	
	//重要函数
	vListInitialise(&ListText);//创建列表ListText
	vListInitialiseItem(&ListItem1);//创建列表项ListItem1
	vListInsert(&ListText,&ListItem1);//插入列表项ListItem1
	uxListRemove(&ListItem1);//删除列表ListItem1
6.时间管理:
	相对延时:
			vTaskDelay("ms");	//延时ms级
	
	绝对延时(相对于相对延时来说):
	定义变量:
			const TickType_t TimeIncrement = pdMS_TO_TICKS(1000);	//把时间转化为时钟节拍
	
	
	
	
	
			PreviousWakeTime = xTaskGetTickCount();	//获取当前的时钟节拍
	实现:
			vTaskDelayUntil(&PreviousWakeTime,TimeIncrement);
7.消息队列:(全局变量尽量不要随意使用)
	全局变量的弊端:(可以使用记录当前状态,最忌讳用来传递参数)
	0.增加程序之间的耦合性,应用层也要关注驱动层的事情,导致分层不合理与模块化编程相违背
	2.阅读比较吃力,可维护性极差,需要找到全局的出处和所有使用的过程,除了原创作者其他人很难维护
	3.全局变量任何地方都被修改,使系统变得不可预测,软件安全性得不到保证,导致产品最终走向死亡
	4.后期维护非常困难,对于全局满天飞的系统
	5.程序初始化就诞生,程序结束才消亡,始终占用数据段上的空间一定程度上造成内存浪费
	6.不让维护人员戳你的脊梁骨养成一个良好的编程习惯
	全局变量应对之道:
	0.全局变量超过3个使用结构体包起来
	1.static到需要使用的文件中
	2.(返回值)return出去这样属性就是只读,使用起来就不用担心使用时修改值
	3.(传参)非要修改值的话可以使用函数传参方式
	4.非要非要extern的话要严格控制在自己.h中,不要放到公共的.h中丢人现眼

	遇到错误:
	创建:
	//动态创建
	QueueHandle_t Key_Queue;
	
	#define Key_Q_Temp		1
	Key_Queue = xQueueCreate(Key_Q_Temp,sizeof(u8)); 	//队列的长度  队列中每个消息长度 return:队列句柄
	
	//静态创建
	QueueHandle_t Key_Queue;
	
	#define Key_Q_Temp	1
	u8 buff[Key_Queue+1];
	StaticQueue_t QueueBuff;
	Key_Queue = xQueueCreateStatic(Key_Q_Temp,sizeof(u8),buff,QueueBuff); //项目数 字节 缓存区 保存队列 return:队列句柄
	
	任务级:
	//发送	
	err = xQueueSend(Key_Queue,&key,10);//同	xQueueSendToBack 完全一样
	err = xQueueSendToBack(Key_Queue,&key,10);	//发送消息到队头	//队列 值 时钟节拍	return:判断值
	err = xQueueSendToFront(Key_Queue,&key,10);	//发送消息到队尾
	err = xQueueOverwrite(Key_Queue,&key);		//带覆盖功能,队列满之后自动覆盖旧消息
	
	//接收
	err = xQueueReceive(Key_Queue,&key,portMAX_DELAY);	//读取之后删除队列项  //队列 值 接收等待时间 	return:判断值
	err = xQueuePeek(Key_Queue,&key,portMAX_DELAY);	//读取之后不删除 	//队列 值 接收等待时间 	return:判断值
	
	中断级:
	//发送:
	err = xQueueSendFromISR(Message_Queue,USART_RX_BUF,&HigherPriorityTaskWoken);/	/同下完全一样
	err = xQueueSendToBackFromISR(Message_Queue,USART_RX_BUF,&HigherPriorityTaskWoken);//发送消息到队尾
	err = xQueueSendToFrontFromISR(Message_Queue,USART_RX_BUF,&HigherPriorityTaskWoken);//发送消息到队头
	err = xQueueOverwriteFromISR(Message_Queue,USART_RX_BUF,&HigherPriorityTaskWoken);//队列满自动覆盖旧值
	//接收:
	err = xQueueReceiveFromISR(Message_Queue,Message_Buff,&TaskWoken);	//读取之后删除队列项
	err = xQueuePeekFromISR(Message_Queue,Message_Buff);			//读取之后不删除
	
	
	锁:
	上锁:
			prvLockQueue();
	
	解锁:
	prvUnlockQueue();

8.信号量:(#include "semphr.h")
	遇到错误:被按键队列的接收死等给卡死了
	优先级翻转:低优先级任务占据信号量时间较长,高优先级任务无法使用此信号量导致高优先级任务阻塞,
	使不使用此信号量的比中等优先级任务比高优先级任务早得到CPU的处理
	二值信号量创建:(没有优先级继承,适用于同步。优先级翻转问题)
	动态创建:
	SemaphoreHandle_t BinarySemaphore;
	BinarySemaphore = xSemaphoreCreateBinary();	//创建成功之后立马先释放(xSemaphoreGive)一次,不然不会运行,
	
	静态创建:
	StaticSemaphore_t SemaphoreBuff;
	BinarySemaphore = xSemaphoreCreateBinaryStatic(SemaphoreBuff);
	
	计数型信号量创建:
	动态创建:
	SemaphoreHandle_t CountingSemaphore;//计数信号量
	CountingSemaphore = xSemaphoreCreateCounting("MAX","InitValue");//最大值 初始值
	
	CountingValue = uxSemaphoreGetCount(CountingSemaphore); //获取信号量当前剩余值
	静态创建:
	SemaphoreHandle_t CountingSemaphore;
	StaticSemaphore_t SemaphoreBuffer;
	CountingSemaphore = xSemaphoreCreateCountingStatic( "MAX","InitValue",&SemaphoreBuffer );
	
	
	互斥信号量创建:(有优先级继承,适用于简单的互斥访问。只能用于任务,不能用于中断。优化优先级翻转问题)
	动态创建:
	SemaphoreHandle_t MutexSemaphore;//计数信号量
	MutexSemaphore = xSemaphoreCreateMutex();
	
	静态创建:
	SemaphoreHandle_t MutexSemaphore;//计数信号量
	StaticSemaphore_t MutexBuffer;
	MutexSemaphore = xSemaphoreCreateMutexStatic(&MutexBuffer);
	
	递归互斥信号量创建:(与之前三种信号量的释放和获取不同。只能用于任务,不能用于中断。)
	#define configUSE_RECURSIVE_MUTEXES		1;
	动态创建:
	SemaphoreHandle_t RecursiveMutexSemaphore;
	RecursiveMutexSemaphore = xSemaphoreCreateRecursiveMutex();
	
	静态创建:
	SemaphoreHandle_t RecursiveMutexSemaphore;
	StaticSemaphore_t RecursiveMutexBuffer;
	RecursiveMutexSemaphore = xSemaphoreCreateRecursiveMutexStatic(&RecursiveMutexBuffer);
	
	任务级私用信号量释放和获取:(only)
	BaseType_t err;
	信号量释放:
	err = xSemaphoreGiveRecursive(RecursiveMutexSemaphore);
	信号量获取:
	err = xSemaphoreTakeRecursive(RecursiveMutexSemaphore,"portTICK_PERIOD_MS");
	
	信号量释放和获取:
	任务级:
	信号量释放:
	xSemaphoreGive(BinarySemaphore);
	信号量获取:
	xSemaphoreTake(BinarySemaphore,portMAX_DELAY);	//获取信号量句柄	阻塞时间
	中断级:
		BaseType_t HigherPriorityTaskWoken;
	
		BaseType_t err;
	信号量释放:
	err = xSemaphoreGiveFromISR(BinarySemaphore,&HigherPriorityTaskWoken);//信号量句柄 标记是否进行任务切换	retuen:Y/N	
								(当HigherPriorityTaskWoken为psTRUE退出中断服务函数之前一定要进行一次任务切换)
	portYIELD_FROM_ISR(HigherPriorityTaskWoken);		//任务切换
	信号量获取:
	err = xSemaphoreTakeFromISR(BinarySemaphore,&HigherPriorityTaskWoken);
	
	在保存变量(HigherPriorityTaskWoken)为pdTRUE时退出中断服务函数之前一定要进行一次任务切换

9.软件定时器:(#include "timers.h")
	遇到错误:
	创建:
	TimerHandle_t TimerHandle;
	void CallbackFunction( TimerHandle_t xTimer );//回调函数
	StaticTimer_t TimerBuffer;
	
	动态创建:
	
	单次/周期定时器:
	TimerHandle = xTimerCreate((const char *			) "CallbackFunction",
								(TickType_t				) 1000,
								(UBaseType_t				) pdFALSE,//pdFALSE单次	pdTRUE周期
								(void *					) 1,
								(TimerCallbackFunction_t	) CallbackFunction );
	静态创建:
	单次/周期定时器:
		PeriodTimer = xTimerCreateStatic(const char *			) "CallbackFunction",
									(TickType_t			) 1000,
									(UBaseType_t			) pdFALSE,//pdFALSE单次	pdTRUE周期
									(void *				) 2,
									(TimerCallbackFunction_t) CallbackFunction,
									(StaticTimer_t	*		) TimerBuffer );	//保护成员变量
	复位软件定时器:.
	BaseType_t err;
	BaseType_t HigherPriorityTaskWoken;
	任务级:
	err = xTimerReset(TimerHandle,0);//句柄 阻塞时间
	中断级:
	err = xTimerResetFromISR(TimerHandle,&HigherPriorityTaskWoken);//句柄  时钟节拍
	开启软件定时器:
	BaseType_t err;
	BaseType_t HigherPriorityTaskWoken;
	任务级:
	err = xTimerStart(TimerHandle,0);//句柄 阻塞时间
	中断级:
	err = xTimerStartFromISR(TimerHandle,&HigherPriorityTask);//句柄  时钟节拍
	关闭软件定时器:
	任务级:
	err = xTimerStop(TimerHandle,0);//句柄 阻塞时间
	中断级:
	err = xTimerStopFromISR(TimerHandle,&HigherPriorityTask);//句柄  时钟节拍

10.事件标志组:(#include "event_groups.h")
	遇到错误:
	悉知:事件标志组的高八位不能用,1616-8)位只能表示8个事件,32位能表示2432-8)个事件
	创建:
	EventGroupHandle_t EventGroupHandle;//创建函数返回的句柄
	EventGroupHandle_t EventGroupBuffer; //静态创建保存数据的数组
	动态创建:
	EventGroupHandle = xEventGroupCreate();
	静态创建:
	EventGroupHandle = xEventGroupCreateStatic(&EventGroupBuffer); //保存数据所需数组
	设置事件位:
	#define BIT_0		(1 << 0)
	#define BIT_1		(1 << 1)
	
	
	
	#define BIT_ALL 	(BIT_0|BIT_1)0:
	任务级:
	EventBits_t EventGroupValue;
	EventGroupValue = xEventGroupClearBits(EventGroupHandle,BIT_0);
	中断级:
	BaseType_t EventGroupValue;
	EventGroupValue = xEventGroupClearBitsFromISR(EventGroupHandle,BIT_0);1:
	任务级:
	EventBits_t EventGroupValue;
	EventGroupValue = xEventGroupSetBits(EventGroupHandle,BIT_0);
	中断级:
	BaseType_t EventGroupValue;
	BaseType_t HigherPriorityTaskWoken;
	EventGroupValue = xEventGroupSetBitsFromISR(EventGroupHandle,BIT_0,&HigherPriorityTaskWoken);
	
	在保存变量(HigherPriorityTaskWoken)为pdTRUE时退出中断服务函数之前一定要进行一次任务切换
	
	获取事件标志组值:
	EventBits_t err;
	任务级:
	err = xEventGroupGetBits(EventGroupHandle);
	中断级:
	err = xEventGroupGetBitsFromISR(EventGroupHandle);
	等待指定的事件位:
	EventBits_t EventValue;
	EventValue = xEventGroupWaitBits((EventGroupHandle_t	) EventGroupHandle,
									(EventBits_t			) BIT_ALL,//操作的标志位
									(BaseType_t			) pdFALSE,//pdTRUE标志位被清除	pdFALSE不会被清除
									(BaseType_t			) pdFALSE, //pdTRUE 满足所有位 pdFALSE 满足其中一位
									(TickType_t			) portMAX_DELAY)//阻塞时间	

11.任务通知:(#include "tasks.h")
	遇到错误:
	悉知:需要打开宏才能使用 #define configUSE_TASK_NOTIFICATIONS		1 
	
	//枚举
	typedef enum
	{
		eNoAction = 0,				/* 通知任务而不更新其通知值. */
		eSetBits,						/* 更新指定bit. */
		eIncrement,					/* 通知值加1. */
		eSetValueWithOverwrite,		/*  覆写的方式更新通知值. */
		eSetValueWithoutOverwrite		/* 不覆写通知值. */
	} eNotifyAction;
	
	发送任务通知:
	任务级:
			xTaskNotifyGive(Task2Task_Handler);	//任务句柄				
			err = xTaskNotify(Task2Task_Handler,Value,"枚举");//任务句柄 任务通知值 任务通知更新的办法
			err = xTaskNotifyAndQuery(Task2Task_Handler,Value,"枚举",&PreviousNotifyValue);
	//任务句柄 任务通知值 任务通知更新办法 保存更新前的任务通知值
	中断级:
			vTaskNotifyGiveFromISR(Task2Task_Handler,&HigherPriorityTaskWoken);//任务句柄 保存变量
			err = xTaskNotifyFromISR(Task2Task_Handler,value,"枚举",&HigherPriorityTaskWoken);	
	//任务句柄  任务通知值  任务通知更新的办法 保存变量
	
			err = xTaskNotifyAndQueryFromISR(Task2Task_Handler,value,"枚举",&PreviousNotifyValue,&HigherPriorityTaskWoken);
	//任务句柄 任务通知值 任务通知更新办法 保存更新前的任务通知值 保存变量
	
	在保存变量(HigherPriorityTaskWoken)为pdTRUE时退出中断服务函数之前一定要进行一次任务切换
	
	获取任务通知:
	vlaue = ulTaskNotifyTake(pdTRUE,portMAX_DELAY);//推荐模拟二值信号量 计数型信号量使用
	//pdFALSE 任务通知值加1(类似于计数型信号量) pdTRUE任务通知值清0(类似于二值信号量)return:任务通知值减少清零的值
	
	err = xTaskNotifyWait(0,0xffffffff,&NotificationValue,portMAX_DELAY);//可以获取任何模拟的任务通知 消息邮箱 事件标志组等
	//不理解,不理解,保存任务通知值 ,阻塞时间  return:pdTRUE获取任务通知成功 pdFALSE获取失败

12.低功耗Tickless:
	打开宏:#define configUSE_TICKLESS_IDLE		1                     //1启用低功耗tickless模式
	
	自定义两个函数对接官方给的宏:
	//低功耗模式Tickless
	#define configPRE_SLEEP_PROCESSING	PreSleepProcessing
	#define configPOST_SLEEP_PROCESSING	PostSleepProcessing
	函数继承声明:
	extern void PreSleepProcessing(uint32_t ulExpectedIdleTime);
	extern void PostSleepProcessing(uint32_t ulExpectedIdleTime);
	主函数进行函数实现:
	//进入低功耗模式前需要处理的事情
	//ulExpectedIdleTime:低功耗模式运行时间
	void PreSleepProcessing(uint32_t ulExpectedIdleTime)
	{
		//关闭某些低功耗模式下不使用的外设时钟,
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, DISABLE);
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, DISABLE);	
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, DISABLE);	
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, DISABLE);	
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, DISABLE);	
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, DISABLE);	
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH, DISABLE);	  
	}
	
	//退出低功耗模式以后需要处理的事情
	//ulExpectedIdleTime:低功耗模式运行时间
	void PostSleepProcessing(uint32_t ulExpectedIdleTime)
	{
		//退出低功耗模式以后打开那些被关闭的外设时钟
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);	
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);	
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);	
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);	
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);	
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH, ENABLE);	              
	}

13.空闲任务钩子函数:
	打开宏#define configUSE_IDLE_HOOK		1                     //1,使用空闲钩子;0,不使用
	实现钩子函数	void vApplicationIdleHook(void)
	void vApplicationIdleHook(void)
	{
		__disable_irq();
		__dsb( portSY_FULL_READ_WRITE );
		__isb( portSY_FULL_READ_WRITE );	
		
		BeforeEnterSleep(void);		//进入睡眠之前关闭不使用的外设时钟,函数自己实现(模拟低功耗函数实现)
		__wfi();					//进入睡眠模式
		AfterExitSleep(void);		//退出低功耗模式之后打开关闭的外设时钟,函数自己实现(如上)
		
		__dsb( portSY_FULL_READ_WRITE );	
		__isb( portSY_FULL_READ_WRITE );
		__enable_irq();
	}
	
	14.内存管理:
	u8 *buffer;
	size_t freemem;
	内存申请:
	buffer=pvPortMalloc(30);
	
	内存释放:
	vPortFree(buffer);
	buffer=NULL;//释放完内存之后必须要要对内存进行清空,不然会造成假清空
	
	获取剩余内存大小:
	freemem = xPortGetFreeHeapSize();
	
	

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

FreeRTOS学习笔记 的相关文章

随机推荐

  • 无人机光流模块使用技巧

    无人机光流模块使用技巧 光流模块在无 GPS 环境下 xff0c 课实时检测飞机水平移动距离 xff0c 实现对四轴无人机长时间的稳定悬停 图1显示的是湖南优象LC 302光流模块的功能框图 xff0c 光流摄像头拍摄无人机垂直向下的画面
  • CMMI 2.0 和 1.3

    CMMI2 0与1 3在组织形式区别很大 xff0c 很多PA和之前的不太一样了 xff0c 而且PA在2 0中叫实践域 xff0c 1 3中叫过程域 不过其实核心内容没有大的变化 xff0c 只是相关内容的位置进行了调整 xff0c 部分
  • ROS2的RVIZ2无法启动

    在新安装的 xff32 xff2f xff33 2中启动rviz2 xff0c 启动错误 xff0c 显示 Failed to create an OpenGL context BadValue integer parameter out
  • 【TCP 重传、滑动窗口、流量控制、拥塞控制】

    文章目录 重传机制超时重传快速重传SACK方法Duplicate SACK 滑动窗口流量控制那操作系统的缓冲区 xff0c 是如何影响发送窗口和接收窗口的呢 xff1f 窗口关闭 拥塞控制慢启动拥塞避免拥塞发生快速恢复 重传机制 TCP 实
  • 【TCP四次挥手】

    文章目录 TCP 四次挥手过程是怎样的 xff1f 为什么挥手需要四次 xff1f 第一次挥手丢失了 xff0c 会发生什么 xff1f 第二次挥手丢失了 xff0c 会发生什么 xff1f 第三次挥手丢失了 xff0c 会发生什么 xff
  • FreeRTOS事件组----任务同步

    有时 xff0c 应用程序的设计需要两个或多个任务才能彼此同步 例如 xff0c 考虑一个设计 xff0c 其中任务A接收一个事件 xff0c 然后将事件所需的一些处理提供给其他三个任务 xff1a 任务B xff0c 任务C和任务D 如果
  • Qt中给按钮设置颜色的方法

    Qt中给按钮设置颜色的方法 第一种 CSS风格第二种 使用QPalette类第三种 使用QColor的另一种方法 对于界面编程来说 xff0c 色彩无疑是一个重点关注的对象 xff0c 界面好不好看 xff0c 色彩占据一大半 这里我在学习
  • codeblocks下载安装教程(完整详细)

    最近又将codeblocks下载了一下 xff0c 将完整的过程记录一下 一 下载教程 进入codeblocks官网 xff0c http www codeblocks org 点击downloads 一般都会选择第一个Download t
  • 使用VSCode需要安装的一些插件

    下载安装VSCode 下载安装 xff1a https code visualstudio com Download 通用插件 Auto Close Tag xff1a 匹配标签 xff0c 关闭对应的标签 Auto Rename Tag
  • QNAP之Container Station(docker)配置Redis

    本文目的 xff1a 使QNAP通过内置的docker安装redis 安装篇 首先ContainerStation中直接搜redis xff0c 有一个qnap官方提供的3 07版本的redis xff08 3年前 xff09 命令处请务必
  • QNAP之基于Container Station(docker)创建Ubuntu可视化桌面vnc

    型号 xff1a TS 231P 配置 xff1a ARM Cortex A15 CPU 64 1 70GHz 1G内存 目的 xff1a 为nas配置一个基于docker的vnc桌面 步骤概要 xff1a 1 创建一个ubuntu 2 安
  • Docker之基于docker-compose创建vsftpd容器

    前言 因为本人很菜 xff0c 每次配置vsftpd都头疼的要死 又因为网上vsftpd的教程会版本不一导致配置总是会出错 因此尝试使用docker来解决这个问题 而单纯只是用docker每次启动需要输入长串命令 xff0c 因此再结合do
  • 驻点运维人员被客户投诉要求换人,换还是不换?

    项目背景 xff1a 一位朋友提到了这样的情况 xff1a 项目背景是 xff1a 我的项目已经进入到运维阶段 xff0c 公司安排了一个运维人员现场驻点 到现在为止 xff0c 我这边已经多次接到客户的投诉 xff0c 说运维人员做事没有
  • 前端通过Ajax,向后端发送form表单的JSON数据,并后端接收JSON,使用fastJSON解析的一个完整案例

    前端代码 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 meta name 61 34 view
  • Linux下饥荒远程服务器配置教程(包含mod的配置)(19/08/22/更新游戏更新后搜索不到服务器的对策)

    目录 xff1a 前言安装环境库安装steamcmd创建默认文件夹关于mod后记 xff1a 关于游戏更新 keyword 关键词 xff1a 饥荒 服务器 配置 linux ubuntu 参考链接 xff1a https blog csd
  • QNAP之基于ContainerStation(docker)下Aria2的配置方法

    型号 xff1a TS 231P 配置 xff1a ARM Cortex A15 CPU 64 1 70GHz 1G内存 目的 xff1a 为nas配置一个基于docker的aria2服务器 qnap从某个版本开始支持ContainerSt
  • BGP协议

    BGP协议 工作层工作原理BGP简单配置 含密码认证配置个人图解BGP 工作层 BGP是工作在应用层的协议 xff0c 但基于传输层的TCP协议 工作原理 路由协议通常分为内部网关协议 xff08 IGP Interior Gateway
  • Docker配置Ubuntu容器、ssh远程连接该容器

    span class token comment 详细请参考 https juejin cn post 6982419819211522079 span span class token comment 1 拉取 ubuntu 镜像 spa
  • Eth-Trunk链路聚合原理、静态和动态配置

    Eth Trunk原理 静态和动态配置 Eth Trunk链路聚合概述Eth Trunk链路聚合模式静态配置模式LACP动态模式 Eth Trunk链路聚合概述 在组网中经常遇到的问题 xff0c 单条链路的宽带无法满足整个园区的流量需求时
  • FreeRTOS学习笔记

    FreeRTOS学习历程 总结 xff1a 关键词 xff1a 动态创建 静态创建 任务级 中断级 一个任务至少有一个 span class token keyword do span span class token punctuatio