修改doc存放位置,增加代码静态检查,完成了README文档,修复了.assets图片分辨率低的问题
|
@ -84,7 +84,7 @@ C语言代码由固定的词汇(关键字)按照固定的格式(语法)
|
||||||
|
|
||||||
对于单个.c文件,从C语言开始到单片机可识别的.bin文件,一般要经历以下几步:
|
对于单个.c文件,从C语言开始到单片机可识别的.bin文件,一般要经历以下几步:
|
||||||
|
|
||||||
![img](.assets/v2-2797ea99d0d38eb9996993bb0ad77ab2_720w.webp)
|
![img](../.assets/v2-2797ea99d0d38eb9996993bb0ad77ab2_720w.webp)
|
||||||
|
|
||||||
首先是编译**预处理**Preprocessing,这一步会展开宏并删除注释,将多余的空格去除。预处理之后会生成.i文件。
|
首先是编译**预处理**Preprocessing,这一步会展开宏并删除注释,将多余的空格去除。预处理之后会生成.i文件。
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ C语言代码由固定的词汇(关键字)按照固定的格式(语法)
|
||||||
|
|
||||||
### C语言内存模型
|
### C语言内存模型
|
||||||
|
|
||||||
<img src=".assets/image-20221112160213066.png" alt="image-20221112160213066" style="zoom:80%;" />
|
<img src="../.assets/image-20221112160213066.png" alt="image-20221112160213066" style="zoom:80%;" />
|
||||||
|
|
||||||
以上是C语言常见的内存模型,即C语言的代码块以及运行时使用的内存(包括函数、变量等)的组织方式。
|
以上是C语言常见的内存模型,即C语言的代码块以及运行时使用的内存(包括函数、变量等)的组织方式。
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ RTOS创建任务的时候也会为每个任务分配一定的栈空间,它会
|
||||||
|
|
||||||
### Debug外设工作原理
|
### Debug外设工作原理
|
||||||
|
|
||||||
![image-20221112145717063](.assets/image-20221112145717063.png)
|
![image-20221112145717063](../.assets/image-20221112145717063.png)
|
||||||
|
|
||||||
DBG支持模块(红框标注部分,也可以看作一个外设)通过一条专用的AHB-AP总线和调试接口相连(Jtag或swd),并且有与**数据**和**外设**总线直接相连的桥接器。它还同时连接了中断嵌套管理器(因此同样可以捕获中断并进行debug)和ITM、DWT、FPB这些调试支持模块。因此DBG可以直接获取内存或片上外设内的数据而不需要占用CPU的资源,并将这些数据通过专用外设总线发送给调试器,进而在上位机中读取。
|
DBG支持模块(红框标注部分,也可以看作一个外设)通过一条专用的AHB-AP总线和调试接口相连(Jtag或swd),并且有与**数据**和**外设**总线直接相连的桥接器。它还同时连接了中断嵌套管理器(因此同样可以捕获中断并进行debug)和ITM、DWT、FPB这些调试支持模块。因此DBG可以直接获取内存或片上外设内的数据而不需要占用CPU的资源,并将这些数据通过专用外设总线发送给调试器,进而在上位机中读取。
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ ITM是instrument trace macrocell指令追踪宏单元的缩写,它用于提供
|
||||||
|
|
||||||
### GDB调试MCU原理
|
### GDB调试MCU原理
|
||||||
|
|
||||||
![image-20221117121323757](.assets/image-20221117121323757.png)
|
![image-20221117121323757](../.assets/image-20221117121323757.png)
|
||||||
|
|
||||||
不论使用MDK(KEIL)还是VSCode还是Ozone,实际上背后的流程相同。首先GDB会建立TCP/IP端口并提供接口,调试服务器(Server)作为硬件调试器和GDB软件的桥梁,将硬件调试器的相关功能(也就是DBG外设支持的那些功能)映射到GDB的接口上(通过连接到GDB建立的端口)。之后启动调试,将可执行文件下载到目标MCU上,然后从main开始执行
|
不论使用MDK(KEIL)还是VSCode还是Ozone,实际上背后的流程相同。首先GDB会建立TCP/IP端口并提供接口,调试服务器(Server)作为硬件调试器和GDB软件的桥梁,将硬件调试器的相关功能(也就是DBG外设支持的那些功能)映射到GDB的接口上(通过连接到GDB建立的端口)。之后启动调试,将可执行文件下载到目标MCU上,然后从main开始执行
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ typedef struct
|
||||||
>
|
>
|
||||||
> **VSCode上线了一款新的插件:**
|
> **VSCode上线了一款新的插件:**
|
||||||
>
|
>
|
||||||
> ![image-20221201134906999](.assets/image-20221201134906999.png)
|
> ![image-20221201134906999](../.assets/image-20221201134906999.png)
|
||||||
>
|
>
|
||||||
> 支持一键配置Arm GNU工具链、MinGW64(make工具)和OpenOCD!可以尝试使用这个插件替代下面的配置流程。并且,此插件还提供了一键下载、一键调试的支持,只需要选择合适的下载器配置即可,全部都是图形化界面的操作!
|
> 支持一键配置Arm GNU工具链、MinGW64(make工具)和OpenOCD!可以尝试使用这个插件替代下面的配置流程。并且,此插件还提供了一键下载、一键调试的支持,只需要选择合适的下载器配置即可,全部都是图形化界面的操作!
|
||||||
>
|
>
|
||||||
|
@ -200,15 +200,15 @@ typedef struct
|
||||||
- **Cortex-Debug**,**Cortex-Debug: Device Support Pack - STM32F4**:提供调试支持。cortex debug还会自动帮助你安装一些调试相关的插件。
|
- **Cortex-Debug**,**Cortex-Debug: Device Support Pack - STM32F4**:提供调试支持。cortex debug还会自动帮助你安装一些调试相关的插件。
|
||||||
- **IntelliCode**,**Makfile Tools**:提供代码高亮支持
|
- **IntelliCode**,**Makfile Tools**:提供代码高亮支持
|
||||||
|
|
||||||
![image-20221112172157533](.assets/image-20221112172157533.png)
|
![image-20221112172157533](../.assets/image-20221112172157533.png)
|
||||||
|
|
||||||
![image-20221112172208749](.assets/image-20221112172208749.png)
|
![image-20221112172208749](../.assets/image-20221112172208749.png)
|
||||||
|
|
||||||
![image-20221112172221756](.assets/image-20221112172221756.png)
|
![image-20221112172221756](../.assets/image-20221112172221756.png)
|
||||||
|
|
||||||
![image-20221112172239386](.assets/image-20221112172239386.png)
|
![image-20221112172239386](../.assets/image-20221112172239386.png)
|
||||||
|
|
||||||
![image-20221112172254809](.assets/image-20221112172254809.png)
|
![image-20221112172254809](../.assets/image-20221112172254809.png)
|
||||||
|
|
||||||
> MinGW、Arm GNU toolchain和OpenOCD也可以通过**MSYS2**使用pacman包管理器(和apt/yum类似)直接安装,这种方法一步到位,**==这是更推荐使用的方式==**,请参看[附录5](##附录5:利用MSYS2安装依赖环境)。
|
> MinGW、Arm GNU toolchain和OpenOCD也可以通过**MSYS2**使用pacman包管理器(和apt/yum类似)直接安装,这种方法一步到位,**==这是更推荐使用的方式==**,请参看[附录5](##附录5:利用MSYS2安装依赖环境)。
|
||||||
>
|
>
|
||||||
|
@ -216,17 +216,17 @@ typedef struct
|
||||||
|
|
||||||
- 安装MinGW,等待界面如下:(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除)
|
- 安装MinGW,等待界面如下:(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除)
|
||||||
|
|
||||||
![image-20221112172051589](.assets/image-20221112172051589.png)
|
![image-20221112172051589](../.assets/image-20221112172051589.png)
|
||||||
|
|
||||||
安装好后,打开MinGW后将所有的支持包勾选,然后安装:
|
安装好后,打开MinGW后将所有的支持包勾选,然后安装:
|
||||||
|
|
||||||
![image-20221112172348408](.assets/image-20221112172348408.png)
|
![image-20221112172348408](../.assets/image-20221112172348408.png)
|
||||||
|
|
||||||
![image-20221112172420037](.assets/image-20221112172420037.png)
|
![image-20221112172420037](../.assets/image-20221112172420037.png)
|
||||||
|
|
||||||
安装完以后,将MinGW的bin文件夹添加到环境变量中的path下,按下菜单键搜索**编辑系统环境变量**打开之后:
|
安装完以后,将MinGW的bin文件夹添加到环境变量中的path下,按下菜单键搜索**编辑系统环境变量**打开之后:
|
||||||
|
|
||||||
![image-20221112172716320](.assets/image-20221112172716320.png)
|
![image-20221112172716320](../.assets/image-20221112172716320.png)
|
||||||
|
|
||||||
图片看不清请打开原图。验证安装:
|
图片看不清请打开原图。验证安装:
|
||||||
|
|
||||||
|
@ -236,7 +236,7 @@ typedef struct
|
||||||
|
|
||||||
- 配置gcc-arm-none-eabi环境变量,**把压缩包解压以后放在某个地方**,然后同上,将工具链的bin添加到PATH:(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除)
|
- 配置gcc-arm-none-eabi环境变量,**把压缩包解压以后放在某个地方**,然后同上,将工具链的bin添加到PATH:(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除)
|
||||||
|
|
||||||
![image-20221112172858593](.assets/image-20221112172858593.png)
|
![image-20221112172858593](../.assets/image-20221112172858593.png)
|
||||||
|
|
||||||
<center>安装路径可能不一样,这里要使用你自己的路径而不是直接抄</center>
|
<center>安装路径可能不一样,这里要使用你自己的路径而不是直接抄</center>
|
||||||
|
|
||||||
|
@ -254,11 +254,11 @@ typedef struct
|
||||||
|
|
||||||
在project manager标签页工具链选择makefile
|
在project manager标签页工具链选择makefile
|
||||||
|
|
||||||
![image-20221112173534670](.assets/image-20221112173534670.png)
|
![image-20221112173534670](../.assets/image-20221112173534670.png)
|
||||||
|
|
||||||
生成的目录结构如下:
|
生成的目录结构如下:
|
||||||
|
|
||||||
![image-20221112174211802](.assets/image-20221112174211802.png)
|
![image-20221112174211802](../.assets/image-20221112174211802.png)
|
||||||
|
|
||||||
Makefile就是我们要使用的构建规则文件。
|
Makefile就是我们要使用的构建规则文件。
|
||||||
|
|
||||||
|
@ -288,7 +288,7 @@ VSCode常用快捷键包括:
|
||||||
|
|
||||||
为了提供完整的代码高亮支持,需要配置Makefile tools插件的make程序路径,`ctrl+,`打开设置,搜索make path找到设置并填写:
|
为了提供完整的代码高亮支持,需要配置Makefile tools插件的make程序路径,`ctrl+,`打开设置,搜索make path找到设置并填写:
|
||||||
|
|
||||||
![image-20221113152513343](.assets/image-20221113152513343.png)
|
![image-20221113152513343](../.assets/image-20221113152513343.png)
|
||||||
|
|
||||||
> mingw32-make就是下面介绍的make工具(配合makefile替代手动调用gcc)。这里之所以只要输入mingw32-make而不用完整路径,是因为我们将mingw的bin文件夹加入环境变量了,因此系统会在PATH下自动寻找对应项
|
> mingw32-make就是下面介绍的make工具(配合makefile替代手动调用gcc)。这里之所以只要输入mingw32-make而不用完整路径,是因为我们将mingw的bin文件夹加入环境变量了,因此系统会在PATH下自动寻找对应项
|
||||||
|
|
||||||
|
@ -314,7 +314,7 @@ mingw32-make -j24 # -j参数表示参与编译的线程数,一般使用-j12
|
||||||
>
|
>
|
||||||
> 我对make的编译命令进行了静默处理,只输出error和warning以及最后的生成文件信息。如果想要解除静默(就是下面所说的“你可以看到大致如下的输出”),需要修改Makefile。**本仓库下的makefile中已经用注释标明。**
|
> 我对make的编译命令进行了静默处理,只输出error和warning以及最后的生成文件信息。如果想要解除静默(就是下面所说的“你可以看到大致如下的输出”),需要修改Makefile。**本仓库下的makefile中已经用注释标明。**
|
||||||
|
|
||||||
![image-20221112191712534](.assets/image-20221112191712534.png)
|
![image-20221112191712534](../.assets/image-20221112191712534.png)
|
||||||
|
|
||||||
就会开始编译了。你可以看到大致如下的输出:
|
就会开始编译了。你可以看到大致如下的输出:
|
||||||
|
|
||||||
|
@ -361,7 +361,7 @@ arm-none-eabi-objcopy -O binary -S build/basic_framework.elf build/basic_framewo
|
||||||
|
|
||||||
这样,你就可以点击VSCode工具栏上方的Terminal->Run task选择你刚刚配置的任务开始编译了。**更方便的方法是使用快捷键:`ctrl+shift+B`。** 之后要配置下载任务和调试任务等,也可以利用这种方法,新建一个xxx_task,实现一键下载、一键调试等。
|
这样,你就可以点击VSCode工具栏上方的Terminal->Run task选择你刚刚配置的任务开始编译了。**更方便的方法是使用快捷键:`ctrl+shift+B`。** 之后要配置下载任务和调试任务等,也可以利用这种方法,新建一个xxx_task,实现一键下载、一键调试等。
|
||||||
|
|
||||||
![image-20221112192133103](.assets/image-20221112192133103.png)
|
![image-20221112192133103](../.assets/image-20221112192133103.png)
|
||||||
|
|
||||||
> 还没配置任务的时候,需要在Terminal标签页中选择Configure Tasks... 创建一个新的.json文件。
|
> 还没配置任务的时候,需要在Terminal标签页中选择Configure Tasks... 创建一个新的.json文件。
|
||||||
>
|
>
|
||||||
|
@ -371,13 +371,13 @@ arm-none-eabi-objcopy -O binary -S build/basic_framework.elf build/basic_framewo
|
||||||
|
|
||||||
Makefile的大部分内容在CubeMX初始化的时候就会帮你生成。如果新增了.c的源文件,你需要在`C_SOURCES`中新增:
|
Makefile的大部分内容在CubeMX初始化的时候就会帮你生成。如果新增了.c的源文件,你需要在`C_SOURCES`中新增:
|
||||||
|
|
||||||
![image-20221112192509718](.assets/image-20221112192509718.png)
|
![image-20221112192509718](../.assets/image-20221112192509718.png)
|
||||||
|
|
||||||
换行需要在行尾加反斜杠\\
|
换行需要在行尾加反斜杠\\
|
||||||
|
|
||||||
如果新增了头文件,在`C_INCLUDES`中新增头文件所在的文件夹:
|
如果新增了头文件,在`C_INCLUDES`中新增头文件所在的文件夹:
|
||||||
|
|
||||||
![image-20221112192610543](.assets/image-20221112192610543.png)
|
![image-20221112192610543](../.assets/image-20221112192610543.png)
|
||||||
|
|
||||||
换行需要在行尾加反斜杠\\
|
换行需要在行尾加反斜杠\\
|
||||||
|
|
||||||
|
@ -412,7 +412,7 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
|
||||||
|
|
||||||
***其他配置需要的文件已经全部在basic_framework中提供***,包括`openocd.cfg STM32F407.svd .vscode/launch.json`。
|
***其他配置需要的文件已经全部在basic_framework中提供***,包括`openocd.cfg STM32F407.svd .vscode/launch.json`。
|
||||||
|
|
||||||
![image-20221115215531879](.assets/image-20221115215531879.png)
|
![image-20221115215531879](../.assets/image-20221115215531879.png)
|
||||||
|
|
||||||
<center>主要需要配置这三个路径,第四个gdbPath可以选配</center>
|
<center>主要需要配置这三个路径,第四个gdbPath可以选配</center>
|
||||||
|
|
||||||
|
@ -422,7 +422,7 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
|
||||||
|
|
||||||
然后选择run and debug标签页,在选项中选择你配置好的选项,开始调试。**或者使用快捷键:`F5`。**
|
然后选择run and debug标签页,在选项中选择你配置好的选项,开始调试。**或者使用快捷键:`F5`。**
|
||||||
|
|
||||||
![image-20221112180103750](.assets/image-20221112180103750.png)
|
![image-20221112180103750](../.assets/image-20221112180103750.png)
|
||||||
|
|
||||||
我们的仓库中默认提供了两种下载器的支持,dap-link(无线调试器属于这一种)和j-link(包括小的j-link OB和黑色大盒子jlink)。
|
我们的仓库中默认提供了两种下载器的支持,dap-link(无线调试器属于这一种)和j-link(包括小的j-link OB和黑色大盒子jlink)。
|
||||||
|
|
||||||
|
@ -430,13 +430,13 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
|
||||||
|
|
||||||
开始调试后,显示的界面如下:
|
开始调试后,显示的界面如下:
|
||||||
|
|
||||||
![](.assets/vscodedebug.png)
|
![](../.assets/vscodedebug.png)
|
||||||
|
|
||||||
1. 变量查看窗口,包括当前调用栈(当前作用域或代码块)内的局部变量、当前文件的静态变量和全局变量。register选项卡可以查看cpu内核的寄存器数值。
|
1. 变量查看窗口,包括当前调用栈(当前作用域或代码块)内的局部变量、当前文件的静态变量和全局变量。register选项卡可以查看cpu内核的寄存器数值。
|
||||||
|
|
||||||
2. 变量watch窗口。右键单击要查看的变量,选择watch加入查看。
|
2. 变量watch窗口。右键单击要查看的变量,选择watch加入查看。
|
||||||
|
|
||||||
![image-20221113131044191](.assets/image-20221113131044191.png)
|
![image-20221113131044191](../.assets/image-20221113131044191.png)
|
||||||
|
|
||||||
还支持直接运行到指针所选处(Run to Cursor)以及直接跳转到指针处执行(Jump to Cursor)。添加行内断点(若一个表达式由多个表达式组成)也是很方便的功能,可以帮助进一步定位bug。
|
还支持直接运行到指针所选处(Run to Cursor)以及直接跳转到指针处执行(Jump to Cursor)。添加行内断点(若一个表达式由多个表达式组成)也是很方便的功能,可以帮助进一步定位bug。
|
||||||
|
|
||||||
|
@ -444,7 +444,7 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
|
||||||
|
|
||||||
VSCode提供的一个最大的便利就是,你可以将鼠标悬停在需要查看的变量上,**不需要添加到watch就能观察变量值。**如果是指针还可以自动解析,获取解引用后的值。结构体也支持直接展开。
|
VSCode提供的一个最大的便利就是,你可以将鼠标悬停在需要查看的变量上,**不需要添加到watch就能观察变量值。**如果是指针还可以自动解析,获取解引用后的值。结构体也支持直接展开。
|
||||||
|
|
||||||
![image-20221113133624273](.assets/image-20221113133624273.png)
|
![image-20221113133624273](../.assets/image-20221113133624273.png)
|
||||||
|
|
||||||
> **现在Cortex-Debug插件也已经支持live watch(变量动态监视)**,最高可设置的刷新频率为4Hz,足堪大用,我们可以宣告KEIL的时代已经落幕!但是更复杂,更高频率的变量观测以及可视化功能还是需要通过ozone完成。
|
> **现在Cortex-Debug插件也已经支持live watch(变量动态监视)**,最高可设置的刷新频率为4Hz,足堪大用,我们可以宣告KEIL的时代已经落幕!但是更复杂,更高频率的变量观测以及可视化功能还是需要通过ozone完成。
|
||||||
|
|
||||||
|
@ -524,13 +524,13 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
|
||||||
|
|
||||||
1. 安装Ozone
|
1. 安装Ozone
|
||||||
|
|
||||||
![image-20221116150122397](.assets/image-20221116150122397.png)
|
![image-20221116150122397](../.assets/image-20221116150122397.png)
|
||||||
|
|
||||||
这一步注意选择install a new instance(安装一个新的实例)。后续一路确认即可。
|
这一步注意选择install a new instance(安装一个新的实例)。后续一路确认即可。
|
||||||
|
|
||||||
2. 安装jlink
|
2. 安装jlink
|
||||||
|
|
||||||
![image-20221116193340770](.assets/image-20221116193340770.png)
|
![image-20221116193340770](../.assets/image-20221116193340770.png)
|
||||||
|
|
||||||
这一步注意不要勾选update dll in other application,否则jlink会把ozone里面老的驱动和启动项替代掉。choose destination和ozone一样,选择install a new instance。如果安装了老的相同版本的jlink,请先卸载(版本相同不用管,直接新装一个)。
|
这一步注意不要勾选update dll in other application,否则jlink会把ozone里面老的驱动和启动项替代掉。choose destination和ozone一样,选择install a new instance。如果安装了老的相同版本的jlink,请先卸载(版本相同不用管,直接新装一个)。
|
||||||
|
|
||||||
|
@ -544,19 +544,19 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
|
||||||
|
|
||||||
安装好两个软件之后,打开ozone后会显示一个new project wizard,如果没有打开,在工具栏的File-> New -> New project wizard。
|
安装好两个软件之后,打开ozone后会显示一个new project wizard,如果没有打开,在工具栏的File-> New -> New project wizard。
|
||||||
|
|
||||||
![image-20221113133904084](.assets/image-20221113133904084.png)
|
![image-20221113133904084](../.assets/image-20221113133904084.png)
|
||||||
|
|
||||||
选择M4内核,为了能够查看外设寄存器的值还需要svd文件。所有mcu的svd都在图中的文件夹里提供,当然你也可以使用我们仓库根目录下的文件。
|
选择M4内核,为了能够查看外设寄存器的值还需要svd文件。所有mcu的svd都在图中的文件夹里提供,当然你也可以使用我们仓库根目录下的文件。
|
||||||
|
|
||||||
![image-20221116150901418](.assets/image-20221116150901418.png)
|
![image-20221116150901418](../.assets/image-20221116150901418.png)
|
||||||
|
|
||||||
接口选择swd,接口速度不需要太高,如果调试的时候需要观察大量的变量并且使用日志功能,可以调高这个值。如果连接了jlikn,上面的窗口中会显示。如果链接了dap-link,比如无线调试器,会出现Unknown CMSIS-dap。选择你要使用的调试器,然后继续。
|
接口选择swd,接口速度不需要太高,如果调试的时候需要观察大量的变量并且使用日志功能,可以调高这个值。如果连接了jlikn,上面的窗口中会显示。如果链接了dap-link,比如无线调试器,会出现Unknown CMSIS-dap。选择你要使用的调试器,然后继续。
|
||||||
|
|
||||||
![image-20221113134252407](.assets/image-20221113134252407.png)
|
![image-20221113134252407](../.assets/image-20221113134252407.png)
|
||||||
|
|
||||||
选择构建之后生成的.elf文件(在项目文件夹下的build中)。这是调试器专用的文件格式,对其内容感兴趣可以自行搜索细节。此外ozone还支持.bin .hex .axf(最后一个是amr-cc,也就是keil的工具链会生成的)等格式。
|
选择构建之后生成的.elf文件(在项目文件夹下的build中)。这是调试器专用的文件格式,对其内容感兴趣可以自行搜索细节。此外ozone还支持.bin .hex .axf(最后一个是amr-cc,也就是keil的工具链会生成的)等格式。
|
||||||
|
|
||||||
![image-20221113134605331](.assets/image-20221113134605331.png)
|
![image-20221113134605331](../.assets/image-20221113134605331.png)
|
||||||
|
|
||||||
这页不要动。如果希望保存jlink的调试日志,最后一个选项选择一个文件或者新建一个日志文件。
|
这页不要动。如果希望保存jlink的调试日志,最后一个选项选择一个文件或者新建一个日志文件。
|
||||||
|
|
||||||
|
@ -574,7 +574,7 @@ Project.SetOSPlugin(“plugin_name”)
|
||||||
|
|
||||||
支持的插件在Ozone的安装目录下的`Plugins/OS`目录:
|
支持的插件在Ozone的安装目录下的`Plugins/OS`目录:
|
||||||
|
|
||||||
![image-20221119174445067](.assets/image-20221119174445067.png)
|
![image-20221119174445067](../.assets/image-20221119174445067.png)
|
||||||
|
|
||||||
我们的项目是F4的板子,内核时Cortex-M4(CM4),因此选用`FreeRTOSPlugin_CM4.js`(输入的时候js后缀不用输)。 ozone默认输入的命令似乎有误,需要手动修改(这好像和ozone的版本有关,请留意)
|
我们的项目是F4的板子,内核时Cortex-M4(CM4),因此选用`FreeRTOSPlugin_CM4.js`(输入的时候js后缀不用输)。 ozone默认输入的命令似乎有误,需要手动修改(这好像和ozone的版本有关,请留意)
|
||||||
|
|
||||||
|
@ -582,7 +582,7 @@ Project.SetOSPlugin(“plugin_name”)
|
||||||
|
|
||||||
下图的配置是笔者常用的layout。每个窗口是否显示、放在什么位置等都是可以自己定义的。通过工具栏的view选项卡可以自行选择需要展示的窗口。
|
下图的配置是笔者常用的layout。每个窗口是否显示、放在什么位置等都是可以自己定义的。通过工具栏的view选项卡可以自行选择需要展示的窗口。
|
||||||
|
|
||||||
![](.assets/ozone.png)
|
![](../.assets/ozone.png)
|
||||||
|
|
||||||
1. 调试控制:和vscode类似
|
1. 调试控制:和vscode类似
|
||||||
|
|
||||||
|
@ -590,11 +590,11 @@ Project.SetOSPlugin(“plugin_name”)
|
||||||
|
|
||||||
如果不需要可视化查看变量变化的趋势,但是想不暂停查看变量的值,请右键点击变量,选择一个合适的refresh rate:
|
如果不需要可视化查看变量变化的趋势,但是想不暂停查看变量的值,请右键点击变量,选择一个合适的refresh rate:
|
||||||
|
|
||||||
![image-20221119173731119](.assets/image-20221119173731119.png)
|
![image-20221119173731119](../.assets/image-20221119173731119.png)
|
||||||
|
|
||||||
如果是一个结构体,你可以为整个结构体都进行刷新率的配置,不需要手动一个个修改。**或直接右键点击窗口**,将refresh打勾:
|
如果是一个结构体,你可以为整个结构体都进行刷新率的配置,不需要手动一个个修改。**或直接右键点击窗口**,将refresh打勾:
|
||||||
|
|
||||||
![image-20221119173918340](.assets/image-20221119173918340.png)
|
![image-20221119173918340](../.assets/image-20221119173918340.png)
|
||||||
|
|
||||||
3. 断点和运行追踪管理
|
3. 断点和运行追踪管理
|
||||||
|
|
||||||
|
@ -639,7 +639,7 @@ Project.SetOSPlugin(“plugin_name”)
|
||||||
|
|
||||||
- 如果当前文件没有你要的变量,你想查看项目中的其他文件夹,在view-> source files中可以打开该项目所有的源文件,双击可以打开源文件。
|
- 如果当前文件没有你要的变量,你想查看项目中的其他文件夹,在view-> source files中可以打开该项目所有的源文件,双击可以打开源文件。
|
||||||
|
|
||||||
![image-20221113142448939](.assets/image-20221113142448939.png)
|
![image-20221113142448939](../.assets/image-20221113142448939.png)
|
||||||
|
|
||||||
- **日志打印**
|
- **日志打印**
|
||||||
|
|
||||||
|
@ -687,7 +687,7 @@ CPU选项卡可以查看CPU的寄存器。
|
||||||
|
|
||||||
在网盘上下载`daplink_register_license.rar`,解压出来之后打开。**请关闭杀毒软件。**
|
在网盘上下载`daplink_register_license.rar`,解压出来之后打开。**请关闭杀毒软件。**
|
||||||
|
|
||||||
![image-20221116152032104](.assets/image-20221116152032104.png)
|
![image-20221116152032104](../.assets/image-20221116152032104.png)
|
||||||
|
|
||||||
根据Ozone打开时提示的daplink的序列号,将其输入注册机,电机generate,就会生成5个license。
|
根据Ozone打开时提示的daplink的序列号,将其输入注册机,电机generate,就会生成5个license。
|
||||||
|
|
||||||
|
@ -964,7 +964,7 @@ download_jlink:
|
||||||
|
|
||||||
安装包已经上传到了网盘的`EC/VSCode+Ozone环境配置/msys2-x86_64-20221028.exe`下,你也可以在msys2的官网直接下载,如果没有ladder速度可能会稍慢,镜像站的下载速度会快许多。安装之后,打开MSYS2 MSYS软件,他是一个类shell的界面,实际上它提供了包括mingw64、ucrt64、clang64等多种不同编译环境在内的一组类linux开发工具合集:
|
安装包已经上传到了网盘的`EC/VSCode+Ozone环境配置/msys2-x86_64-20221028.exe`下,你也可以在msys2的官网直接下载,如果没有ladder速度可能会稍慢,镜像站的下载速度会快许多。安装之后,打开MSYS2 MSYS软件,他是一个类shell的界面,实际上它提供了包括mingw64、ucrt64、clang64等多种不同编译环境在内的一组类linux开发工具合集:
|
||||||
|
|
||||||
![image-20221119222946103](.assets/image-20221119222946103.png)
|
![image-20221119222946103](../.assets/image-20221119222946103.png)
|
||||||
|
|
||||||
输入以下命令然后一路回车即可:
|
输入以下命令然后一路回车即可:
|
||||||
|
|
||||||
|
@ -973,7 +973,7 @@ pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-arm-none-eabi-toolchain mi
|
||||||
# 需要注意ctrl+V不是黏贴快捷键,而是Ins+Shift.或者右键点击空白处选择黏贴也可以.
|
# 需要注意ctrl+V不是黏贴快捷键,而是Ins+Shift.或者右键点击空白处选择黏贴也可以.
|
||||||
```
|
```
|
||||||
|
|
||||||
![image-20221119223148604](.assets/image-20221119223148604.png)
|
![image-20221119223148604](../.assets/image-20221119223148604.png)
|
||||||
|
|
||||||
<center>比如上面这样,会让你选择,直接敲回车即可,等待安装</center>
|
<center>比如上面这样,会让你选择,直接敲回车即可,等待安装</center>
|
||||||
|
|
||||||
|
@ -1006,7 +1006,7 @@ pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-arm-none-eabi-toolchain mi
|
||||||
|
|
||||||
修改好之后,便可以在vscode中使用了:
|
修改好之后,便可以在vscode中使用了:
|
||||||
|
|
||||||
![image-20230723132711865](.assets/image-20230723132711865.png)
|
![image-20230723132711865](../.assets/image-20230723132711865.png)
|
||||||
|
|
||||||
linux下熟悉的ls/mkdir/find/ld/cat等命令和工具也一应俱全了。
|
linux下熟悉的ls/mkdir/find/ld/cat等命令和工具也一应俱全了。
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
# 2023 EC basic-framework
|
# 2023 EC basic-framework
|
||||||
|
|
||||||
> **代码参考了哈工深南宫小樱战队的框架设计和RMUA官方开源RoboRTS-firmware框架,在此鸣谢。**
|
|
||||||
|
|
||||||
> 每个bsp/module/application都有对应文档,建议阅读之后再看代码&进行开发。框架的搭建思路和讲解视频戳这里:[basic_framework讲解](https://www.bilibili.com/video/BV1Bd4y1E7CN)。
|
> 每个bsp/module/application都有对应文档,建议阅读之后再看代码&进行开发。框架的搭建思路和讲解视频戳这里:[basic_framework讲解](https://www.bilibili.com/video/BV1Bd4y1E7CN)。
|
||||||
> 开发之前必看的文档:**README.md & VSCode+Ozone使用方法.md** 。开发app层请看application目录下的文档,若要开发module以及bsp务必把上层文档也浏览一遍以熟悉接口定义的方式。
|
> 开发之前必看的文档:**README.md & VSCode+Ozone使用方法.md** 。开发app层请看application目录下的文档,若要开发module以及bsp务必把上层文档也浏览一遍以熟悉接口定义的方式。
|
||||||
> **程序的运行流程和框架所有app/module/bsp的数据流图直接拉到本文档底部。**
|
> **程序的运行流程和框架所有app/module/bsp的数据流图直接拉到本文档底部。**
|
||||||
|
@ -35,7 +33,7 @@
|
||||||
|
|
||||||
- **代码格式**:
|
- **代码格式**:
|
||||||
|
|
||||||
在vscode-设置-扩展-C/C++-C_Cpp:style下修改。默认为`Visual Studio`。编写完新的代码后,使用右键-格式化文档(注:请勿对cube生成的文件使用此操作)。此操作不会改变文档的内容,但会改变缩进、空行、符号位置等,使代码更加统一、整洁。
|
在vscode-设置-扩展-C/C++-C_Cpp:style下修改。默认为`Visual Studio`。编写完新的代码后,使用`右键-格式化`或`shift+alt+f`(请勿对cube生成的文件使用此操作否则重新生成异常)。此操作不会改变文档的内容,但会改变缩进、空行、符号位置等,使代码更加统一、整洁。
|
||||||
|
|
||||||
**在cubemx生成的文件(尤其是main.c和freertos.c)时,务必按照cubemx的提示将用户代码放在usercode注释代码块内,否则重新生成时会被覆盖.**
|
**在cubemx生成的文件(尤其是main.c和freertos.c)时,务必按照cubemx的提示将用户代码放在usercode注释代码块内,否则重新生成时会被覆盖.**
|
||||||
|
|
||||||
|
@ -189,7 +187,7 @@ ROOT:.
|
||||||
│ .gitignore # git版本管理忽略文件
|
│ .gitignore # git版本管理忽略文件
|
||||||
│ .mxproject # CubeMX项目文件
|
│ .mxproject # CubeMX项目文件
|
||||||
│ basic_framework.ioc # CubeMX初始化配置文件
|
│ basic_framework.ioc # CubeMX初始化配置文件
|
||||||
| debug_ozone.jdebug # ozone debug调试配置和缓存文件
|
│ debug_ozone.jdebug # ozone debug调试配置和缓存文件
|
||||||
│ LICENSE # 开源协议文件
|
│ LICENSE # 开源协议文件
|
||||||
│ Makefile # 编译管理文件,为make(mingw32-make)命令的目标
|
│ Makefile # 编译管理文件,为make(mingw32-make)命令的目标
|
||||||
│ openocd_dap.cfg # 用于OpenOCD调试使用的配置文件,dap用
|
│ openocd_dap.cfg # 用于OpenOCD调试使用的配置文件,dap用
|
||||||
|
@ -199,13 +197,13 @@ ROOT:.
|
||||||
│ stm32.jflash # jlink的烧录的配置文件,一键下载用
|
│ stm32.jflash # jlink的烧录的配置文件,一键下载用
|
||||||
│ STM32F407.svd # F407外设地址映射文件,用于调试
|
│ STM32F407.svd # F407外设地址映射文件,用于调试
|
||||||
│ STM32F407IGHx_FLASH.ld # F407IGH(C板MCU)目标FLASH地址和链接规则,用于编译(作为链接阶段的链接器)
|
│ STM32F407IGHx_FLASH.ld # F407IGH(C板MCU)目标FLASH地址和链接规则,用于编译(作为链接阶段的链接器)
|
||||||
| task.ps1 # powershell脚本,一键编译并进入ozone调试/reset开发板用
|
│ task.ps1 # powershell脚本,一键编译并进入ozone调试/reset开发板用
|
||||||
│ TODO.md # 项目待完成的任务
|
│ TODO.md # 项目待完成的任务
|
||||||
│ VSCode+Ozone使用方法.md # 开发环境配置和前置知识介绍
|
│ VSCode+Ozone使用方法.md # 开发环境配置和前置知识介绍
|
||||||
│ 修改HAL配置时文件目录的更改.md # 重新配置CubeMX时的步骤和注意事项
|
│ 修改HAL配置时文件目录的更改.md # 重新配置CubeMX时的步骤和注意事项
|
||||||
│ 必须做&禁止做.md # 开发必看,规范和要求
|
│ 必须做&禁止做.md # 开发必看,规范和要求
|
||||||
| 如何定位bug.md # 开发必看,快速定位bug并进行修复.还提供了一些debug典例
|
│ 如何定位bug.md # 开发必看,快速定位bug并进行修复.还提供了一些debug典例
|
||||||
|
|
│
|
||||||
├─.vscode
|
├─.vscode
|
||||||
│ launch.json # 调试的配置文件
|
│ launch.json # 调试的配置文件
|
||||||
│ settings.json # 工作区配置文件,根据自己的需要配置
|
│ settings.json # 工作区配置文件,根据自己的需要配置
|
||||||
|
@ -215,7 +213,7 @@ ROOT:.
|
||||||
├─application # 应用层
|
├─application # 应用层
|
||||||
├─bsp # 板级支持包
|
├─bsp # 板级支持包
|
||||||
├─modules # 模块层
|
├─modules # 模块层
|
||||||
|
|
│
|
||||||
├─Src #hal生成的外设初始化源文件
|
├─Src #hal生成的外设初始化源文件
|
||||||
├─Inc #hal生成的外设初始化头文件
|
├─Inc #hal生成的外设初始化头文件
|
||||||
├─Drivers #hal driver和cmsis drivers
|
├─Drivers #hal driver和cmsis drivers
|
||||||
|
@ -230,11 +228,11 @@ ROOT:.
|
||||||
|
|
||||||
### 软件分层
|
### 软件分层
|
||||||
|
|
||||||
![image-20221113211942850](.assets/framework.png)
|
<img src="../.assets/image-20230725153133419.png" style="zoom:67%;" />
|
||||||
|
|
||||||
### 运行任务
|
### 运行任务
|
||||||
|
|
||||||
![image-20230413195155471](.assets/image-20230413195155471.png)
|
<img src="../.assets/image-20230725152433502.png" style="zoom: 50%;" />
|
||||||
|
|
||||||
### 初始化流程
|
### 初始化流程
|
||||||
|
|
||||||
|
@ -251,8 +249,8 @@ main函数唯一需要的函数是app层的`robot.c`中的`RobotInit()`函数,
|
||||||
|
|
||||||
### 程序运行流程
|
### 程序运行流程
|
||||||
|
|
||||||
![运行](.assets/总程序流程.png)
|
![](../.assets/image-20230725153635454.png)
|
||||||
|
|
||||||
### 程序数据流
|
### 程序数据流
|
||||||
|
|
||||||
![数据流](.assets/数据流.png)
|
![](../.assets/dataflow.svg)
|
After Width: | Height: | Size: 87 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 64 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 201 KiB |
After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 53 KiB |
BIN
.assets/数据流.png
Before Width: | Height: | Size: 274 KiB |
141
README.md
|
@ -13,15 +13,27 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 功能介绍
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 架构
|
## 架构
|
||||||
|
|
||||||
|
总览。
|
||||||
|
|
||||||
### 软件栈
|
### 软件栈
|
||||||
|
|
||||||
|
<img src=".assets/image-20230725153133419.png" alt="image-20230725153133419" style="zoom: 67%;" />
|
||||||
|
|
||||||
|
在CubeMX初始化生成的依赖文件基础之上新增了可选的CMSIS-DSP和Segger RTT。
|
||||||
### 多任务协作
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 设计思想
|
### 设计思想
|
||||||
|
|
||||||
|
@ -34,13 +46,50 @@
|
||||||
有了上面的大体认知,我们分别介绍框架的三层结构。
|
有了上面的大体认知,我们分别介绍框架的三层结构。
|
||||||
|
|
||||||
- **bsp**即板级支持包,提供对开发板外设的软件抽象,让module层能使用和硬件无关的接口(由bsp提供)进行数据处理与交互。bsp层和ST的HAL为强耦合,与硬件直接绑定。若要向其他的ST芯片移植,基本不需要修改bsp层;若是其他单片机则建议保留**接口设计**,对接口调用进行重现实现。每一种外设的头文件中都定义了一个**XXXInstance**(xxx为外设名),其中包含了使用该外设所需要的所有数据,如发送/接收的数据,长度,id(如果有),父指针(指向module实例的指针,用于回调)等。由于C没有`class`,因此所有bsp的接口都需要传入一个额外的参数:XXXInstance*,用于实现c++的`this`指针以区分具体是哪一个实例调用了接口。
|
- **bsp**即板级支持包,提供对开发板外设的软件抽象,让module层能使用和硬件无关的接口(由bsp提供)进行数据处理与交互。bsp层和ST的HAL为强耦合,与硬件直接绑定。若要向其他的ST芯片移植,基本不需要修改bsp层;若是其他单片机则建议保留**接口设计**,对接口调用进行重现实现。每一种外设的头文件中都定义了一个**XXXInstance**(xxx为外设名),其中包含了使用该外设所需要的所有数据,如发送/接收的数据,长度,id(如果有),父指针(指向module实例的指针,用于回调)等。由于C没有`class`,因此所有bsp的接口都需要传入一个额外的参数:XXXInstance*,用于实现c++的`this`指针以区分具体是哪一个实例调用了接口。
|
||||||
- **module**即模块层,包括了需要开发板硬件外设支持的(一般用于通信)真实**硬件模组**如电机、舵机、imu、测距传感器,以及通过
|
|
||||||
|
- **module**即模块层,包括了需要开发板硬件外设支持的(一般用于通信)真实**硬件模组**如电机、舵机、imu、测距传感器,和通过软件实现的**算法**如PID、滤波器、状态观测器;还有用于兼容不同控制信息模块(遥控器/ps手柄/图传链路/上位机)的统一接口模块,以及为app层提供数据交互的message center。
|
||||||
|
|
||||||
|
module层仍然是基于实例的,一个app会包含多个module的instance。当app便可以用硬件无关的接口使用module,如要求电机以一定速度运动、关闭气阀、给超级电容或上位机发送一些反馈数据等。在有了方便的bsp之后,只需要在你构建的module中包含必须的bsp,然后为app提供合理的接口即可。
|
||||||
|
|
||||||
|
- **app**是框架层级中最高的部分。目前的框架设计里,会有多个app任务运行在freertos中,当然你也可以根据需要启动一些事件驱动的任务,所有的任务安排都放在`app/robot_task`中。当前的app层仅是一个机器人开发的示例,有了封装程度极高的module,你可以在app完成任何事情。
|
||||||
|
|
||||||
|
目前的app设计里,可以兼容多块开发板的情况,通过**条件编译**切换开发板的位置。如步兵机器人可以将主控MCU放在云台上,而超级电容控制板同时作为底盘板。使用CAN/SPI/UART将两者连接,便可以通过**`app/robot_def.h`**中的宏完成设置。可以根据需要,设置更多的开发板(双云台哨兵、工程机器人)。
|
||||||
|
|
||||||
|
这套框架可以轻松扩展到所有机器人上,在我们的仓库中,有步兵机器人、平衡步兵机器人、哨兵机器人、英雄机器人、工程机器人以及空中机器人的代码实例,皆按照本框架中的三层结构开发。若设计了新的机器人,只需要在robot_def.h中修改传感器的位置、底盘轮距轴距、拨弹盘容量、弹舱载弹量等参数便可以**立刻实现部署**。
|
||||||
|
|
||||||
|
至于bsp和module中每个instance的设计,我们采用了**面向对象**的C风格代码,整个框架也统一了变量和函数命名方式,调用层级和数据流十分清晰(下一个章节也有插图阐述)。
|
||||||
|
|
||||||
|
为了避免出现”底层代码包含上层头文件“的情况,我们让bsp层instance在注册时要求module提供数据发送/接收的回调函数指针,从而在发生对应中断或事件时完成对module函数的”反向调用“。事实上,你也可以进一步将这套思想放入app的设计中,当某个事件发生时触发app的任务,而不是将app的任务定时运行(这可以提高运行效率,降低cpu占用)。
|
||||||
|
|
||||||
|
bsp和module的instance在初始化时接口皆为**`XXXInstance* XXXRegister(XXX_Init_Config_s* conf)`**,传入该实例所需的config参数,返回一个实例指针(看作this指针),之后要调用模块的功能,传入该指针即可。我们还提供了守护线程,以供module选用,当异常情况发生时在LOG中发送warning、触发蜂鸣器或LED进行声光报警以及错误/离线回调函数,保证系统的鲁棒性和安全性。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 执行顺序与数据流
|
## 执行顺序与数据流
|
||||||
|
|
||||||
|
### 初始化
|
||||||
|
|
||||||
|
![image-20230725153635454](.assets/image-20230725153635454.png)
|
||||||
|
|
||||||
|
### 任务结构
|
||||||
|
|
||||||
|
app、module和bsp都有相应的rtos任务。其中bsp为创建任务提供了封装工具bsp_tools,旨在将复杂的回调函数转移到任务中而不是在中断内执行,以保证系统响应的实时性和数据完整性。有一些module和app根据功能需要会创建定时任务或事件驱动的任务,这些任务都在初始化时注册,并在特定的时刻被唤醒或周期执行。
|
||||||
|
|
||||||
|
<img src=".assets/image-20230725152433502.png" alt="image-20230725152433502" style="zoom:50%;" />
|
||||||
|
|
||||||
|
### 数据流
|
||||||
|
|
||||||
|
![](.assets/dataflow.svg)
|
||||||
|
|
||||||
|
<center>建议浏览器打开SVG查看<center>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,25 +109,101 @@
|
||||||
|
|
||||||
### IDE?
|
### IDE?
|
||||||
|
|
||||||
使用VSCode作为“IDE”。需要的插件支持均已经在[VSCode+Ozone使用方法.md](VSCode+Ozone使用方法.md)中给出。通过VSCode强大的插件系统、language server以及代码补全高亮助力效率倍增。编译则使用集成的task进行,还可以将开发环境终端加入VSCode进一步提升体验。基本的调试如变量&寄存器查看均已在插件中提供支持,`launch.json`可以进行高自由度的自定义。
|
使用VSCode作为“IDE”。需要的插件支持均已经在[VSCode+Ozone使用方法.md](.Doc/VSCode+Ozone使用方法.md)中给出。通过VSCode强大的插件系统、language server以及代码补全高亮助力效率倍增。编译则使用集成的task进行,还可以将开发环境终端加入VSCode进一步提升体验。基本的调试如变量&寄存器查看均已在插件中提供支持,`launch.json`可以进行高自由度的自定义。
|
||||||
|
|
||||||
`Git`集成与额外插件补充让版本管理和协作从未如此简单,`live share`把你的伙伴们聚在一起集思广益,一同对抗困难的bug。更多特性和开发技巧请参考"如何使用本框架"章节。
|
`Git`集成与gitlens/gitgraph/githistory额外插件补充让版本管理和协作从未如此简单,`live share`把你的伙伴们聚在一起集思广益,一同对抗困难的bug。更多好用的插件、特性和开发技巧请参考"**如何使用本框架**"章节。
|
||||||
|
|
||||||
> **不论如何,请不要使用KEIL作为你的代码编辑器。**
|
> **不论如何,请不要使用KEIL作为你的代码编辑器。**
|
||||||
|
|
||||||
### 调试和性能分析
|
### 调试和性能分析
|
||||||
|
|
||||||
- 基础的调试可以在VSCode中完成。cortex-debug插件的最新版本已经支持多个gdb-server(jlink/stlink/openocd/pyocd)的live watch(动态变量监视)和变量示波器(可视化)。若不是有特别的需求,**请勿使用串口调试器**。
|
- 基础的调试可以在VSCode中完成。cortex-debug插件的最新版本已经支持多个gdb-server(jlink/stlink/openocd/pyocd)的live watch(动态变量监视)和变量示波器(可视化)。若不是有特别的需求,*请勿使用串口调试器*。
|
||||||
|
|
||||||
- 有高速变量查看和数据记录、多路数据可视化的需求(如进行pid参数整定、查找难以定位的bug)时,使用**Segger Ozone**。
|
- 有高速变量查看和数据记录、多路数据可视化的需求(如进行pid参数整定、查找难以定位的bug)时,使用**Segger Ozone**。
|
||||||
- FreeMaster也可以作为调试的备选项。
|
- FreeMaster也可以作为调试的备选项。
|
||||||
- 基本的、日常性能分析可以通过`bsp_dwt`完成。若要分析关于任务运行和每个函数执行的详细信息和时间,推荐使用**Segger Systemviewer**。
|
- 基本的、日常性能分析可以通过`bsp_dwt`完成。若要分析关于任务运行和每个函数执行的详细信息和时间,推荐使用**Segger Systemviewer**。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 如何使用本框架
|
## 如何使用本框架
|
||||||
|
|
||||||
|
仓库中有各种各样的说明文档和使用帮助。
|
||||||
|
|
||||||
|
### 编译烧录
|
||||||
|
|
||||||
|
本项目是基于RoboMaster开发板C型的示例,MCU为STM32F407IG,使用了板载的imu bmi-088,驱动标准的步兵机器人:2自由度GM6020云台、m2006电机拨盘+2*m3508电机摩擦轮的发射机构和MG90舵机弹舱盖,以及带有超级电容控制器的4轮麦克纳姆底盘。
|
||||||
|
|
||||||
|
首先在`app/robot_def.h`中根据注释修改开发板和机器人配置,再在各个app中修改初始化配置(如电机id,上位机通信波特率/使用串口或VCP,imu速率,超级电容id等)。
|
||||||
|
|
||||||
|
接着根据[VSCode+Ozone使用方法.md](.Doc/VSCode+Ozone使用方法.md)配置好编译下载环境之后(***再次建议使用Msys2+mingw64/ucrt64/clang64的方式配置环境!***),在VSCode中打开项目,点击上方tab页的终端(terminal)->运行构建任务(run build task),便启动编译,若没有问题,最终会在终端中输出如下信息:
|
||||||
|
|
||||||
|
![image-20230725154910307](.assets/image-20230725154910307.png)
|
||||||
|
|
||||||
|
工具链会预测ram,ccram以及flash的使用情况,并报告最终二进制文件的大小和存放位置。
|
||||||
|
|
||||||
|
随后,通过调试器将开发板连接至你的电脑,点击上方tab页的终端(terminal)->运行任务(run task),选择download_dap or download_jlink(或你自己编写的stlink/ulink/...),便会开始下载,终端或jFlash中会提示擦除、下载、验证的进度。
|
||||||
|
|
||||||
|
想要调试,在左侧tab页选择合适的调试选项,按F5或图形界面的绿色小三角形按钮,开始调试。
|
||||||
|
|
||||||
|
**更详细的开发流程,请参照`.Doc/VSCode+Ozone使用方法.md`**
|
||||||
|
|
||||||
|
### 基本文档
|
||||||
|
|
||||||
|
根目录下的README.md即本说明文档,帮助开发者速览本项目。
|
||||||
|
|
||||||
|
`.Doc`目录下有**8**个markdown文档,分别为:
|
||||||
|
|
||||||
|
- Bug_Report.md :提供了一些提交issues的模板范例,若在使用中出现问题请按照模板提供信息。
|
||||||
|
- TODO.md :框架后续开发计划和维护说明
|
||||||
|
- **VSCode+Ozone使用方法.md** :重要,开发必看。介绍了当前开发工作流和传统KEIL开发的不同,先讲解一些与工具链有关的基础知识,然后说明了如何配置开发环境,安装必要的软件和一些”操作“。还涉及了VSCode编辑调试和Ozone示波器&trace功能的使用指南。
|
||||||
|
- 合理地进行PID参数整定.md :介绍了如何为PID控制器进行参数整定,包括简单的经验准则和基于模型的前馈控制、扰动消除等方法。
|
||||||
|
- 如何定位bug.md :当嵌入式开发出现bug时,以更高效地方法进行错误定位和复现。简单的调试器使用技巧。
|
||||||
|
- 必须做&禁止做.md :字如其名
|
||||||
|
- **架构介绍与开发准则.md** : 重要,必看。若你希望为bsp或module增添新的模块,组装新的app,请参照此文档的编码和命名规范进行。阅读该文档有助于理解并写出和框架代码风格一致的程序。内含该项目的**文件树**,以框架的工作目录。
|
||||||
|
- 让VSCode成为更称手的IDE.md :安装好用的插件,对编辑器进行个性化配置,提升开发效率
|
||||||
|
|
||||||
|
### 阅读代码
|
||||||
|
|
||||||
|
框架中的三层结构都有详尽的注释帮助阅读和二次开发,三个抽象层都有各自总览的说明文档,而每个bsp/module/app都配有对应的个性化说明文档,提供了接口说明和改进或进一步开发的建议。
|
||||||
|
|
||||||
|
建议以自上而下的方式阅读代码,app-》module-》bsp,我们还提供了框架的说明视频,分别讲解每个抽象层和总体的设计思路,还有一些杂碎的开发相关知识:[basic_framework教程]()
|
||||||
|
|
||||||
|
### VSCode集成工具
|
||||||
|
|
||||||
|
我们在`.vscode`下提供了编写好的一些任务,包括编译,烧录,启动RTT终端(LOG),启动Ozone调试等。有些功能需要配置vscode的插件设置或将一些可执行文件加入环境变量,这些步骤已经在[VSCode+Ozone使用方法.md](.Doc/VSCode+Ozone使用方法.md)中给出;`launch.json`里包含了最常见的四种调试任务:使用jlink-server/openocd,启动或附加调试。
|
||||||
|
|
||||||
|
### for pro-user
|
||||||
|
|
||||||
|
Makefile提供了脚本化的Makefile.upgrade,使用后者可以获取更好的开发体验。
|
||||||
|
|
||||||
|
可以自行添加需要的编译优化,进行更高级别的定制。
|
||||||
|
|
||||||
|
ST官方现在将HAL放入github维护。想要获取最新的支持,可以自行下载,加入本项目编译。
|
||||||
|
|
||||||
|
若希望纯开源使用,可以自定义openocd调试和烧录选项,参考根目录的openocd_dap.cfg和openocd_jlink.cfg。
|
||||||
|
|
||||||
|
若希望自己编译特定版本的cmsis-dsp或cmsis-os,请前往官方的github仓库下载,将构建规则加入makefile。
|
||||||
|
|
||||||
|
我们还增加了CMakeLists.txt以融入更现代化的构建系统,若你希望使用cmake,相信你有能力配置相关的开发环境。可以参考我们的[***powerful_framework***](https://gitee.com/hnuyuelurm/powerful_framework).
|
||||||
|
|
||||||
|
如果实时系统任务需要的栈空间不够,请在CubeMX初始化配置中增大任务栈。一些freertos支持的高级功能请自行在配置页开启宏定义后重新生成。
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 后续计划
|
## 后续计划
|
||||||
|
|
||||||
|
- `.Doc/TODO.md`中列举了一些可能的功能增强和优化。
|
||||||
|
- 为三个层级都增加入门级培训教程,可以单独运行各个模块以方便上手。
|
||||||
|
- 优化pub-sub消息机制的性能,同时将app的任务尽可能修改为**状态机+事件驱动**的回调机制。
|
||||||
|
- 使用Qt或命令行为机器人配置(主要是robot_def和各个任务中的module初始化配置)编写UI界面,实现无代码机器人部署。
|
||||||
|
- 为框架编写ROSdriver,通过usb连接到上位机(NUC),合并视觉/算法和电控的工作流。
|
||||||
|
|
|
@ -214,7 +214,7 @@ void ChassisTask()
|
||||||
chassis_cmd_recv.wz = 0;
|
chassis_cmd_recv.wz = 0;
|
||||||
break;
|
break;
|
||||||
case CHASSIS_FOLLOW_GIMBAL_YAW: // 跟随云台,不单独设置pid,以误差角度平方为速度输出
|
case CHASSIS_FOLLOW_GIMBAL_YAW: // 跟随云台,不单独设置pid,以误差角度平方为速度输出
|
||||||
chassis_cmd_recv.wz = -1.5 * chassis_cmd_recv.offset_angle * abs(chassis_cmd_recv.offset_angle);
|
chassis_cmd_recv.wz = -1.5f * chassis_cmd_recv.offset_angle * abs(chassis_cmd_recv.offset_angle);
|
||||||
break;
|
break;
|
||||||
case CHASSIS_ROTATE: // 自旋,同时保持全向机动;当前wz维持定值,后续增加不规则的变速策略
|
case CHASSIS_ROTATE: // 自旋,同时保持全向机动;当前wz维持定值,后续增加不规则的变速策略
|
||||||
chassis_cmd_recv.wz = 4000;
|
chassis_cmd_recv.wz = 4000;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "cmsis_os.h"
|
#include "cmsis_os.h"
|
||||||
|
|
||||||
|
#include "robot.h"
|
||||||
#include "ins_task.h"
|
#include "ins_task.h"
|
||||||
#include "motor_task.h"
|
#include "motor_task.h"
|
||||||
#include "referee_task.h"
|
#include "referee_task.h"
|
||||||
|
@ -53,9 +54,10 @@ void OSTaskInit()
|
||||||
HTMotorControlInit(); // 没有注册HT电机则不会执行
|
HTMotorControlInit(); // 没有注册HT电机则不会执行
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartINSTASK(void const *argument)
|
__attribute__((noreturn)) void StartINSTASK(void const *argument)
|
||||||
{
|
{
|
||||||
static float ins_start, ins_dt;
|
static float ins_start;
|
||||||
|
static float ins_dt;
|
||||||
INS_Init(); // 确保BMI088被正确初始化.
|
INS_Init(); // 确保BMI088被正确初始化.
|
||||||
LOGINFO("[freeRTOS] INS Task Start");
|
LOGINFO("[freeRTOS] INS Task Start");
|
||||||
for (;;)
|
for (;;)
|
||||||
|
@ -71,9 +73,10 @@ void StartINSTASK(void const *argument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartMOTORTASK(void const *argument)
|
__attribute__((noreturn)) void StartMOTORTASK(void const *argument)
|
||||||
{
|
{
|
||||||
static float motor_dt, motor_start;
|
static float motor_dt;
|
||||||
|
static float motor_start;
|
||||||
LOGINFO("[freeRTOS] MOTOR Task Start");
|
LOGINFO("[freeRTOS] MOTOR Task Start");
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -86,9 +89,10 @@ void StartMOTORTASK(void const *argument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartDAEMONTASK(void const *argument)
|
__attribute__((noreturn)) void StartDAEMONTASK(void const *argument)
|
||||||
{
|
{
|
||||||
static float daemon_dt, daemon_start;
|
static float daemon_dt;
|
||||||
|
static float daemon_start;
|
||||||
BuzzerInit();
|
BuzzerInit();
|
||||||
LOGINFO("[freeRTOS] Daemon Task Start");
|
LOGINFO("[freeRTOS] Daemon Task Start");
|
||||||
for (;;)
|
for (;;)
|
||||||
|
@ -104,9 +108,10 @@ void StartDAEMONTASK(void const *argument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartROBOTTASK(void const *argument)
|
__attribute__((noreturn)) void StartROBOTTASK(void const *argument)
|
||||||
{
|
{
|
||||||
static float robot_dt, robot_start;
|
static float robot_dt;
|
||||||
|
static float robot_start;
|
||||||
LOGINFO("[freeRTOS] ROBOT core Task Start");
|
LOGINFO("[freeRTOS] ROBOT core Task Start");
|
||||||
// 200Hz-500Hz,若有额外的控制任务如平衡步兵可能需要提升至1kHz
|
// 200Hz-500Hz,若有额外的控制任务如平衡步兵可能需要提升至1kHz
|
||||||
for (;;)
|
for (;;)
|
||||||
|
@ -120,7 +125,7 @@ void StartROBOTTASK(void const *argument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartUITASK(void const *argument)
|
__attribute__((noreturn)) void StartUITASK(void const *argument)
|
||||||
{
|
{
|
||||||
LOGINFO("[freeRTOS] UI Task Start");
|
LOGINFO("[freeRTOS] UI Task Start");
|
||||||
MyUIInit();
|
MyUIInit();
|
||||||
|
|
|
@ -21,11 +21,11 @@ static osThreadId cbkid_list[MX_SIG_LIST_SIZE];
|
||||||
static CallbackTask_t cbkinfo_list[MX_SIG_LIST_SIZE];
|
static CallbackTask_t cbkinfo_list[MX_SIG_LIST_SIZE];
|
||||||
|
|
||||||
// 死循环任务,执行cbk函数指针,每次执行完毕后等待sig信号
|
// 死循环任务,执行cbk函数指针,每次执行完毕后等待sig信号
|
||||||
static void CallbackTaskBase(const void *cbk)
|
__attribute__((noreturn)) static void CallbackTaskBase(void const *cbk)
|
||||||
{
|
{
|
||||||
void (*cbk_func)(void *) = (void (*)(void *))((CallbackTask_t *)cbk)->callback;
|
void (*cbk_func)(void const *) = (void (*)(void const *))((CallbackTask_t const *)cbk)->callback;
|
||||||
void *ins = ((CallbackTask_t *)cbk)->ins;
|
void const *ins = ((CallbackTask_t const *)cbk)->ins;
|
||||||
uint32_t sig = ((CallbackTask_t *)cbk)->sig;
|
uint32_t sig = ((CallbackTask_t const *)cbk)->sig;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -46,7 +46,7 @@ uint32_t CreateCallbackTask(char *name, void *cbk, void *ins, osPriority priorit
|
||||||
|
|
||||||
osThreadDef_t threadDef;
|
osThreadDef_t threadDef;
|
||||||
threadDef.name = name;
|
threadDef.name = name;
|
||||||
threadDef.pthread = CallbackTaskBase;
|
threadDef.pthread = &CallbackTaskBase;
|
||||||
threadDef.tpriority = priority;
|
threadDef.tpriority = priority;
|
||||||
threadDef.instances = 0;
|
threadDef.instances = 0;
|
||||||
threadDef.stacksize = 128;
|
threadDef.stacksize = 128;
|
||||||
|
|
|
@ -48,7 +48,7 @@ static float uint_to_float(int x_int, float x_min, float x_max, int bits)
|
||||||
static void HTMotorDecode(CANInstance *motor_can)
|
static void HTMotorDecode(CANInstance *motor_can)
|
||||||
{
|
{
|
||||||
uint16_t tmp; // 用于暂存解析值,稍后转换成float数据,避免多次创建临时变量
|
uint16_t tmp; // 用于暂存解析值,稍后转换成float数据,避免多次创建临时变量
|
||||||
uint8_t *rxbuff = motor_can->rx_buff;
|
uint8_t const *rxbuff = motor_can->rx_buff;
|
||||||
HTMotorInstance *motor = (HTMotorInstance *)motor_can->id;
|
HTMotorInstance *motor = (HTMotorInstance *)motor_can->id;
|
||||||
HTMotor_Measure_t *measure = &(motor->measure); // 将can实例中保存的id转换成电机实例的指针
|
HTMotor_Measure_t *measure = &(motor->measure); // 将can实例中保存的id转换成电机实例的指针
|
||||||
|
|
||||||
|
@ -127,9 +127,9 @@ HTMotorInstance *HTMotorInit(Motor_Init_Config_s *config)
|
||||||
|
|
||||||
HTMotorEnable(motor);
|
HTMotorEnable(motor);
|
||||||
HTMotorSetMode(CMD_MOTOR_MODE, motor); // 确保电机已经上电并执行电机模式
|
HTMotorSetMode(CMD_MOTOR_MODE, motor); // 确保电机已经上电并执行电机模式
|
||||||
DWT_Delay(0.05);
|
DWT_Delay(0.05f);
|
||||||
HTMotorCalibEncoder(motor); // 将当前编码器位置作为零位
|
HTMotorCalibEncoder(motor); // 将当前编码器位置作为零位
|
||||||
DWT_Delay(0.05); // 保证下一个电机发送时CAN是空闲的,注意应用在初始化模块的时候不应该进入中断
|
DWT_Delay(0.05f); // 保证下一个电机发送时CAN是空闲的,注意应用在初始化模块的时候不应该进入中断
|
||||||
ht_motor_instance[idx++] = motor;
|
ht_motor_instance[idx++] = motor;
|
||||||
return motor;
|
return motor;
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ void HTMotorSetRef(HTMotorInstance *motor, float ref)
|
||||||
* @brief 为了避免总线堵塞,为每个电机创建一个发送任务
|
* @brief 为了避免总线堵塞,为每个电机创建一个发送任务
|
||||||
* @param argument 传入的电机指针
|
* @param argument 传入的电机指针
|
||||||
*/
|
*/
|
||||||
void HTMotorTask(void const *argument)
|
__attribute__((noreturn)) void HTMotorTask(void const *argument)
|
||||||
{
|
{
|
||||||
float set, pid_measure, pid_ref;
|
float set, pid_measure, pid_ref;
|
||||||
HTMotorInstance *motor = (HTMotorInstance *)argument;
|
HTMotorInstance *motor = (HTMotorInstance *)argument;
|
||||||
|
|