当前位置: 首页 > news >正文

STM32(F103ZET6)第十九课:FreeRtos的移植和使用

目录

  • 需求
  • 一、FreeRtos简介
  • 二、移植FreeRtos
    • 1.复制代码
    • 2.内存空间分配和内核相关接口
    • 3.FreeRtosConfig
    • 4.添加到工程中
    • 三、任务块操作
    • 1.任务四种状态
    • 2.创建任务过程

需求

1.将FreeRtos(嵌入式实时操作系统)移植到STM32中。
2.在该系统中实现任务的创建、挂起、恢复和删除。
3.将板子上写的传感器模块的数据获取,移植到FreeRtos(嵌入式实时操作系统)环境下。
在这里插入图片描述

一、FreeRtos简介

裸机执行流程:前后台系统
在这里插入图片描述
操作系统执行流程:
在这里插入图片描述
加入操作系统的作用:用户想要实现多个任务并行的效果,但是单片机只有一个核心,同时只能处理一件事,通过加入操作系统,可以实现任务快速的切换,给人一种多个任务同时在执行的错觉。
FreeRtos的概念:
在这里插入图片描述在这里插入图片描述

二、移植FreeRtos

移植之前,找一个工程mian.c清空,然后移植FreeRTOS。因为加上操作系统之后,编程方式就变了,之前的while(1)就不在使用了。

1.复制代码

从官网下载的FreeRTOS 包含 Demo 例程和内核源码(比较重要,我们就需要提取该目录下的大部分文件)。 FreeRTOS 文件夹下的 Source 文件夹里面包含的是 FreeRTOS 内核的源代码,
我们移植 FreeRTOS 的时候就需要这部分源代码; FreeRTOS 文件夹下的 Demo 文件夹里
面包含了 FreeRTOS 官方为各个单片机移植好的工程代码, FreeRTOS 为了推广自己,会
给各种半导体厂商的评估板写好完整的工程程序,这些程序就放在 Demo 这个目录下,这
部分 Demo 非常有参考价值。我们把 FreeRTOS 到 STM32 的时候,FreeRTOSConfig.h 这
个头文件就是从这里拷贝过来的。
在这里插入图片描述
将源码直接复制到想要移植的工程文件下,改名为FreeRtos:
在这里插入图片描述
这里我们再重点分析下 FreeRTOS/ Source 文件夹下的文件,具体见图 13-6。“include”
文件夹和“portable”文件夹包含的是 FreeRTOS 的通用的头文件和 C 文件,这两部分的文
件试用于各种编译器和 include 处理器, 是通用的。需要移植的头文件和 C 文件放在编号
portblle 这个文件夹。
在这里插入图片描述
我们打开 portable 这个文件夹,可以看到里面很多与编译器相关的文件夹, 在不同的
编译器中使用不同的支持文件。文件夹“Keil”就是我们就是我们使用的编译器,当打开 “Keil”
文件夹的时候,你会看到一句话“See-also-the-RVDS-directory.txt”,其实 “Keil” 里面的内容
跟 RVDS 里面的内容一样,所以我们只需要 RVDS 文件夹里面的内容即可。而 MemMang
文件夹下存放的是跟内存管理相关的,我们的重点是RVDS文件夹
在这里插入图片描述
打开 RVDS 文件夹, 下面包含了各种处理器相关的文件夹,从文件夹的名字我们就非
常熟悉了,有 M0、 M3、 M4 等各种系列, FreeRTOS 是一个软件,单片机是一个硬件,
FreeRTOS 要想运行在一个单片机上面,它们就必须关联在一起,那么怎么关联?还是得通
过写代码来关联,这部分关联的文件叫接口文件,通常由汇编和 C 联合编写。这些接口文
件都是跟硬件密切相关的,不同的硬件接口文件是不一样的,但都大同小异。编写这些接口
文件的过程我们就叫移植,移植的过程通常由 FreeRTOS 和 MCU 原厂的人来负责,移植
好的这些接口文件就放在 RVDS 这个文件夹的目录下。
在这里插入图片描述

2.内存空间分配和内核相关接口

