FreeRTOS创建任务

2023-05-16

CPU有这些寄存器。R0-R12为通用寄存器。R13为栈顶指针,在OS时候中断函数的R13使用MSP的指针(内核态)。非中断里面使用PSP指针(用户态)。
在这里插入图片描述

正是有双堆栈指针可以保证OS切换任务不会盖用户程序的堆栈状态。对于OS和任务都是C语言编译的逻辑。OS可不知道任务在要切换时候运行的指令,对于OS来说也不需要关心任务执行的指令。只要确保以下就可以保证任务切换出去后再切换回来时候保持不变。

1.剥夺任务CPU后运行其他指令不会覆盖任务用的内存空间。TCB、栈空间等。
2.任务切换回来的时候能把任务切换前的CPU寄存器状态恢复。包括R13的PSP指针。

保证以上两条就可以进行CPU调度,让CPU在多个任务之间来回切换。
要保证内存不被其他程序乱覆盖,首先通过公共方法申请和释放内存地址。申请的本质就是内存管理方法把没人用的内存地址给程序返回使用。内存管理方法通过空闲内存链表管理空闲内存。基于申请内存程序不做越界访问就不会破坏别人的数据。
要保证任务后面重新运行时候能接着之前停止时候运行。那么就要确保CPU的寄存器和之前状态一样。那么就必须把切换之前的寄存器值保存起来供恢复时候使用。既然任务要让出CPU,那么把寄存器值依次压入任务自己的栈就行了。停止的任务栈里保存自己停止时候的CPU状态,恢复时候出栈恢复CPU寄存器值。出栈完成后任务的栈正好也是停止任务时候的栈内存状态。

任务内存布局类似下图(OS内存管理占用一大片内存给不同任务分配,启动汇编文件时候申请一片给裸机用。MSP栈执行在该片区域):
在这里插入图片描述

由于ARM栈是向下生长的。即PUSH后栈顶像低地址移动,POP时候像高地址移动。因为OS要管理任务,栈向下生长可能会堆栈溢出。所以先申请栈内存,再申请TCB结构体内存。为的就是让堆栈溢出时候盖的也是别的任务的空间。还能通过当前任务TCB检测是否堆栈溢出。先后并没有严格要求。
在这里插入图片描述
对应具体一个任务,运行时候不断基于PSP指针入栈出栈,基于栈执行指令。让出CPU时候中断逻辑基于MSP栈控制执行逻辑。这时候PSP没变。在中断里面把寄存器和PSP压入任务自己栈。
在这里插入图片描述

向下生长的栈入栈出栈示意图。
在这里插入图片描述

FreeRTOS通过调用下面方法创建任务。

//pxTaskCode:任务函数 void 函数名(void *pvParameters)
//pcName:任务名称,小于configMAX_TASK_NAME_LEN,建议小于16
//usStackDepth:堆栈大小(整数)
//pvParameters:给任务传递的参数
//uxPriority:任务优先级(整数)
//pxCreatedTask:任务的句柄,后期用他操作任务
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)
{
	//TCB对象
	TCB_t* pxNewTCB;
	//返回值
	BaseType_t xReturn;

	StackType_t* pxStack;
	//调用heap申请内存,申请栈的空间
	pxStack = pvPortMalloc((((size_t)usStackDepth) * sizeof(StackType_t)));
	//栈申请成功就申请TCB
	if (pxStack != NULL)
	{
		//调用heap申请内存,申请TCB空间
		pxNewTCB = (TCB_t*)pvPortMalloc(sizeof(TCB_t));
		if (pxNewTCB != NULL)
		{
			//TCB指向栈底
			pxNewTCB->pxStack = pxStack;
		}
		else
		{
			 //TCB申请失败就是否栈空间
			vPortFree(pxStack);
		}
	}
	else
	{
		pxNewTCB = NULL;
	}
	//申请TCB和栈成功后的操作
	if (pxNewTCB != NULL)
	{
		//初始化新创建的任务
		prvInitialiseNewTask(pxTaskCode, pcName, (uint32_t)usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB);
		//把任务加入就绪列表
		prvAddNewTaskToReadyList(pxNewTCB);
		//返回创建成功1
		xReturn = pdPASS;
	}
	else
	{
		//返回申请空间失败-1
		xReturn = -1;
	}
	return xReturn;
}

