diff --git a/.Doc/Bug_Report.md b/.Doc/Bug_Report.md
deleted file mode 100644
index ee0936c..0000000
--- a/.Doc/Bug_Report.md
+++ /dev/null
@@ -1,69 +0,0 @@
-# 异常报告
-
-已知可能出现的bug将会列在此处,并指明修复期限和任务执行者。
-
-使用中遇到的bug和错误放在此处。参照下列格式:
-
-## 标题用简短的一句话描述
-
-### 出现问题的application/module/bsp
-
-描述你的使用方法,应该贴上图片或代码块,以及硬件连线等
-
-### 尝试解决的方案
-
-你的尝试,以及猜测可能的错误
-
-### 如何复现问题
-
-问题能否稳定复现?描述复现方法等
-
-### 紧急程度
-
-这里用⭐表示。最大5颗⭐。
-
-如果不修复,会有何种其他牵连情况发生?
-
----
-
-不同的问题用 --- 分隔开
-
-你还可以使用Stepsize插件在代码出现问题(可能出现问题)的地方添加issues并详尽描述。或在gitee上增加issues。
-
-当然,最快的方法是在群里提问。
-
-## 使用LK电机并挂载在hcan2上时会出现HardFault
-
-> 已修复此问题。修复日志请查看当前目录下的“如何定位bug.md”。
-
-使用MF9025v2电机,并将其配置在CAN2上。经过一次LKMotorControl,第二次进入时hcan->instance会在HAL_CAN_Add_Tx_Message()结束时被未知的语句修改成奇怪的值,造成HardFault
-
-### 尝试解决的方案
-
-单步调试无果,在HAL_CAN_Add_Tx_Message()返回的那一步hcan->instance会莫名其妙变成0,hcan2也会被修改到一个0x8000xxx的地址上(hcan是HAL库自定的全局变量)
-
-### 如何复现问题
-
-使用LK电机并将其挂载在CAN2上,连接电机后直接运行。在第二次进入MotorTAsk中的LKMotorControl时,于检查空闲CAN邮箱时,由于hcan2被修改,访问CAN2外设状态时会访问野指针导致HardFault。
-
-### 紧急程度
-
-⭐⭐⭐⭐⭐
-
-## 总线挂载多个电机后,pitch和yaw的GM6020电机出现编码器反馈值跳动
-
-> 已修复,详细信息见“如何定位bug.md”
-
-CAN1总线挂载5个电机,4\*3508+1\*6020,控制报文发送频率为500Hz,电机的反馈频率皆为1kHz.云台在控制时会出现突然跳动.添加到Ozone graph查看发现ECD(编码器)值在静止状态下也会出现突然抖动,并且幅度超过4000.但不会出现超过编码器反馈值范围的值.
-
-### 尝试解决的方案
-
-若使用单个6020电机,不会出现此问题. 曾认为是指针越界导致`motor_measure->ecd`值被修改, 需要进一步观察其他反馈值是否出现问题. 且反馈值始终在编码器范围之内.
-
-### 如何复现问题
-
-同时启用CAN1和CAN2,并在单条CAN总线上挂载超过5个电机.
-
-### 紧急程度
-
-⭐⭐⭐
\ No newline at end of file
diff --git a/.Doc/TODO.md b/.Doc/TODO.md
deleted file mode 100644
index 323ce7b..0000000
--- a/.Doc/TODO.md
+++ /dev/null
@@ -1,183 +0,0 @@
-# Work To be done & optimized
-
-- **待完成**:不完成可能导致整车功能不完整
-- **待优化**:对已有的功能进行性能提高/模块解耦/可维护性增强
-- **待添加**:不紧急的/锦上添花的功能
-
-**==标为黄色高亮的代表紧急程度高。==**
-
-## assorted
-
-- [ ] 由于我们读写和传递的数据结构都不大,基本不会发生读写时任务切换的情况。典型的数据读写时间都是~μs,故没有对数据访问的接口添加互斥锁或关闭全局中断。后续有需求(如大量数据复制)可以添加。可以新增一个bsp_mutex或者module层的ds,提供相应支持。实际上freertos提供了一些供线程(任务)间进行数据交互的类型和函数,请查阅对应文档。
-
-最简单的防止重入或数据竞争的方式是创建一个bool类型值实现互斥访问。当一个线程或中断要访问某个变量时,先检查这个变量对应的bool锁是否为1,若不为1则赋值为1表明当前有线程访问变量,之后可以开始对该变量的操作,结束读写后释放锁即赋0。不像osSemaphore或osMessageQueue等只允许在中断中添加消息或释放信号量/互斥量,这种变量锁可以在任意处加锁解锁。
-
-若锁获取失败,则直接退出,或将当前线程挂起等待下一次唤醒。最常见的情况是一个线程需要从一块数据区或缓冲区读取数据而某个中断会向这个区域写入数据,线程在读取的时候很可能会被中断打断。那么中断进入时发现该数据已经被上锁,就不会强行写入。为了保证数据的实时性,你可以选择将数据存入队列或启动一个新的任务,当锁释放时再写入数据。如果数据量较小,你不在乎开销,则可以使用freerots提供的osMessageQueue或osMessageMailbox。
-
-目前,我们在bsp_dwt中添加了一个位锁,防止中断中调用DWTGetDeltaT或DWTGetTimeline函数更新DWT维护的时间时打断任务中的相同函数导致计数被重复更新,或引起错误的DWT溢出检测。
-
-## BSP
-
-### 待完成
-
-
-
-### 待优化
-
-#### bsp_pwm
-
-- [x] 是否允许修改预分频计数器?
-
-### 待添加
-
-#### bsp_iic
-
-- [ ] 添加10位地址的支持
-
-#### bsp_blueteetch
-
-- [x] 增加蓝牙功能,方便调试和测试
-
-#### bsp_wifi
-
-- [ ] 增加无线局域网功能,方便调试和测试
-
----
-
-## Module
-
-### 待完成
-
-Unicom
-
-- [ ] 为键鼠/遥控器/ps手柄/视觉上位机等各种控制器提供一套统一的接口,把发来数据转化为标准的控制数据,包括底盘速度云台角度等等
-
-- [ ] 给每个模块增加调试的条件编译,并增加bsp log的输出。或直接在运行时添加log等级,输出不同的信息。
-
-#### ==servo_motor==
-
-舵机模块,需要预先定义90/180/360连续旋转的电机类型,并且能够设定max和min位置。
-
-- [x] 编写舵机模块(待测试和优化)
-- [x] 可能需要串口舵机的支持?
-
-#### imu
-
-- [ ] 完善bmi088模块和算法的交互,添加异步量测更新的SO3上的IEKF
-
-> 继续使用四元数(S3)也许是一个更好的选择,改动较小且运算开销也较小。后续考虑修改一套ESKF_INS并移植到框架中。
-
-#### ==master_machine==
-
-- [ ] 增加IMU数据的时间戳
-- [ ] 增加加速度计数据
-- [ ] 重构seasky protocol的接口
-- [ ] 增加数据未更新的处理
-
-需要一个更简单的协议以加快速度。若有必要,可能需要重新编写一个简单的调试上位机UI。
-
-
-### 待优化
-
-#### buzzer
-
-> 是否需要在module层就和**daemon**模块配合?
-
-当前实现为buzzer是单独的module,若需要蜂鸣器警报的module可以自行包含buzzer.h以创建不同情况下的警报,如电机离线、堵转、遥控器离线等。
-
-也许还有其他方式提醒离线和异常。
-
-目前急需一个无线遥控继电器,防止机器人的急停模式失效。
-
-#### BMI088
-
-- [ ] 完善和SO3 IEKF的交互,增加异步任务的唤醒和数据传递(IMU中断唤起任务)
-
-根据BMI088的datasheet在初始标定完成后将gyro和acc都设置为中断触发,当数据准备好时传感器会在对应的引脚输出跳变,通过EXTI捕获跳变并触发中断,在回调函数中启动SPI DMA传输。陀螺仪数据来到时进行姿态的预测即propagation,加速度计数据到来时进行量测更新(correct)。
-
-也许需要找到一种更好的方式构建INS任务以方便和其他模块、应用的交互。
-
-另外,若要进一步提升自瞄效果,在姿态得到更新时(陀螺仪和imu的数据到来时),需要额外的引脚连接到相机上完成硬触发采集,以获得更好的时间对齐效果,防止视觉得到的姿态数据发生漂移。目前视觉端假设姿态更新的频率是1khz(当前每次完成姿态解算都会向上位机发送当前的姿态)
-
-#### remote_control
-
-- [ ] 增加长按/短按检测 (是否有必要?)
-
-#### message_center
-
-- [ ] 增加队列剩余信息和数据时间戳的支持
-- [ ] 提供直接传递指针的接口?
-
-#### can_comm
-
-- [ ] 增加can_comm数据未更新的处理
-
-#### controller
-
-- [ ] 将PID的初始化改写为PIDRegister的形式,在controller统一分配内存.
-
-#### dji_motor
-
-- [ ] 增加3508和2006的开环零位校准函数
-- [ ] 为实例增加低通滤波系数变量,使不同电机有不同的配置
-
-#### LKmotor
-
-- [ ] 正反转标志位设置,需要修改反馈量和pid计算
-
-#### HTmotor
-
-- [ ] 正反转标志位设置,需要修改反馈量和pid计算
-
-### 待添加
-
-#### unicomm
-
-- [ ] 完成初版构建
-
-#### step_motor
-
-- [ ] 增加步进电机模块
-
-#### referee_communication
-
-- [ ] 增加裁判系统多机通信功能
-
-#### controller
-
-- [ ] 增加扰动观测器,可能需要新增模块
-- [ ] 增加基于模型的控制器,可能需要新增模块
-
-#### ws2816
-
-- [ ] 通过bsp_pwm添加支持
-
----
-
-## APP
-
-### 待完成
-
-#### all app
-
-- [ ] 增加调试的条件编译,使得在没有连接其他应用时也可以假装有那些应用而正常调试运行
-
-#### ==shoot==
-
-- [ ] 增加卡弹检测和反转
-
-### 待优化
-
-#### robot_cmd
-
-- [ ] 优化消息发布和接收性能(若皆为异步并在robottask中执行,实际上可以只传递指针)
-
-#### gimbal
-
-- [x] 增加底盘速度前馈控制
-
-#### chassis
-
-- [x] 根据电机的实际速度计算底盘的真实运动(轮式里程计)
-- [ ] 若为双板,根据IMU的数据对电机实际速度进行融合
-
diff --git a/.Doc/VSCode+Ozone使用方法.md b/.Doc/VSCode+Ozone使用方法.md
deleted file mode 100644
index 68b37a3..0000000
--- a/.Doc/VSCode+Ozone使用方法.md
+++ /dev/null
@@ -1,1052 +0,0 @@
-# VSCode+Ozone开发STM32的方法
-
-
neozng1@hnu.edu.cn
-
-[TOC]
-
-## 前言
-
-了解过嵌入式开发的你一定接触过Keil,这款20世纪风格UI的IDE伴随很多人度过了学习单片机的岁月。然而由于其缺少代码补全、高亮和静态检查的支持,以及为人诟病的一系列逆天的设置、极慢的编译速度(特别是在开发HAL库时),很多开发者开始转向其他IDE。
-
-IAR、CubeIDE等都是广为使用的“其他”IDE,但是他们也有各自的缺点,不能让笔者满意。作为IDE界的艺术家,JetBrains推出的Clion也在相当程度上完善了对嵌入式开发的支持。不过,在体验过多款IDE后,还是**VSCode**这款高度定制化的编辑器最让人满意。强大的补全和snippet以及代码高亮、定义跳转甩KEIL十条街。
-
-而Ozone则是SEGGER(做jilnk的)推出的调试应用,支持变量实时更新,变量曲线可视化,SEGGER RTT日志,DBG虚拟串口等功能,大大扩展了调试的功能。很多人习惯使用串口进行可视化调试,如vofa,串口调试助手等。然而通过这些方式进行调试,都是对内核有**侵入性**的,会占有内核资源并且导致定时器的时间错乱。由于DBG有单独连接到FLASH和CPU寄存器的高速总线(类似于DMA),可以在不影响程序正常运行的情况下以极高的频率直接获取变量值。
-
-下面,将从工具链介绍、环境配置以及调试工作流三个方面介绍以VSCode为编辑器,Ozone为调试接口的开发环境。
-
-开发的大致流程为:
-
-~~~mermaid
-graph LR
-CubeMX进行初始化 --> VSCode编写代/进行编译/简单调试 --> Ozone变量可视化调试+log
-~~~
-
-***本教程不仅希望教会你如何配置环境,同样会告诉你每一步究竟是在做什么,而不是简单的复制黏贴邯郸学步。***
-
-## 前置知识
-
-1. 计算机速成课:[Crash Course Computer Science](https://www.bilibili.com/video/av21376839/?vd_source=ddae2b7332590050afe28928f52f0bda)
-
-2. 从零到一打造一台计算机:
-
- [编程前你最好了解的基本硬件和计算机基础知识(模拟电路)](https://www.bilibili.com/video/BV1774114798/?spm_id_from=333.788.recommend_more_video.11&vd_source=ddae2b7332590050afe28928f52f0bda)
-
- [编程前你最好了解的基本硬件和计算机基础知识(数字电路)](https://www.bilibili.com/video/BV1Hi4y1t7zY/?spm_id_from=333.788.recommend_more_video.0)
-
- [从0到1设计一台计算机](https://www.bilibili.com/video/BV1wi4y157D3/?spm_id_from=333.788.recommend_more_video.0&vd_source=ddae2b7332590050afe28928f52f0bda)
-
-3. C语言基础:[程序设计入门——C语言](https://www.icourse163.org/course/ZJU-199001?from=searchPage&outVendor=zw_mooc_pcssjg_)
-
-***务必学完以上课程再开始本教程的学习,以及后续的开发。***
-
-万丈高楼不可平地而起,地基不牢只会导致递归学习。
-
-> 如果有可能,还应该学习:[哈佛大学公开课:计算机科学cs50](https://open.163.com/newview/movie/courseintro?newurl=%2Fspecial%2Fopencourse%2Fcs50.html)。你将会对单片机和计算机有不同的理解。
-
-## 预备知识
-
-1. C语言从源代码到.bin和.hex等机器代码的编译和链接过程
-
-3. C语言的内存模型
-
-4. C语言标准,动态链接库和静态编译的区别,一些编译器的常用选项
-
-5. STM32F4系列的DBG外设工作原理
-
-6. GDB调试器、硬件调试器和DBG的关系
-
-### 编译全过程
-
-C语言代码由固定的词汇(关键字)按照固定的格式(语法)组织起来,简单直观,程序员容易识别和理解,但是CPU只能识别二进制形式的指令,并且这些指令是和硬件相关的(感兴趣的同学可以搜索**指令集**相关内容)。这就需要一个工具,将C语言代码转换成CPU能够识别的二进制指令,对于我们的x86平台windows下的程序就是.exe后缀的文件;对于单片机,一般来说是.bin或.hex等格式的文件(调试文件包括axf和elf)。
-
-能够完成这个转化过程的工具是一个特殊的软件,叫做**编译器(Compiler)**。常见的编译器包括开源的GNU GCC,windows下微软开发的visual C++,以及apple主导的llvm/clang。编译器能够识别代码中的关键字、表达式以及各种特定的格式,并将他们转换成特定的符号,也就是**汇编语言**(再次注意汇编语言是平台特定的),这个过程称为**编译(Compile)**。
-
-对于单个.c文件,从C语言开始到单片机可识别的.bin文件,一般要经历以下几步:
-
-
-
-首先是编译**预处理**Preprocessing,这一步会展开宏并删除注释,将多余的空格去除。预处理之后会生成.i文件。
-
-然后,开始**编译**Compilation的工作。编译器会将源代码进行语法分析、词法分析、语义分析等,根据编译设置进行性能优化,然后生成汇编代码.s文件。汇编代码仍然是以助记符的形式记录的文本,比如将某个地址的数据加载到CPU寄存器等,还需要进一步翻译成二进制代码。
-
-下一步就是进行**汇编**Assemble,编译器会根据汇编助记符和机器代码的查找表将所有符号进行替换,生成.o .obj等文件。但请注意,这些文件并不能直接使用(烧录),我们在编写代码的时候,都会包含一些**库**,因此编译结果应当有多个.o文件。我们还需要一种方法将这些目标文件缝合在一起,使得在遇到函数调用的时候,程序可以正确地跳转到对应的地方执行。
-
-最后一步就由链接器Linker(也称LD)完成,称为**链接**Linking。比如你编写了一个motor.c文件和.h文件,并在main.c中包含了motor.h,使用了后者提供的`MotorControl()`函数。那么,链接器会根据编译器生成.obj文件时留下的函数入口地址,将main.o里的调用映射到生成的motor.o中。链接完成后,就生成了单片机可以识别的可执行文件,通过支持的串口或下载器烧录,便可以运行。
-
-> 另外,上图可以看到左侧的**静态库**,包括`.lib .a`,比如我们在STM32中使用的DSP运算库就是这种文件。他在本质上和.o文件相同,只要你在你编写的源文件中包含了这些库的头文件,链接器就可以根据映射关系找到头文件中声明的函数在库文件的地址。(直接提供库而不是.c文件,就可以防止源代码泄露,因此一些不开源的程序会提供函数调用的头文件和接口具体实现的库;你也可以编写自己的库,感兴趣自行搜索)
-
-链接之后,实际上还要进行不同代码片段的重组、地址重映射,详细的内容请参看:[C/C++语言编译链接过程](https://zhuanlan.zhihu.com/p/88255667),这篇教程还提供了以GCC为例的代码编译示例。
-
-### C语言内存模型
-
-
-
-以上是C语言常见的内存模型,即C语言的代码块以及运行时使用的内存(包括函数、变量等)的组织方式。
-
-> 有些平台的图与此相反,栈在最下面(内存低地址),其他区域都倒置,不影响我们理解
-
-**代码段**即我们编写的代码,也就是前面说的编译和链接之后最终生成的可执行文件占据的空间。一些常量,包括字符串和使用`const`关键字修饰的变量被放在常量存储区。`static`修饰的静态变量(包括函数静态变量和文件静态变量)以及全局变量放在常量区上面一点的全局区(也称静态区)。
-
-然后就是最重要的**堆**和**栈**。在一个代码块内定义的变量会被放在栈区,一旦离开作用域(出了它被定义的`{}`的区域),就会立刻被销毁。在调用函数或进入一个用户自定义的`{}`块,都会在栈上开辟一块新的空间,空间的大小和内存分配由操作系统或C库自动管理。**一般来说,直接通过变量访问栈内存,速度最快**(对于单片机)。而堆则是存储程序员自行分配的变量的地方,即使用`malloc(),realloc() ,new`等方法获取的空间,都被分配在这里。
-
-> 在CubeMX初始化的时候,Project mananger标签页下有一个Linker Setting的选项,这里是设置最小堆内存和栈内存的地方。如果你的程序里写了大规模的数组,或使用`malloc()`等分配了大量的空间,可能出现栈溢出或堆挤占栈空间的情况。需要根据MCU的资源大小,设置合适的stack size和heap size。
-
-RTOS创建任务的时候也会为每个任务分配一定的栈空间,它会替代MCU的硬件裸机进行内存的分配。可以在CubeMX中设置。如果一个任务里定义了大量的变量,可能导致实时系统运行异常,请增大栈空间。
-
-> 开发板C型使用F407IG芯片,片上RAM的大小为1MB。
-
-### C language标准和编译器
-
-不同的C语言标准(一般以年份作代号)支持的语法特性和关键字不同,拥有的功能也不同。一般来说语言标准都是向前兼容的,在更新之后仍然会保存前代的基本功能支持(legacy support)。不过,为了程序能够正常运行,我们还需要一些硬件或平台支持的组件。比如`malloc()`这个函数,在linux平台和windows平台上的具体实现就相去甚远,跟单片机更是差了不止一点。前两者一般和对应的操作系统有关,后者在裸机上则是直接通过硬件或ST公司提供的硬件抽象层代码实现。
-
-然而,不同编译器提供的代码实现也不尽相同,比如使用clang和gcc这两种c语言编译器,他们对于一些标准库(也称C库,包括stdio,stdlib,string等在内的实现)的函数的实现就不太一样。再如`__packed`是arm-cc提供的一个字节不对齐关键字,在一些其他编译器中就不支持这种实现。
-
-以前大家常用的KEIL使用的是ARM提供的arm-cc工具链(非常蛋疼,甚至不支持uint8_t=0b00001111这种二进制定义法),而该教程选用的是开源的**Arm GNU Toolchain**。在非目标机且和目标机平台不同的平台上进行开发被成为**跨平台开发**,进行的编译也被成为**交叉编译**(在一个平台上生成另一个平台上的 可执行代码)。
-
-> 工具链包含了编译器,链接器以及调试器等开发常用组件。我们使用的Arm GNU toolchain中,编译器是`arm-none-eabi-gcc.exe`,链接器是`arm-none-eabi-ld.exe`,调试器则是`arm-none-eabi-gdb.exe`。通过跨平台调试器和j-link/st-link/dap-link,我们就可以在自己的电脑上对异构平台(即单片机)的运行进行调试了。
-
-==***特别注意,在新框架中我们使用的是arm-none-eabi-gcc,此编译器不支持`__packed`关键字,若要进行字节压缩(不对齐字节),应该使用预编译指令`#pragma pack(1)`***==。
-
-### Debug外设工作原理
-
-
-
-DBG支持模块(红框标注部分,也可以看作一个外设)通过一条专用的AHB-AP总线和调试接口相连(Jtag或swd),并且有与**数据**和**外设**总线直接相连的桥接器。它还同时连接了中断嵌套管理器(因此同样可以捕获中断并进行debug)和ITM、DWT、FPB这些调试支持模块。因此DBG可以直接获取内存或片上外设内的数据而不需要占用CPU的资源,并将这些数据通过专用外设总线发送给调试器,进而在上位机中读取。
-
-FPB是flash patch breakpoint闪存指令断点的缩写,用于提供代码断点插入的支持,当CPU的指令寄存器读取到某一条指令时,FPB会监测到它的动作,并通知TPIU暂停CPU进行现场保护。
-
-DWT是data watch trace数据观察与追踪单元的缩写,用于比较debug变量的大小,并追踪变量值的变化。当你设定了比较断点规则(当某个数据大于/小于某个值时暂停程序)或将变量加入watch进行查看,DWT就会开始工作。DWT还提供了一个额外的计时器,即所有可见的TIM资源之外的另一个硬件计时器(因为调试其他硬件定时器的计时由于时钟变化可能定时不准,而DWT定时器是始终正常运行的)。它用于给自身和其他调试器模块产生的信息打上时间戳。我们的bsp中也封装了dwt计时器,你可以使用它来计时。
-
-ITM是instrument trace macrocell指令追踪宏单元的缩写,它用于提供非阻塞式的日志发送支持(相当于大家常用的串口调试),SEGGER RTT就可以利用这个模块,向上位机发送日志和信息。这个硬件还可以追踪CPU执行的所有指令,这也被称作**trace**(跟踪),并将执行过的指令全部通过调试器发送给上位机。当debug无法定位bug所在的时候,逐条查看cpu执行的指令是一个绝佳的办法,特别是你有大量的中断或开启了实时系统时。
-
-以上三个模块都需要通过TPIU(trace port interface unit)和外部调试器(j-link等)进行连接,TPIU会将三个模块发来的数据进行封装并通过DWT记录时间,发送给上位机。
-
-### GDB调试MCU原理
-
-
-
-不论使用MDK(KEIL)还是VSCode还是Ozone,实际上背后的流程相同。首先GDB会建立TCP/IP端口并提供接口,调试服务器(Server)作为硬件调试器和GDB软件的桥梁,将硬件调试器的相关功能(也就是DBG外设支持的那些功能)映射到GDB的接口上(通过连接到GDB建立的端口)。之后启动调试,将可执行文件下载到目标MCU上,然后从main开始执行
-
-> 当然你也可以选择从其他启动点开始执行,调试器开始执行的位置叫做**entry point**。同样,在MCU已经正在运行程序的时候,可以**attach**到程序上开始监控(attach=附加,贴上;很形象了)。
-
-> 而对于直接运行在电脑上的程序(.exe),就不需要GDBserver和物理调试器,GDB程序可以直接访问电脑上运行的程序和CPU的寄存器等。
-
-### 字节对齐
-
-这是内存硬件设计和汇编语言设计的结果。在使用结构体的时候,如果你不做任何事情,编译器会自动帮助你完成字节对齐以提高内存访问的效率。stm32是4字节地址和数据总线的设计,单词可以传输32位数据,因此,访问4字节数据(也就是stm32的“字”,“字长”)效率最高。然而,历史的缘由导致一个内存地址只存储8位的数据,如果你要访问float数据,则一次需要读取4个地址。当这四个地址是连续的时候,你只需要一次就可以将数据读出。然而,如果一个float数据被存放在0x03-0x07这四个地址,cpu首先要读出0x00-0x03这四个连续的地址,然后再取出最后一个字节;随后读取0x04-0x07这四个连续的字节,再取出前三个字节;最后将最后一个字节和前三个字节拼接在一起,形成我们需要的float数据。
-
-`#pragma`可能是最复杂的预编译指令,不同的编译器支持不同的`#pragma`指令,如常用的`#pragma once`可以替代header guard。arm gnu gcc编译器支持通过`#pragma pack()`来设置字节对齐,支持的对齐参数包括空/1/2/4/8,会启动对应长度的对齐方式。用于通信的结构体(串口/CAN/spi等外设接收数据的时候都是连续的,不会像结构体一样被编译器对齐)在声明时,采用如下的方式:
-
-```c
-#pragma pack(1) // 从这句话开始,使用字节对齐(1),即紧凑,关闭对齐
-
-typedef struct
-{
- uint8_t id;
- // ...
-
-} CANInstance;
-
-#pragma pack() // 从这里开始,恢复默认配置,一般来说默认配置是 pack(4),如果遇到double/longlong等也会变为8字节对齐
-// 使用两个#pragma包裹你的结构体声明
-```
-
-如果您有兴趣,可以了解一下内存硬件的组织和连接方式,包括奇偶地址/片选/行列扩展等,可以帮助你更好地理解字节对齐。
-
-## 环境配置
-
-> ***所有需要编辑的配置文件都已经在basic_framework的仓库中提供,如果不会写,照猫画虎。***
-
-- **软件安装**
-
-队伍NAS和资料硬盘内提供了所有必要的依赖,安装包和插件,目录是`/EC/VSCode+Ozone环境配置`,请以公共账号登陆网盘,ip地址为`49.123.113.2:5212`,账号`public@rm.cloud`,密码`public`。
-
-对于非队内的开发者,我们提供了网盘下载方式。所有安装包也可以在此百度网盘链接下获得:[archive.zip](https://pan.baidu.com/s/1sO_EI4cToyIAcScOQx-JSg?pwd=6666)
-
-```shell
-# 网盘中的文件:
-basic_framework.zip # 本仓库文件,注意为了保证最新,建议从仓库clone并定时pull(或自动fetch)
-daplink_register_license.rar # daplink license注册机
-gcc-arm-none-eabi-10.3-2021.10-win32.zip # arm-gnu-toolchain,注意,这个版本太老,编译最新的框架可能出现一些编译参数不支持的情况。请通过Msys2直接安装或到arm官网下载最新的12.x版本。
-JLinkARM.dll # 修改过的jlink运行链接库
-JLink_Windows_V722b.exe # JLink软件包
-mingw-get-setup.exe # mingw工具链(更推荐的方式是使用msys2安装)
-OpenOCD.zip # OpenOCD
-Ozone_doc.pdf # Ozone使用手册
-Ozone_Windows_V324_x86.exe # Ozone安装包
-VSCodeUserSetup-x64-1.73.1.exe # VSCode安装包
-# 最佳实践是下载msys2并在mingw64中安装软件包!!!
-# 如果你喜欢clang,可以使用clang下的arm工具链。
-```
-
-> 2022-12-01更新:
->
-> **VSCode上线了一款新的插件:**
->
-> 
->
-> 支持一键配置Arm GNU工具链、MinGW64(make工具)和OpenOCD!可以尝试使用这个插件替代下面的配置流程。并且,此插件还提供了一键下载、一键调试的支持,只需要选择合适的下载器配置即可,全部都是图形化界面的操作!
->
-> 你可以尝试使用这个插件进行环境的配置。当然,环境变量仍然需要手动添加。
->
-> ==**另外,如果你不想配置太多东西也不想了解底层的信息,可以尝试Embedded IDE插件。它支持直接在VSCode中编辑KEIL MDK的项目,相关信息请自行查阅,或直接查看EIDE的项目网站:**==[https://em-ide.com](https://em-ide.com/)
-
-- 安装STM32CubeMX,并安装F4支持包和DSP库支持包
-
-- 安装VSCode,并安装以下插件:
-
- - **C/C++**:提供C/C++的调试和代码高亮支持
- - **Better C++ Syntax**:提供更丰富的代码高亮和智能提示
- - **C/C++ Snippets**:提供代码块(关键字)补全
- - **Cortex-Debug**,**Cortex-Debug: Device Support Pack - STM32F4**:提供调试支持。cortex debug还会自动帮助你安装一些调试相关的插件,包括RTOS支持和内存查看等。
- - **IntelliCode**,**Makfile Tools**:提供代码高亮支持。喜欢clang的同学可以使用clangd。
-
- 
-
- 
-
- 
-
- 
-
- 
-
- > MinGW、Arm GNU toolchain和OpenOCD也可以通过**MSYS2**使用pacman包管理器(和apt/yum类似)直接安装,这种方法一步到位,**==这是更推荐使用的方式==**,请参看[附录5](##附录5:利用MSYS2安装依赖环境)。
- >
- > **当然,你也可以直接按照下面的方法安装这两个工具。**不过,强烈推荐使用附录5中的方法。下面的方法将在发布完整版更新的时候被删除。
-
-- 安装MinGW,等待界面如下:(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除)
-
- 
-
- 安装好后,打开MinGW后将所有的支持包勾选,然后安装:
-
- 
-
- 
-
- 安装完以后,将MinGW的bin文件夹添加到环境变量中的path下,按下菜单键搜索**编辑系统环境变量**打开之后:
-
- 
-
- 图片看不清请打开原图。验证安装:
-
- 打开命令行(win+R,cmd,回车),输入`gcc -v`,如果没有报错,并输出了一堆路径和参数说明安装成功。
-
- 安装完之后,建议将ming的bin文件夹下的mingw32-make.exe复制一份,并将copy更名为make.exe
-
- > 当然,更推荐的方式是将MinGW终端集成到VSCode中,防止类linux环境和Win的环境冲突,特别是你的电脑中安装了其他工具链的时候,如MSVC、LLVM等。
-
-- 配置gcc-arm-none-eabi环境变量,**把压缩包解压以后放在某个地方**,然后同上,将工具链的bin添加到PATH:(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除)
-
- 
-
- 安装路径可能不一样,这里要使用你自己的路径而不是直接抄
-
- 验证安装:
-
- 打开命令行,输入`arm-none-eabi-gcc -v`,如果没有报错,并输出了一堆路径和参数说明安装成功。
-
-> 添加到环境变量PATH的意思是,当一些程序需要某些依赖或者要打开某些程序时,系统会自动前往PATH下寻找对应项。**一般需要重启使环境变量生效。**
-
-**若你不希望扰乱系统的环境变量,可以参照附录5将Msys2/MinGW64的终端集成到VSCode中方便开发**。
-
-- **将OpenOCD解压到一个文件夹里**,稍后需要在VSCode的插件中设置这个路径。(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除)
-
-- **CubeMX生成代码**:
-
- 在project manager标签页工具链选择makefile
-
- 
-
- 生成的目录结构如下:
-
- 
-
- Makefile就是我们要使用的构建规则文件。
-
- > **如果你使用basic_framework,不需要重新生成代码。**
-
-- **建议将ozone和jlink的目录一同加入环境变量,方便我们后续的一键下载和一键调试配置**
-
-## VSCode编译和调试配置
-
-VSCode常用快捷键包括:
-
-| 功能 | 快捷键 |
-| ---------------------- | ------------- |
-| 选中当前行 | Ctrl+L |
-| 删除当前行 | Ctrl+Shift+K |
-| 重命名变量 | F2 |
-| 跳转到定义 | Ctrl+点击 |
-| 在打开的文件页中切换 | Ctrl+Tab |
-| 在当前文件查找 | Ctrl+F |
-| 在整个项目文件夹中查找 | Ctrl+Shift+F |
-| 查找所有引用 | Alt+Shift+F12 |
-| 返回上一动作 | Alt+左 |
-
-更多快捷键可以按ctrl+K再按ctrl+S显示,并且可以修改成你最习惯的方式。此外,使用Snippets可以大幅度提高重复性的代码编写速度,它可以直接帮你补全一个代码块(如for、while、switch);补全和snippet都使用`Tab`键接受代码提示的提议,通过↑和↓键切换提示。
-
-### 编译
-
-为了提供完整的代码高亮支持,需要配置Makefile tools插件的make程序路径,`ctrl+,`打开设置,搜索make path找到设置并填写:
-
-
-
-> mingw32-make就是下面介绍的make工具(配合makefile替代手动调用gcc)。这里之所以只要输入mingw32-make而不用完整路径,是因为我们将mingw的bin文件夹加入环境变量了,因此系统会在PATH下自动寻找对应项
-
-用VSCode打开创建的项目文件夹,**Makefile Tools插件会询问你是否帮助配置intellisense,选择是。**
-
-此时就可以享受intellicode带来的各种便利的功能了。我们的项目使用Makefile进行编译,在之前的编译介绍中,以GCC编译器为例,如果需要编译一个文件,要输入如下命令:
-
-```shell
-gcc your_source_code_name.c -o output # your_source_code_name是待编译的文件名
-```
-
-然而,你面对的是一个拥有几百个.c和.h文件以及大量的链接库,如果要将所有文件都输入进去,那将是一件苦恼的事。Makefile在gcc命令上提供了一层抽象,通过编写makefile来指定参与编译的文件和编译选项,再使用`make`命令进行编译,它会自动将makefile的内容“翻译”为gcc命令。这样,编译大型项目就不是一件困难的事了。更多关于makefile的指令介绍,参见[附录3](##附录3:Makefile指令介绍)。
-
-> 实际上,在使用keil MDK开发的时候,它调用的仍然是底层的arm cc工具链中的编译器和链接器,在配置“魔术棒”添加项目文件以及包含目录的时候,实际做的使其和makefile差不多。keil使用的参数可以在魔棒的C/C++选项卡下看到。
-
-对于一个已经拥有makefile的项目,打开一个终端,输入:
-
-```shell
-mingw32-make -j24 # -j参数表示参与编译的线程数,一般使用-j12
-```
-
-> 注意,多线程编译的时候输出的报错信息有时候可能会被打乱(多个线程同时往一个terminal写入程序运行的信息),要是看不清报错,请使用`mingw32-make`,不要进行多线程编译。
->
-> 我对make的编译命令进行了静默处理,只输出error和warning以及最后的生成文件信息。如果想要解除静默(就是下面所说的“你可以看到大致如下的输出”),需要修改Makefile。**本仓库下的makefile中已经用注释标明。**
-
-
-
-就会开始编译了。你可以看到大致如下的输出:
-
-```shell
-arm-none-eabi-gcc -c -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -DUSE_HAL_DRIVER -DSTM32F407xx -DARM_MATH_CM4 -DARM_MATH_MATRIX_CHECK -DARM_MATH_ROUNDING -IHAL_N_Middlewares/Inc -IHAL_N_Middlewares/Drivers/STM32F4xx_HAL_Driver/Inc -IHAL_N_Middlewares/Drivers/STM32F4xx_HAL_Driver/Inc/Legacy -IHAL_N_Middlewares/Drivers/CMSIS/Device/ST/STM32F4xx/Include -IHAL_N_Middlewares/Drivers/CMSIS/Include -IHAL_N_Middlewares/Drivers/CMSIS/DSP/Include -IHAL_N_Middlewares/Middlewares/ST/STM32_USB_Device_Library/Core/Inc -IHAL_N_Middlewares/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc -IHAL_N_Middlewares/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS -IHAL_N_Middlewares/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F -IHAL_N_Middlewares/Middlewares/Third_Party/FreeRTOS/Source/include -IHAL_N_Middlewares/Middlewares/Third_Party/FreeRTOS/Source/include -IHAL_N_Middlewares/Middlewares/Third_Party/SEGGER/RTT -IHAL_N_Middlewares/Middlewares/Third_Party/SEGGER/Config -IHAL_N_Middlewares/Middlewares/ST/ARM/DSP/Inc -Iapplication -Ibsp -Imodules/algorithm -Imodules/imu -Imodules/led_light -Imodules/master_machine -Imodules/motor -Imodules/referee -Imodules/remote -Imodules/super_cap -Og -Wall -fdata-sections -ffunction-sections -g -gdwarf-2 -MMD -MP -MF"build/stm32f4xx_hal_pwr_ex.d" -Wa,-a,-ad,-alms=build/stm32f4xx_hal_pwr_ex.lst HAL_N_Middlewares/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c -o build/stm32f4xx_hal_pwr_ex.o
-```
-
-仔细看你会发现,make命令根据makefile的内容,调用arm-none-eabi-gcc编译器,传入了一堆的参数以及编译选项然后运行。
-
-最后输出的结果如下:
-
-```shell
- text data bss dec hex filename
- 31100 484 35916 67500 107ac build/basic_framework.elf
-arm-none-eabi-objcopy -O ihex build/basic_framework.elf build/basic_framework.hex
-arm-none-eabi-objcopy -O binary -S build/basic_framework.elf build/basic_framework.bin
-```
-
-由于使用了多线程编译,比KEIL的蜗牛单线程要快了不少。以上内容代表了生成的可执行文件的大小以及格式和内容。.elf文件就是我们需要传递给调试器的东西,在[使用VSCode调试](###简单调试)部分会介绍。典型的编译时间大致如下:
-
-1. 从零开始重新编译:~10s
-2. 修改文件后编译:~3s
-
-当然了,你可能觉得每次编译都要在命令行里输入参数,太麻烦了。我们可以编写一个`task.json`,这是VSCode的一个任务配置,内容大致如下:
-
-```json
-{
- // See https://go.microsoft.com/fwlink/?LinkId=733558
- "version": "2.0.0",
- "tasks": [
- {
- "label": "build task", // 任务标签
- "type": "shell", // 任务类型,因为要调用mingw32-make,是在终端(CMD)里运行的,所以是shell任务
- "command": "mingw32-make -j24",// 要执行的任务命令
- "problemMatcher": [],
- "group": {
- "kind": "build",
- "isDefault": true
- }
- }
- ]
-}
-```
-
-这样,你就可以点击VSCode工具栏上方的Terminal->Run task选择你刚刚配置的任务开始编译了。**更方便的方法是使用快捷键:`ctrl+shift+B`。** 之后要配置下载任务和调试任务等,也可以利用这种方法,新建一个xxx_task,实现一键下载、一键调试等。
-
-
-
-> 还没配置任务的时候,需要在Terminal标签页中选择Configure Tasks... 创建一个新的.json文件。
->
-> P.S. VSCode中的大部分配置都是通过json文件保存的。当前工作区的配置在项目文件夹中的.vscode下,全局配置在设置中修改。全局配置在当前工作区没有配置的时候会生效,反之被前者覆盖。
-
-### 如果你编写了新的代码文件
-
-Makefile的大部分内容在CubeMX初始化的时候就会帮你生成。如果新增了.c的源文件,你需要在`C_SOURCES`中新增:
-
-
-
-换行需要在行尾加反斜杠\\
-
-如果新增了头文件,在`C_INCLUDES`中新增头文件所在的文件夹:
-
-
-
-换行需要在行尾加反斜杠\\
-
-**添加完之后,重新编译即可**。
-
-> 和KEIL新增文件的方式很相似,但是更方便。
-
-
-- **另外**,如果你使用的时linux/Unix like/MacOS,则可以直接使用根目录下的Makefile.upgrade(复制替换到Makefile中),我们在其中定义了递归添加源文件和头文件目录的规则,不再需要手动添加新增的源文件和头文件路径。如果你使用windows+mingw/Msys2,则需要在mingw环境下执行编译指令,否则报错(因为makefile中使用了一些shell指令是cmd和powershell不支持的,后续考虑在makefile中添加os判断规则以自动替换目录查找指令)。若你坚持使用cmd/powershell,请参照`Makefile.upgrade`中的注释将makefile修改为对应指令格式以支持该环境下的使用。
-
-### 简单的调试配置
-
-> 在VSCode中调试不能像Keil一样查看变量动态变化,但是支持以外的所有操作,如查看外设和反汇编代码,设置断点触发方式等。
->
-> **用于调试的配置参考这篇博客**:[Cortex-debug 调试器使用介绍](https://blog.csdn.net/qq_40833810/article/details/106713462),这里包含了一些背景知识的介绍。你也可以直接查看下面的教程。
-
-> ❗❗❗***==注意==***❗❗❗
->
-> **如果你的用户名是中文,请先按照[附录6](##附录6:Windows修改用户名为英文)将自己的用户名改成英文。**
-
-你需要配置**arm gnu工具链的路径**(工具链包括编译器、链接器和调试器等),**OpenOCD的路径**(使得GDB调试器可以找到OpenOCD并调用它,从而连接硬件调试器如j-link等),**JlinkGDBServer**的路径,以及该工作区(文件夹)的**launch.json文件**(用于启动vscode的调试任务)。
-
-VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
-
-1. 搜索**armToolchainPath**,设置你的arm gcc toolchain的`bin`文件夹。bin是binary的缩写,实际上文件夹内部是一些可执行文件,整个工具链都在这里(注意该文件夹是刚刚解压的**arm gcc toolchain的根目录**下的bin文件夹,里面有很多以arm-none-eabi为前缀的可执行文件)。此路径必须配置。
-2. 搜索**openocdPath**,设置你的openocd路径(需要包含到openocd的可执行文件)。使用daplink调试需要配置这个路径。
-3. 搜索**JLinkGBDServer**,设置JlinkGDBServerlCL.exe的路径(在Jlink安装目录下,CL代表command line命令行版本)。使用jlink调试需要配置这个路径。
-
-**注意**,windows下路径需要使用两个反斜杠`\\`代表下一级文件夹。
-
-> 如果你使用附录5中的方法安装,前两个的路径都在Msys2/mingw64/bin下。
-
-***其他配置需要的文件已经全部在basic_framework中提供***,包括`openocd.cfg STM32F407.svd .vscode/launch.json`。
-
-
-
-主要需要配置这三个路径,第四个gdbPath可以选配
-
-如果教程中的启动json文件看不懂,请看仓库里的`.vscode`下的`launch.json`,照葫芦画瓢。注意把我写的路径替换掉或注释掉。`launch.json`已经添加了详细的注释。
-
-根目录下已经提供了C板所需的.svd和使用无线调试器时所用的openocd.cfg配置文件。
-
-然后选择run and debug标签页,在选项中选择你配置好的选项,开始调试。**或者使用快捷键:`F5`。**
-
-
-
-我们的仓库中默认提供了两种下载器的支持,dap-link(无线调试器属于这一种)和j-link(包括小的j-link OB和黑色大盒子jlink)。
-
-### 调试介绍
-
-开始调试后,显示的界面如下:
-
-
-
-1. 变量查看窗口,包括当前调用栈(当前作用域或代码块)内的局部变量、当前文件的静态变量和全局变量。register选项卡可以查看cpu内核的寄存器数值。
-
-2. 变量watch窗口。右键单击要查看的变量,选择watch加入查看。
-
- 
-
- 还支持直接运行到指针所选处(Run to Cursor)以及直接跳转到指针处执行(Jump to Cursor)。添加行内断点(若一个表达式由多个表达式组成)也是很方便的功能,可以帮助进一步定位bug。
-
- 右键点击添加到watch窗口的变量,**可以临时修改它们的值。**调参的时候非常好用。
-
- VSCode提供的一个最大的便利就是,你可以将鼠标悬停在需要查看的变量上,**不需要添加到watch就能观察变量值。**如果是指针还可以自动解析,获取解引用后的值。结构体也支持直接展开。
-
- 
-
- > **现在Cortex-Debug插件也已经支持live watch(变量动态监视)**,最高可设置的刷新频率为4Hz,足堪大用,我们可以宣告KEIL的时代已经落幕!但是更复杂,更高频率的变量观测以及可视化功能还是需要通过ozone完成。
-
-3. 调用栈。表明在进入当前代码块之前调用了哪些函数,称之为栈也是因为调用的顺序从下至上。当前函数结束之后栈指针会减小,控制权会返还给上一级的调用者。通过调用栈可以确认程序是**如何**(按怎样的顺序)运行到当前位置的。
-
-4. 片上外设。这里可以查看外设的**控制寄存器**和**状态寄存器**的值,如果通过断点无法定位bug,则需要查找数据手册和Cortex M4指南的相关内容,根据寄存器值来判断程序当前的情况。
-
-5. 断点。所有添加的断点都会显示于此,注意,不像我们自己的电脑,单片机的DBG外设对断点的数量有限制(资源所限),超过5个断点会导致debug失败,此时将断点减少即可。由于单行代码编译之后可能会对应多条汇编指令,或一条表达式由多个表达式构成,你还可以插入**行内断点**以逐个执行表达式或汇编语句,你还可以在汇编窗口插入断点调试汇编代码,帮助你发现错误。
-
- 对于不方便判断何时需要停止代码执行进行观察和测试的情况,你可以右键行号左侧的断点栏插入条件断点,输入表达式,当表达式满足时才会进入断点。
-
-6. 调试控制台。调试器输出的信息会显示在这里,要**查看**和**追踪**的变量的信息也会显示在这里。如果调试出现问题,报错信息同样也会在这里显示。要是出现异常,可以复制这里的信息在搜索引擎里查找答案,不过最好的方法是查询gdb和openocd的官方文档。
-
-7. 调试控制。
-
- - 复位:单片机复位
- - 继续运行/暂停
- - 单步跳过,如果这一行有函数调用,不会进入内部
- - 进入,如果这一行有函数调用,会进入函数内部
- - 跳出,跳出当前调用栈顶层的函数,即如果在函数内部会直接运行到return
- - 重启调试器(当然单片机也会复位,一般出现异常的时候使用这个按钮)
- - 终止调试
-
-> **如果你希望在编译之后立刻启动调试**,不要分两次点击,你可以在`launch.json`中添加一个`prelaunchtask`(意为在启动调试之前要运行的任务),将他设置为我们在[编译章节](###编译)介绍的构建任务。我们已经提供了这个选项,取消注释即可使用。
->
-> 如果你想在VSCode中也使用segger RTT viewer的功能(即bsp_log提供的日志功能),请参阅[附录2](##附录2:在VSCode中启用SEGGER RTT日志)。
->
-> 如果想直接下载代码不想调试,参阅[附录4](##附录4:VSCode直接烧录代码)。
-
-### RTT Viewer日志功能
-
-> 2023/07/23:补充,Cortex-Debug插件最近似乎集成了RTT Viewer的支持,只需要设置好RTT client的路径,便可以一键启动RTT终端,查看串行调试器中发送的内容。还支持以一定的格式将RTT发来的内容进行可视化(示波器),但支持程度不如Ozone。可以自行查看插件的wiki和文档进行配置。
-
-本框架添加了vscode下Segger RTT client的支持。在`.vscode/task.json`中已经添加了启动rtt viewer client的任务。你也可以将此任务作为附加启动任务和调试一起启动,方便查看日志。要使用日志,请包含`bsp_log.h`。注意,需要将jlink的安装目录添加到环境变量中。
-
-### 更好的编辑体验
-
-建议安装以下插件:
-
-1. Hex Hover Converter,鼠标悬停在数值上的时候会自动显示其对应的16、2、10进制值和编码
-
-2. Hex Editor,在查看汇编代码和机器代码的时候,提供2、10、16进制转换,并且可以以16进制或2进制的格式编辑文件。
-
-3. GitLens和git graph,提供强大的可视化commit记录和UI支持
-
-4. Blockman - Highlight Nested Code Blocks 此插件会高亮嵌套的代码块(即花括号包围的部分或for/while/ifelse代码块),对于多层条件和循环嵌套效果非常炸裂
-
-5. bookmark 提供代码中插入书签的功能,从而快速在页面间跳转。
-
-6. Code Issue Manager,为团队提供issues和todo管理,方便协同开发
-
-7. github copilot:超强,超快,需要一些小钱(10块用一年!你也可以在github上申请student pack,需要学信网认证和学生卡,但有一定概率无法通过) 在插件中你也可以找到一些免费的copilot替代品。推荐配合copilot labs一起使用,其支持解释选中代码、修复选中代码中的bug、增加选中代码可读性、提高选中代码的稳定性等功能,可以在你编写完代码后,根据之前的代码记录和你的编写习惯,高效地重构/优化/debug你的代码,还可以一键生成文档和注释!(文档仅作参考,你还是需要修改它自动以提高准确性)
-
-8. `ctrl+k ctrl+s`配置属于你的快捷键,提高效率!
-
-9. live share,和你的小伙伴一起结对编程
-
----
-
----
-
-## Ozone可视化调试和LOG功能
-
-> ~~Ozone暂时只支持jlink。~~
->
-> 22/11/16**重要更新**:安装Ozone3.24 32-bit和J-Link7.22b目前可以支持Jlink和**dap-link(包括ATK无线调试器)**
-
-### 软件安装
-
-安装Ozone和J-link工具箱(驱动、gdb以及各种调试工具)。安装包都在网盘里。
-
-**注意,如果希望支持daplink(包括正点原子无线调试器),请务必安装网盘对应的版本(Ozone3.24 32-bit和J-Link7.22b)。**
-
-> 经过测试发现只有32位的ozone3.24支持daplink。
-
-应该先安装Ozone,再安装jlink。以下为步骤:
-
-1. 安装Ozone
-
- 
-
- 这一步注意选择install a new instance(安装一个新的实例)。后续一路确认即可。
-
-2. 安装jlink
-
- 
-
- 这一步注意不要勾选update dll in other application,否则jlink会把ozone里面老的驱动和启动项替代掉。choose destination和ozone一样,选择install a new instance。如果安装了老的相同版本的jlink,请先卸载(版本相同不用管,直接新装一个)。
-
-3. **替换动态链接库**
-
- **将网盘上下载的`JLinkARM.dll`放到JLink和Ozone的安装目录下,替换原来的库。下载下来的库经过修改,使得J-LinkOB在使用的时候不会报“The JLink is defective"和”you are using a clone version“的错误。**
-
- **之后如果安装其他版本的jlink,也请注意*==不要勾选==*update DLL in other application,否则会替换掉修改过的动态链接库。**
-
-### 配置调试项目
-
-安装好两个软件之后,打开ozone后会显示一个new project wizard,如果没有打开,在工具栏的File-> New -> New project wizard。
-
-
-
-选择M4内核,为了能够查看外设寄存器的值还需要svd文件。所有mcu的svd都在图中的文件夹里提供,当然你也可以使用我们仓库根目录下的文件。
-
-
-
-接口选择swd,接口速度不需要太高,如果调试的时候需要观察大量的变量并且使用日志功能,可以调高这个值。如果连接了jlikn,上面的窗口中会显示。如果链接了dap-link,比如无线调试器,会出现Unknown CMSIS-dap。选择你要使用的调试器,然后继续。
-
-
-
-选择构建之后生成的.elf文件(在项目文件夹下的build中)。这是调试器专用的文件格式,对其内容感兴趣可以自行搜索细节。此外ozone还支持.bin .hex .axf(最后一个是amr-cc,也就是keil的工具链会生成的)等格式。
-
-
-
-这页不要动。如果希望保存jlink的调试日志,最后一个选项选择一个文件或者新建一个日志文件。
-
-### 启用FreeRTOS支持
-
-注意,如果你的代码使用了实时系统,在载入项目的时候Ozone会进行对应的提示。选择载入支持实时系统的插件即可。
-
-如果没有提示,请在console中输入下面的命令然后回车即可:
-
-```shell
-Project.SetOSPlugin(“plugin_name”)
-# plugin_name是启用的实时系统支持插件名
-# 我们要使用的命令是Project.SetOSPlugin ("FreeRTOSPlugin_CM4")
-```
-
-支持的插件在Ozone的安装目录下的`Plugins/OS`目录:
-
-
-
-我们的项目是F4的板子,内核时Cortex-M4(CM4),因此选用`FreeRTOSPlugin_CM4.js`(输入的时候js后缀不用输)。 ozone默认输入的命令似乎有误,需要手动修改(这好像和ozone的版本有关,请留意)
-
-### 常用调试窗口和功能
-
-下图的配置是笔者常用的layout。每个窗口是否显示、放在什么位置等都是可以自己定义的。通过工具栏的view选项卡可以自行选择需要展示的窗口。
-
-
-
-1. 调试控制:和vscode类似
-
-2. 变量watch窗口,这里的变量不会实时更新,只有在暂停或遇到断点的时候才会更新。若希望实时查看,在这里右键选择需要动态查看的变量,选择Graph,他就会出现在**窗口8**的位置。
-
- 如果不需要可视化查看变量变化的趋势,但是想不暂停查看变量的值,请右键点击变量,选择一个合适的refresh rate:
-
- 
-
- 如果是一个结构体,你可以为整个结构体都进行刷新率的配置,不需要手动一个个修改。**或直接右键点击窗口**,将refresh打勾:
-
- 
-
-3. 断点和运行追踪管理
-
-4. 调试控制台,输出调试器的信息。
-
-5. 终端,支持一些jlink script的命令。**单片机通过log模块发送的日志也会显示在这里。**
-
-6. 代码窗口,用于添加断点、添加查看等。鼠标悬停在变量上可以快速查看变量值和类型。希望打开整个项目文件,点击工具栏的view选项卡,单击Source Files就可以打开一个项目中所有源文件的窗口。右键点击函数或变量可以跳转到定义和声明、查看汇编代码等。按**F12**跳转到定义。
-
-7. **变量可视化窗口,这就是Ozone的大杀器。**在变量添加到查看(watch)之后,右键点击watch中的变量选择Graph,变量会被添加到可视化查看中。你可以选择“示波器”的显示时间步长以及颜色等信息,还可以更改采样率。
-
- **注意,如果添加到动态调试窗口中没有反应,请在窗口8中修改一下”Sample Freq“为100Hz或200Hz即可**。
-
-8. 窗口8和7配合。在窗口8中会实时显示变量值,并且统计平均值和最大最小值,**而且还会将所有采样值保存到一个csv文件当中**,如果需要进一步分析可以导出这个数据文件。若要进行系统辨识、前馈设计等,这无疑是最好的方法。这还可以方便我们观察采样值的异常,进一步提升debug的效率。
-
-9. 内存视图。可以直接查看任意内存位置的值。
-
-> 再次注意,这些窗口是否开启以及位置都是可以自定义的。
->
-> **另外,如果使用dap-link,调试过程中可能会反复提示没有license,请查阅[附录1](##附录1:为daplink添加license)获取解决方案。**
-
-如果在调试过程中发现bug或者需要更改代码,不需要终止调试或者关闭窗口。直接前往vscode修改并重新编译,Ozone会自动检测到.elf文件的变化,询问你是否重新加载项目。选择是后会自动开始下载并进入调试。
-
-- **变量动态查看(可视化)**
-
- - **在变量的watch窗口右键点击变量,选择一个refresh rate也可以实时查看变量(和keil一样)。**
-
- - 如果没有打开窗口,现在view->timeline中打开可视化窗口。动态变量查看的窗口也在view->data sampling。
-
- 启用动态变量查看的流程如下:
-
- ```mermaid
- graph LR
- 在代码窗口中选中需要观察的变量 --> 添加到watch窗口 --> 在watch选择要动态查看的变量 --> 添加到Datasample窗口
- ```
-
- 第一步的快捷键是`ctrl+w`,选中变量之后按。
-
- 第二部的快捷键是`ctrl+g`,选中watch中的变量后按。
-
- 第三步可以修改示波器的步长和采样频率。
-
- - 如果当前文件没有你要的变量,你想查看项目中的其他文件夹,在view-> source files中可以打开该项目所有的源文件,双击可以打开源文件。
-
- 
-
-- **日志打印**
-
-在Terminal窗口查看,还可以通过命令直接控制单片机的运行(不过不常用)。
-
-未打开窗口则在view-> terminal中打开。使用bsp_log打印的日志会输出到该窗口中.
-
-- **外设查看**
-
-在view-> register中打开窗口,选择Peripherals可以查看所有外设寄存器
-
-CPU选项卡可以查看CPU的寄存器。
-
-- **调用栈**
-
-在view-> call stack中打开窗口。
-
-### 常用快捷键
-
-| 组合 | 功能 |
-| -------------------- | ---------------------------------------------------- |
-| ctrl+w | 添加到查看 |
-| ctrl+g | 添加到动态查看(需要先添加到查看) |
-| f12 | 跳转到定义 |
-| f5 | 启动调试 |
-| f10 | 单步跳过 |
-| f11 | 单步进入 |
-| shift+f11 | 单步跳出 |
-| 右键+break on change | 当变量发生变化的时候进入此断点 |
-| ctrl+H | 展示调用图,会列出该函数调用的所有函数(内部调用栈) |
-
-如果你使用拥有多个按键的鼠标,推荐将侧键前设置为ctrl+点击以查看声明/定义,侧键后设置为添加到watch(debug),侧滚轮设置为前进后退(历史)
-
-你还可以按ctrl+K ctrl+S进入快捷键设置页面,将tab设置为下一个提示,用enter接受intelliSense建议,这样不需要将手移出主键盘区域. 将ctrl+;设置为移动到行尾,同时打开c/c++的函数括号不全,这样不需要手动敲击括号.
-
-将alt+k设置为左移,alt+l设置为右移,这样不需要方向键.
-
-选择最适合自己的配置!
-
-### 保存调试项目
-
-退出时可以将调试项目保存在项目的根目录下,方便下次调试使用,不需要重新设置。可以为jlink和daplink分别保存一套调试配置。
-
-## 附录1:为daplink添加license
-
-在网盘上下载`daplink_register_license.rar`,解压出来之后打开。**请关闭杀毒软件。**
-
-
-
-根据Ozone打开时提示的daplink的序列号,将其输入注册机,电机generate,就会生成5个license。
-
-windows菜单搜索J-link license manager,点击添加license,将注册机生成的五个license依次复制黏贴并添加到的license manager中即可。
-
-## 附录2:在VSCode中启用SEGGER RTT日志
-
-若使用Jlink进行调试,只需要在开始调试之前把`log`任务启动,便可以在终端中看到jlink rtt viewer的日志输出。
-
-若使用daplink/cmsis-dap调试,**请使用Jlink调试任务启动**,并且在**调试任务启动之后再打开`log`任务**。
-
-`bsp_log.h`中提供了不同的日志输出接口,包括封装好的三种层级的日志(info warning error),和用户可以自定义输出格式的`PrintLog()`。还提供了一些简单的将浮点数据转化为字符串的函数方便进行日志输出。
-
-## 附录3:Makefile指令介绍
-
-> 如果想要进一步学习Makefile,可以参考这个链接:[Makefile Tutorial By Example](https://makefiletutorial.com/)。你会发现,当项目越来越大的时候,makefile也会变得复杂起来,这就有了后继者**CMake**。cmake可以根据一定的规则,生成makefile,然后再利用make命令调用gcc进行程序的编译。~~也许以后还会有ccccmake~~
-
-```makefile
-# makefile是CubeMX自动生成的,我们需要自己添加新编写的源文件路径和头文件文件夹,也可以额外加入自己需要的参数满足需求
-######################################
-# target
-######################################
-TARGET = basic_framework # 编译生成的目标文件名,如本项目会生成basic_framework.elf/bin/hex三个
-# 注意,makefile会自动生成一个叫@的变量,其值等于TARGET.
-# 在makefile中获取变量的值需要通过$(var_name),即加上括号并在前面使用$
-
-######################################
-# building variables
-######################################
-# debug build?
-DEBUG = 1 # 是否启用debug编译.程序分为DEBUG版和RELEASE版,后者在编译时不会插入调试符号和调试信息相关支持的内容,使得程序运行速度提高.
-# optimization
-OPT = -Og # 编译优化等级,-Og表示调试级,常见的级别请看代码块下面的表格.
-
-
-
-#######################################
-# paths
-#######################################
-# Build path
-BUILD_DIR = build # 编译的中间文件和目标文件存放路径,为了区分项目文件和编译输出,一般构建一个build(构建)文件夹,用于存放上述文件. 这个表达式也在生成了一个BUILD_DIR变量(可以把Makefile当作一种语言)
-
-######################################
-# source
-######################################
-# C sources, 参与编译的C源代码全部放置于此.注意如果换行写需要在行尾空格之后加反斜杠,最后一行不要加
-# p.s. C语言的宏如果不能一行写完,也要在行尾加反斜杠,表示一行没有结束
-C_SOURCES = \
-HAL_N_Middlewares/Src/main.c \
-HAL_N_Middlewares/Src/gpio.c \
-HAL_N_Middlewares/Src/adc.c \
-HAL_N_Middlewares/Src/can.c
-
-# ASM sources 汇编源文件,第一个是stm32的启动文件,包含了bootloader的信息使得程序可以找到main函数的入口,第二个文件是添加对segger rtt viewer的支持.
-ASM_SOURCES += \
-startup_stm32f407xx.s \
-HAL_N_Middlewares/Middlewares/Third_Party/SEGGER/RTT/SEGGER_RTT_ASM_ARMv7M.s
-
-#######################################
-# binaries, 下面是要执行的指令
-#######################################
-PREFIX = arm-none-eabi- # 指令之前加的前缀,这里也是申明了一个变量
-# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx)
-# either it can be added to the PATH environment variable.
-ifdef GCC_PATH # 和C语言的宏类似,如果在Makefile里定义或给make命令传递了GCC_PATH变量会执行以下内容.但实际上我们执行的是else的内容
-CC = $(GCC_PATH)/$(PREFIX)gcc
-AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp
-CP = $(GCC_PATH)/$(PREFIX)objcopy
-SZ = $(GCC_PATH)/$(PREFIX)size
-else
-# 定义了一个cc变量,其保存的内容实际上是gcc编译器的路径.makefile中要获取一个变量的值,需通过$(var).这里makefile会自动在环境变量里寻找gcc路径.CC里保存的内容是arm-none-eabi-gcc,就是我们添加到环境变量的arm gnu工具链的路径下的一个可执行文件.你可以尝试在cmd中输入arm-none-eabi-gcc,会发现这是一个可执行的程序.之前我们在验证安装的时候就运行了arm-none-eabi-gcc -v命令.
-CC = $(PREFIX)gcc
-# 定义了一个AS变量,稍后会用于C/ASM混合编译
-AS = $(PREFIX)gcc -x assembler-with-cpp
-# 定义变量.objcopy能够将目标文件进行格式转换.我们实际上要生成的目标文件是.elf,objcopy可以将其转化为hex和bin格式,用于其他用途.
-CP = $(PREFIX)objcopy
-# size命令可以获取可执行文件的大小和包含内容信息.
-SZ = $(PREFIX)size
-endif
-HEX = $(CP) -O ihex # 这里用到了上面定义的CP,命令含义为将其转换成hex,i的前缀表示intel格式
-BIN = $(CP) -O binary -S # 转化为二进制文件
-
-#######################################
-# CFLAGS, 在编译C语言程序的时候给GCC编译器传入的参数
-#######################################
-# cpu
-CPU = -mcpu=cortex-m4 # 目标CPU类型.我们前面介绍过,不同的平台支持的汇编指令不同,一条相同的C语言表达式在翻译成汇编的时候会有不同的实现.比如8051单片机就只有加法器,因此他的乘除法都是通过多次加法和减法实现的,编译器就要完成这一工作.再比如STM32F4系列拥有浮点运算单元(FPU),可以直接在硬件上实现浮点数的加减法.这里指定编译的目标平台是cortex-m4内核的mcu.
-
-# fpu 上面说了我们的f407是有FPU的,需要传入特殊的参数.fpv4-sp-d16表示float point,m4内核,single presicion, 16个dword(4字节)运算寄存器.
-FPU = -mfpu=fpv4-sp-d16
-
-# float-abi 使用软件还是硬件实现浮点运算.也就是我们说的如果没有FPU就只能使用软件实现浮点运算.这里选择hard硬件
-FLOAT-ABI = -mfloat-abi=hard
-
-# mcu 把上面几个变量合起来弄成一条长的参数
-# Thumb是ARM体系结构中的一种16位指令集,这里-mthumb会启用它,感兴趣的同学可以进一步搜索.
-MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)
-
-# macros for gcc
-# AS defines
-AS_DEFS = # 汇编的一些宏定义
-
-# C defines
-C_DEFS = \ # C语言的宏定义
--DUSE_HAL_DRIVER \ # 使用HAL库.HAL库的许多头文件和源文件里会判断是否定义了这个宏
--DSTM32F407xx \ # HAL库会根据使用的MCU的不同进行条件编译,这是一个很好的封装技术
--DARM_MATH_CM4 # 启用ARM MATH运算库,我们在卡尔曼滤波和最小二乘法的时候会用到矩阵运算
-
-# AS includes
-AS_INCLUDES = -IHAL_N_Middlewares/Inc
-# 汇编包含目录.汇编语言也和C一样可以多个文件联合编译,在没有C语言的时候大家都是利用这种方式开发的.在一些运算资源极其受限的情况下也会直接编写汇编.
-# CubeMX生成的HAL包含目录Inc下有一些头文件里面就包含了一些汇编要用到的头文件
-
-# C includes, C语言的包含目录,将所有参与编译的头文件目录放在这里,注意是目录不需要精确到每一个文件.
-# 不想一行写完记得行尾加\,最后一行不要加
-C_INCLUDES = \
--IHAL_N_Middlewares/Inc \
--IHAL_N_Middlewares/Drivers/STM32F4xx_HAL_Driver/Inc
-
-
-# compile gcc flags, gcc的编译参数,这些参数自己感兴趣的话去搜索一下.这还将之前定义的一些参数以变量的形式放过来.
-ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
-
-CFLAGS += $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
-
-ifeq ($(DEBUG), 1)
-CFLAGS += -g -gdwarf-2
-endif
-
-
-# Generate dependency information
-CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"
-
-
-#######################################
-# LDFLAGS,传递给链接器的参数
-#######################################
-# link script
-LDSCRIPT = STM32F407IGHx_FLASH.ld # 需要参与链接的文件.这个文件指明了特定MCU的内存分布情况,使得链接器可以按照此规则进行链接和地址重映射.
-
-# libraries,要添加的库,这里我们要使用编译好的math运算库.在CubeMX里面生成的时候可以在第三方库选择DSP运算库,生成makefile时会自动添加进来.
-LIBS = -lc -lm -lnosys \
--larm_cortexM4lf_math
-LIBDIR = \ # 和上一行命令对应,这里引入库的目录,gcc会自动去目录里寻找需要的库文件
--LHAL_N_Middlewares/Drivers/CMSIS/Lib/GCC
-LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections
-
-# default action: build all
-all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
-
-
-#######################################
-# build the application
-#######################################
-# list of objects
-# OBJECTS保存了所有.c文件的文件名(不包含后缀),可以理解为一个文件名列表.notdir会判断是否是文件夹
-OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
-vpath %.c $(sort $(dir $(C_SOURCES))) # 对.c文件进行排序,百分号%是通配符,意为所有.c文件vpath是makefile会搜索的文件的路径.如果最终找不到编译中产生的依赖文件所在的路径且不指定搜索路径,makefile会报错没有规则制定目标(no rule to build target)
-
-# list of ASM program objects
-# 把所有.s文件的文件名加到OBJECTS里面
-OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))
-vpath %.s $(sort $(dir $(ASM_SOURCES))) # 对.s文件的文件名也进行排序
-
-# 以下是编译命令,命令之前被高亮的@就是静默输出的指令.删除前面的@会将输出显示到命令行.
-# 如@$(CC) -c $(CFLAGS) ...... 去掉第一个@即可.
-
-# 意味根据makefile,在BUILD_DIR变量指定的路径下将参与编译的所有.c文件编译成.o文件
-$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
- @$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
- # 上面这句话翻译一下实际上是gcc -c -many_param build/xxx -o build
- # 意思是将所有参与编译的文件都列出来,传递一堆编译参数,让他们生成.o文件,并且放在build文件夹下
-# 意为根据makefile,将.s文件编译成.o文件,具体和上一条命令差不多
-$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
- @$(AS) -c $(CFLAGS) $< -o $@
-# 根据前两步生成的目标文件(.o,这些文件的名字保存在OBJECTS变量里),进行链接生成最终的.elf
-$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
- @$(CC) $(OBJECTS) $(LDFLAGS) -o $@
- @$(SZ) $@ # 输出生成的.elf文件的大小和格式信息
-
-$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
- $(HEX) $< $@ # elf转换成hex
-
-$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
- $(BIN) $< $@ # 转换成bin
-
-$(BUILD_DIR): # 如果makefile所处的文件目录下没有build文件夹,这里会新建一个build文件夹.
- @mkdir $@
-
-#######################################
-# clean up,清除编译信息,可以在命令行中通过rm -r build执行,实际上就是把build文件夹删掉
-#######################################
-clean:
- rm -r $(BUILD_DIR)
-# 你的makefile可能会使用cmd而不是powershell来调用内核,而cmd不支持rm命令,因此可能要修改为rd (remove directory),cmd传入参数的方式为 /x ,x为要传入的参数
-
-
-#######################################
-# dependencies
-#################################
-######
--include $(wildcard $(BUILD_DIR)/*.d) # 包含所有的依赖文件(d=dependency),这是编译产生的中间文件,当hello.c包含hello.h而后者又包含了其他头文件时,会产生一个hello.d,它包含了hello.h中包括的其他的头文件的信息,提供给hello.c使用.
-
-# *** EOF ***
-
-```
-
-另外,我们还在仓库的根目录提供了Makefile.upgrade文件,在该makefile中,我们提供了一些基于命令行的更高级的特性,例如自动源文件索引和头文件目录包含等,使用之后若添加了新的源文件就不再需要手动添加路径了。这里面还增加了一些为嵌入式选择的gcc优化参数。要启用高级特性,将其内容复制到你的makefile即可。
-
-- **编译优化等级**:
-
-| 优化级别 | 说明 | 备注 |
-| -------- | ------------------------------------------------ | ------------------------------------------------------------ |
-| -O0 | 关闭所有优化 | 代码空间大,执行效率低 |
-| -O1 | 基本优化等级 | 编译器在不花费太多编译时间基础上,试图生成更快、更小的代码 |
-| -O2 | O1的升级版,推荐的优化级别 | 编译器试图提高代码性能,而不会增大体积和占用太多编译时间 |
-| -O3 | 最危险的优化等级 | 会延长代码编译时间,生成更大体积、更耗内存的二进制文件,大大增加编译失败的几率和不可预知的程序行为,得不偿失 |
-| -Og | O1基础上,去掉了那些影响调试的优化 | 如果最终是为了调试程序,可以使用这个参数。不过光有这个参数也是不行的,这个参数只是告诉编译器,编译后的代码不要影响调试,但调试信息的生成还是靠 -g 参数的 |
-| -Os | O2基础上,进一步优化代码尺寸 | 去掉了那些会导致最终可执行程序增大的优化,如果想要更小的可执行程序,可选择这个参数。 |
-| -Ofast | 优化到破坏标准合规性的点(等效于-O3 -ffast-math ) | 是在 -O3 的基础上,添加了一些非常规优化,这些优化是通过打破一些国际标准(比如一些数学函数的实现标准)来实现的,所以一般不推荐使用该参数。 |
-
-## 附录4:VSCode直接烧录代码
-
-有时候你对自己的代码特别自信,不想debug想直接下载代码,那么直接通过openocd或J-Flash即可(随jlink一起安装)。要是觉得这样有点麻烦还要再开一个软件,他们两者都支持通过命令行执行。你可以在vscode的tasks.json中编写一个额外的任务来实现。这里,我通过给Makefile添加伪构建目标来利用make命令执行下载操作:
-
-```makefile
-#######################################
-# download without debugging
-#######################################
-OPENOCD_FLASH_START = 0x08000000 # 如果切换芯片可能需要修改此值
-
-download_dap:
- openocd -f openocd_dap.cfg -c init -c halt -c "flash write_image erase $(BUILD_DIR)/$(TARGET).hex $(OPENOCD_FLASH_START)" -c reset -c shutdown
-
-download_jlink:
- openocd -f openocd_jlink.cfg -c init -c halt -c "flash write_image erase $(BUILD_DIR)/$(TARGET).hex $(OPENOCD_FLASH_START)" -c reset -c shutdown
-```
-
-首先设定了flash烧录区的起始地址,下面两个构建目标分别用于daplink和jlink的下载。我们统一使用openocd进行烧录。命令中,`-c`表明的是启动openocd之后要执行的命令,openocd作为一个gdbserver是用作调试的,因此这里我们在`flash write_image`之后直接`reset`让单片机复位开始运行程序,然后立刻退出调试,从而达到下载程序运行但不调试的目的。
-
-> 若你认为在makefile中使用伪构建任务不合适,也可以自行在`task.json`中编写一个任务。
-
-接下来我们希望能够直接下载,不要在命令行里面输入`make download_dap`这么复杂的指令,我们可以利用make构建伪造目标来实现命令行命令执行,因此在tasks.json中添加如下两个任务:
-
-```json
- {
- "label": "download dap",
- "type": "shell",
- "command":"make download_dap",
- "group": {
- "kind": "build",
- "isDefault": false,
- },
- },
- {
- "label": "download jlink",
- "type": "shell",
- "command":"make download_jlink",
- "group": {
- "kind": "build",
- "isDefault": false,
- }
- },
-// 实际上也可以直接编写命令行指令,他们是等效的
-```
-
-这样,在工具栏的Terminal页面,就可以选择对应的任务直接下载执行了。你也可以通过快捷键`ctrl+shift+B`唤起任务执行页面进行选择。如果你希望立刻检验你代码修改的效果,在下载之前进行编译,那么在`command`信息下新增加一个`mingw32-make -j24`即可,或者添加一个`preLaunchTask`。对于调试,如果不想点两下想在修改代码之后直接调试,也可以在launch.json中增加`preLaunchTask`(文件中已经添加,需要的话取消注释即可)。
-
-> 实际上换用arm gnu工具链之后,可以指定多线程编译,因此消耗的时间非常短,建议都加上先编译的选项,不会占用额外的时间。可以把默认task设置成编译后下载,把默认debug设置成编译后调试,提升开发效率。
-
-## 附录5:利用MSYS2安装依赖环境
-
-之所以要使用Linux进行C++开发,是因为在开发环境中配置依赖包、依赖应用和库非常的方便。Debian系有apt,Fedora和Redhat系有yum,他们都可以方便地帮助我们下载开发软件必须的一些文件和工具。在windows的宇宙最强IDEVisual Studio中配置头文件和动态链接库可以称得上是最折磨的事。好在,现在Windows下也有可以使用的包管理工具了:[MSYS2](https://www.msys2.org/)。
-
-安装包已经上传到了网盘的`EC/VSCode+Ozone环境配置/msys2-x86_64-20221028.exe`下,你也可以在msys2的官网直接下载,如果没有ladder速度可能会稍慢,镜像站的下载速度会快许多。安装之后,打开MSYS2 MSYS软件,他是一个类shell的界面,实际上它提供了包括mingw64、ucrt64、clang64等多种不同编译环境在内的一组类linux开发工具合集:
-
-
-
-输入以下命令然后一路回车即可:
-
-```shell
-pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-arm-none-eabi-toolchain mingw-w64-x86_64-ccache mingw-w64-x86_64-openocd
-# 需要注意ctrl+V不是黏贴快捷键,而是Ins+Shift.或者右键点击空白处选择黏贴也可以.
-```
-
-
-
-比如上面这样,会让你选择,直接敲回车即可,等待安装
-
-刚进来第一次安装可能还会更新一下数据库,也是全部更新就行。
-
-安装好之后,把Msys2下的mingw64的bin加入PATH环境变量:`D:\Msys2\mingw64\bin`(这是我的路径,注意要选自己的)。
-
-注意,如果选用此安装方式,**OpenOCD的可执行文件也会被放在上面这个路径下**,记得稍后在VSCode中配置的时候找到这里。相应的scripts放在`D:\Msys2\mingw64\share\openocd`下。
-
-通过这种方式安装之后,还可以选用ccache加速编译。ccache会根据之前的编译输出建立缓存,使得之后编译时可以直接读取缓存。要开启这个功能,直接在Makefile中搜索PREFIX,将下面一行的内容替代原有内容(即增加ccache在arm-none-eabi-之前)。
-
-
-
-- **将msys2的各种终端集成到vscode当中**
-
-当你的系统中存在各种不同的编译环境时,将他们的路径一同添加到系统环境变量PATH中可能导致错误的工具和指令调用,也有可能在编译中匹配错误的库和头文件。为了防止这种事情发生,最好是只在特定的工具集中添加它们需要的环境变量。Msys2提供了各种子环境的终端(shell),你可以将它们集成到Vscode的终端中,当要进行对应的开发时,就新建一个你需要的环境的终端。
-
-`ctrl+,`打开vscode设置或直接打开vscode设置的.json文件,添加以下内容便会将对应的环境终端集成在vscode中:
-
-```json
- "terminal.integrated.defaultProfile.windows": "mysys2-mingw64", // 若希望为默认终端可以加入这一句
- "terminal.integrated.profiles.windows": {
- "mysys2-mingw64": {
- "path": "cmd.exe", // 意思是使用cmd作为父进程启动终端
- "args": ["/c","C:\\msys64\\msys2_shell.cmd -defterm -mingw64 -no-start -here"]
- // msys2_shell.cmd在msys的安装目录下,这里要改为你自己的目录
- }
- }
-```
-
-修改好之后,便可以在vscode中使用了:
-
-
-
-linux下熟悉的ls/mkdir/find/ld/cat等命令和工具也一应俱全了。
-
-不过,这时配置的build task和其他download task仍然在powershell或cmd中启动,若没有添加环境变量它们无法找到对应的可执行文件,这时候你就要修改`task.json`,将使用的shell改为mingw64即可(若你使用ucrt或clang同理)。
-
-## 附录6:Windows修改用户名为英文
-
-1. 右键【任务栏win徽标】->【计算机管理】->【本地用户和组】->【用户】->右键【中文用户名】->【重命名】
-
- > 如果是win10,则是:右键【计算机(一般放在桌面上,如果没有的话桌面右键选择个性化,然后打开桌面图标)】->【管理】->【本地用户和组】->【用户】->右键【中文用户名】->【重命名】
-
- **注意这个英文用户名后续还要使用**
-
-2. **以管理员权限**启动命令提示符,输入
-
- ```shell
- net user administrator /active:yes
- ```
-
- 如果杀毒软件提示恶意修改,请放行
-
-3. 重启电脑,登录的时候选择**Administrator**账户,需要进行一些简单的设置,直接一路确定即可。
-
-4. 进入C盘的用户文件夹下,把你原来的用户文件夹名称改成刚刚设定的英文用户名。
-
-5. 【Windows+R】->【运行】->输入 regedit ->回车
-
- 找到`HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Profilelist`,把这个标签页下每个选项都点开看,其中有一个页面对应的`ProfileImagePath`值是以你用户名命名的文件夹路径,比如我的路径是`C:\User\小曾`。
-
- 双击,把这个路径改成你新设的用户名,比如我的`C:\User\Neo`
-
-6. 重启电脑,进入修改好的用户,
-
-7. **以管理员权限**启动命令提示符,输入
-
- ```shell
- net user administrator /active:no
- ```
-
- 如果杀毒软件提示恶意修改,请放行。这会关闭Administator账户。
diff --git a/.Doc/合理地进行PID参数整定.md b/.Doc/合理地进行PID参数整定.md
deleted file mode 100644
index 019c099..0000000
--- a/.Doc/合理地进行PID参数整定.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# 利用Ozone进行model-based PID tunning
-
-Ozone的实时变量可视化监测(示波器)功能可以很好地帮助我们观察控制器在时域的表现,典型的有上升时间、超调量和稳态时间等。
-
-## 调试顺序
-
-先内环,后外环。若有已知的外部扰动如阻力、重力等可以在**保持kp不变**的情况下添加积分环节,并查看达到稳态时积分的输出,该输出值可以作为**前馈**作用通过feedforward_ptr一同送入下一个串级控制器。在没有模型的时候,计算前馈一般通过**数据驱动**的方法,如稳态误差-参考值关系拟合。
-
-经典的经验式整定方法有简单的Ziegler-Nicols法和Cohen-Coon法,还有需要一定的系统辨识的Chien-Hrones-Reswick、Tyreus-Luyben和Skogestad法。这些方法在网络上或提出方法的论文中都有详尽的说明,这里不再赘述。
-
-我们可以使用上述方法确定一套参数的初值,再根据时域表现进行精细的参数调整。
-
-以笔者个人的纯调参无模型云台调试经验,可以进行如下步骤:
-
-1. 首先整定P参数,使用二分法确定大致范围。将电机参考速度和实际速度在Ozone示波器同一窗口中打开以观察时域表现。把pid的ref值添加到变量观测,方便修改(只要修改ref值,每次就可以触发阶跃信号输入)。当P达到欠阻尼且波动只有一个周期(只有超调一个峰)时,开始添加D参数。
-2. 添加微分参数。务必打开微分滤波器,并根据你的闭环带宽(速度环要跟随的频率)设置滤波系数。目前使用的是一阶低通滤波,后续考虑增加高阶滤波器和特殊的带宽滤波器(切比雪夫、巴特沃斯等)。调节D参数至P进入临界阻尼或过阻尼的状态(没有超调)。
-3. 交替增大比例系数和微分系数,直到出现不可控的微分抖动,然后减小两者的值直到出现一个合适的平衡(调个大概即可,没有模型的情况下很难达到均衡)
-4. **固定PD参数**,查看不同目标值的**静差**。如果没有对云台进行建模,则拟合目标值与静差的关系(线性、多项式、指数、对数),并将该值作为前馈加入系统,以补偿PD无法影响的扰动项。
-5. 增加额外的积分控制以消除前馈模型不准确带来的影响。务必使用积分分离和变速积分。参数不要求精细,一般来说大致即可。
-
-## model-based控制
-
-无模型的控制显然存在其劣势和效果上限,为了提高性能,我们需要对云台进行建模。
-
-建模的方式包括动力学方程推导和数据驱动的系统辨识。
-
-动力学方程的推导即分析系统的输入(电机的扭矩)和输出(速度/角度)的关系,得到系统动态的微分方程,然后使输入等于微分方程中除输出外的项,从而让输出的动态变为简单的一阶线性常微分方程,以最快的方式到达期望位置。此时再额外增加PID控制器,用于补偿建模得到的系统和实际不匹配造成的误差。建模考虑的因素越全面,建模的效果可能会越好。
-
-系统辨识的经典方法是伯德图法即频域分析。通过给定一系列的正弦输入,观察系统的输出表现得到系统的相频曲线和幅频特性曲线,并选择一个特定结构的系统对曲线进行拟合(最小二乘或极大似然估计),对得到的系统应用超前-滞后补偿控制器以确定合适的PID参数,在裕度和带宽之间权衡,使得系统的频率响应满足设计要求。
-
-Ozone可以非常方便的获取系统的频率响应数据。
-
diff --git a/.Doc/如何定位bug.md b/.Doc/如何定位bug.md
deleted file mode 100644
index eeb9189..0000000
--- a/.Doc/如何定位bug.md
+++ /dev/null
@@ -1,166 +0,0 @@
-# how to locate bug in your code
-
-[toc]
-
-只讨论运行中的bug(指程序的运行结果不符合你的期望)和异常(直接异常终止)。编译期出现的warning和error不在此范畴,他们都可以通过直接阅读报错信息解决。
-
-## Debug方法论
-
-**首先**,请阅读module和bsp的标准使用示例,检查你的代码和示例是否有所不同。如果你正在编写一个新的模块,务必使用**增量式编程**的方法构建你的模块,每完成一部分的功能就进行单元测试,看看是否符合你的期望。**千万不要一口气写完**,这时候再来测试,你就无从下手了。
-
-如果确认软件没有问题,先别急着单步调试,检查一下硬件连接是否正确,包括CAN的H和L,串口的TX RX以及电源和GND。 如果你的硬件有多个相同的接口但是使用不同的功能,你得好好看看是否插错接口了。 软件中对hdevice(hcan/hspi/htim等)的设定是否和CUBEMX中配置的一致? 模块的id和地址是否写错。
-
-**修改之后要保存,编译,再调试/下载**。建议你把自动保存打开,并勤劳地commit。push时注意reset这些调试时产生的commit,合并成一次提交。你也可以新建一个分支用于解决bug,这是git的最佳实践。
-
-同时注意条件编译的兼容,你是否测试一些应用或模块,却使用了错误的 `#define`?
-
-完成上面的两步仍然无济于事,开始单步调试吧。在调试的同时,再仔细看看你的代码是否写错变量名和运算符,比如,把 `==`写成了 `=`,那么判断条件将永远是 `true`。在值得怀疑的地方,打开汇编视图,查看你要访问的地址是否正确。一步一步往下的同时,关注调用栈是否符合你的期望,添加必要的变量到调试窗口,看看他们何时发生意想不到的变化。**条件断点**是一个杀手级功能,你可以设置一些条件,让条件满足时程序在此处停下。下面的一些常见问题可能对你的调试有所帮助。
-
-如果一切正常(或者应该说你没有发现异常,虽然他确实在那里),试着查看你使用的外设寄存器值。这时候你要用到芯片的数据手册和功能描述手册。在运行的每一步中,对照datasheet的寄存器状态和改变,看看是否符合你期望的程序行为。寄存器分为控制寄存器/状态就寄存器/数据寄存器,参照datasheet就可以明白这些寄存器是控制哪些功能,描述什么状态以及内部是什么数据。
-
-如果你的数据是连续或规则的,记得使用Ozone可视化工具配合条件断点。
-
-> 也可以让copilot帮帮你,选中你认为可能出错的代码,选择copilot brush-》debug
-
-## 一些常见问题
-
-### HardFault_Handler()
-
-99%是由于野指针和非法内存访问导致的。在HardFault函数内添加一句 `asm("bx lr");`, 并在此处加上断点。当代码运行至此处时,选择跳出,程序会跳转回出错之前最后一句执行的语句。
-
-查看你是否在出错前的最后一次操作中访问了非法地址或使用了已经被析构的指针。 `memcpy`的目标地址和源地址重合也可能引发硬件错误。另外,如果使用指针访问了一个非对齐地址(请参考__pack()相关的说明),这是CMSIS架构中不允许的(有些架构可以修改启动文件使其支持);例如你有四个uint8类型的数据被存储在0x03-0x07的地址内,这时候你通过强制类型转换,以float的方式读取这四个字节,就会发生非对齐访问。 虽然结构体可以通过 `__pack(1)`来压缩,编译器会对结构体变量进行处理,在读取非对齐字段时分别读取拆分的两个部分再进行合并,从而支持非对齐访问;但前述的行为却是未定义的,编译器在编译代码的时候并不知道你会以分开的方式访问这段内存,即使知道,他也无法预测栈上分配的空间是否能对齐。
-
-常见的错误还包括使用未初始化的指针(内部可能时垃圾值,指向未知的地址)和初始化为NULL的指针(指向0x00地址)。`free`一个指针两次也可能导致错误。
-
-### 通信外设传递的数据没有进行压缩
-
-经典的 `__pack()`问题。这种问题大多出现在结构体的传输上。用于通信的结构体请在两端用 `#pragma __pack(1)`和 `#pragma __pack()`包裹。否则传输时会出现空字节,使得数据和你使用的协议对不上号。
-
-### Delay或定时器卡死永远不跳出
-
-Systick和HAL_Delay以及使用TIM来定时的方法,都需要通过**中断**来更新时间。如其重装载计数器上限为65535,当计数达到此值时会触发中断,在中断处理函数中,增加一次溢出的时间。如果此时有更高优先级的中断或同优先级的中断正在运行,且他们耗时很长 or 调用了这些依赖中断的Delay函数,那么将会形成**死锁**,永不见天日。 如果中断被关闭,这些计时也无法更新。 这里推荐使用DWT定时器(在 `bsp_dwt`中实现),其重载计数器是64位的,按照stm32f407 168MHz的运行频率,需要两天多的时间才会发生溢出,因此仅依赖其重载计数器,计算两次tick的差值就可以实现高精度的定时(除非你delay超过两天,你在搞笑)。
-
-### 静态变量的陷阱
-
-注意,函数内的静态变量只会在程序启动的时候初始化一次,之后不论多少次重入,都会保存上一次修改的值。
-
-然而,如果静态变量被放在头文件里,则每个包含该头文件的其他源文件,都会拥有一份自己的备份,这些备份之间是互不影响的(详见编译期的头文件展开)。 千万不要认为静态变量是全局的,它只是在当前文件内有效。
-
-### 指针越界读写/内存泄漏
-
-有时候,你发现你使用的变量值变成了奇怪的数,或者你的程序突然崩溃了,但是你并没有在代码中对这个变量进行过修改。这时候,你应该检查一下你的指针是否越界了。 你也许没有正确的将void\*指针cast成期望的类型,使其访问了不该访问的位置;例如,一个uint8类型长度为4数组,你希望将其转化为float进行读取。但你在声明数组时只分配了3个字节,使用float\*访问就会触及未知的第四个字节,第四个位置上存放的可能是其他变量的值,这时候访问其他变量就会出现奇怪的值。 或者,你在 `memset()`和 `memcpy()`的时候没有正确设置源地址和目标地址或长度。
-
-### 实时系统
-
-中断中使用实时系统的接口时记得使用有 `ISR`后缀的版本,它们对中断的调用做了特殊处理。所有中断的优先级都是高于RTOS中任务的优先级的。
-
-若期望某个任务以1KHz频率运行,你可能会在任务循环外加一个 `OS_Delay(1)`,但是你的任务执行时间要是超过了1ms,系统的调度就会出现异常,倘若你还在此任务内认为每次进入的时间间隔是1ms并据此编写了一些依赖周期性的代码,那便是大错特错了。
-
-对于实时性和周期性要求高的任务,使用 `vTaskDelayUntil()`,这可以获得更高的定时精度。
-
-不同的任务/中断调用了相同的函数,或使用了共享变量/全局变量/函数内的static变量会导致读\&写冲突,也被称作**数据竞争**。这一般只会在任务繁重且中断频率高时出现。要避免这种情况,访问共享变量时应进入临界区(关闭全局中断)或使用**互斥锁**。消息队列也是一个不错的选择,这些功能在FreeRTOS中都提供了支持。
-
-### 中断
-
-中断不要放入太复杂的逻辑和运算。使用标志位或将要处理的数据转移到队列中,于任务中检查标志位,判断是否要进行数据的处理。否则可能出现中断过于复杂/频繁使得通信出现overrun error
-
-强烈建议初始化时不要使用和中断相关的功能,若你在中断过程中访问了一些尚未初始化的变量,就很大概率会出现前述的野指针/越界等问题。 非要使用,请添加一个标志位,并让中断判断初始化是否完成。**当前框架在初始化机器人的时候关闭了全局中断,所以千万不要使用中断和与symstick/HALtick有关的延时!**
-
-### 强制类型转换
-
-long long的范围比float小。无符号和有符号数直接转换可能变成负数。**应该在一切可能表达运算顺序错误的地方加上括号以明确操作的顺序,即使你知道不同运算符的优先级。** 使用移位操作要注意你的变量类型,请不要相信编译器的临时变量生成,务必加上类型转换。
-
-例如:`#define MY_MACRO_NUMBER 3.0f`,使用宏定义一些带小数点的数据时记得加上.0或f后缀,干脆两个都加。无符号定义要加u后缀。
-
-### 宏
-
-换行用 `\` ,注意同一个代码块展开后用花括号 `{}`包裹,特别注意宏展开之后是直接的文本替换!!!
-
-用已有的宏定义宏并且进行运算时,要将后面的字段用括号包围,因为:
-
-```c
-#define YOUR_DEF SOMETHING
-// 宏通过空格来解析替换字段,YOUR_DEF空格后的第一个字段当作替换文本
-```
-
-**宏只在当前文件生效**,如果宏放在.c那么对其他的文件是不可见的,这也一般称作私有宏。
-
-## 典型debug案例一
-
-这是一个结合了软件和硬件且有多模块耦合的异常。该bug发生在调试平衡步兵的底盘过程当中。
-
-### 引发bug的原因
-
-1. 指针在强制类型转换中变成了错误的类型,使得指向的内存地址被错误地修改
-2. CAN总线负载过大导致电机反馈消息丢失
-
-这里是发生bug的代码片段:
-
-```c
-static void LKMotorDecode(CANInstance *_instance)
-{
- static LKMotor_Measure_t *measure;
- static uint8_t *rx_buff;
- rx_buff = _instance->rx_buff;
- measure = &((LKMotorInstance *)_instance)->measure; // 通过caninstance保存的id获取对应的motorinstance
- // 上面一行应为: measure = &(((LKMotorInstance *)_instance->id)->measure);
- measure->last_ecd = measure->ecd;
- measure->ecd = ...
-
- // ....
-
-}
-```
-
-这是问题1的出处。can instance中保存了父指针,即拥有该instance的LKMotorInstance。这里想通过强制类型转换将 `void*`类型的 `id`转换成电机的instance指针类型并访问其measure成员变量以从CAN反馈的报文中更新量测值。然而却直接将can instance转换成motor instance。
-
-随后,更新之后的数据被覆写到can instance内部,使得其成员变量改变,包括hcan、txbuf、rxbuf、tx/rxlen等。hcan是HAL定义的can句柄类型,里面保存了指向can状态和控制寄存器的指针以及其他HAL状态信息,然而其值被电机反馈回来的值覆写,之后HAL的接口访问hcan时将引起异常。
-
-第二个问题则不是显式存在的:
-
-```c
-void MotorControlTask()
-{
- DJIMotorControl();
-
- HTMotorControl();
-
- LKMotorControl();
-
- ServeoMotorControl();
-
- StepMotorControl();
-}
-```
-
-这是motortask的内容,此任务将以500hz的频率运行。在发生bug时,我们将4个HT04电机和2个LK MF9025电机全部连接到CAN1上。注意,HT04不支持多电机指令,因此占用的带宽较大。在 `LKMotorControl()`完成参考值计算和CAN发送之后立刻会调用 `HTMotorControl()`,后者需要连续发送4条报文。而HT和LK电机都会在接收到控制指令之后发送反馈信息报文。由于HT电机的控制在LK电机控制之后立刻执行,导致总线被占据,LK电机发送的反馈数据仲裁失败无法获得总线占有权,使得主机收不到反馈数据。
-
-### bug的发现和定位的尝试
-
-程序的大体情况如下,当时进行轮足式倒立摆机器人的测试,启用了balance.c,在其中注册了4个HT04电机(can1)和2个LK9025电机(can2)。控制报文的发送频率均为500Hz。
-
-测试时发现,9025电机可以接收到mcu发送的控制指令并响应,但是mcu始终无法获得反馈值,`LKMotorInstance->measure`的所有成员变量一直是零。由于CAN是总线架构,电机能接收到数据说明通信正常。HT04电机也可以正常控制并收到反馈信息。在 `LKMotorDecode()`函数中添加断点发现能够成功进入1~2次,随后便引发HardFault。
-
-此时内心有些动摇,开始检查硬件连线。我们尝试把LK电机也挂载到CAN1总线上。开始单步调试,发现LK电机可以正常接收一次反馈报文,之后就进入 `Hardfault_handler()`。HT和DJI电机均无此问题。进一步进行每条指令的调试,发现在成功接收到一次报文之后(接收报文指的是can发生中断并在处理函数中调用LK电机的解码函数,我们并没有查看measure值是否刷新,实际上这时候反馈值仍然为零),进入该电机的控制报文发送时,通过在 `Hardfault_handler()`中添加汇编语句 `asm("bx lr")`,即跳转到最后一次执行的指令,发现访问 `hcan->state`会引起硬件错误。遇到这种情况,说明发生了越界访问或使用了野指针。检查hcan的值,发现是一个非常大的地址。因此怀疑hcan指针被其他的内存访问语句修改。
-
-有了方向之后,进一步对每一个函数都进行单步进入调试,同时时刻监测hcan1的值。然而,这时候出现即使一开始就单步调试也无法进入LK电机解码函数的问题。于是,怀疑是CAN过滤器的配置问题,使得LK电机反馈报文被过滤,检查LK的接收id无误后,认为可能由于LK电机的发送和接收ID都比较大(0x140和0x280),CAN标准ID放不下。但是查阅CAN specification后发现standar ID可以容纳11位的值,应该不会有问题。于是把过滤器配置为mask模式,让bxCAN控制器接收所有报文(即不进行过滤)。然而还是不奏效,仍然无法收到数据。
-
-这时候想起HT电机是不支持多电机控制指令的,因此500Hz的控制频率似乎有些过高,相当于2ms内要完成2x4+1+2=11次CAN报文的发送。计算1M波特率下最大通信速率,果然超出了负载。于是降低 `MotorTask()`的频率为200Hz,果然能重新接收到数据了。
-
-继续单步调试,终于发现在 `LKMotorDecode()`中,通过强制类型转换获取LKMotorInstance的时候,用错了变量,使得反馈值被写入电机的 `CANInstance`内,导致hcan指向随机的地址,最终造成访问时引发hardfault。
-
-修改之后,将LK电机挂载到CAN2上,控制频率回到500Hz,程序正常运行。
-
-### 解决方案
-
-均衡总线负载,调节任务运行时间。
-
-# 典型debug案例二
-
-这仍然是一个CAN总线引发的bug。使用的电机均为DJI电机。当多个电机接入时,会产生反馈值跳变的情况。起初认为**总线负载过高**,(控制频率为500Hz,反馈频率均为1kHz,计算之后得出CAN的负载率接近90%),但将电机减少为一半甚至更少时仍然出现此问题。**单独使用CAN1且仅挂载一个电机则问题消失**,同时使用CAN1和CAN2(不论单个总线挂载几个电机)则问题再次出现。
-
-**单步调试发现反馈值并未因指针越界而被纂改**。仔细检查代码的计算发现并未出错,打开Ozone查看反馈值曲线,发现确实偶发跳变,但跳变值并未超出反馈值范围,即即使发生跳变值仍然在**正常范围内**,因此不像是总线负载过大导致数据帧错误或指针越界修改的随机值。加入多个电机同时查看反馈值,**发现反馈跳变之后会和另一电机的反馈值相同**,呈现“你跳到我我跳到你”的图景。怀疑CAN中断被**重入**,即一个中断未完成时另一个CAN报文到来,打断了当前的中断并执行了**相同的反馈解码函数**。但CAN1和CAN2的中断优先级均为5,因此不可能打断彼此。打开CubeMX查看初始化配置,发现两个CAN的FIFO0和FIFO1中断优先级不同,分别是5和6。则FIFO1的溢出中断会被FIFO0打断,且我们在电机的解码函数中使用了一些**静态变量**用于存储触发接收中断的电机报文的相关信息,故而新进入的中断覆写了之前中断的静态变量值,使得之前中断在恢复之后存储了前者的值,导致自身反馈错误。
-
-将优先级统一设为5,编译之后重新运行,反馈值正常。
-
-> “同时使用CAN1和CAN2(不论几个电机)则问题再次出现。” 导致此问题的原因是初始化CAN时按照rxid分配FIFO,因此注册的电机会被交替分配到不同的FIFO,故不论注册了几个电机(只要多于2)、注册到哪条总线都会出现FIFO1中断被FIFO0打断的情况。
diff --git a/.Doc/必须做&禁止做.md b/.Doc/必须做&禁止做.md
deleted file mode 100644
index 0858ab7..0000000
--- a/.Doc/必须做&禁止做.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# MUST & MUSTNOTMUSTNOT
-
-## 禁止过度摸鱼
-
-提供工作效率!
-## 禁止在临界区使用延时,这会导致因中断关闭使得定时器无法进入中断更新时间,进而卡死系统
-
-除非你使用的是基于计数寄存器差值的延时方法,或阻塞式的for延时。
-**若有必要,应该使用`bsp_dwt.h`提供的接口。
-
-## 若任务耗时较长导致可能出现数据读写被中断或更高优先级的任务打断,请为你的数据添加锁
-
-若同时要求数据的实时性,考虑将低优先级线程设置为由高优先级任务唤醒,或添加位互斥锁(而不是osMutex!确保中断也可以使用)。
-
-## 禁止图方便直接将电机/电调连接在开发板的xt30接口上,否则电机的反电动势可能烧毁开发板
-
-后续考虑增加一个xt30转接器,其上实现隔离电路,再连接开发板充当分电板。
-
-## 请给你编写的bsp和module提供详细的文档和使用示例,并为接口增加安全检查
-
-用于调试的条件编译和(若有可能)log输出也是必须的。
-
-另外,“treat your user as idot!”
-
-## NO WARNING
-
-makefile中已经启用了`-Werror`选项,所有的warning都会被视为error,别妄图带着warning通过编译!
diff --git a/.Doc/架构介绍与开发指南.md b/.Doc/架构介绍与开发指南.md
deleted file mode 100644
index e37b702..0000000
--- a/.Doc/架构介绍与开发指南.md
+++ /dev/null
@@ -1,275 +0,0 @@
-# 2023 EC basic-framework
-
-> 每个bsp/module/application都有对应文档,建议阅读之后再看代码&进行开发。框架的搭建思路和讲解视频戳这里:[basic_framework讲解](https://www.bilibili.com/video/BV1Bd4y1E7CN)。
-> 开发之前必看的文档:**README.md & VSCode+Ozone使用方法.md** 。开发app层请看application目录下的文档,若要开发module以及bsp务必把上层文档也浏览一遍以熟悉接口定义的方式。
-> **程序的运行流程和框架所有app/module/bsp的数据流图直接拉到本文档底部。**
-
-此框架为机器人通用设计,当前的app层是为步兵设计的。不同的机器人只需要重新编写应用层。在我们的战队仓库中有英雄、工程、哨兵、平衡步兵等兵种,可作参考。
-
-此框架在RoboMaster A型开发板的移植也已在组织仓库中提供。
-
-[TOC]
-
-## 基本信息和开发规范
-
-- **开发方式**:
-
- 本框架使用stm32cubemx生成,基于makefile编译系统(后期拟修改为cmake+nijna+makefile以提高编译速度,对于目前的版本您可以考虑自行安装ccache以提高编译速度),使用arm gnu工具链开发,利用arm-none-eabi-gcc编译(make命令,命令行为mingw32-make)。
-
- > 目前已经支持CMakeLists构建。
-
- > ***==!deprecated==***:若需使用keil5开发,请在stm32cubemx的`project manager`标签页下将工具链改为MDK,然后在keil中自行添加所需包含的.c文件和头文件。关于如何在keil下添加dsplib,请参考文档。在vscode中也有**KEIL assistant**和**Embedded IDE**插件可供使用。
- >
- > ***强烈推荐使用VSCode进行开发,Ozone进行调试。***
-
- VSCode可通过Cortex-Debug利用OpenOCD进行调试,jlink/stlink/dap-link都支持,具体的使用方法和环境配置教程在[VSCode+Ozone使用方法](./VSCode+Ozone使用方法.md)中。**请使用UTF-8编码查看\&编辑此项目**。
- **此外,本项目中使用到的物理变量值均采用标准单位制**,若有特殊需求,可以通过module层的`general_def.h`添加物理量转换关系的宏。
-
-- **分层**:
-
- 本框架主要代码分为**BSP、Module、APP**三层。三层的代码分别存放在同名的三个文件夹中,这三个文件夹存放在根目录下。开发过程中主要编写APP层代码,Module层与BSP层不建议修改。如需添加module(如oled屏幕、其他传感器和外设等),请按照规范编写并联系组长提交commit到dev分支或对应的功能名分支,完善后合并至主分支。在配置git的时候,将自己的`user.name`配置成英文缩写或易懂的nick name。
-
- BSP层构建于ST的HAL(硬件抽象层)之上,针对RoboMaster竞赛所用电控外设和模块的特点对其进行了进一步封装;Module层是基于bsp的封装打造的各种模块,旨在为app层提供**硬件无关的接口**,即应用层不应该出线任何与片上外设相关的代码。
-
- **main.c的位置在**`Src/main.c`
-
-- **代码格式**:
-
- 在vscode-设置-扩展-C/C++-C_Cpp:style下修改。默认为`Visual Studio`。编写完新的代码后,使用`右键-格式化`或`shift+alt+f`(请勿对cube生成的文件使用此操作否则重新生成异常)。此操作不会改变文档的内容,但会改变缩进、空行、符号位置等,使代码更加统一、整洁。
-
- **在cubemx生成的文件(尤其是main.c和freertos.c)时,务必按照cubemx的提示将用户代码放在usercode注释代码块内,否则重新生成时会被覆盖.**
-
- 请保持良好的注释编写习惯,建议安装doxygen插件。务必统一在.h文件中为外部接口编写注释,并给类型定义编写必要的注释。对于私有函数(.c文件中static修饰),请在.c文件中进行注释。对于复杂的代码段,也请添加注释。
-
- 每个功能模块编写完之后,及时添加说明文档。内容参照已有的文档,要进行简短的**总体说明、代码结构、外部接口和类型定义、私有函数和变量,以及使用的说明和范例**。如果有特别需要注意的地方,也请说明。
-
- ==**在编写代码的时候,注意添加安全检查,“treat your users as idiots!”**==
-
-- **面向对象设计**:
-
- C语言不存在“成员函数”的概念。为实现类似效果,所有按照这一思想构建的函数都会有一个传入参数,将结构体(对象)传入。
-
-- **代码风格:**
-
- 函数统一使用**动宾短语**,建议不超过4个单词。每个单词首字母大写:
-
- ```c
- void SetMotorControl()
- ```
-
- 变量命名使用下划线命名法,统一小写。尽量不要使用缩写,并注意让变量名本身能够表达其含义:
-
- ```c
- uint8_t gimbal_recv_cmd;
- ```
-
- 后续可能将指针类型的变量名都加上`ptr_`或`p`前缀。私有变量加上下划线`_`前缀。
-
- 在利用`typedef`定义新的类型时,使用单词首字母大写+下划线隔开+定义后缀的方式:
-
- ```c
- typedef struct
- {
- float Accel[3];
- float Gyro[3];
- } IMU_Data_t;
-
- typedef struct
- {
- can_instance_config_s can_config;
- uint8_t send_data_len;
- uint8_t recv_data_len;
- } CANComm_Init_Config_s;
-
- typedef struct
- {
- float *other_angle_feedback_ptr;
- float *other_speed_feedback_ptr;
-
- PID_t current_PID;
- PID_t speed_PID;
- PID_t angle_PID;
-
- float pid_ref; // 将会作为每个环的输入和输出顺次通过串级闭环
- } Motor_Controller_s;
- ```
-
- 数据类型单一、结构不复杂的类型以`_t`后缀结尾(表明这是一种数据,type);复杂的结构体类型使用`_s`结尾,表明其功能和内涵多(structure)。对于某个bsp、module,其类型结构体应该称为`xxxInstance`:
-
- ```c
- typedef struct _
- {
- CAN_HandleTypeDef *can_handle; // can句柄
- CAN_TxHeaderTypeDef txconf; // CAN报文发送配置
- uint32_t tx_id; // 发送id
- uint32_t tx_mailbox; // CAN消息填入的邮箱号
- uint8_t tx_buff[8]; // 发送缓存,最大为8
- uint8_t rx_buff[8]; // 接收缓存
- uint32_t rx_id; // 接收id
- uint8_t rx_len; // 接收长度,可能为0-8
- // 接收的回调函数,用于解析接收到的数据
- void (*can_module_callback)(struct _ *); // callback needs an instance to tell among registered ones
- } CANInstance;
- ```
-
-
-
-
-## 其他IDE支持
-
-你还可以尝试VSC的EIDE插件+ozone的方式开发ac5/6工具链的程序。ac5/6工具链由于为arm出品的商业闭源软件,对mcu硬件架构的针对性优化更多,编译出来的程序优化效果往往更好、体积更小,执行速度快过arm-gnu工具链。
-
-另外的可能是Visual Studio + VisualGDB,根据VisualGDB的官网进行配置即可,可以利用VS提供的各种测试调试性能分析功能。对于熟悉VS丰富的功能支持的开发者,可以选择此方式。
-
-还可以尝试VSC的插件KEIL assistant,通过此法你需要在根目录打开cubeide配置文件,在project manager标签页选择将工具链改为MDK,**我们非常不推荐这种方式**。若要使用CubeIDE,也在相同的地方修改工具链。
-
-***不过开发本框架的最佳实践仍然是VSCode+Ozone。***
-
-> 只要你学习了[VSCode+Ozone使用方法](./VSCode+Ozone使用方法.md)文档内的*预备知识* ,掌握了工具链的用途和原理之后,不论换用什么IDE什么编译器,你都可以切换自如。
-
-
-
-## BSP层(Board Sopport Package)
-
-- 主要功能:实现对STM HAL的封装功能,进一步抽象硬件。
- - 在本框架中,BSP层与cubeMX初始化有一定程度的耦合,若没有在CUBEMX中开启某个外设,则在application不能初始化使用了对应外设的module。对该层的修改可能需要使用cube重新生成工程(主要是外设的配置,通信速度,时钟频率和分频数等)。该层也是唯一允许直接出现stm32HAL库函数的代码层,**在非BSP层编写代码时,如需使用HAL_...函数,请思考是否有同功能的BSP_...函数**。不过,由于ST的HAL已经对硬件进行较高的抽象(如以handle_xxx的方式描述一个硬件外设或功能引脚),因此即使需要更换开发板,必须修改的内容也极少。
- - 最简单的(如gpio)仅是对HAL库函数的封装。较为复杂的则会进行一定程度的处理(如can)
-
-**编写和使用指南**
-
-- 补充与修改:某款主控对应的BSP层应保持相同,当认为该层可能缺少部分功能或有错误时,请联系组长确认后解决并更新整个框架,**请勿自行修改提交**。 请在你修改/增加的bsp_XXX.md中提供测试用例和使用示范以及任何其他需要注意的事项,并在代码必要的地方添加注释。
-- 代码移植:BSP层也是在不同系列、型号的stm32间执行代码移植时主要需要关注的代码层。向功能更强系列移植一般只需要重配cube,而向功能较少的系列移植还需要去掉其不支持的功能。如果仅是对同一型号的开发板进行CUBEMX初始化配置的修改,一般只需要给app层的应用重新分配外设和引脚,或修改波特率和通信频率等。
-- 子文件与文件夹:
- - bsp.c/h:该层用于bsp基础功能初始化的文件,其中`bsp.h`被include至main.c中,以实现必须的底层初始化,目前需要初始化的bsp只有log和dwt,**不同主频的MCU需要修改dwt初始化的参数**。**注意**,有些外设如串口和CAN不需要在bsp.c中进行模块层的初始化,他们会在module层生成实例(即C语言中的结构体)并注册到bsp层时自动进行初始化。以此达到提高运行速度避免未使用的模块被加载的问题。
- - bsp_xxx.c/h:每一个成对的.c/h对应一种外设,当上面两个代码层需要使用某个外设时,这里的文件就是对应的交互接口。
-- 注册回调函数与接收:通信类外设模块有的定义了回调函数(函数指针类型),module层的模块需要自行处理接收回调函数,在注册bsp的时候应传入对应参数格式的回调函数指针,使得接收中断发生的时候bsp层可以自行找到对应的上层回调函数进行调用。这也是回调函数设计的初衷:为底层代码调用上层代码提供接口,当特定事件发生的时候完成触发(自行搜索hook函数)。
-
-## Module层
-
-- 主要功能:实现对设备的封装,如将IMU、PC、电机等视为一个完整的功能模块,让应用层(app)不需要关心其底层的具体实现,直接使用接口。
-
-- 文件夹
-
- - **注意,module层没有也不需要进行统一初始化**。app层的应用会包含一些模块,因此由app来调用各个模块的init()或register()函数,只有当一个module被app实例化,这个模块才会存在。
-
- > ~~命名为init()的初始化一般来说是开发板的独占资源,即有且只有一个这样的模块,无法拥有多个实例,如板载陀螺仪、LED、按键等。命名为register()的模块则可以拥有多个,比如电机。~~ legacy support,为了保证代码风格统一,所有接口统一命名为xxxRegister()。
-
- - algorithm:该层软件库存放位置,这些功能与硬件无关,而是提供通用的数据结构和“算子”以供该层的其他部分调用,主要是算法、控制器、底盘和位姿解算等。
-
-- module编写和使用指南:
-
- - 初始化:
-
- 根据代码对应的函数说明,传入对应的配置文件。对于某些需要集中设置的参数,一般于模块的头文件中会额外设定一个xxx_config_s的结构体用于初始化的参数传递。如果不需要进行这样的集中设置,则是直接传入对应的参数或module结构体中本就存在的成员变量。
-
- - 结构体:
-
- 也就是所说的“实例”,定义一个module结构体,对于app层来说就是拥有某一个功能模块的实例,比如一个特定的电机。在对电机进行操作的时候,为实现面向对象的功能,需要在接口函数中传入该结构体指针。
-
- - 函数:
-
- .c中存放的static函数和static变量相当于这个类的private函数,.h中的则相当于public。相似的driver的public函数应较为统一。由于通信格式,使用方法等的不同,不同通信设备在读取操作、数据格式上可能有所不同,这些不同应该在driver的内部处理。**由于C语言没有对象的概念,对于通信类的module,不同的实例需要在module.c中保存一份指针,用于处理数据接收的解析。**
-
- - 封装程度:
-
- app层使用时与底层实现无关。如在使用电机时,这个电机的数据该和哪些电机的数据在一个数据包中发送,can的过滤器设置,均属于应该自动处理的功能;通信类的模块应该封装到只有初始化、发送和读取。对于电机,则是用于初始化的`register`和发送控制命令`set_control`两个函数和一个实时更新的用于给app层提供该信息的数据结构体(电机反馈信息)。
-
-Module层主要存放的是类型定义和实例指针数组,在该层没有进行实例化(定义或通过malloc分配空间),若在APP层没有实例化,则该模块的存在与否不会影响编译后的可执行文件,只会占用.c文件中的static变量和代码区的少量内存(有些module只会保存每个实例对象的指针,在没有初始化的时候仅仅占用一个指针数组的空间)。因此,基于本框架的其他工程没有必要删除APP层未使用的module文件。
-
-务必为模块添加说明文档和使用范例,以及其他需要注意的事项(如果有)。
-
-> **面向对象小指南:**
->
-> 由于C语言没有对象的概念,对于需要使用通信的module,在其.c文件下都需要保存每个实例的指针,在收到消息时(发生回调)遍历所有实例指针,找到收到消息的实例。这种处理方式可能会导致实时性下降,例如CAN接收时要遍历所有注册了CAN的实例,进入module层还需要一次遍历。用C++则可以将对象的this指针和模块的回调函数进行绑定,生成一个可调用对象然后再进行CAN的注册,使得其不需要module层的遍历。
->
-> 考虑在实例中加入一个额外的`void*`域成员(成员变量),其内容为module层实例的地址。这样CAN收到消息时只需要遍历所有CAN instance,对于相同的模块,可以在其回调函数内部获取CAN instance的`void*`指针并通过强制类型转换cast成模块的实例结构体指针类型,从而访问特定的模块。
-> 这实际上是保存“对象”的parent pointer,使得实例可以访问拥有自己的实例(访问自己的父亲)。和回调函数配合,就可以防止交叉包含并为底层访问上层内容提供支持。
-
-## APP层(application)
-
-- 功能:实现机器人的控制,对机器人**控制**结构进行抽象。
-
- 在完成BSP层和Module层后,如果在APP层没有控制代码,则代码并无实际功能。换言之,BSP层与Module层的存在是为了APP层更简单、更合理、更易于扩展和移植。本框架的初始目标即是实现:在APP层仅需思考逻辑并用无关硬件的C语言代码实现即可完成整个机器人的控制。所有需要使用的模块和算法都在Module层提供,开发板外设硬件的抽象在bsp层完成。**所有使用到的模块都在APP层初始化**,因此不需要module自行初始化。
-
-- APP层按照机械设计结构(如云台、发射、底盘、夹爪、抬升、机械臂)建立对应的子文件夹,在其中完成初始化和相关逻辑功能的编写。还有用于发布指令的云台指令应用和底盘指令应用,前者应该包含一个遥控器模块和一个视觉通信模块,后者包含裁判系统模块。它们包含的模块都会处理一些指令和控制信息,这样还可以方便兼容双板。
-
-- 单双板切换在application的`robot_def.h`中进行,**修改宏定义可以切换开发板的设定模式**。当设定为单板的时候,在`robot.c`中会对gimbal,chassis,shoot,robot_cmd四个应用都进行初始化。对于双板的情况,需要将上板配置为gimbal board,下板配置为chassis board,它们会分别初始化gimbal/shoot/robot_cmd和chassis
-
-- 对于单板的情况,所有应用之间的信息交互通过message center完成。而使用双板时,需要通过板间通信传递控制信息(默认遥控器接收机和pc在云台板,裁判系统在底盘板,因此需要互发信息)。当前通过**条件编译**来控制信息的去向(发往message center/接收,还是通过can comm发送/接收),后续考虑将双板通信纳入message center的实现中,根据`robot_def.h`的开发板定义自动处理通信,降低应用层级的逻辑复杂度。
-
-## 文件树
-
-板级支持包的每个组件,每个moduel,以及每个app都有对应的说明文档.
-
-```shell
-ROOT:.
-│ .gitignore # git版本管理忽略文件
-│ .mxproject # CubeMX项目文件
-│ basic_framework.ioc # CubeMX初始化配置文件
-│ debug_ozone.jdebug # ozone debug调试配置和缓存文件
-│ LICENSE # 开源协议文件
-│ Makefile # 编译管理文件,为make(mingw32-make)命令的目标
-| Makefile.upgrade # 编译管理文件的升级版, 资深用户使用
-| CMakeLists.txt # cmake构建规则, 资深用户使用
-│ openocd_dap.cfg # 用于OpenOCD调试使用的配置文件,dap用
-│ openocd_jlink.cfg # 用于OpenOCD调试使用的配置文件,jlink用
-│ README.md # 本说明文档
-│ startup_stm32f407xx.s # F407汇编启动文件
-│ stm32.jflash # jlink的烧录的配置文件,一键下载用
-│ STM32F407.svd # F407外设地址映射文件,用于调试
-│ STM32F407IGHx_FLASH.ld # F407IGH(C板MCU)目标FLASH地址和链接规则,用于编译(作为链接阶段的链接器)
-│ task.ps1 # powershell脚本,一键编译并进入ozone调试/reset开发板用
-│
-├─.vscode
-│ launch.json # 调试的配置文件
-│ settings.json # 工作区配置文件,根据自己的需要配置
-│ tasks.json # 任务配置文件,包括一键编译下载调试等
-│
-├─.assets # 说明文档的图片
-├─.Doc # 本框架的各类说明文档
-├─.github # github action CI支持文件
-│
-├─application # 应用层
-├─bsp # 板级支持包
-├─modules # 模块层
-│
-├─Src # hal生成的外设初始化源文件
-├─Inc # hal生成的外设初始化头文件
-├─Drivers # hal driver和cmsis drivers
-└─Middlewares # STusb ext, rtos, segger rtt等
-```
-
-## BSP/Module/Application介绍
-
-在对应应用、模块和板级支持包文件夹下。每个.c文件或完整的功能模块都有说明文档。在编写新代码时注意按照规范编写说明文档。
-
-## 整体架构
-
-### 软件分层
-
-
-
-### 运行任务
-
-
-
-### 初始化流程
-
-~~~mermaid
-graph TD
-HAL库初始化 --> BSP初始化 --> Application初始化 --> app调用其拥有模块的初始化 --> 启动操作系统
-~~~
-
-**注意,应用初始化不得放入其对应任务中,即使是在死循环前,否则可能导致一些需要定时器的任务初始化异常**。
-
-APP会调用其所有的模块的初始化函数(注册函数),这是因为本框架的设计思想是任何模块在被注册(构造/初始化)之前,都是不存在的,当且仅当定义了一个模块结构体(也称实例)的时候,才有一个实体的概念。
-
-main函数唯一需要的函数是app层的`robot.c`中的`RobotInit()`函数,它首先会调用BSP初始化,然后进行所有应用的初始化;每个应用会调用对应模块的初始化;一些依赖通信外设的模块会将通信支持相关的bsp进行初始化。初始化结束之后实时系统启动。
-
-### 程序运行流程
-
-
-
-### 程序数据流
-
-
diff --git a/.Doc/版本更替.md b/.Doc/版本更替.md
deleted file mode 100644
index be11b39..0000000
--- a/.Doc/版本更替.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# 版本更替
-
-随着比赛的推进,我们的代码也在不断的更新,在不同的结点下会发布稳定可用版本,以便于大家使用。
-
-指路gitee release页面:[https://gitee.com/hnuyuelurm/basic_framework/tags](https://gitee.com/hnuyuelurm/basic_framework/tags)
-
-release页面会有一个版本号,例如`v1.0`,这个版本号就是我们的代码版本号,每次发布新的版本,版本号都会增加。
-
-第一次使用尽量避免直接clone
\ No newline at end of file
diff --git a/.Doc/让VSCode成为更称手的IDE.md b/.Doc/让VSCode成为更称手的IDE.md
deleted file mode 100644
index 10861fb..0000000
--- a/.Doc/让VSCode成为更称手的IDE.md
+++ /dev/null
@@ -1,136 +0,0 @@
-# 让VSCode变成你熟悉的形状
-
-VSCode的各种配置如快捷键、高亮颜色、主题、界面形状和位置等(也包括各种插件的设置)可以通过在`ctrl+,`打开的设置页面修改,更好的方式是你已经尝试过的——通过xxx.json文件进行配置。VSCode的配置系统同样通过`.json`文件完成,且存在继承和覆盖的关系。VSCode的底层配置`setting.json`是针对整个VSCode进行设置的,而工作区目录下创建的`.vscode/setting.json`则可以覆盖底层配置。了解了基本的配置结构后,这里将介绍一些入手必备的设置和推荐安装的插件。
-
-[TOC]
-
-## 快捷键
-
-不管使用什么软件,基本的快捷键一定可以帮助你提高效率,更专注于当前正在做的事——减少双手离开主键盘区的频率和时间。
-
-常用的快捷键已经在[VSCode的基础操作](VSCode+Ozone使用方法.md)中介绍,这里推荐一些shortcuts的组合,可以直接`ctrl+k&s`打开快捷键设置或进入`setting.json`手动修改。当然,你不一定要和我们的建议完全一致,**根据自己的习惯定制才是最好的!**
-
-- `ctrl+;`设置为移动到行尾,同时保留`end`,这样在输完函数参数之后不用按`→`或使用鼠标
-- `alt+j/k`设置为向左向右移动,这样在修改的时候不用按方向键;可以设置组合键达到”移动到符号末尾”的功能实现按符号或单词移动
-- `tab`改为移动到下一个建议(智能提示),`enter`设置为接受当前建议。如果只有一个建议,`tab`直接接受;`alt+tab`移动到上一个建议。
-- 设置一个组合键用于选中当前单词
-- 记住当前文件查找和全局查找的组合,最好再学习一下**正则表达式**。还有”选中当前所有出现“,可以快速定位当前文件有哪些地方用了这个变量/函数。
-- 熟练使用`ctrl+tab`切换当前已经打开的文件
-- 可以在`setting.json`中将`task.json`中的任务绑定成你需要的快捷键,比如默认`ctrl+shift+b`是构建任务。把一些常用的命令行操作写成task,通过快捷键瞬间触发。
-- 善用右键菜单中的peek xxx功能、展开调用层级和头文件/源文件跳转,以及git查看文件差异的功能,这在理清代码结构、查看之前的更改的时候非常有用。当然,不是让你按右键,是使用快捷键。如果你的键盘上有一个像文件一样的图标,当你聚焦在编辑区的时候可以按下它来替代右键(展开菜单)。
-- more...
-
-*若你使用触控板和笔记本电脑,也可以利用触控板实现一些实在找不到的快捷键功能。*一开始你可能会决定快捷键难记又难按,当你熟练之后,却会在无形之中极大提升你的效率。
-
-
-
-## 代码高亮
-
-虽然VSCode默认的语法高亮已经吊打KEIL和CubeIDE之流,但你是否发现变量全是浅蓝色,字符串、数值字面量内部也无法区分?无出其右,我们可以自定义各种entity的颜色!
-
-建议让copilot协助你完成,打开`setting.json`开始设置吧:
-
-- global、private member、public member、local设置为不同的颜色
-- 私有函数和公开函数设置为不同的颜色
-- static函数设置特殊的颜色?
-- 函数参数变量设置不同的颜色?
-
-
-
-## 终端工具
-
-你至少应该学习bash(msys2中会集成一套类linux的bash工具)的基础指令,如果有可能,也学习一下powershell。在chatGPT或者Copilot的帮助下,这易如反掌。当它们无能为力时请务必查阅**官方文档**,而不是在CSDN中💩里淘🪙。
-
-为你的终端配置好看的颜色、字体和背景,但不要花太多时间。一定要让你的终端具有补全和历史记录记忆功能。
-
-学会在命令行中使用一些常用的git操作,虽然vscode中已经提供了强大的图形化集成。
-
-务必学习vi/vim/nano的基础操作。
-
-熟悉在终端中创建/追加/移动/复制/删除文件和文件夹。
-
-学习gnu工具链的简单指令,协助你与编译报错信息一起定位bug和错误(常常是undefined reference或未定义函数、未定义就使用)。
-
-也许,了解一下shell的工作原理,或者更多,现代操作系统的运行架构?
-
-> 为basic_framework通过串口/SWD建立一套简单的cmd?有很多开源代码的实现,期待你的PR!
-
-
-
-## 进一步提高效率
-
-首先,快捷键一定要按的顺手,最好能让双手处于标准指法的起始状态就可以轻松触发。一定不要超过三个键,否则按起来手掌大开大合。
-
-建议打开函数的自动括号补全(一般在对应语言的插件设置中寻找),同时习惯snippets的使用,并根据自己的需要自定义一些方便的snippets。
-
-如果你认为vim很酷,那它确实很酷。vscode中有fake-vim插件,喜欢折腾的话,vim会让你在双手始终保持在键盘区,劈里啪啦地编码,只不过学习成本较高,曲线复杂。
-
-你最好升级一下默认的shell,windows下有好看的posh,linux则有广为流传的zsh。具体如何配置,自行查阅**官方文档**。
-
-记住,最好将不同软件开发使用的环境隔离开,所以你需要把msys2集成到vscode中!(macOS和linux用户忽略)
-
-把开发中常用但又繁琐的流程自动化,积累一套你自己的脚本库。
-
-....
-
-
-
-## 插件
-
-> 学习一个插件的使用,最好的方式是阅读插件的wiki和说明文档,而不是在搜索引擎里面搜索!询问ChatGPT或者Copilot Chat也是一个比较好的办法,初级的问题它们几乎不会犯错。
-
-- **Better C++ Syntax**
-
-用于静态解析C++代码,为intellisense以及language server提供代码高亮和完整的智能提示选项。
-
-- **Blockman**
-
-为代码分块。不同的作用域会被浅色背景边框包围,同时高亮当前focus的代码块,方便在大段代码中定位程序控制流。
-
-- **Bookmarks**
-
-为代码添加书签,可以在左侧tab页中跳转到对应位置,方便阅读代码时往复查看,也有助于阅读理解。右键点击代码行号左侧(即打断点的地方)可以添加书签或带label的书签。
-
-- **C/C++ Snippets**
-
-为基本的语句(关键字)提供代码补全,如输入`for`自动生成下面的代码:
-
-```c
-for (size_t i = 0; i < count; i++)
-{
- /* code */
-}
-```
-
-补全之后,按下tab会进入不同的位置,方便进一步修改snippet。你也可以在VSCode中自定义常用的snippet补全。
-
-- **Code Issue Manager**
-
-可以在代码的任意地方插入“便签”和“评注”,支持多人协作。是一个比注释更好的TODO list和注意事项提醒。插入的issue支持markdown格式。
-
-- **Doxygen Documention Generator**
-
-为你的代码生成doxygen文档格式的注释。同时也支持一些基本的注释块生成。输入`/**`再按下回车会根据当前注释的位置自动生成合适的注释块。本框架中的注释均通过该插件生成。
-
-- **Github Copilot / Copilot Labs / Copilot Chat**
-
-体验大模型的威力。尤其是Copilot Chat非常适合为你提供一门语言的入门级咨询。
-
-- **Gitlens**
-
-方便地通过图形化的方式管理你的git仓库。
-
-- **HexEditor & Hex Hover Converter**
-
-以十六进制编辑文件 & 鼠标悬停在任意数值类型上时自动提供2/8/16进制的转换。
-
-- **Live Share**
-
-和你的伙伴一起coding。
-
-- **SonarLint**
-
-VSCode上最强大的静态检查工具,在VSCode自动静态检查的基础上提供更严格的代码建议,尽可能降低出错的可能。其中也包含了不同语言的最佳实践。
-
-cmake可以通过添加`DCMAKE_EXPORT_COMPILE_COMMANDS=True` 的指令(直接在cmakelists中通过`set()`设定也可以),makefile则通过Makefile Tools插件设置生成`compile_commands.json`的路径。
-
diff --git a/.assets/00937839b59a4c039ee8ecb8a5136e3c.png b/.assets/00937839b59a4c039ee8ecb8a5136e3c.png
deleted file mode 100644
index a890de4..0000000
Binary files a/.assets/00937839b59a4c039ee8ecb8a5136e3c.png and /dev/null differ
diff --git a/.assets/CANcomm.png b/.assets/CANcomm.png
deleted file mode 100644
index b4a0a76..0000000
Binary files a/.assets/CANcomm.png and /dev/null differ
diff --git a/.assets/allrobot.jpg b/.assets/allrobot.jpg
deleted file mode 100644
index 6b8c991..0000000
Binary files a/.assets/allrobot.jpg and /dev/null differ
diff --git a/.assets/balance.gif b/.assets/balance.gif
deleted file mode 100644
index 1667114..0000000
Binary files a/.assets/balance.gif and /dev/null differ
diff --git a/.assets/dataflow.svg b/.assets/dataflow.svg
deleted file mode 100644
index a2af8bf..0000000
--- a/.assets/dataflow.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/.assets/engineering.gif b/.assets/engineering.gif
deleted file mode 100644
index 6fb86fd..0000000
Binary files a/.assets/engineering.gif and /dev/null differ
diff --git a/.assets/image-20221112145717063.png b/.assets/image-20221112145717063.png
deleted file mode 100644
index 1dd4f1b..0000000
Binary files a/.assets/image-20221112145717063.png and /dev/null differ
diff --git a/.assets/image-20221112160213066.png b/.assets/image-20221112160213066.png
deleted file mode 100644
index 69b81ca..0000000
Binary files a/.assets/image-20221112160213066.png and /dev/null differ
diff --git a/.assets/image-20221112172051589.png b/.assets/image-20221112172051589.png
deleted file mode 100644
index cb5d993..0000000
Binary files a/.assets/image-20221112172051589.png and /dev/null differ
diff --git a/.assets/image-20221112172157533.png b/.assets/image-20221112172157533.png
deleted file mode 100644
index 9308765..0000000
Binary files a/.assets/image-20221112172157533.png and /dev/null differ
diff --git a/.assets/image-20221112172208749.png b/.assets/image-20221112172208749.png
deleted file mode 100644
index db2d3f9..0000000
Binary files a/.assets/image-20221112172208749.png and /dev/null differ
diff --git a/.assets/image-20221112172221756.png b/.assets/image-20221112172221756.png
deleted file mode 100644
index 72d1c45..0000000
Binary files a/.assets/image-20221112172221756.png and /dev/null differ
diff --git a/.assets/image-20221112172239386.png b/.assets/image-20221112172239386.png
deleted file mode 100644
index 8c74f9d..0000000
Binary files a/.assets/image-20221112172239386.png and /dev/null differ
diff --git a/.assets/image-20221112172254809.png b/.assets/image-20221112172254809.png
deleted file mode 100644
index d587ada..0000000
Binary files a/.assets/image-20221112172254809.png and /dev/null differ
diff --git a/.assets/image-20221112172348408.png b/.assets/image-20221112172348408.png
deleted file mode 100644
index 7f202c6..0000000
Binary files a/.assets/image-20221112172348408.png and /dev/null differ
diff --git a/.assets/image-20221112172420037.png b/.assets/image-20221112172420037.png
deleted file mode 100644
index ed9e9d2..0000000
Binary files a/.assets/image-20221112172420037.png and /dev/null differ
diff --git a/.assets/image-20221112172716320.png b/.assets/image-20221112172716320.png
deleted file mode 100644
index 59286af..0000000
Binary files a/.assets/image-20221112172716320.png and /dev/null differ
diff --git a/.assets/image-20221112172858593.png b/.assets/image-20221112172858593.png
deleted file mode 100644
index 703615d..0000000
Binary files a/.assets/image-20221112172858593.png and /dev/null differ
diff --git a/.assets/image-20221112173534670.png b/.assets/image-20221112173534670.png
deleted file mode 100644
index 504cd6e..0000000
Binary files a/.assets/image-20221112173534670.png and /dev/null differ
diff --git a/.assets/image-20221112174211802.png b/.assets/image-20221112174211802.png
deleted file mode 100644
index 5f2da6f..0000000
Binary files a/.assets/image-20221112174211802.png and /dev/null differ
diff --git a/.assets/image-20221112180103750.png b/.assets/image-20221112180103750.png
deleted file mode 100644
index 6908be1..0000000
Binary files a/.assets/image-20221112180103750.png and /dev/null differ
diff --git a/.assets/image-20221112191712534.png b/.assets/image-20221112191712534.png
deleted file mode 100644
index cf1953f..0000000
Binary files a/.assets/image-20221112191712534.png and /dev/null differ
diff --git a/.assets/image-20221112192133103.png b/.assets/image-20221112192133103.png
deleted file mode 100644
index 5fb211b..0000000
Binary files a/.assets/image-20221112192133103.png and /dev/null differ
diff --git a/.assets/image-20221112192509718.png b/.assets/image-20221112192509718.png
deleted file mode 100644
index c73da28..0000000
Binary files a/.assets/image-20221112192509718.png and /dev/null differ
diff --git a/.assets/image-20221112192610543.png b/.assets/image-20221112192610543.png
deleted file mode 100644
index 245cb4e..0000000
Binary files a/.assets/image-20221112192610543.png and /dev/null differ
diff --git a/.assets/image-20221113125439857.png b/.assets/image-20221113125439857.png
deleted file mode 100644
index cdd69c2..0000000
Binary files a/.assets/image-20221113125439857.png and /dev/null differ
diff --git a/.assets/image-20221113131044191.png b/.assets/image-20221113131044191.png
deleted file mode 100644
index b74ab20..0000000
Binary files a/.assets/image-20221113131044191.png and /dev/null differ
diff --git a/.assets/image-20221113133624273.png b/.assets/image-20221113133624273.png
deleted file mode 100644
index deabf6a..0000000
Binary files a/.assets/image-20221113133624273.png and /dev/null differ
diff --git a/.assets/image-20221113133904084.png b/.assets/image-20221113133904084.png
deleted file mode 100644
index 103ee21..0000000
Binary files a/.assets/image-20221113133904084.png and /dev/null differ
diff --git a/.assets/image-20221113134252407.png b/.assets/image-20221113134252407.png
deleted file mode 100644
index fe2ed0f..0000000
Binary files a/.assets/image-20221113134252407.png and /dev/null differ
diff --git a/.assets/image-20221113134605331.png b/.assets/image-20221113134605331.png
deleted file mode 100644
index fc69e89..0000000
Binary files a/.assets/image-20221113134605331.png and /dev/null differ
diff --git a/.assets/image-20221113142448939.png b/.assets/image-20221113142448939.png
deleted file mode 100644
index 84e0755..0000000
Binary files a/.assets/image-20221113142448939.png and /dev/null differ
diff --git a/.assets/image-20221113152513343.png b/.assets/image-20221113152513343.png
deleted file mode 100644
index d3a217a..0000000
Binary files a/.assets/image-20221113152513343.png and /dev/null differ
diff --git a/.assets/image-20221113212706633.png b/.assets/image-20221113212706633.png
deleted file mode 100644
index 58a6cdb..0000000
Binary files a/.assets/image-20221113212706633.png and /dev/null differ
diff --git a/.assets/image-20221115215531879.png b/.assets/image-20221115215531879.png
deleted file mode 100644
index 484cbce..0000000
Binary files a/.assets/image-20221115215531879.png and /dev/null differ
diff --git a/.assets/image-20221116150122397.png b/.assets/image-20221116150122397.png
deleted file mode 100644
index 3e7195b..0000000
Binary files a/.assets/image-20221116150122397.png and /dev/null differ
diff --git a/.assets/image-20221116150901418.png b/.assets/image-20221116150901418.png
deleted file mode 100644
index 263d1c1..0000000
Binary files a/.assets/image-20221116150901418.png and /dev/null differ
diff --git a/.assets/image-20221116152032104.png b/.assets/image-20221116152032104.png
deleted file mode 100644
index 27ec34e..0000000
Binary files a/.assets/image-20221116152032104.png and /dev/null differ
diff --git a/.assets/image-20221116193340770.png b/.assets/image-20221116193340770.png
deleted file mode 100644
index e71f1fa..0000000
Binary files a/.assets/image-20221116193340770.png and /dev/null differ
diff --git a/.assets/image-20221117121323757.png b/.assets/image-20221117121323757.png
deleted file mode 100644
index bd64745..0000000
Binary files a/.assets/image-20221117121323757.png and /dev/null differ
diff --git a/.assets/image-20221119173731119.png b/.assets/image-20221119173731119.png
deleted file mode 100644
index 08d19eb..0000000
Binary files a/.assets/image-20221119173731119.png and /dev/null differ
diff --git a/.assets/image-20221119173918340.png b/.assets/image-20221119173918340.png
deleted file mode 100644
index 7775198..0000000
Binary files a/.assets/image-20221119173918340.png and /dev/null differ
diff --git a/.assets/image-20221119174445067.png b/.assets/image-20221119174445067.png
deleted file mode 100644
index 719019e..0000000
Binary files a/.assets/image-20221119174445067.png and /dev/null differ
diff --git a/.assets/image-20221119222946103.png b/.assets/image-20221119222946103.png
deleted file mode 100644
index c482f16..0000000
Binary files a/.assets/image-20221119222946103.png and /dev/null differ
diff --git a/.assets/image-20221119223148604.png b/.assets/image-20221119223148604.png
deleted file mode 100644
index 651b6e1..0000000
Binary files a/.assets/image-20221119223148604.png and /dev/null differ
diff --git a/.assets/image-20221201134906999.png b/.assets/image-20221201134906999.png
deleted file mode 100644
index 0212df4..0000000
Binary files a/.assets/image-20221201134906999.png and /dev/null differ
diff --git a/.assets/image-20221201150945052.png b/.assets/image-20221201150945052.png
deleted file mode 100644
index 9f6193e..0000000
Binary files a/.assets/image-20221201150945052.png and /dev/null differ
diff --git a/.assets/image-20221201152530558.png b/.assets/image-20221201152530558.png
deleted file mode 100644
index c1c8208..0000000
Binary files a/.assets/image-20221201152530558.png and /dev/null differ
diff --git a/.assets/image-20221201152904044.png b/.assets/image-20221201152904044.png
deleted file mode 100644
index 9e65a2a..0000000
Binary files a/.assets/image-20221201152904044.png and /dev/null differ
diff --git a/.assets/image-20221201155228196.png b/.assets/image-20221201155228196.png
deleted file mode 100644
index 00e389a..0000000
Binary files a/.assets/image-20221201155228196.png and /dev/null differ
diff --git a/.assets/image-20230202151939109.png b/.assets/image-20230202151939109.png
deleted file mode 100644
index 39981bc..0000000
Binary files a/.assets/image-20230202151939109.png and /dev/null differ
diff --git a/.assets/image-20230723132711865.png b/.assets/image-20230723132711865.png
deleted file mode 100644
index 7607573..0000000
Binary files a/.assets/image-20230723132711865.png and /dev/null differ
diff --git a/.assets/image-20230725152433502.png b/.assets/image-20230725152433502.png
deleted file mode 100644
index 2daf96e..0000000
Binary files a/.assets/image-20230725152433502.png and /dev/null differ
diff --git a/.assets/image-20230725153133419.png b/.assets/image-20230725153133419.png
deleted file mode 100644
index 6a802f6..0000000
Binary files a/.assets/image-20230725153133419.png and /dev/null differ
diff --git a/.assets/image-20230725153635454.png b/.assets/image-20230725153635454.png
deleted file mode 100644
index 3785972..0000000
Binary files a/.assets/image-20230725153635454.png and /dev/null differ
diff --git a/.assets/image-20230725154910307.png b/.assets/image-20230725154910307.png
deleted file mode 100644
index a4104db..0000000
Binary files a/.assets/image-20230725154910307.png and /dev/null differ
diff --git a/.assets/ozone.png b/.assets/ozone.png
deleted file mode 100644
index e419317..0000000
Binary files a/.assets/ozone.png and /dev/null differ
diff --git a/.assets/sentry_infantry12.gif b/.assets/sentry_infantry12.gif
deleted file mode 100644
index a7dcfc0..0000000
Binary files a/.assets/sentry_infantry12.gif and /dev/null differ
diff --git a/.assets/v2-2797ea99d0d38eb9996993bb0ad77ab2_720w.webp b/.assets/v2-2797ea99d0d38eb9996993bb0ad77ab2_720w.webp
deleted file mode 100644
index 63a0078..0000000
Binary files a/.assets/v2-2797ea99d0d38eb9996993bb0ad77ab2_720w.webp and /dev/null differ
diff --git a/.assets/vscodedebug.png b/.assets/vscodedebug.png
deleted file mode 100644
index e76fb36..0000000
Binary files a/.assets/vscodedebug.png and /dev/null differ
diff --git a/.assets/yuelu_badge.png b/.assets/yuelu_badge.png
deleted file mode 100644
index ffbedf5..0000000
Binary files a/.assets/yuelu_badge.png and /dev/null differ