MemMang 文件夹下存放的是跟内存管理相关的,总共有五个 heap 文件以及一
个 readme 说明文件,这五个 heap 文件在移植的时候必须使用一个,因为 FreeRTOS 在
创建内核对象的时候使用的是动态分配内存,而这些动态内存分配的函数则在这几个文件里
面实现,不同的分配算法会导致不同的效率与结果,后面在内存管理中我们会讲解每个文件
的区别,由于现在是初学,所以我们选用 heap4.c 即可。
在这里插入图片描述
FreeRTOS 为我们提供了 cortex-m0、m3、m4 和 m7 等内核的单片机的接口文件,
只要是使用了这些内核的 MCU 都可以使用里面的接口文件。我们这里以 ARM_CM3 这个
文件夹为例,看看里面的文件,里面只有“port.c”与“portmacro.h”两个文件, port.c 文件里
面的内容是由 FreeRTOS 官方的技术人员为 Cortex-M3 内核的处理器写的接口文件,里面
核心的上下文切换代码是由汇编语言编写而成;portmacro.h 则是 port.c 文件对应的头文
件,主要是一些数据类型和宏定义。
在这里插入图片描述
首先在我们的 STM32 裸机工程模板根目录下新建一个文件夹,命名为“FreeRTOS”,
并且在 FreeRTOS 文件夹下新建两个空文件夹,分别命名为“src”与“port”,src 文件夹用于
保存 FreeRTOS 中的核心源文件,也就是我们常说的‘.c 文件’, port 文件夹用于保存内存
管理以及处理器架构相关代码,这些代码 FreeRTOS 官方已经提供给我们的,直接使用即可,
在前面已经说了, FreeRTOS 是软件,我们的开发版是硬件,软硬件必须有桥梁来连接,这
些 与 处 理 器 架 构 相 关 的 代 码 , 可 以 称 之 为 RTOS 硬 件 接 口 层 , 它 们 位 于
FreeRTOS/Source/Portable 文件夹下。
在这里插入图片描述
打开 FreeRTOS 源码,在“FreeRTOSvX.X.X\FreeRTOS\Source”目录下找到所有的‘.c 文
件’,将它们拷贝到我们新建的 src 文件夹中。
在这里插入图片描述
打开 FreeRTOS VX.X.X 源码,在“FreeRTOS VX.X.X \FreeRTOS\Source\portable”目录
下找到“ MemMang”文件夹与“ RVDS”文件夹,将它们拷贝到我们新建的 port 文件夹中。
在这里插入图片描述
打开 FreeRTOS VX.X.X 源码,在“FreeRTOS VX.X.X \FreeRTOS\Source” 目录下找到
“include”文件夹,它是我们需要用到 FreeRTOS 的一些头文件,将它直接拷贝到我们新建的
FreeRTOS 文件夹中,完成这一步之后就可以看到我们新建的 FreeRTOS 文件夹已经有 3
个文件夹,这 3 个文件夹就包含 FreeRTOS 的核心文件,至此,FreeRTOS 的源码就提取
完成
在这里插入图片描述

3.FreeRtosConfig