该方法先给任务申请栈内存

//调用heap申请内存,申请栈的空间
pxStack = pvPortMalloc((((size_t)usStackDepth) * sizeof(StackType_t)));

申请栈空间成功后再申请TCB内存,让TCB的栈底指针指向栈内存开始地址。

//调用heap申请内存,申请TCB空间
pxNewTCB = (TCB_t*)pvPortMalloc(sizeof(TCB_t));
if (pxNewTCB != NULL)
{
	//TCB指向栈底
	pxNewTCB->pxStack = pxStack;
}

内存申请成功后就初始化新创建的任务

//执行新任务的初始化
static void prvInitialiseNewTask(TaskFunction_t pxTaskCode,
	const char* const pcName, 
	const uint32_t ulStackDepth,
	void* const pvParameters,
	UBaseType_t uxPriority,
	TaskHandle_t* const pxCreatedTask,
	TCB_t* pxNewTCB)
{
	//栈顶
	StackType_t* pxTopOfStack;
	UBaseType_t x;

	//栈向下生长,算的栈结束地址
  //得到栈顶地址。空栈时候指向栈的开始位置。ARM栈向下生长,所以栈开始时候栈顶是高内存位置
	pxTopOfStack = &(pxNewTCB->pxStack[ulStackDepth - (uint32_t)1]);
	pxTopOfStack = (StackType_t*)(((portPOINTER_SIZE_TYPE)pxTopOfStack) & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK))); 
  //保存任务名称
	if (pcName != NULL)
	{
		for (x = (UBaseType_t)0; x < (UBaseType_t)16; x++)
		{
			pxNewTCB->pcTaskName[x] = pcName[x];
			if (pcName[x] == (char)0x00)
			{
				break;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}

		//设置结束位
		pxNewTCB->pcTaskName[16 - 1] = '\0';
	}
	else
	{
		//没名字直接设置结束
		pxNewTCB->pcTaskName[0] = 0x00;
	}
	//如果给的优先级大于最大优先级,就给最大的优先级
	if (uxPriority >= (UBaseType_t)configMAX_PRIORITIES)
	{
		uxPriority = (UBaseType_t)configMAX_PRIORITIES - (UBaseType_t)1U;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
	//保存优先级
	pxNewTCB->uxPriority = uxPriority;
	//设置基础优先级
	pxNewTCB->uxBasePriority = uxPriority;
	pxNewTCB->uxMutexesHeld = 0;
	//初始化状态列表像
	vListInitialiseItem(&(pxNewTCB->xStateListItem));
	//初始化事件列表项
	vListInitialiseItem(&(pxNewTCB->xEventListItem));

	//将pxNewTCB设置为从ListItem_t返回的链接。这样我们就可以得到
  //从列表中的通用项返回包含 TCB
	listSET_LIST_ITEM_OWNER(&(pxNewTCB->xStateListItem), pxNewTCB);

	//事件列表始终按优先顺序排列。按最大优先级减去优先级保存
	listSET_LIST_ITEM_VALUE(&(pxNewTCB->xEventListItem), (TickType_t)configMAX_PRIORITIES - (TickType_t)uxPriority); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
	listSET_LIST_ITEM_OWNER(&(pxNewTCB->xEventListItem), pxNewTCB);

	//delay终止标志默认为FALSE
	pxNewTCB->ucDelayAborted = pdFALSE;

	//初始化 TCB 堆栈,使其看起来好像任务已经在运行,
  //但已被调度程序中断。 返回地址已设置
  //到任务功能的开始。 堆栈初始化后
  //栈顶变量被更新。
	pxNewTCB->pxTopOfStack = pxPortInitialiseStack(pxTopOfStack, pxTaskCode, pvParameters);
	//传入了任务句柄,就把TCB设置到任务句柄
	if (pxCreatedTask != NULL)
	{
		//设置tcb到句柄
		*pxCreatedTask = (TaskHandle_t)pxNewTCB;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
}

初始化任务逻辑里先按申请栈大小通过栈开始地址加大小算到栈底位置。(因为ARM栈向下生长),申请的栈内存返回的地址是内存低地址。所以要换算出栈底地址。如果是向上生长的栈不用计算,申请的地址就是栈底。

  //栈向下生长,算的栈结束地址
  //得到栈顶地址。空栈时候指向栈的开始位置。ARM栈向下生长,所以栈开始时候栈顶是高内存位置
	pxTopOfStack = &(pxNewTCB->pxStack[ulStackDepth - (uint32_t)1]);
	pxTopOfStack = (StackType_t*)(((portPOINTER_SIZE_TYPE)pxTopOfStack) & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK))); 

