diff --git a/index.html b/index.html index bc3f2f8ffe21d0b07f054991d0acdf9632755ca9..50b916251814e0e14b910f26f5d911ed841fb3a0 100644 --- a/index.html +++ b/index.html @@ -82,7 +82,7 @@ var url = 'https://gitee.com/rtthread/docs-online/blob/master/' + vm.route.file var editHtml = '[:pencil: 修改此文档 ](' + url + ')      [:page_with_curl:《修改规范说明》](/README?id=在线文档开发介绍)\n' - return '_Last modified {docsify-updated}_ ' + '\n\n'+ + return '\n\n'+ editHtml + html + '\n\n----\n' + diff --git a/other/novice-guide/README.md b/other/novice-guide/README.md index c9100854d95aa12609cb73e4141ffde6a0793d61..93b72e1e1d1f418716a22f582281b819257664a9 100644 --- a/other/novice-guide/README.md +++ b/other/novice-guide/README.md @@ -133,7 +133,9 @@ RT-Thread Studio :可以在 Studio 中下载源码包并创建 rt-thread 工 [PIN 设备](/rt-thread-version/rt-thread-standard/programming-manual/device/pin/pin.md) -[UART 设备](/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart.md) +[UART 设备](/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/uart.md) + +[UART 设备V2版本](/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/uart.md) [CAN 设备](/rt-thread-version/rt-thread-standard/programming-manual/device/can/can.md) diff --git a/rt-thread-version/rt-thread-nano/finsh-port/an0045-finsh-port.md b/rt-thread-version/rt-thread-nano/finsh-port/an0045-finsh-port.md index 780376fe487bf9734e0efc7b6c0d71f637957ab8..7867098074af1d4dcfe92ac2c052fff2331a782a 100644 --- a/rt-thread-version/rt-thread-nano/finsh-port/an0045-finsh-port.md +++ b/rt-thread-version/rt-thread-nano/finsh-port/an0045-finsh-port.md @@ -1,18 +1,21 @@ # 在 RT-Thread Nano 上添加控制台与 FinSH 本篇文档分为两部分: -- 第一部分是添加 UART 控制台,用来向控制台对接的终端输出打印信息;该部分只需要实现两个函数,初始化和系统输出函数,即可完成 UART 控制台打印功能。 -- 第二部分是移植 FinSH 组件,用以在控制台输入命令调试系统;该部分的实现基于第一部分,只需要添加 FinSH 组件源码并再对接一个系统输入函数即可实现。 +- 第一部分是添加 UART 控制台(实现打印):用来向控制台对接的终端输出打印信息;该部分只需要实现两个函数,串口初始化和系统输出函数,即可完成 UART 控制台打印功能。 +- 第二部分是移植 FinSH 组件(实现命令输入),用以在控制台输入命令调试系统;该部分的实现基于第一部分,只需要添加 FinSH 组件源码并再对接一个系统输入函数即可实现。 下面将对这两部分进行说明。 -## 在 Nano 上添加 UART 控制台 +## 在 Nano 上添加 UART 控制台(实现打印) 在 RT-Thread Nano 上添加 UART 控制台打印功能后,就可以在代码中使用 RT-Thread 提供的打印函数 rt_kprintf() 进行信息打印,从而获取自定义的打印信息,方便定位代码 bug 或者获取系统当前运行状态等。实现控制台打印(需要确认 rtconfig.h 中已使能 `RT_USING_CONSOLE` 宏定义),需要完成基本的硬件初始化,以及对接一个系统输出字符的函数,本小节将详细说明。 ### 实现串口初始化 -使用串口对接控制台的打印,首先需要初始化串口,如引脚、波特率等。 uart_init() 需要在 board.c 中的 `rt_hw_board_init()` 函数中调用。 +使用串口对接控制台的打印,首先需要初始化串口,如引脚、波特率等。 初始化的串口函数 uart_init() 有以下两种调用方式,二选一: + +1. 方法一:默认使用宏 INIT_BOARD_EXPORT() 进行自动初始化,不需要显式调用,如下所示。 +2. 方法二:可以使用显式调用:uart_init() 需要在 board.c 中的 `rt_hw_board_init()` 函数中调用。 ```c /* 实现 1:初始化串口 */ @@ -43,7 +46,7 @@ static int uart_init(void) return 0; } -INIT_BOARD_EXPORT(uart_init); +INIT_BOARD_EXPORT(uart_init); /* 默认选择初始化方法一:使用宏 INIT_BOARD_EXPORT 进行自动初始化 */ ``` ```c @@ -51,7 +54,7 @@ INIT_BOARD_EXPORT(uart_init); void rt_hw_board_init(void) { .... - uart_init(); // 在 rt_hw_board_init 函数中调用 串口初始化 函数 + uart_init(); /* 初始化方法二:可以选择在 rt_hw_board_init 函数中直接调用 串口初始化 函数 */ .... } ``` @@ -96,7 +99,7 @@ void rt_hw_console_output(const char *str) ![示例](figures/ok1.png) -## 在 Nano 上添加 FinSH 组件 +## 在 Nano 上添加 FinSH 组件(实现命令输入) [RT-Thread FinSH](https://www.rt-thread.org/document/site/programming-manual/finsh/finsh/) 是 RT-Thread 的命令行组件(shell),提供一套供用户在命令行调用的操作接口,主要用于调试或查看系统信息。它可以使用串口 / 以太网 / USB 等与 PC 机进行通信,使用 FinSH 组件基本命令的效果图如下所示: @@ -119,13 +122,19 @@ void rt_hw_console_output(const char *str) 勾选 shell,这将自动把 FinSH 组件的源码到工程: -![勾选 shell](figures/add.png) +![勾选 shell](figures/add-3.1.5.png) + +然后在 rtconfig.h 中打开 finsh 相关选项,如下图: + +![keil finsh](figures/keil-finsh-3.1.5.png) #### Cube MX 添加 FinSH 源码 打开一个 cube 工程,点击 Additional Software,在 Pack Vendor 中可勾选 RealThread 快速定位 RT-Thread 软件包,然后在 RT-Thread 软件包中勾选 shell,即可添加 FinSH 组件的源码到工程中。 -![Cube MX 添加 FinSH 源码](figures/cube-add-finsh-src.png) +![Cube MX 添加 FinSH 源码](figures/cube-add-finsh-src-3.1.5.png) + +然后在生成后的代码中,找到 rtconfig.h,使能 `#include "finsh_config.h"` 。 #### 其他 IDE 添加 FinSH 源码 @@ -138,14 +147,23 @@ void rt_hw_console_output(const char *str) 2、目标工程添加 FinSH 源码: - 打开工程,新建 `finsh` 分组,添加工程中 `finsh` 文件夹下的所有. c 文件,如下图; + + ``` + cmd.c + msh.c + shell.c + finsh_port.c + ``` + - 添加 `finsh` 文件夹的头文件路径(点击 `Project -> Options... ` 进入弹窗进行添加,如下图); -- 在 rtconfig.h 中添加 `#define RT_USING_FINSH` 宏定义,这样 FinSH 将生效,如下图。 -![添加 finsh 源码](figures/finsh-src.png) +- 在 rtconfig.h 中使能 `#define RT_USING_FINSH` 宏定义,这样 FinSH 将生效,如下图。 + +![添加 finsh 源码](figures/finsh-src-3.1.5.png) ![添加 finsh 头文件路径](figures/iar-finsh-h.png) -![添加 finsh 所需宏定义](figures/rtconfig-add.png) +![添加 finsh](figures/rtconfig-add-3.1.5.png) ### 实现 rt_hw_console_getchar @@ -156,9 +174,9 @@ void rt_hw_console_output(const char *str) char rt_hw_console_getchar(void); ``` -- rt_hw_console_getchar():控制台获取一个字符,即在该函数中实现 uart 获取字符,可以使用查询方式获取(注意不要死等,在未获取到字符时,需要让出 CPU),也可以使用中断方式获取。 +- rt_hw_console_getchar():控制台获取一个字符,即在该函数中实现 uart 获取字符,可以使用查询方式获取(注意不要死等,在未获取到字符时,需要让出 CPU),推荐使用中断方式获取。 -**示例代码**:如下是基于 STM32F103 HAL 串口驱动对接的 rt_hw_console_getchar(),完成对接 FinSH 组件,其中获取字符采用查询方式,示例仅做参考。 +**示例代码**:如下是基于 STM32F103 HAL 串口驱动对接的 rt_hw_console_getchar(),完成对接 FinSH 组件,其中获取字符采用查询方式,示例仅做参考,可自行实现中断方式获取字符。 ```c char rt_hw_console_getchar(void) @@ -463,9 +481,15 @@ A: 不可以。但是可以通过其他方法实现打印浮点数的目的, ![示例](figures/ok1.png) -A:可能的原因有:UART 驱动未实现字符输入函数、未打开 FinSH 组件等;如果手动开启了 HEAP,需要确定 HEAP 是否过小,导致 tshell 线程创建失败 。 +A:可能的原因有:UART 驱动未实现字符输入函数、未打开 FinSH 组件等;如果开启了 HEAP,需要确定 HEAP 是否过小,导致 tshell 线程创建失败 。 ### Q: 出现 hard fault。 A: ps 后关注各个线程栈的最大利用率,若某线程出现 100% 的情况,则表示该线程栈过小,需要将值调大。 +### Q:使用 AC6 编译错误。 + +A:汇编文件识别失败造成的,识别错误的情况下会识别为 c 文件,可以右击文件,将汇编文件的文件类型改为汇编类型,再次编译即可。 + + + diff --git a/rt-thread-version/rt-thread-nano/finsh-port/figures/add-3.1.5.png b/rt-thread-version/rt-thread-nano/finsh-port/figures/add-3.1.5.png new file mode 100644 index 0000000000000000000000000000000000000000..fbe8d3209c3ac6ee6274ac7aa86d7ab8acbfcf2e Binary files /dev/null and b/rt-thread-version/rt-thread-nano/finsh-port/figures/add-3.1.5.png differ diff --git a/rt-thread-version/rt-thread-nano/finsh-port/figures/cube-add-finsh-src-3.1.5.png b/rt-thread-version/rt-thread-nano/finsh-port/figures/cube-add-finsh-src-3.1.5.png new file mode 100644 index 0000000000000000000000000000000000000000..9d46e1ebb2bf0e052a2e4d6f4c97ccf08b7eb4e1 Binary files /dev/null and b/rt-thread-version/rt-thread-nano/finsh-port/figures/cube-add-finsh-src-3.1.5.png differ diff --git a/rt-thread-version/rt-thread-nano/finsh-port/figures/finsh-src-3.1.5.png b/rt-thread-version/rt-thread-nano/finsh-port/figures/finsh-src-3.1.5.png new file mode 100644 index 0000000000000000000000000000000000000000..dac5ecb5dc69603217ce5dbcd718db312c264376 Binary files /dev/null and b/rt-thread-version/rt-thread-nano/finsh-port/figures/finsh-src-3.1.5.png differ diff --git a/rt-thread-version/rt-thread-nano/finsh-port/figures/keil-finsh-3.1.5.png b/rt-thread-version/rt-thread-nano/finsh-port/figures/keil-finsh-3.1.5.png new file mode 100644 index 0000000000000000000000000000000000000000..278c7422da8037bb6ce54b723a85f617fc8acf7c Binary files /dev/null and b/rt-thread-version/rt-thread-nano/finsh-port/figures/keil-finsh-3.1.5.png differ diff --git a/rt-thread-version/rt-thread-nano/finsh-port/figures/rtconfig-add-3.1.5.png b/rt-thread-version/rt-thread-nano/finsh-port/figures/rtconfig-add-3.1.5.png new file mode 100644 index 0000000000000000000000000000000000000000..790f41d766f26768befad957374c6b265c273c57 Binary files /dev/null and b/rt-thread-version/rt-thread-nano/finsh-port/figures/rtconfig-add-3.1.5.png differ diff --git a/rt-thread-version/rt-thread-nano/nano-config/an0043-nano-config.md b/rt-thread-version/rt-thread-nano/nano-config/an0043-nano-config.md index cf9620a860d2a8fbf6dbcc9682b5d7fd97b81cc8..ee7e5423058974cf43217fd232c6e09f61c09a2e 100644 --- a/rt-thread-version/rt-thread-nano/nano-config/an0043-nano-config.md +++ b/rt-thread-version/rt-thread-nano/nano-config/an0043-nano-config.md @@ -2,36 +2,17 @@ RT-Thread Nano 的配置在 rtconfig.h 中进行,通过开关宏定义来使能或关闭某些功能,接下来对该配置文件中的宏定义进行说明。 -## 头文件 - -头文件 `RTE_Components.h` 仅由 Keil MDK 工程生成,其中仅定义了一个打开 FinSH 组件的宏 `RTE_USING_FINSH`。 - -```c - -#if defined (__CC_ARM) || (__CLANG_ARM) -#include "RTE_Components.h" /* 用来开关 FinSH 组件,仅 MDK 会产生该文件 */ - -#if defined(RTE_USING_FINSH) -#define RT_USING_FINSH -#endif //RTE_USING_FINSH - -#endif //(__CC_ARM) || (__CLANG_ARM) - -``` - -非 Keil MDK 则不需要该头文件,若需打开 FinSH 组件,可直接在 rtconfig.h 中手动定义 `RT_USING_FINSH` 打开 FinSH 组件。 - ## 基础配置 -1、设置系统最大优先级,可设置范围 8 到 256,默认值 8,可修改。 +1、设置系统最大优先级,可设置范围 8 到 256,默认值 32,可修改。 ```c -#define RT_THREAD_PRIORITY_MAX 8 +#define RT_THREAD_PRIORITY_MAX 32 ``` 2、设置 RT-Thread 操作系统节拍,表示多少 tick 每秒,如默认值为 100 ,表示一个时钟节拍(os tick)长度为 10ms。常用值为 100 或 1000。时钟节拍率越快,系统的额外开销就越大。 ```c -#define RT_TICK_PER_SECOND 100 +#define RT_TICK_PER_SECOND 1000 ``` 3、字节对齐时设定对齐的字节个数,默认 4,常使用 ALIGN(RT_ALIGN_SIZE) 进行字节对齐。 @@ -48,16 +29,15 @@ RT-Thread Nano 的配置在 rtconfig.h 中进行,通过开关宏定义来使 ```c #define RT_USING_COMPONENTS_INIT ``` -6、开启 `RT_USING_USER_MAIN` 宏,则打开 user_main 功能,默认需要开启,这样才能调用 RT-Thread 的启动代码;main 线程的栈大小默认为 256,可修改。 +6、开启 `RT_USING_USER_MAIN` 宏,则打开 user_main 功能,默认需要开启,这样才能调用 RT-Thread 的启动代码;main 线程的栈大小可修改。 ```c #define RT_USING_USER_MAIN -#define RT_MAIN_THREAD_STACK_SIZE 256 +#define RT_MAIN_THREAD_STACK_SIZE 512 ``` ## 内核调试功能配置 - -定义 `RT_DEBUG` 宏则开启 debug 模式,默认关闭。若开启系统调试,则可以打印系统 LOG 日志。 +定义 `RT_DEBUG` 宏则开启 debug 模式。若开启系统调试,则在实现打印之后可以打印系统 LOG 日志。请在代码开发与调试过程中打开该项,帮助调试定位问题,在代码发布时关闭该项。 ```c //#define RT_DEBUG // 关闭 debug @@ -94,7 +74,7 @@ RT-Thread Nano 的配置在 rtconfig.h 中进行,通过开关宏定义来使 系统支持的 IPC 有:信号量、互斥量、事件集、邮箱、消息队列。通过定义相应的宏打开或关闭该 IPC 的使用。 ```c -#define RT_USING_SEMAPHORE // 设置是否使用 信号量 +#define RT_USING_SEMAPHORE // 设置是否使用 信号量,默认打开 //#define RT_USING_MUTEX // 设置是否使用 互斥量 @@ -111,41 +91,54 @@ RT-Thread 内存管理包含:内存池、内存堆、小内存算法。通过 ```c //#define RT_USING_MEMPOOL // 是否使用 内存池 -//#define RT_USING_HEAP // 是否使用 内存堆 +#define RT_USING_HEAP // 是否使用 内存堆 #define RT_USING_SMALL_MEM // 是否使用 小内存管理 //#define RT_USING_TINY_SIZE // 是否使用 小体积的算法,牵扯到 rt_memset、rt_memcpy 所产生的体积 ``` -## FinSH 控制台配置 -定义 RT_USING_CONSOLE 则开启控制台功能,失能该宏则关闭控制台,不能实现打印;修改 RT_CONSOLEBUF_SIZE 可配置控制台缓冲大小。 +## FinSH 配置 + +当系统加入 FinSH 组件源码后,需要在 rtconfig.h 中开启以下项 ```c -#define RT_USING_CONSOLE // 控制台宏开关 -#define RT_CONSOLEBUF_SIZE 128 // 设置控制台数据 buf 大小,默认 128 byte +#include "finsh_config.h" ``` -FinSH 组件的使用通过定义 RT_USING_FINSH 开启,开启后可对 FinSH 组件相关的参数进行配置修改,FINSH_THREAD_STACK_SIZE 的值默认较小,请根据实际情况改大。 +该头文件中包含了对 FinSH 组件的配置。如下是该头文件中包含的 FinSH 组件的配置项: + ```c -#if defined (RT_USING_FINSH) // 开关 FinSH 组件 +/* 打开 FinSH 组件 */ +#define RT_USING_FINSH - #define FINSH_USING_MSH // 使用 FinSH 组件 MSH 模式 - #define FINSH_USING_MSH_ONLY // 仅使用 MSH 模式 +/* 使用 MSH 模式 */ +#define FINSH_USING_MSH +#define FINSH_USING_MSH_ONLY - #define __FINSH_THREAD_PRIORITY 5 // 设置 FinSH 组件优先级,配置该值后通过下面的公式进行计算 - #define FINSH_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 8 * __FINSH_THREAD_PRIORITY + 1) +/* tshell 线程的优先级与线程栈大小 */ +#define FINSH_THREAD_PRIORITY 21 // 请检查系统最大优先级的值,该值必须在系统支持的优先级范围之内 +#define FINSH_THREAD_STACK_SIZE 1024 - #define FINSH_THREAD_STACK_SIZE 512 // 设置 FinSH 线程栈大小,范围 1-4096 +/* 使用符号表,使用命令描述 */ +#define FINSH_USING_SYMTAB +#define FINSH_USING_DESCRIPTION +``` - #define FINSH_HISTORY_LINES 1 // 设置 FinSH 组件记录历史命令个数,值范围 1-32 - #define FINSH_USING_SYMTAB // 使用符号表,需要打开,默认打开 +注意:若未加入 FinSH 组件源码,请勿开启此项。 +## DEVICE 框架配置 -#endif +当系统中加入 device 框架源码时,则需要在 rtconfig.h 中开启以下项 + +```c +#define RT_USING_DEVICE ``` +开启该项则将加入 device 框架源码。 + +注意:若未加入 device 源码,请勿开启此项。 ## 常见问题 Q:移植完成之后出现 hard fault。 -A:在默认情况下,系统配置的各种线程栈大小均较小,若不能正常运行,很有可能是栈不够用,可将栈值调大。例如 main 线程栈大小默认为 256,在实际使用时,main 中可能加入其它代码导致栈不够用的情况;FinSH 组件的线程 tshell,默认栈 512 也比较小,在使用时可以调大。 \ No newline at end of file +A:在默认情况下,系统配置的各种线程栈大小均较小,若不能正常运行,很有可能是栈不够用,可将栈值调大。例如 main 线程栈大小默认为 256,在实际使用时,main 中可能加入其它代码导致栈不够用的情况;FinSH 组件的线程 tshell,默认栈 512 也比较小,在使用时可以调大。 diff --git a/rt-thread-version/rt-thread-nano/nano-port-cube/an0041-nano-port-cube.md b/rt-thread-version/rt-thread-nano/nano-port-cube/an0041-nano-port-cube.md index 9f316ef1b8fb70d446be87fb0ee101495d3d434a..e41dcad59a9a24d642b8128b9b2bb356a94bf1a2 100644 --- a/rt-thread-version/rt-thread-nano/nano-port-cube/an0041-nano-port-cube.md +++ b/rt-thread-version/rt-thread-nano/nano-port-cube/an0041-nano-port-cube.md @@ -24,7 +24,7 @@ RT-Thread Nano 已集成在 CubeMX 中,可以直接在 IDE 中进行下载添 ![完成安装](figures/from_url.png) -`check` 通过后,点击 OK 回到 `User Defined Packs Manager` 界面,再次点击 OK,CubeMX 自动连接服务器,获取包描述文件。回到 `Manage embedded software packages` 界面,就会发现 `RT-Thread Nano 3.1.3` 软件包,选择该软件包,点击 `Install Now`,如下图所示: +`check` 通过后,点击 OK 回到 `User Defined Packs Manager` 界面,再次点击 OK,CubeMX 自动连接服务器,获取包描述文件。回到 `Manage embedded software packages` 界面,就会发现 `RT-Thread Nano 3.1.5` 软件包,选择该软件包,点击 `Install Now`,如下图所示: ![选择版本](figures/exisit_pack.png) @@ -54,17 +54,17 @@ RT-Thread Nano 已集成在 CubeMX 中,可以直接在 IDE 中进行下载添 ### 选择 Nano 组件 -选中芯片型号之后,点击 `Additional Softwares`,进入 `Additional Software Components selection` 界面,在 `Pack Vendor` 中选择 `RealThread`, 然后根据需求选择 RT-Thread 组件(此处只移植 Nano,只选择 kernel 即可),然后点击 OK 按钮,如下图所示: +选中芯片型号之后,点击 `Softwares Packages`->`Select Components`,进入组件配置界面,选择 `RealThread`, 然后根据需求选择 RT-Thread 组件,然后点击 OK 按钮,如下图所示: -![选择软件包](figures/pack_choice.png) +![选择软件包](figures/pack_choice-3.1.5.png) -> 注意:RT-Thread Nano 软件包中包含 kernel 与 shell 两个部分,仅选择 kernel 表示只使用 RT-Thread 内核,工程中会添加内核代码;选择 kernel 与 shell 表示在使用 RT-Thread Nano 的基础上使用 FinSH Shell 组件,工程中会添加内核代码与 FinSH 组件的代码,FinSH 的移植详见 [《在 RT-Thread Nano 上添加控制台与 FinSH》](../finsh-port/an0045-finsh-port.md)。 +> 注意:RT-Thread Nano 软件包中包含 kernel, shell 和 device 三个部分,仅选择 kernel 表示只使用 RT-Thread 内核,工程中会添加内核代码;选择 kernel 与 shell 表示在使用 RT-Thread Nano 的基础上使用 FinSH Shell 组件,工程中会添加内核代码与 FinSH 组件的代码,FinSH 的移植详见 [《在 RT-Thread Nano 上添加控制台与 FinSH》](../finsh-port/an0045-finsh-port.md)。再选择 device 表示使用 rt-thread 的 device 框架,用户基于此框架编写外设驱动并注册后,就可以使用 device 统一接口操作外设。 ### 配置 Nano 选择组件之后,对组件参数进行配置。在工程界面 `Pinout & Configuration` 中,进入所选组件参数配置区,按照下图进行配置 -![配置 rt-thread](figures/pack_config.png) +![配置 rt-thread](figures/pack_config-3.1.5.jpg) ### 工程管理 @@ -80,9 +80,9 @@ RT-Thread Nano 已集成在 CubeMX 中,可以直接在 IDE 中进行下载添 ### 中断与异常处理 -RT-Thread 操作系统重定义 `HardFault_Handler`、`PendSV_Handler`、`SysTick_Handler` 中断函数,为了避免重复定义的问题,在生成工程之前,需要在中断配置中,代码生成的选项中,取消选择三个中断函数(对应注释选项是 `Hard fault interrupt`, `Pendable request`, `Time base :System tick timer`),最后点击生成代码,具体操作如下图中步骤 11-15 所示: +RT-Thread 操作系统重定义 `HardFault_Handler`、`PendSV_Handler`、`SysTick_Handler` 中断函数,为了避免重复定义的问题,在生成工程之前,需要在中断配置中,代码生成的选项中,取消选择三个中断函数(对应注释选项是 `Hard fault interrupt`, `Pendable request`, `Time base :System tick timer`),最后点击生成代码,具体操作如下图 所示: -![中断配置](figures/nvic_config.png) +![中断配置](figures/nvic_config-3.1.5.png) 等待工程生成完毕,点击打开工程,如下图所示,即可进入 MDK5 工程中。 @@ -182,7 +182,7 @@ void rt_hw_board_init() ### Q: check 网址失败 -**A**: 建议升级 Cube MX 版本至 5.0。 +**A**: 建议升级 Cube MX 版本至 5.0 以上。 ### Q: CubeMX 如何升级 diff --git a/rt-thread-version/rt-thread-nano/nano-port-cube/figures/exisit_pack.png b/rt-thread-version/rt-thread-nano/nano-port-cube/figures/exisit_pack.png index a6e53960a94f759d11beb57d5e3dc5a9c359bc73..7065689a2be853a08897ba5a17569cb3498ab9f1 100644 Binary files a/rt-thread-version/rt-thread-nano/nano-port-cube/figures/exisit_pack.png and b/rt-thread-version/rt-thread-nano/nano-port-cube/figures/exisit_pack.png differ diff --git a/rt-thread-version/rt-thread-nano/nano-port-cube/figures/finish.png b/rt-thread-version/rt-thread-nano/nano-port-cube/figures/finish.png index 7eae30ed16775866dbc5e0a256433215169139a5..048f851cf54a34a21469e1d5ce6aab006be16993 100644 Binary files a/rt-thread-version/rt-thread-nano/nano-port-cube/figures/finish.png and b/rt-thread-version/rt-thread-nano/nano-port-cube/figures/finish.png differ diff --git a/rt-thread-version/rt-thread-nano/nano-port-cube/figures/installed_url.png b/rt-thread-version/rt-thread-nano/nano-port-cube/figures/installed_url.png index d2a9de0c1989a63ee79191d994420791f8841bb5..1167f5f359507c3c41c2004b2a67b31facea025d 100644 Binary files a/rt-thread-version/rt-thread-nano/nano-port-cube/figures/installed_url.png and b/rt-thread-version/rt-thread-nano/nano-port-cube/figures/installed_url.png differ diff --git a/rt-thread-version/rt-thread-nano/nano-port-cube/figures/nvic_config-3.1.5.png b/rt-thread-version/rt-thread-nano/nano-port-cube/figures/nvic_config-3.1.5.png new file mode 100644 index 0000000000000000000000000000000000000000..5c3695a72ca6ff9c60a10fd711697b8c4efa9599 Binary files /dev/null and b/rt-thread-version/rt-thread-nano/nano-port-cube/figures/nvic_config-3.1.5.png differ diff --git a/rt-thread-version/rt-thread-nano/nano-port-cube/figures/pack_choice-3.1.5.png b/rt-thread-version/rt-thread-nano/nano-port-cube/figures/pack_choice-3.1.5.png new file mode 100644 index 0000000000000000000000000000000000000000..7e3641e1f271146d90dac75868a00c533bb3e53e Binary files /dev/null and b/rt-thread-version/rt-thread-nano/nano-port-cube/figures/pack_choice-3.1.5.png differ diff --git a/rt-thread-version/rt-thread-nano/nano-port-cube/figures/pack_config-3.1.5.jpg b/rt-thread-version/rt-thread-nano/nano-port-cube/figures/pack_config-3.1.5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..520d4df7cf39f416155da773a1d30e1918dac12e Binary files /dev/null and b/rt-thread-version/rt-thread-nano/nano-port-cube/figures/pack_config-3.1.5.jpg differ diff --git a/rt-thread-version/rt-thread-nano/nano-port-gcc-riscv/an0042-nano-port-gcc-riscv.md b/rt-thread-version/rt-thread-nano/nano-port-gcc-riscv/an0042-nano-port-gcc-riscv.md index 8dfbaa36795b2363cb1b68cba6781170e6d26736..1a1d9104acb0c475a120fb069804211bc2237390 100644 --- a/rt-thread-version/rt-thread-nano/nano-port-gcc-riscv/an0042-nano-port-gcc-riscv.md +++ b/rt-thread-version/rt-thread-nano/nano-port-gcc-riscv/an0042-nano-port-gcc-riscv.md @@ -59,6 +59,7 @@ ipc.c irq.c kservice.c mem.c +mempool.c object.c scheduler.c thread.c @@ -197,5 +198,5 @@ RT-Thread 提供中断管理方法,当系统没有实现类似中断向量表 ... ``` -RT-Thread Nano 默认未开启宏 RT_USING_HEAP,故只支持静态方式创建任务及信号量。若要通过动态方式创建对象则需要在 rtconfig.h 文件里开启 RT_USING_HEAP 宏定义。完整配置详见 [《 RT-Thread Nano 配置》](../nano-config/an0043-nano-config.md)。 +RT-Thread Nano 完整配置详见 [《 RT-Thread Nano 配置》](../nano-config/an0043-nano-config.md)。 diff --git a/rt-thread-version/rt-thread-nano/nano-port-iar/an0040-nano-port-iar.md b/rt-thread-version/rt-thread-nano/nano-port-iar/an0040-nano-port-iar.md index 9de9bc20b040e35ebf3846c6a34d321bbfc404a1..9f215d0c6b5ac6a33da983ae872df9cee7641f59 100644 --- a/rt-thread-version/rt-thread-nano/nano-port-iar/an0040-nano-port-iar.md +++ b/rt-thread-version/rt-thread-nano/nano-port-iar/an0040-nano-port-iar.md @@ -63,6 +63,7 @@ ipc.c irq.c kservice.c mem.c +mempool.c object.c scheduler.c thread.c @@ -197,5 +198,5 @@ void rt_hw_board_init() ... ``` -RT-Thread Nano 默认未开启宏 RT_USING_HEAP,故只支持静态方式创建任务、信号量等对象。若要通过动态方式创建对象则需要在 rtconfig.h 文件里开启 RT_USING_HEAP 宏定义。完整配置详见 [《 RT-Thread Nano 配置》](../nano-config/an0043-nano-config.md)。 +若不开启宏 RT_USING_HEAP,则只支持静态方式创建任务、信号量等对象。若要通过动态方式创建对象则需要在 rtconfig.h 文件里开启 RT_USING_HEAP 宏定义。完整配置详见 [《 RT-Thread Nano 配置》](../nano-config/an0043-nano-config.md)。 diff --git a/rt-thread-version/rt-thread-nano/nano-port-keil/figures/os_tick.png b/rt-thread-version/rt-thread-nano/nano-port-keil/figures/os_tick.png new file mode 100644 index 0000000000000000000000000000000000000000..b456a1a9d9d204e7861653517286306335e29e4a Binary files /dev/null and b/rt-thread-version/rt-thread-nano/nano-port-keil/figures/os_tick.png differ diff --git a/rt-thread-version/rt-thread-nano/nano-port-keil/figures/rtos2.png b/rt-thread-version/rt-thread-nano/nano-port-keil/figures/rtos2.png new file mode 100644 index 0000000000000000000000000000000000000000..d340d115e035c2c4c2a1476179064f1bb1eb0d31 Binary files /dev/null and b/rt-thread-version/rt-thread-nano/nano-port-keil/figures/rtos2.png differ diff --git a/rt-thread-version/rt-thread-nano/nano-port-principle/an0044-nano-port-principle.md b/rt-thread-version/rt-thread-nano/nano-port-principle/an0044-nano-port-principle.md index 8a55b25526fa3e74dcd206db46c4ad3b61b6adc2..249c40201f0cbab80493d726ac2ef6d13d71e758 100644 --- a/rt-thread-version/rt-thread-nano/nano-port-principle/an0044-nano-port-principle.md +++ b/rt-thread-version/rt-thread-nano/nano-port-principle/an0044-nano-port-principle.md @@ -60,11 +60,11 @@ int entry(void) 最终调用 main() 函数进入用户 main()。 -### 上下文切换 context_xx.s +### 上下文切换 context_xx.S 上下文切换表示 CPU 从一个线程切换到另一个线程、或者线程与中断之间的切换等。在上下文切换过程中,CPU 一般会停止处理当前运行的代码,并保存当前程序运行的具体位置以便之后继续运行。 -在该文件中除了实现上下文切换的函数外,还需完成全局开关中断函数,详见编程指南 [《内核移植》 - CPU 架构移植](../../../programming-manual/porting/porting/) 章节中的 “实现全局开关中断 ” 小节与 “实现上下文切换” 小节。 +在该文件中除了实现上下文切换的函数外,还需完成全局开关中断函数,详见编程指南 [《内核移植》 - CPU 架构移植](../../../programming-manual/porting/porting/) 章节中的 “实现全局开关中断” 小节与 “实现上下文切换” 小节。 | 需实现的函数 | 描述 | | ------------------------------------------------------------ | ------------------------------------------------------------ | @@ -114,7 +114,7 @@ int entry(void) 1. 配置系统时钟。 2. 实现 OS 节拍。 -3. 初始化外设:如 GPIO/UART 等等。 +3. 初始化外设:如 GPIO/UART 等等,若需要请在此处调用。 4. 初始化系统内存堆,实现动态堆内存管理。 5. 板级自动初始化,使用 INIT_BOARD_EXPORT() 自动初始化的函数会在此处被初始化。 6. 其他必要的初始化,如 MMU 配置(需要时请自行在 rt_hw_board_init 函数中调用应用函数实现)。 @@ -123,39 +123,47 @@ int entry(void) /* board.c */ void rt_hw_board_init(void) { - /* System Clock Update */ - SystemCoreClockUpdate(); + /* 第一部分:系统初始化、系统时钟配置等 */ + HAL_init(); // 一些系统层初始化,若需要则增加此部分 + SystemClock_Config(); // 配置系统时钟 + SystemCoreClockUpdate(); // 更新系统时钟频率 SystemCoreClock - /* System Tick Configuration */ + /* 第二部分:配置 OS Tick 的频率,实现 OS 节拍(并在中断服务例程中实现 OS Tick 递增) */ _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); + /* 第三部分:初始化硬件外设,若有需要,则放在此处调用 */ + + /* 第四部分:系统动态内存堆初始化 */ #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP) rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get()); #endif - /* Call components board initial (use INIT_BOARD_EXPORT()) */ + /* 第五部分:使用 INIT_BOARD_EXPORT() 进行的初始化 */ #ifdef RT_USING_COMPONENTS_INIT rt_components_board_init(); #endif + + /* 第六部分:其他初始化 */ } ``` -### 配置系统时钟 +### 一、配置系统时钟 -系统时钟是给各个硬件模块提供工作时钟的基础,一般在 `rt_hw_board_init()` 函数中完成,可以调用库函数实现配置,也可以自行实现。 +系统时钟是给各个硬件模块提供工作时钟的基础,在 `rt_hw_board_init()` 函数中完成,可以调用库函数实现配置,也可以自行实现。 -如下是 stm32 配置系统时钟调用示例(调用库函数 SystemCoreClockUpdate()): +如下是配置系统时钟调用示例: ```c /* board.c */ void rt_hw_board_init() { - SystemCoreClockUpdate(); // 在无库函数使用时,一般使用 rt_hw_clock_init() 配置,函数名不做要求,函数自行实现 + /* 第一部分:系统初始化、系统时钟配置等 */ + rt_hw_clock_init() // 时钟初始化,函数名不做要求,函数自行实现,如 SystemClock_Config()、SystemCoreClockUpdate() ... } ``` -### 实现 OS 节拍 +### 二、实现 OS 节拍 OS 节拍也叫时钟节拍或 OS tick。任何操作系统都需要提供一个时钟节拍,以供系统处理所有和时间有关的事件。 @@ -168,11 +176,12 @@ OS 节拍也叫时钟节拍或 OS tick。任何操作系统都需要提供一个 void rt_hw_board_init() { ... + /* 第二部分:配置 OS Tick 的频率,实现 OS 节拍(并在中断服务例程中实现 OS Tick 递增) */ _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); // 使用 SysTick 实现时钟节拍 ... } -/* 中断服务例程 */ +/* systick 中断服务例程 */ void SysTick_Handler(void) { /* enter interrupt */ @@ -192,6 +201,7 @@ void SysTick_Handler(void) void rt_hw_board_init() { ... + /* 第二部分:配置 OS Tick 的频率,实现 OS 节拍(并在中断服务例程中实现 OS Tick 递增) */ rt_hw_timer_init(); // 使用 硬件定时器 实现时钟节拍,一般命名为 rt_hw_timer_init() ... } @@ -203,7 +213,7 @@ int rt_hw_timer_init(void) // 函数自行实现,并需要装载中断服务 rt_hw_interrupt_umask(IRQ_PBA8_TIMER2_3); } -/* 中断服务例程 */ +/* TIMER 中断服务例程 */ static void rt_hw_timer_isr(int vector, void *param) { rt_interrupt_enter(); @@ -215,7 +225,7 @@ static void rt_hw_timer_isr(int vector, void *param) > [!NOTE] > 注:在初始化时钟节拍的时候,会用到宏 `RT_TICK_PER_SECOND`。通过修改该宏的值,可以修改系统中一个时钟节拍的时间长度。 -### 硬件外设初始化 +### 三、硬件外设初始化 硬件初始化,如 UART 初始化等(对接控制台),需要在 rt_hw_board_init() 函数中手动调用 UART 初始化函数。 @@ -224,12 +234,14 @@ static void rt_hw_timer_isr(int vector, void *param) void rt_hw_board_init(void) { .... + /* 第三部分:初始化硬件外设,若有需要,则放在此处调用 */ uart_init(); .... } ``` +注意,uart_init() 或者其他的外设初始化函数,若已经使用了宏 INIT_BOARD_EXPORT() 进行初始化,则不需要在此进行显式调用。两种初始化方法选择一种即可。 -### 实现动态内存堆 +### 四、实现动态内存堆 RT-Thread Nano 默认不开启动态内存堆功能,开启 RT_USING_HEAP 将可以使用动态内存功能,即可以使用 rt_malloc、rt_free 以及各种系统动态创建对象的 API。动态内存堆管理功能的初始化是通过 rt_system_heap_init() 函数完成的,动态内存堆的初始化需要指定堆内存的起始地址和结束地址,函数原型如下: diff --git a/rt-thread-version/rt-thread-standard/_sidebar.md b/rt-thread-version/rt-thread-standard/_sidebar.md index 1ebcd68e634d4731f27945c2f48528622be8211a..bb457a9111ee175bff95125beb403ae7473c0aa0 100644 --- a/rt-thread-version/rt-thread-standard/_sidebar.md +++ b/rt-thread-version/rt-thread-standard/_sidebar.md @@ -32,7 +32,8 @@ - 设备和驱动 - [I/O设备模型](/rt-thread-version/rt-thread-standard/programming-manual/device/device.md) - - [UART设备](/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart.md) + - [UART设备](/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/uart.md) + - [UART设备V2版本](/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/uart.md) - [PIN设备](/rt-thread-version/rt-thread-standard/programming-manual/device/pin/pin.md) - [ADC设备](/rt-thread-version/rt-thread-standard/programming-manual/device/adc/adc.md) - [DAC设备](/rt-thread-version/rt-thread-standard/programming-manual/device/dac/dac.md) diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/figures/uart-dma b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/figures/uart-dma similarity index 100% rename from rt-thread-version/rt-thread-standard/programming-manual/device/uart/figures/uart-dma rename to rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/figures/uart-dma diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/figures/uart-dma.png b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/figures/uart-dma.png similarity index 100% rename from rt-thread-version/rt-thread-standard/programming-manual/device/uart/figures/uart-dma.png rename to rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/figures/uart-dma.png diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/figures/uart-int b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/figures/uart-int similarity index 100% rename from rt-thread-version/rt-thread-standard/programming-manual/device/uart/figures/uart-int rename to rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/figures/uart-int diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/figures/uart-int.png b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/figures/uart-int.png similarity index 100% rename from rt-thread-version/rt-thread-standard/programming-manual/device/uart/figures/uart-int.png rename to rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/figures/uart-int.png diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/figures/uart.vsdx b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/figures/uart.vsdx similarity index 100% rename from rt-thread-version/rt-thread-standard/programming-manual/device/uart/figures/uart.vsdx rename to rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/figures/uart.vsdx diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/figures/uart1.png b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/figures/uart1.png similarity index 100% rename from rt-thread-version/rt-thread-standard/programming-manual/device/uart/figures/uart1.png rename to rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/figures/uart1.png diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart.md b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/uart.md similarity index 100% rename from rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart.md rename to rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/uart.md diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/mcfg_dma.jpg b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/mcfg_dma.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0776e193f1363771971808d8f0b66332b18a779f Binary files /dev/null and b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/mcfg_dma.jpg differ diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/mcfg_int.jpg b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/mcfg_int.jpg new file mode 100644 index 0000000000000000000000000000000000000000..18ce4565bc5d126d6958aa2983ab3d29c9520d38 Binary files /dev/null and b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/mcfg_int.jpg differ diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/mcfg_txdma_intrx.jpg b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/mcfg_txdma_intrx.jpg new file mode 100644 index 0000000000000000000000000000000000000000..43acc89b50ce0d7852fce747a9b59d23a2d4f01b Binary files /dev/null and b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/mcfg_txdma_intrx.jpg differ diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/mcfg_txpoll_rxint.jpg b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/mcfg_txpoll_rxint.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0bfac41c8bebd3de6aab8fe190725e1d559f2c28 Binary files /dev/null and b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/mcfg_txpoll_rxint.jpg differ diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/uart-dma b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/uart-dma new file mode 100644 index 0000000000000000000000000000000000000000..56b46e9e688c7cd7272297b4384a31fa37b5a53c --- /dev/null +++ b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/uart-dma @@ -0,0 +1,24 @@ +@startuml + +actor û + +participant Ӧó +participant ISR +participant DMA +participant û + +Ӧó->Ӧó: ʼϢ +Ӧó->Ӧó: ýջص +Ӧó->Ӧó: ݴ߳ + +Ӧó->Ӧó: ݴ߳ȴϢ + +û->DMA: ûһַ + +DMA->ISR: DMAһַ뻺ж + +ISR->Ӧó: ýջصϢм߳ + +Ӧó->Ӧó: ݴ̻߳ȡϢбӻȡһַ + +@enduml \ No newline at end of file diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/uart-dma.png b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/uart-dma.png new file mode 100644 index 0000000000000000000000000000000000000000..dcc008ef9285c57d6e2f6b2017dc44b884b60ea1 Binary files /dev/null and b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/uart-dma.png differ diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/uart.vsdx b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/uart.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..e98d48e2c0773249bca850e55ef40231500996c5 Binary files /dev/null and b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/uart.vsdx differ diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/uart1.png b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/uart1.png new file mode 100644 index 0000000000000000000000000000000000000000..8f1404b7522001a78fe2c051712daa7896707496 Binary files /dev/null and b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/figures/uart1.png differ diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/uart.md b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/uart.md new file mode 100644 index 0000000000000000000000000000000000000000..7dce8ba2f6e29203b353e8ef8f3e253e1d037c7e --- /dev/null +++ b/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/uart.md @@ -0,0 +1,697 @@ +# UART 设备 v2 版本 + +> [!NOTE] +> 注:目前只有 github 的 master 分支上的 stm32l475-pandora 的 BSP 进行了串口 V2 版本的适配。 + +> [!NOTE] +> 注:如果用户已经清楚了解[旧版本的串口框架](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v1/uart),那么可直接跳过该文档的前部分关于串口介绍的内容,从[访问串口设备](uart?id=%e8%ae%bf%e9%97%ae%e4%b8%b2%e5%8f%a3%e8%ae%be%e5%a4%87)章节开始查阅即可。 + +## UART 简介 + +UART(Universal Asynchronous Receiver/Transmitter)通用异步收发传输器,UART 作为异步串口通信协议的一种,工作原理是将传输数据的每个字符一位接一位地传输。是在应用程序开发过程中使用频率最高的数据总线。 + +UART 串口的特点是将数据一位一位地顺序传送,只要 2 根传输线就可以实现双向通信,一根线发送数据的同时用另一根线接收数据。UART 串口通信有几个重要的参数,分别是波特率、起始位、数据位、停止位和奇偶检验位,对于两个使用 UART 串口通信的端口,这些参数必须匹配,否则通信将无法正常完成。UART 串口传输的数据格式如下图所示: + +![串口传输数据格式](figures/uart1.png) + +* 起始位:表示数据传输的开始,电平逻辑为 “0” 。 + +* 数据位:可能值有 5、6、7、8、9,表示传输这几个 bit 位数据。一般取值为 8,因为一个 ASCII 字符值为 8 位。 + +* 奇偶校验位:用于接收方对接收到的数据进行校验,校验 “1” 的位数为偶数 (偶校验) 或奇数(奇校验),以此来校验数据传送的正确性,使用时不需要此位也可以。 + +* 停止位: 表示一帧数据的结束。电平逻辑为 “1”。 + +* 波特率:串口通信时的速率,它用单位时间内传输的二进制代码的有效位 (bit) 数来表示,其单位为每秒比特数 bit/s(bps)。常见的波特率值有 4800、9600、14400、38400、115200 等,数值越大数据传输的越快,波特率为 115200 表示每秒钟传输 115200 位数据。 + +## 访问串口设备 + +应用程序通过 RT-Thread 提供的 I/O 设备管理接口来访问串口硬件,相关接口如下所示: + +| **函数** | **描述** | +| --------------------------- | -------------------------- | +| rt_device_find() | 查找设备 | +| rt_device_open() | 打开设备 | +| rt_device_read() | 读取数据 | +| rt_device_write() | 写入数据 | +| rt_device_control() | 控制设备 | +| rt_device_set_rx_indicate() | 设置接收回调函数 | +| rt_device_set_tx_complete() | 设置发送完成回调函数 | +| rt_device_close() | 关闭设备 | + +### 查找串口设备 + +应用程序根据串口设备名称获取设备句柄,进而可以操作串口设备,查找设备函数如下所示, + +```c +rt_device_t rt_device_find(const char* name); +``` + +| **参数** | **描述** | +| -------- | ---------------------------------- | +| name | 设备名称 | +| **返回** | —— | +| 设备句柄 | 查找到对应设备将返回相应的设备句柄 | +| RT_NULL | 没有找到相应的设备对象 | + +一般情况下,注册到系统的串口设备名称为 uart0,uart1 等,使用示例如下所示: + +```c +#define SAMPLE_UART_NAME "uart2" /* 串口设备名称 */ +static rt_device_t serial; /* 串口设备句柄 */ +/* 查找串口设备 */ +serial = rt_device_find(SAMPLE_UART_NAME); +``` + +### 打开串口设备 + +通过设备句柄,应用程序可以打开和关闭设备,打开设备时,会检测设备是否已经初始化,没有初始化则会默认调用初始化接口初始化设备。通过如下函数打开设备: + +```c +rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags); +``` + +| **参数** | **描述** | +| ---------- | ------------------------------- | +| dev | 设备句柄 | +| oflags | 设备模式标志 | +| **返回** | —— | +| RT_EOK | 设备打开成功 | +| -RT_EBUSY | 如果设备注册时指定的参数中包括 RT_DEVICE_FLAG_STANDALONE 参数,此设备将不允许重复打开 | +| 其他错误码 | 设备打开失败 | + +oflags 参数支持下列取值 (可以采用或的方式支持多种取值): + +```c +/* 接收模式参数 */ +#define RT_DEVICE_FLAG_RX_BLOCKING 0x1000 /* 接收阻塞模式 */ + +#define RT_DEVICE_FLAG_RX_NON_BLOCKING 0x2000 /* 接收非阻塞模式 */ + +/* 发送模式参数 */ +#define RT_DEVICE_FLAG_TX_BLOCKING 0x4000 /* 发送阻塞模式 */ + +#define RT_DEVICE_FLAG_TX_NON_BLOCKING 0x8000 /* 发送非阻塞模式 */ + +#define RT_DEVICE_FLAG_STREAM 0x040 /* 流模式 */ +``` + +用户使用串口时,不再根据硬件工作模式(轮询、中断、DMA)选择,而是根据具体的操作方式去配置,一般情况下,我们会选择使用 发送阻塞模式 以及 接收非阻塞模式 来进行开发。如下例子: + +```c +rt_device_open(dev, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING); // 串口设备使用模式为 (发送阻塞 接收非阻塞) 模式 +``` + +> [!NOTE] +> 注:为了避免 阻塞 / 非阻塞模式 和 轮询 / 中断 / DMA 模式 在文中描述上可能存在的误解,故本文以 应用层操作模式 指代 阻塞 / 非阻塞模式,以 硬件工作模式 指代 轮询 / 中断 / DMA 模式。 + +而对于流模式 `RT_DEVICE_FLAG_STREAM`,主要是当串口外设作为控制台时才会使用,该模式用来解决用户回车换行的问题,在正常的串口外设通信场景中,该模式一般不会使用。 + +> [!NOTE] +> 注:`RT_DEVICE_FLAG_STREAM` 流模式用于向串口终端输出字符串:当输出的字符是 `"\n"` (对应 16 进制值为 0x0A)时,自动在前面输出一个 `"\r"`(对应 16 进制值为 0x0D) 做分行。 + +流模式 RT_DEVICE_FLAG_STREAM 可以和接收发送模式参数使用或 “|” 运算符一起使用。 + +#### 硬件工作模式选择 + +由于用户层使用串口时,只关心应用层操作模式,不再关心硬件工作模式,使得应用层开发变得更加便捷,也增加了应用程序的可移植性。倘若用户开发时比较关心硬件具体的工作模式,那么应该对其工作模式如何选择? + +串口外设的遵循如下规则: + +1. 模式优先级为:DMA 模式 > 中断模式 > 轮询模式。即当有 DMA 配置时,默认使用 DMA 模式,以此类推。且非必要条件,不选择使用轮询模式。 +2. 串口默认配置接收和发送缓冲区 +3. 默认使用阻塞发送、非阻塞接收模式 + +> [!NOTE] +> 注:由于串口控制台的工作场景的独特性,其硬件工作模式为中断接收和轮询发送,用户使用时不建议参照串口控制台的模式进行配置,建议参照串口设备使用示例进行使用。 + +为了更加直观的表示应用层操作模式与硬件工作模式的对应关系,下面以图表和示例的方式进行说明。 + +**发送端的模式对应关系如下表所示:** + +| 编号 | 配置发送缓冲区(有 / 无)说明 | 硬件工作模式(TX) | 应用层操作模式(TX) | +| ---- | --------------------------------------- | ------------------ | -------------------- | +| (1) | **不使用缓存区,且设置缓存区长度为0** | 轮询 | 阻塞 | +| (2) | 不支持该模式 | 轮询 | 非阻塞 | +| (3) | 使用缓存区 | 中断 | 阻塞 | +| (4) | 使用缓存区 | 中断 | 非阻塞 | +| (5) | **不使用缓存区,但需要设置缓冲区长度大于0** | DMA | 阻塞 | +| (6) | 使用缓存区 | DMA | 非阻塞 | + +对于编号 (1) 模式,如果必须使用轮询模式时,一定要将缓冲区大小配置为 0,因为如果缓冲区大小不为 0,在应用层使用发送阻塞模式时,将会使用中断模式(如果开 DMA,则使用 DMA 模式)。 + +对于编号 (2) 模式,当用户设置为 DMA 阻塞模式时,虽然设置了缓冲区不为 0,但是该缓冲区并不会进行初始化,而是直接进行 DMA 数据搬运。从而省去了内存搬运造成的性能下降的问题。需要注意的是,当使用 DMA 阻塞模式时,虽然不用缓冲区,但是也要将缓冲区长度设置为大于 0 的值,因为当缓冲区长度为 0 时,将会错误地使用轮询模式。 + +**接收端的模式对应关系如下表所示:** + +| 编号 | 配置接收缓冲区(有 / 无)说明 | 硬件工作模式(RX) | 应用层操作模式(RX) | +| ---- | ------------------------------------- | ------------------ | -------------------- | +| (1) | **不使用缓存区,且设置缓存区长度为0** | 轮询 | 阻塞 | +| (2) | 不支持该模式 | 轮询 | 非阻塞 | +| (3) | 使用缓存区 | 中断 | 阻塞 | +| (4) | 使用缓存区 | 中断 | 非阻塞 | +| (5) | 使用缓存区 | DMA | 阻塞 | +| (6) | 使用缓存区 | DMA | 非阻塞 | + +对于编号 (1) 模式,如果必须使用轮询模式时,一定要将缓冲区大小配置为 0,因为如果缓冲区大小不为 0,在应用层使用接收阻塞模式时,将会使用中断模式(如果开 DMA,则使用 DMA 模式)。 + +下面举例说明如何配置硬件工作模式: + +##### 配置发送接收为 DMA 模式 + +在 menuconfig 中配置效果如下: + +![menuconfig](figures/mcfg_dma.jpg) + +上图所示,对于 UART1 的配置为开启 DMA RX 和 DMA TX,且发送和接收缓存区大小设置为 1024 字节。 + +由此用户在应用层对串口的接收和发送的操作模式进行配置时,无论配置阻塞或者非阻塞,均使用的是 DMA 模式。 + +##### 配置发送接收为中断模式 + +在 menuconfig 中配置效果如下: + +![menuconfig](figures/mcfg_int.jpg) + +上图所示,对于 UART1 的配置为关闭 DMA RX 和 DMA TX,且发送和接收缓存区大小设置为 1024 字节。 + +由此用户在应用层对串口的接收和发送的操作模式进行配置时,无论配置阻塞或者非阻塞,均使用的是中断模式。 + +##### 配置发送 DMA 模式、接收中断模式 + +在 menuconfig 中配置效果如下: + +![menuconfig](figures/mcfg_txdma_intrx.jpg) + +上图所示,对于 UART1 的配置为关闭 DMA RX 和开启 DMA TX,且发送和接收缓存区大小设置为 1024 字节。 + +由此用户在应用层对串口的接收和发送的操作模式进行配置时,无论配置阻塞或者非阻塞,均使用的是 DMA 发送模式和中断接收模式。 + +##### 配置发送轮询模式、接收中断模式(串口控制台默认模式) + +在 menuconfig 中配置效果如下: + +![menuconfig](figures/mcfg_txpoll_rxint.jpg) + +上图所示,对于 UART1 的配置为关闭 DMA RX 和 DMA TX,且发送和接收缓存区大小设置为 1024 字节。并且设置 `UART1 TX buffer size` 为 0。 + +由此用户在应用层对串口的接收和发送的操作模式进行配置时,发送只能使用阻塞模式,接收可以使用阻塞和非阻塞模式。串口控制台默认使用这样的配置模式,且操作模式为阻塞发送和非阻塞接收。 + +串口数据接收和发送数据的模式分为 3 种:中断模式、轮询模式、DMA 模式。在使用的时候,这 3 种模式只能**选其一**,若串口的打开参数 oflags 没有指定使用中断模式或者 DMA 模式,则默认使用轮询模式。 + +### 控制串口设备 + +通过控制接口,应用程序可以对串口设备进行配置,如波特率、数据位、校验位、接收缓冲区大小、停止位等参数的修改。控制函数如下所示: + +```c +rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg); +``` + +| **参数** | **描述** | +| ---------- | ---------------------------------------------- | +| dev | 设备句柄 | +| cmd | 命令控制字,可取值:RT_DEVICE_CTRL_CONFIG | +| arg | 控制的参数,可取类型: struct serial_configure | +| **返回** | —— | +| RT_EOK | 函数执行成功 | +| -RT_ENOSYS | 执行失败,dev 为空 | +| 其他错误码 | 执行失败 | + +控制参数结构体 struct serial_configure 原型如下: + +```c +struct serial_configure +{ + rt_uint32_t baud_rate; /* 波特率 */ + rt_uint32_t data_bits :4; /* 数据位 */ + rt_uint32_t stop_bits :2; /* 停止位 */ + rt_uint32_t parity :2; /* 奇偶校验位 */ + rt_uint32_t bit_order :1; /* 高位在前或者低位在前 */ + rt_uint32_t invert :1; /* 模式 */ + rt_uint32_t rx_bufsz :16; /* 接收数据缓冲区大小 */ + rt_uint32_t tx_bufsz :16; /* 发送数据缓冲区大小 */ + rt_uint32_t reserved :4; /* 保留位 */ +}; +``` + +RT-Thread 提供的配置参数可取值为如下宏定义: + +```c +/* 波特率可取值 */ +#define BAUD_RATE_2400 2400 +#define BAUD_RATE_4800 4800 +#define BAUD_RATE_9600 9600 +#define BAUD_RATE_19200 19200 +#define BAUD_RATE_38400 38400 +#define BAUD_RATE_57600 57600 +#define BAUD_RATE_115200 115200 +#define BAUD_RATE_230400 230400 +#define BAUD_RATE_460800 460800 +#define BAUD_RATE_921600 921600 +#define BAUD_RATE_2000000 2000000 +#define BAUD_RATE_3000000 3000000 +/* 数据位可取值 */ +#define DATA_BITS_5 5 +#define DATA_BITS_6 6 +#define DATA_BITS_7 7 +#define DATA_BITS_8 8 +#define DATA_BITS_9 9 +/* 停止位可取值 */ +#define STOP_BITS_1 0 +#define STOP_BITS_2 1 +#define STOP_BITS_3 2 +#define STOP_BITS_4 3 +/* 极性位可取值 */ +#define PARITY_NONE 0 +#define PARITY_ODD 1 +#define PARITY_EVEN 2 +/* 高低位顺序可取值 */ +#define BIT_ORDER_LSB 0 +#define BIT_ORDER_MSB 1 +/* 模式可取值 */ +#define NRZ_NORMAL 0 /* normal mode */ +#define NRZ_INVERTED 1 /* inverted mode */ + +#define RT_SERIAL_RX_MINBUFSZ 64 /* 限制接收缓冲区最小长度 */ +#define RT_SERIAL_TX_MINBUFSZ 64 /* 限制发送缓冲区最小长度 */ +``` + +RT-Thread 提供的默认串口配置如下,即 RT-Thread 系统中默认每个串口设备都使用如下配置: + +```c +/* Default config for serial_configure structure */ +#define RT_SERIAL_CONFIG_DEFAULT \ +{ \ + BAUD_RATE_115200, /* 115200 bits/s */ \ + DATA_BITS_8, /* 8 databits */ \ + STOP_BITS_1, /* 1 stopbit */ \ + PARITY_NONE, /* No parity */ \ + BIT_ORDER_LSB, /* LSB first sent */ \ + NRZ_NORMAL, /* Normal mode */ \ + RT_SERIAL_RX_MINBUFSZ, /* rxBuf size */ \ + RT_SERIAL_TX_MINBUFSZ, /* txBuf size */ \ + 0 \ +} +``` + +> [!NOTE] +> 注:虽然默认串口配置设置了 rx_bufsz 和 tx_bufsz 的大小,但是其缓冲区具体长度会在底层驱动初始化时再次配置,这里无需关心其值。 + +若实际使用串口的配置参数与默认配置参数不符,则用户可以通过应用代码进行修改。修改串口配置参数,如波特率、数据位、校验位、缓冲区接收 buffsize、停止位等的示例程序如下: + +```c +#define SAMPLE_UART_NAME "uart2" /* 串口设备名称 */ +static rt_device_t serial; /* 串口设备句柄 */ +struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; /* 初始化配置参数 */ + +/* step1:查找串口设备 */ +serial = rt_device_find(SAMPLE_UART_NAME); + +/* step2:修改串口配置参数 */ +config.baud_rate = BAUD_RATE_9600; // 修改波特率为 9600 +config.data_bits = DATA_BITS_8; // 数据位 8 +config.stop_bits = STOP_BITS_1; // 停止位 1 +config.rx_bufsz = 128; // 修改缓冲区 rx buff size 为 128 +config.parity = PARITY_NONE; // 无奇偶校验位 + +/* step3:控制串口设备。通过控制接口传入命令控制字,与控制参数 */ +rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config); + +/* step4:打开串口设备。以非阻塞接收和阻塞发送模式打开串口设备 */ +rt_device_open(serial, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING); +``` + +### 发送数据 + +向串口中写入数据,可以通过如下函数完成: + +```c +rt_size_t rt_device_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size); +``` + +| **参数** | **描述** | +| ---------- | ------------------------------------------ | +| dev | 设备句柄 | +| pos | 写入数据偏移量,此参数串口设备未使用 | +| buffer | 内存缓冲区指针,放置要写入的数据 | +| size | 写入数据的大小 | +| **返回** | —— | +| 写入数据的实际大小 | 如果是字符设备,返回大小以字节为单位; | +| 0 | 需要读取当前线程的 errno 来判断错误状态 | + +调用这个函数,会把缓冲区 buffer 中的数据写入到设备 dev 中,写入数据的大小是 size。 + +向串口写入数据示例程序如下所示: + +```c +#define SAMPLE_UART_NAME "uart2" /* 串口设备名称 */ +static rt_device_t serial; /* 串口设备句柄 */ +char str[] = "hello RT-Thread!\r\n"; +struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; /* 配置参数 */ +/* 查找串口设备 */ +serial = rt_device_find(SAMPLE_UART_NAME); + +/* 以非阻塞接收和阻塞发送模式打开串口设备 */ +rt_device_open(serial, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING); +/* 发送字符串 */ +rt_device_write(serial, 0, str, (sizeof(str) - 1)); +``` + +### 设置发送完成回调函数 + +在应用程序调用 `rt_device_write()` 写入数据时,如果底层硬件能够支持自动发送,那么上层应用可以设置一个回调函数。这个回调函数会在底层硬件数据发送完成后 (例如 DMA 传送完成或 FIFO 已经写入完毕产生完成中断时) 调用。可以通过如下函数设置设备发送完成指示 : + +```c +rt_err_t rt_device_set_tx_complete(rt_device_t dev, rt_err_t (*tx_done)(rt_device_t dev,void *buffer)); +``` + +| **参数** | **描述** | +| -------- | ------------ | +| dev | 设备句柄 | +| tx_done | 回调函数指针 | +| **返回** | —— | +| RT_EOK | 设置成功 | + +调用这个函数时,回调函数由调用者提供,当硬件设备发送完数据时,由设备驱动程序回调这个函数并把发送完成的数据块地址 buffer 作为参数传递给上层应用。上层应用(线程)在收到指示时会根据发送 buffer 的情况,释放 buffer 内存块或将其作为下一个写数据的缓存。 + +### 设置接收回调函数 + +可以通过如下函数来设置数据接收指示,当串口收到数据时,通知上层应用线程有数据到达 : + +```c +rt_err_t rt_device_set_rx_indicate(rt_device_t dev, rt_err_t (*rx_ind)(rt_device_t dev,rt_size_t size)); +``` + +| **参数** | **描述** | +| -------- | ------------ | +| dev | 设备句柄 | +| rx_ind | 回调函数指针 | +| dev | 设备句柄(回调函数参数)| +| size | 缓冲区数据大小(回调函数参数)| +| **返回** | —— | +| RT_EOK | 设置成功 | + +该函数的回调函数由调用者提供。若串口以中断接收模式打开,当串口接收到一个数据产生中断时,就会调用回调函数,并且会把此时缓冲区的数据大小放在 size 参数里,把串口设备句柄放在 dev 参数里供调用者获取。 + +若串口以 DMA 接收模式打开,当 DMA 完成一批数据的接收后会调用此回调函数。 + +一般情况下接收回调函数可以发送一个信号量或者事件通知串口数据处理线程有数据到达。使用示例如下所示: + +```c +#define SAMPLE_UART_NAME "uart2" /* 串口设备名称 */ +static rt_device_t serial; /* 串口设备句柄 */ +static struct rt_semaphore rx_sem; /* 用于接收消息的信号量 */ + +/* 接收数据回调函数 */ +static rt_err_t uart_input(rt_device_t dev, rt_size_t size) +{ + /* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */ + rt_sem_release(&rx_sem); + + return RT_EOK; +} + +static int uart_sample(int argc, char *argv[]) +{ + serial = rt_device_find(SAMPLE_UART_NAME); + + /* 以非阻塞接收和阻塞发送模式打开串口设备 */ + rt_device_open(serial, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING); + + /* 初始化信号量 */ + rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO); + + /* 设置接收回调函数 */ + rt_device_set_rx_indicate(serial, uart_input); +} + +``` + +### 接收数据 + +可调用如下函数读取串口接收到的数据: + +```c +rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size); +``` + +| **参数** | **描述** | +| ------------------ | ---------------------------------------------- | +| dev | 设备句柄 | +| pos | 读取数据偏移量,此参数串口设备未使用 | +| buffer | 缓冲区指针,读取的数据将会被保存在缓冲区中 | +| size | 读取数据的大小 | +| **返回** | —— | +| 读到数据的实际大小 | 如果是字符设备,返回大小以字节为单位 | +| 0 | 需要读取当前线程的 errno 来判断错误状态 | + +读取数据偏移量 pos 针对字符设备无效,此参数主要用于块设备中。 + +串口使用中断接收模式并配合接收回调函数的使用示例如下所示: + +```c +static rt_device_t serial; /* 串口设备句柄 */ +static struct rt_semaphore rx_sem; /* 用于接收消息的信号量 */ + +/* 接收数据的线程 */ +static void serial_thread_entry(void *parameter) +{ + char ch; + + while (1) + { + /* 从串口读取一个字节的数据,没有读取到则等待接收信号量 */ + while (rt_device_read(serial, -1, &ch, 1) != 1) + { + /* 阻塞等待接收信号量,等到信号量后再次读取数据 */ + rt_sem_take(&rx_sem, RT_WAITING_FOREVER); + } + /* 读取到的数据通过串口错位输出 */ + ch = ch + 1; + rt_device_write(serial, 0, &ch, 1); + } +} +``` + +### 关闭串口设备 + +当应用程序完成串口操作后,可以关闭串口设备,通过如下函数完成: + +```c +rt_err_t rt_device_close(rt_device_t dev); +``` + +| **参数** | **描述** | +| ---------- | ---------------------------------- | +| dev | 设备句柄 | +| **返回** | —— | +| RT_EOK | 关闭设备成功 | +| -RT_ERROR | 设备已经完全关闭,不能重复关闭设备 | +| 其他错误码 | 关闭设备失败 | + +关闭设备接口和打开设备接口需配对使用,打开一次设备对应要关闭一次设备,这样设备才会被完全关闭,否则设备仍处于未关闭状态。 + +## 新旧版本串口使用区别 + +* 使用 `rt_devide_open()` 的入参 `oflags` 区别: + + ```c + // 旧版本 oflags 的参数取值 + RT_DEVICE_FLAG_INT_RX + RT_DEVICE_FLAG_INT_TX + RT_DEVICE_FLAG_DMA_RX + RT_DEVICE_FLAG_DMA_TX + + // 新版本 oflags 的参数取值 + RT_DEVICE_FLAG_RX_NON_BLOCKING + RT_DEVICE_FLAG_RX_BLOCKING + RT_DEVICE_FLAG_TX_NON_BLOCKING + RT_DEVICE_FLAG_TX_BLOCKING + ``` + + **为了兼容旧版本的框架,使用新版本串口框架时旧版本的应用代码可直接使用,只需注意一点,旧版本的 oflags 参数不再起作用,默认使用新版本的操作模式: 接收非阻塞发送阻塞模式。** + +* 缓冲区宏定义区别 + + 旧版本接收缓冲区统一为 `RT_SERIAL_RB_BUFSZ` ,旧版本没有发送缓冲区的设置。 + + 新版本缓冲区进行了分离接收和发送,并且也可以对各个串口进行单独设置,例如: + + ```c + // 设置 串口 2 的发送缓冲区为 256 字节,接收缓冲区为 1024 字节,见 rtconfig.h + #define BSP_UART2_RX_BUFSIZE 256 + #define BSP_UART2_TX_BUFSIZE 1024 + ``` + + **当从新版本往旧版本进行迁移时,如果使用了`RT_SERIAL_RB_BUFSZ`,那么需要将本参数更改为对应的串口的具体的宏定义** + +* 串口配置 `serial_configure` 成员变量 `bufsz` 的区别: + + 旧版本的 `bufsz` 指代串口接收缓冲区的大小,新版本由于需要分别设置发送和接收缓冲区,因此成员变量调整为 `rx_bufsz` 和 `tx_bufsz`。 + + ```c + // 旧版本 + struct serial_configure + { + rt_uint32_t baud_rate; + + rt_uint32_t data_bits :4; + rt_uint32_t stop_bits :2; + rt_uint32_t parity :2; + rt_uint32_t bit_order :1; + rt_uint32_t invert :1; + rt_uint32_t bufsz :16; + rt_uint32_t reserved :6; + }; + + // 新版本 + struct serial_configure + { + rt_uint32_t baud_rate; + + rt_uint32_t data_bits :4; + rt_uint32_t stop_bits :2; + rt_uint32_t parity :2; + rt_uint32_t bit_order :1; + rt_uint32_t invert :1; + rt_uint32_t rx_bufsz :16; + rt_uint32_t tx_bufsz :16; + rt_uint32_t reserved :6; + }; + ``` + +## 串口设备使用示例 + +### 非阻塞接收和阻塞发送模式 + +当串口接收到一批数据后会调用接收回调函数,接收回调函数会把此时缓冲区的数据大小通过消息队列发送给等待的数据处理线程。线程获取到消息后被激活,并读取数据。 + +此例程以开启了 DMA 发送和接收模式为例,一般情况下 DMA 接收模式会结合 DMA 接收半完成中断、完成中断和串口空闲中断完成数据接收。 + +* 此示例代码不局限于特定的 BSP,根据 BSP 注册的串口设备,修改示例代码宏定义 SAMPLE_UART_NAME 对应的串口设备名称即可运行。 + +运行序列图如下图所示: + +![串口 DMA 接收及轮询发送序列图](figures/uart-dma.png) + +```c +/* + * 程序清单:这是一个串口设备 开启 DMA 模式后使用例程 + * 例程导出了 uart_dma_sample 命令到控制终端 + * 命令调用格式:uart_dma_sample uart1 + * 命令解释:命令第二个参数是要使用的串口设备名称,为空则使用默认的串口设备 + * 程序功能:通过串口输出字符串 "hello RT-Thread!",并通过串口输出接收到的数据,然后打印接收到的数据。 +*/ + +#include + +#define SAMPLE_UART_NAME "uart1" /* 串口设备名称 */ + +/* 串口接收消息结构 */ +struct rx_msg +{ + rt_device_t dev; + rt_size_t size; +}; +/* 串口设备句柄 */ +static rt_device_t serial; +/* 消息队列控制块 */ +static struct rt_messagequeue rx_mq; + +/* 接收数据回调函数 */ +static rt_err_t uart_input(rt_device_t dev, rt_size_t size) +{ + struct rx_msg msg; + rt_err_t result; + msg.dev = dev; + msg.size = size; + + result = rt_mq_send(&rx_mq, &msg, sizeof(msg)); + if (result == -RT_EFULL) + { + /* 消息队列满 */ + rt_kprintf("message queue full!\n"); + } + return result; +} + +static void serial_thread_entry(void *parameter) +{ + struct rx_msg msg; + rt_err_t result; + rt_uint32_t rx_length; + static char rx_buffer[BSP_UART1_RX_BUFSIZE + 1]; + + while (1) + { + rt_memset(&msg, 0, sizeof(msg)); + /* 从消息队列中读取消息 */ + result = rt_mq_recv(&rx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER); + if (result == RT_EOK) + { + /* 从串口读取数据 */ + rx_length = rt_device_read(msg.dev, 0, rx_buffer, msg.size); + rx_buffer[rx_length] = '\0'; + /* 通过串口设备 serial 输出读取到的消息 */ + rt_device_write(serial, 0, rx_buffer, rx_length); + /* 打印数据 */ + rt_kprintf("%s\n",rx_buffer); + } + } +} + +static int uart_dma_sample(int argc, char *argv[]) +{ + rt_err_t ret = RT_EOK; + char uart_name[RT_NAME_MAX]; + static char msg_pool[256]; + char str[] = "hello RT-Thread!\r\n"; + + if (argc == 2) + { + rt_strncpy(uart_name, argv[1], RT_NAME_MAX); + } + else + { + rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX); + } + + /* 查找串口设备 */ + serial = rt_device_find(uart_name); + if (!serial) + { + rt_kprintf("find %s failed!\n", uart_name); + return RT_ERROR; + } + + /* 初始化消息队列 */ + rt_mq_init(&rx_mq, "rx_mq", + msg_pool, /* 存放消息的缓冲区 */ + sizeof(struct rx_msg), /* 一条消息的最大长度 */ + sizeof(msg_pool), /* 存放消息的缓冲区大小 */ + RT_IPC_FLAG_FIFO); /* 如果有多个线程等待,按照先来先得到的方法分配消息 */ + + /* 以 DMA 接收及轮询发送方式打开串口设备 */ + rt_device_open(serial, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING); + /* 设置接收回调函数 */ + rt_device_set_rx_indicate(serial, uart_input); + /* 发送字符串 */ + rt_device_write(serial, 0, str, (sizeof(str) - 1)); + + /* 创建 serial 线程 */ + rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10); + /* 创建成功则启动线程 */ + if (thread != RT_NULL) + { + rt_thread_startup(thread); + } + else + { + ret = RT_ERROR; + } + + return ret; +} +/* 导出到 msh 命令列表中 */ +MSH_CMD_EXPORT(uart_dma_sample, uart device dma sample); +```