拷贝 FreeRTOSConfig.h 文件到 user 文件夹
FreeRTOSConfig.h 文件是 FreeRTOS 的工程配置文件,因为 FreeRTOS 是可以裁剪的
实时操作内核,应用于不同的处理器平台,用户可以通过修改这个 FreeRTOS 内核的配置头
文件来裁剪 FreeRTOS 的功能,所以我们把它拷贝一份放在 user 这个文件夹下面
在这里插入图片描述
其中,FreeRTOSConfig.h 是直接从 demo 文件夹下面拷贝过来的,该头文件对裁剪整个FreeRTOS 所需的功能的宏均做了定义,有些宏定义被使能,有些宏定义被失能,一开始我们只需要配置最简单的功能即可。要想随心所欲的配置 FreeRTOS 的功能,必须对这些宏定义的功能有所掌握。
比较重要的宏文件:
#define configUSE_TIME_SLICING 1 //使能时间片调度(默认式使能的)
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 //硬件计算前导零指令,如果所使用的, MCU 没有这些硬件指令的话此宏应该设置为 0
#define configUSE_TICKLESS_IDLE 0 //置 1:使能低功耗 tickless 模式;置 0:保持系统节拍(tick)中断一直运行
#define configUSE_QUEUE_SETS 1 //启用队列
#define configUSE_TASK_NOTIFICATIONS 1 //开启任务通知功能,默认开启
#define configUSE_MUTEXES 1 //使用互斥信号量
#define configUSE_RECURSIVE_MUTEXES 1 //使用递归互斥信号量
#define configUSE_COUNTING_SEMAPHORES 1 //为 1 时使用计数信号量
#define configQUEUE_REGISTRY_SIZE 10 //设置可以注册的信号量和消息队列个数
#define configUSE_APPLICATION_TASK_TAG 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1 //支持动态内存申请
#define configUSE_MALLOC_FAILED_HOOK 0 //使用内存申请失败钩子函数
#define configCHECK_FOR_STACK_OVERFLOW 1// 大于 0 时启用堆栈溢出检测功能,如果使用此功能用户必须提供一个栈溢出钩子函数如果使用的话此值可以为 1 或者 2,因为有两种栈溢出检测方法
#define configGENERATE_RUN_TIME_STATS 0 //启用运行时间统计功能
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configUSE_TIMERS 1 //启用软件定时器
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-1) //软件定时器优先级
#define configTIMER_QUEUE_LENGTH 10 //软件定时器队列长度
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE*2) //软件定时器任务堆栈大小
//可选函数配置选项
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
//中断服务函数 也可以修改起始文件
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler

4.添加到工程中

添加 FreeRTOS 源码到工程组文件夹
在这里插入图片描述
配置 FreeRTOS 头文件路径
在这里插入图片描述

三、任务块操作

1.任务四种状态

在这里插入图片描述
四种形态:
运行态
当任务实际执行时,它被称为处于运行状态。 任务当前正在使用处理器。 如果运行 RTOS 的处理器只有一个内核, 那么在任何给定时间内都只能有一个任务处于运行状态。
就绪态
准备就绪任务指那些能够执行(它们不处于阻塞或挂起状态), 但目前没有执行的任务, 因为同等或更高优先级的不同任务已经处于运行状态。
阻塞态
如果任务当前正在等待时间或外部事件,则该任务被认为处于阻塞状态。 例如,如果一个任务调用vTaskDelay(),它将被阻塞(被置于阻塞状态), 直到延迟结束-一个时间事件。 任务也可以通过阻塞来等待队列、信号量、事件组、通知或信号量 事件。 处于阻塞状态的任务通常有一个"超时"期, 超时后任务将被超时,并被解除阻塞, 即使该任务所等待的事件没有发生。
“阻塞”状态下的任务不使用任何处理时间,不能 被选择进入运行状态。
挂起态
与“阻塞”状态下的任务一样, “挂起”状态下的任务不能 被选择进入运行状态,但处于挂起状态的任务 没有超时。 相反,任务只有在分别通过 vTaskSuspend() 和 xTaskResume() API 调用明确命令时 才会进入或退出挂起状态。
调度机制
和裸机操作不同,操作系统中执行的是一个一个任务块,通过任务调度器(使用相关的调度算法)来决定当前时刻要执行哪个任务。
调度方式主要有两种:
1.抢占式调度:任务优先级不同时使用。每个任务都有自己的优先级,高优先级的任务会抢占低优先级的任务。
2.时间片调度:任务优先级相同时使用。当多个任务优先级相同时,任务调度器会在每一次系统节拍到的时候切换任务。
其实说白了就是:STM32执行的是线性代码,只有中断能打断。而FreeRtos执行的是不同等级的任务块,等级越高任务块就越先执行,相同等级的任务块执行时系统会来回切换。
优先级不能设置为0,因为FreeRtos的空闲任务优先级为0,一般情况下我们不去抢。

2.创建任务过程

1、首先要添加FreeRTOS相关头文件。这是必须的!
在这里插入图片描述
2、创建一个句柄,TaskHandle_t 类型
在这里插入图片描述在这里插入图片描述
3、创建任务