然后保存任务优先级和名称

	//保存任务名称
	if (pcName != NULL)
	{
		for (x = (UBaseType_t)0; x < (UBaseType_t)16; x++)
		{
			pxNewTCB->pcTaskName[x] = pcName[x];
			if (pcName[x] == (char)0x00)
			{
				break;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}

		//设置结束位
		pxNewTCB->pcTaskName[16 - 1] = '\0';
	}
	else
	{
		//没名字直接设置结束
		pxNewTCB->pcTaskName[0] = 0x00;
	}
	//如果给的优先级大于最大优先级,就给最大的优先级
	if (uxPriority >= (UBaseType_t)configMAX_PRIORITIES)
	{
		uxPriority = (UBaseType_t)configMAX_PRIORITIES - (UBaseType_t)1U;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
	//保存优先级
	pxNewTCB->uxPriority = uxPriority;
	//设置基础优先级
	pxNewTCB->uxBasePriority = uxPriority;
	pxNewTCB->uxMutexesHeld = 0;

然后初始化任务状态和事件列表项

//初始化状态列表项
	vListInitialiseItem(&(pxNewTCB->xStateListItem));
	//初始化事件列表项
	vListInitialiseItem(&(pxNewTCB->xEventListItem));

	//将pxNewTCB设置为从ListItem_t返回的链接。这样我们就可以得到
  //从列表中的通用项返回包含 TCB
	listSET_LIST_ITEM_OWNER(&(pxNewTCB->xStateListItem), pxNewTCB);

	//事件列表始终按优先顺序排列。按最大优先级减去优先级保存
	listSET_LIST_ITEM_VALUE(&(pxNewTCB->xEventListItem), (TickType_t)configMAX_PRIORITIES - (TickType_t)uxPriority); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
	listSET_LIST_ITEM_OWNER(&(pxNewTCB->xEventListItem), pxNewTCB);

	//delay终止标志默认为FALSE
	pxNewTCB->ucDelayAborted = pdFALSE;

然后模拟ARM硬件自动入栈寄存器操作。把栈按硬件压栈顺序依次压入PSR,PC,LR,R12,R3,R2,R1,R0的初始值。然后再按照OS上下文切换压栈其他寄存器顺序压栈腾出相应空间。确保任务被调度时候出栈特定数量值后正好是任务栈的初始状态。模拟入栈得根据芯片文档芯片自动入栈的顺序和OS入栈其他寄存器顺序定,该操作不可少。否则OS第一次调度任务时候按正常出栈就直接溢出了。因为切换任务逻辑理解为任务都压栈了任务上下文。最后把任务TCB结构体地址设置到返回的TCB句柄。

	//初始化 TCB 堆栈,使其看起来好像任务已经在运行,
  //但已被调度程序中断。 返回地址已设置
  //到任务功能的开始。 堆栈初始化后
  //栈顶变量被更新。
	pxNewTCB->pxTopOfStack = pxPortInitialiseStack(pxTopOfStack, pxTaskCode, pvParameters);
	//传入了任务句柄,就把TCB设置到任务句柄
	if (pxCreatedTask != NULL)
	{
		//设置tcb到句柄
		*pxCreatedTask = (TaskHandle_t)pxNewTCB;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}

模拟入栈逻辑如下。和芯片文档和OS入栈顺序对应。

//模拟硬件初始化栈
//pxTopOfStack:
//pxCode:
//pvParameters:
StackType_t* pxPortInitialiseStack(StackType_t* pxTopOfStack,
	TaskFunction_t pxCode,
	void* pvParameters)
{
	//模拟堆栈帧,因为它将由上下文切换创建中断。
	//PSR:状态寄存器
	//PC:程序计数器
	//LR:链接寄存器
	//依次压入PSR,PC,LR,R12,R3,R2,R1,R0
	pxTopOfStack--;
	//入栈初始状态
	*pxTopOfStack = portINITIAL_XPSR;
	pxTopOfStack--;
	//PC赋值成为了执行任务的函数的入口
	//为了严格遵守 Cortex-M 规范,任务起始地址应清除第0位,因为它是在退出ISR时加载到PC中的。
	*pxTopOfStack = ((StackType_t)pxCode) & portSTART_ADDRESS_MASK;
	pxTopOfStack--;
	//入栈链接到错误跳转
	*pxTopOfStack = (StackType_t)prvTaskExitError;
	//空出位置
	pxTopOfStack -= 5;
	//任务参数放入R0对应位置
	*pxTopOfStack = (StackType_t)pvParameters;
	//空出位置
	pxTopOfStack -= 8;

	return pxTopOfStack;
}

任务堆栈初始化好之后就把任务状态列表项加入就绪列表。这样任务就处于创建好等待调度的状态了。启动调度器之后就按优先级从就绪列表取任务出栈上下文执行任务的逻辑了。同时后续可以通过TCB结构体句柄操作任务。

//把任务加入就绪列表
prvAddNewTaskToReadyList(pxNewTCB);

这就是FreeRTOS创建任务的过程,大体归纳为以下:
1.申请栈内存
2.申请TCB结构体内存
3.计算栈底地址设置到TCB栈底指针
4.模拟硬件入栈寄存器和OS入栈寄存器
5.把TCB状态列表项挂入就绪列表等待调度

理解双堆栈指针(MSP和PSP)。中断函数调度逻辑执行在MSP上,在保存任务上下文时候不会因为调度逻辑本身破坏程序状态。MSP运行状态为内核态。任务运行状态是用户态。内核态运行堆栈和用户态堆栈通过双堆栈指针分开。

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

FreeRTOS创建任务 的相关文章

  • Ubuntu下dpkg -i 安装deb报错 trying to overwrite shared

    问题表述 Ubuntu 22 04下 xff0c 执行下述命令时报错 xff1a 命令 xff1a span class token function sudo span dpkg i libglapi mesa 22 0 5 0ubunt
  • 4k高分屏Windows10下软件字体过小解决办法

    在Windows10下使用Matlab xff0c 由于是4k显示屏 xff0c 本来以为Matlab会出现字体过小的情况 xff0c 结果并没有出现什么问题 字体显示一切正常 xff0c 然而在打开Simulink时 xff0c Matl
  • Eigen矩阵运算开源库使用完全指南

    Eigen库是一个开源的矩阵运算库 xff0c 其利用C 43 43 模板编程的思想 xff0c 构造所有矩阵通过传递模板参数形式完成 由于模板类不支持库链接方式编译 xff0c 而且模板类要求全部写在头文件中 xff0c 从而导致导致Ei
  • “轻松搞定CMake”系列之CMakeLists文件编写语法规则详解

    文章目录 基本语法规则常见CMakeLists txt中指令剖析从VS项目配置过程理解CMakeLists内容CMake中常用变量汇总常用CMakeLists文件模板基础模板使用OpenCV库CMakeLists文件模板使用PCL库CMak
  • Centos7 XFS(dm-0):Internal error XFS_WANT_CORRUPTED_GOTO

    在k8s的道路上我们都是小白 xff0c 每天启动虚机都会遇到各种各样的问题 xff0c 这不 部署的k8s虚机启动发现操作系统启动异常 xff0c 提示如下报错信息 XFS xff08 dm 0 xff09 Internal error
  • 招聘笔试行测题之图形推理题解题思路汇总

    在一些公司的招聘过程中 xff0c 多少都会在笔试过程中遇到行测题 xff0c 这些行测题如果没有事先做过一些针对性的训练 xff0c 还是会感觉挺费劲的 xff0c 本博客主要汇总行测题中的图形推理题的一些解题思路 xff0c 供大家参考
  • ROS之tf空间坐标变换完全详解

    本博文主要汇总了自己在使用ROS中tf坐标变换包时查找的一些参考资料和博客 xff0c 包括了tf和部分tf2的使用 xff0c 在此感谢本博文中出现的所有的博客链接 xff01 参考资源 xff1a ROS官网详细介绍 xff1a htt
  • Word2016写论文之尾注功能——参考文献自动编号与引用(包括方括号去除方法)

    本系列文章主要详细介绍本人在使用Word2016写论文过程所用到的各种操作 xff0c 这些操作都非常的实用 xff0c 能够大为减少论文排版的工作量 其中很多方法也都是参考网上一些优秀博客的 xff0c 经过本人的实践成功之后才记录在此
  • vnc 设置不同用户登录

    a 在root用户下切换到其他用户 xff0c 以wolf用户为例 xff1a su wolf b 设置vnc连接密码 xff1a vncpasswd c 启动vnc服务 xff1a vncserver
  • 推荐几款常用的性能测试工具

    对内容不感兴趣拉到最后领取今天的外卖红包 常用的性能测试工具 对于开发人员来说 xff0c 首选是一些开源免费的性能 xff08 压力 xff09 测试软件 xff0c 例如 ab xff08 ApacheBench xff09 JMete
  • kubeadmin 快速部署k8s集群

    安装要求 在开始之前 xff0c 部署Kubernetes集群机器需要满足以下几个条件 xff1a 一台或多台机器 xff0c 操作系统 CentOS7 x 86 x64硬件配置 xff1a 2GB或更多RAM xff0c 2个CPU或更多
  • GetCurrentDirectory、SetCurrentDirectory和GetModuleFileName

    一 学习 GetModuleFileName xff1a 方法一 xff1a 想要访问执行程序 exe 路径下的文件 xff0c 有以下几个步骤 xff1a 1 先通过函数GetModuleFileName获取执行程序的绝对路径 TCHAR
  • C++定义全局类对象

    可能我这个全局类的说法不是很准确 xff0c 不过其实就是变量的扩展延伸 比如你想把一个类让全部的CPP都能用 xff0c 而不是一个变量 xff0c 那么需要这样定义 xff1a 假设有一个预编译头stdafx h 在stdafx h中加
  • Linux服务器VG扩容、LV扩容

    测试环境中K8s集群部署过程中发现磁盘大小太小 xff0c 需要对现有虚机的磁盘进行扩容 xff0c 计划 步骤1 虚机增加一块磁盘 步骤2 将磁盘添加到原有vg组中 步骤3 通过vg中资源给原有磁盘挂载目录进行lv扩容 实施步骤 xff1
  • Openstack云平台脚本部署之Neutron网络服务配置(九)

    目录 一 简介 二 部署脚本 2 1 网络节点独立部署 2 2 控制节点与网络节点融合部署 2 3 脚本详细介绍 三 参考文档 四 源码 五 系列文章 一 简介 Openstack网络服务Neutron主要负责网络连接任务 xff0c 包括
  • Android开发java调用C简单示例

    目录 下载NDK和CMake新建NDK项目写入C 43 43 代码 xff0c 并运行 本文使用的Android Studio版本是windows版Android Studio Bumblebee 2021 1 1 Patch 2 先看下最
  • 互联网单点登录集成方案

    为了迎合公司互联网化经营 xff0c 业务部门均纷纷上马了互联网的项目 xff0c 部门应用之间各自为政 xff0c 无法形成公司整体品牌效应 xff0c 以及影响用户体验 xff0c 故 xff0c 有了以下的单点登录集成方案 概述 整合
  • 【软件教程】如何让vscode连接ssh时记住密码

    准备软件 客户机安装vscode xff08 vscode官网https code visualstudio com xff09 客户机和服务器配置ssh xff0c 确保能够连接 VSCode ssh记住密码教程 一 在Client客户机
  • 车辆检测--DAVE: A Unified Framework for Fast Vehicle Detection and Annotation

    DAVE A Unified Framework for Fast Vehicle Detection and Annotation ECCV2016 本文使用深度学习进行车辆检测和属性学习 提出的系统为 Detection and Ann
  • 对抗学习用于目标检测--A-Fast-RCNN: Hard Positive Generation via Adversary for Object Detection

    A Fast RCNN Hard Positive Generation via Adversary for Object Detection CVPR 2017 Caffe code https github com xiaolonw a

随机推荐

  • 人脸识别--SphereFace: Deep Hypersphere Embedding for Face Recognition

    SphereFace Deep Hypersphere Embedding for Face Recognition CVPR2017 https github com wy1iu sphereface pytorch https gith
  • 运动相机检测无人机-- Detecting Flying Objects using a Single Moving Camera

    Detecting Flying Objects using a Single Moving Camera PAMI 2017 http cvlab epfl ch research unmanned detection https dri
  • [转载]Python SMTP发送邮件-smtplib模块

    在进入正题之前 xff0c 我们需要对一些基本内容有所了解 xff1a 常用的电子邮件协议有SMTP POP3 IMAP4 xff0c 它们都隶属于TCP IP协议簇 xff0c 默认状态下 xff0c 分别通过TCP端口25 110和14
  • c语言和c++有什么区别

    差不多是win98跟winXP的关系 C 43 43 是在C的基础上增加了新的理论 xff0c 玩出了新的花样 所以叫C加加 C是一个结构化语言 xff0c 它的重点在于算法和数据结构 C程序的设计首要考虑的是如何通过一个过程 xff0c
  • 梳理LVM逻辑卷管理,

    在Linux操作系统会时不时碰到卷有关的操作 xff0c 以下也是罗列了相关操作内容 xff0c 仅供参考 创建PV VG LV的方法 将各物理磁盘或分区的系统类型设为Linux LVM xff0c 其system ID为8e xff0c
  • 使用sqlyog连接 Mysql 出现1251错误

    使用sqlyog连接 Mysql 出现1251错误 简述 xff1a 1251 client does not support authentication protocol requested by server consider upg
  • 准备给ubuntu18.04安装杀毒软件

    如题 xff0c 电脑最近总出现些奇奇怪怪的小问题 xff0c 还是得装个杀毒软件 xff0c 看是不是中病毒了 输入sudo apt get install clamtk 安装完成后 xff0c 输入clamtk 即可 xff0e 卸载方
  • 使用Nginx代理地址

    DotNetCore在Linux发布时候 xff0c 由于不止一个产品组发布网站 xff0c 不像以前大家都用IIS的80发布网站 那么就存在大家抢80端口的情况 xff0c 为了让大家不比加上端口为此用Nginx代理URL实现网站地址代理
  • CentOS安装Cache数据库

    适用CentOS7 6 CentOS8上安装Intersystem公司的Cache数据库 xff0c 资料基本是空白 xff0c 分享一下 首先安装解压软件unzip和libicu xff0c 最小化安装的缺 xff0c 全安装的不缺 yu
  • Cache数据库之ECP搭建

    Cache作为非关系数据库 xff0c 其强大毋庸置疑 首先其Globle结构 xff0c 直接暴露的表Globel数据 xff0c 以及提供的M语言操作Globle达到的最优查询速度 ECP xff08 企业缓存协议 xff09 更是提供
  • Sebia电泳绘图

    Sebia这仪器真是个奇葩的存在 自己仪器有图不存文件 xff0c LIS要的话还得自己按数据绘制 还有蛋白电泳 固定电泳 画不画参考线等不同要求 xff08 奇葩的很 xff09 按理这种事不属于lis范围 xff0c 无奈国内lis太卷
  • nginx代理与负载均衡

    随着谷歌浏览器不断的改变https调用websocket和非https资源的策略 xff0c 从谷歌大概70以后不允许https调用非https资源和ws的websocket 后面实现了wss解决谷歌这一策略的影响 随着谷歌到90后版本限制
  • FreeRTOS学习第一篇

    之前在STM32Nano开发板开发是基于裸机开发 xff0c 即自己在main方法写死循环 死循环轮流执行各个任务逻辑的方法 这样做直接简单 xff0c 但是不同任务有不同优先级 xff0c 对CPU响应要求不同 逻辑容易某个任务卡住了 x
  • FreeRTOS之heap4

    操作系统离不开内存管理 FreeRTOS提供了5种内存管理方法 实现在portable MemMang里heap1到heap5 每种管理方案策略不同 我采用的是比较有代表性的heap4管理方案 该模式定义了ucHeap全局数组充当堆内存池
  • FreeRTOSMini

    最近在研究实时操作系统FreeRTOS FreeRTOS作为开源的RTOS xff0c 源码规模不大 xff0c 可以供操作系统学习 xff0c 加上我的STM32 Nano开发板正好可以学习OS 借着五一放假宅家里学习 实现的FreeRT
  • 双master节点+keepalived方式部署K8s 1.18.20

    相关部署方式也挺多 xff0c 自己采用双master节点 43 单node节点方式 xff0c 并且采用keepalived部署1 18 20版本 xff0c 中间也出现过相关小问题 xff0c 但都一一处理 xff0c 记录以给需要的同
  • FreeRTOS之TCB

    FreeRTOSMini实现了最小任务调度 现在分开介绍进程调度重要部分 进程调度的基础首先是定义任务调度的数据结构 xff0c 来保存任务堆栈结构和任务状态所在状态列表 xff0c 然后就是任务的优先级唯一号等 最小Mini内核参照 Fr
  • FreeRTOS任务调度主要变量

    之前介绍的和FreeRTOS任务调度相关的数据结构即内存分配实现 xLIST heap 4 TCB结构体 任务调度就是基于这些结构体实现 这次介绍调度相关的主要变量 代码在FreeRTOSMini c文件签名部分 span class to
  • Base64串介绍

    以前写winform时候没接触过Base64 刚开始接触时候还不知道是个啥 最开始接触Base64串时候是仪器出图 很长一段时间我还真以为Base64就是表示图的 xff0c 很多人也是这么认为的 xff0c 这次介绍一下什么是Base64
  • FreeRTOS创建任务

    CPU有这些寄存器 R0 R12为通用寄存器 R13为栈顶指针 xff0c 在OS时候中断函数的R13使用MSP的指针 xff08 内核态 xff09 非中断里面使用PSP指针 xff08 用户态 xff09 正是有双堆栈指针可以保证OS切