Ret = xTaskCreate(LED_Task, //创建任务的任务函数名"LED1_Toggle",//任务名字50,//任务栈深度。32位单片机*4NULL,//创建任务时传递参数,没有就给NULL1,//任务优先级&LED_TaskHandle);//任务的句柄,用于后边删除,挂起任务if(Ret == pdPASS){printf("LED_Task创建完成\r\n");}Ret = xTaskCreate(KEY_Task, //创建任务的任务函数名"KEY_Task",//任务名字100,//任务栈深度。32位单片机*4NULL,//创建任务时传递参数,没有就给NULL2,//任务优先级&KEY_TaskHandle);//任务的句柄,用于后边删除,挂起任务if(Ret == pdPASS){printf("KEY_Task创建完成\r\n");}printf("开启FreeRTOS调度器\r\n");//调度器启动完成之后,FreeRTOS会获取CPU控制权,会按照任务优先级执行创建的任务vTaskStartScheduler();printf("开启FreeRTOS调度器成功\r\n");

创建完成后一定要打开调度器。
4、写与句柄对应的任务函数,通常要加while(1)每个任务都是1个无限循环程序,内容根据需求来定。
在这里插入图片描述在这里插入图片描述
接下来重点了解一下创建函数:

在这里插入图片描述
在这里插入图片描述
简单来说:
参数1:实现任务的函数名
参数2:自己起一个任务名
参数3:分配空间,栈深度(32位单片机*4)
参数4:任务函数传参时使用
参数5:任务优先级(越高优先级越高)
参数6:该任务的句柄

相关文章:

STM32(F103ZET6)第十九课:FreeRtos的移植和使用

目录 需求一、FreeRtos简介二、移植FreeRtos1.复制代码2.内存空间分配和内核相关接口3.FreeRtosConfig4.添加到工程中三、任务块操作1.任务四种状态2.创建任务过程 需求 1.将FreeRtos(嵌入式实时操作系统)移植到STM32中。 2.在该系统中实现任务的创建、…...

索尼的Web3蓝图:从技术创新到现实应用的全方位布局

近年来,随着区块链技术和加密资产的迅猛发展,全球科技巨头纷纷投入其中,力图在Web3浪潮中占据一席之地。作为传统科技行业的巨头,索尼(Sony)也不甘落后,积极推动其Web3战略布局,展现出其在新兴领域的强烈野…...

探索Java中的分布式消息队列与事件总线:架构、实现与最佳实践

引言 在现代分布式系统中,消息队列和事件总线已经成为实现松耦合、高扩展性和高可用性架构的关键组件。无论是微服务架构、事件驱动架构,还是实时数据处理,消息队列和事件总线都扮演着至关重要的角色。本文将深入探讨Java中的分布式消息队列…...

HTML零基础教程(超详细)

一、什么是HTML HTML,全称超文本标记语言(HyperText Markup Language),是一种用于创建网页的标准标记语言。它通过一系列标签来定义网页的结构、内容和格式。HTML文档是由HTML元素构成的文本文件,这些元素包括标题、段…...

011.Python爬虫系列_bs4解析

我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈 入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈 虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈 PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈 Oracle数…...

django摄影竞赛小程序论文源码调试讲解

2系统关键技术及工具简介 系统开发过程中设计的关键技术是系统的核心,而开发工具则会影响的项目开发的进程和效率。第二部分便描述了系统的设计与实现等相关开发工具。 2.1 Python简介 Python 属于一个高层次的脚本语言,以解释性,编译性&am…...

Unity-OpenCV-Imgproc函数概览

OpenCV-Imgproc函数概览 函数名功能描述createLineSegmentDetector创建一个智能指针到 LineSegmentDetector 对象并初始化它。此算法用于检测图像中的线段。getGaussianKernel返回高斯滤波器的系数。这些系数用于平滑图像或进行高斯模糊。getDerivKernels返回计算图像空间导数的…...

水晶连连看 - 无限版软件操作说明书

水晶连连看 – 无限版游戏软件使用说明书 文章目录 水晶连连看 – 无限版游戏软件使用说明书1 引言1.1 编写目的1.2 项目名称1.3 项目背景1.4 项目开发环境 2 概述2.1 目标2.2 功能2.3 性能 3 运行环境3.1 硬件3.2 软件 4 使用说明4.1 游戏开始界面4.2 游戏设定4.2.1 游戏帮助4…...

目标检测-YOLOv3

YOLOv3介绍 YOLOv3 (You Only Look Once, Version 3) 是 YOLO 系列目标检测模型的第三个版本,相较于 YOLOv2 有了显著的改进和增强,尤其在检测速度和精度上表现优异。YOLOv3 的设计目标是在保持高速的前提下提升检测的准确性和稳定性。下面是对 YOLOv3 …...

vscode好用的快捷键整理~

vscode好用的快捷键 将当前行复制并插入到上一行 shift alt ↑将当前行复制并插入到上一行 shift alt ↓将光标复制到上一行 ctrl alt ↑将光标复制到下一行 ctrl alt ↓删除当前行 ctrl x 本身是剪切当前行,也可以作为删除当前行来用选中下一个相同的片段…...

Docker in Docker 实践 on mac

在尝试tekton构建ci pipeline是,需要在k8 pod里build image,于是研究了如何docker in docker。 1. 编写自己的dind docker image FROM docker:20.10.16-dind ENV DOCKER_HOST unix:///var/run/docker.sock 2. docker build 自己的dind docker image并…...

Flask-Session扩展,使用Redis存储会话数据

深入理解Flask-session扩展Redis Flask 应用中使用 flask-session 扩展将 session 数据存储在 Redis 中是一种高效且可扩展的方法,特别是在需要处理大量用户或需要分布式部署的应用中。以下是如何在 Flask 应用中配置 flask-session 以使用 Redis 存储 session 的步…...

urdf ( xacro ) 的 collision碰撞参数设置

目录 写在前面的话整体流程1 URDF 文件结构2 查看原始碰撞形状描述3 加入简单碰撞形状描述方法一 Meshlab 自动测量方法二 人为测量 4 加入XACRO函数简化描述 最终结果展示侧视图正视图碰撞几何体中心点设置不对出现的结果 写在前面的话 本文使用的 URDF 文件是由 solidworks …...

iOS——方法交换Method Swizzing

什么是方法交换 Method Swizzing是发生在运行时的,主要用于在运行时将两个Method进行交换,我们可以将Method Swizzling代码写到任何地方,但是只有在这段Method Swilzzling代码执行完毕之后互换才起作用。 利用Objective-C Runtimee的动态绑定…...

【有啥问啥】大模型应用中的哈希链推理任务

大模型应用中的哈希链推理任务 随着人工智能技术的快速发展,尤其是大模型(如GPT、BERT、Vision Transformer等)的广泛应用,确保数据处理和模型推理的透明性与安全性变得愈发重要。哈希链推理任务作为一种技术手段,能够…...

DevExpress WinForms v24.1新版亮点:功能区、数据编辑器全新升级

DevExpress WinForms拥有180组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜…...

FreeRTOS内部机制学习01(任务创建的细节以及任务调度的内部机制)

文章目录 前言:首先要谢谢韦东山老师的无私奉献,让我学到了很多东西,我做这个笔记是害怕我会忘记,所以就记录了下来,希望对大家有帮助!关于寄存器CPU内部的寄存器这些寄存器到底要保存一些什么?…...

CANoe突然出现Trace窗口筛选项无法显示的问题

原因:和最近window的推送的补丁包有关 同事通过网上的操作,一顿操作猛如虎,卸载掉了这个插件,结果电脑文件夹无法打开和闪退。 IT的同事通过cmd命令也无法恢复。 dism /online /cleanup-image /scanhealth dism /online /cleanu…...

Linux日志-sar日志

作者介绍:简历上没有一个精通的运维工程师。希望大家多多关注作者,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 Linux 系统中的日志是记录系统活动和事件的重要工具,它们可以帮助管理员监视系统状态、调查问题以及了解系统运行…...

全国计算机二级考试C语言篇3——选择题

C语言部分——C语言概述 1.程序模块化的优点 程序模块化的优点在于它可以使程序的开发、维护和复用变得更简单。下面是一些主要的优点: 降低复杂度:模块化可以将复杂的问题分解成更小的、更易管理的部分。 可维护性:模块化使得代码更易于维护…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

Docker 本地安装 mysql 数据库

Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

OD 算法题 B卷【正整数到Excel编号之间的转换】

文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...