这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
cc2640r2f:uart [2017/09/09 12:57] wuyl |
cc2640r2f:uart [2021/06/22 23:14] (当前版本) |
||
---|---|---|---|
行 7: | 行 7: | ||
## 概述 ## | ## 概述 ## | ||
- | UART 用于芯片和串行端口之间的数据传输。UART 驱动程序经过多层的封装简化了应用程序对 UART 外设的读写操作,应用程序开发者只需要调用封装好的驱动接口就可以操作串口进行读写了。当然 UART 也有多种操作模式,例如:阻塞、非阻塞、轮询以及文本/ | + | UART 用于芯片和串行端口之间的数据传输。UART 驱动程序经过多层的封装简化了应用程序对 UART 外设的读写操作,应用程序开发者只需要调用封装好的驱动接口就可以操作串口进行读写了。 |
+ | |||
+ | 当然 UART 也有多种操作模式,例如:阻塞、非阻塞、轮询以及文本/ | ||
## UART 驱动的分层实现 ## | ## UART 驱动的分层实现 ## | ||
行 13: | 行 15: | ||
虽然在应用层直接调用几个驱动接口就可操作 UART 进行读写,但是在驱动程序内部从接口函数到底层硬件操作是通过了多层封装的。如图 1 所示是 UART 驱动程序的分层实现图。 | 虽然在应用层直接调用几个驱动接口就可操作 UART 进行读写,但是在驱动程序内部从接口函数到底层硬件操作是通过了多层封装的。如图 1 所示是 UART 驱动程序的分层实现图。 | ||
- | 图1 UART 驱动程序的分层实现 | + | 图1. UART 驱动程序的分层实现 |
![](http:// | ![](http:// | ||
- | 图 1 可以看出应用程序开发者只需要直接调用中间件层的驱动接口(例如:UART_init、UART_open 等等)就可以实现 UART 驱动功能。这里的中间件层就是程序中的 UART.c 和 UART.h 所在层。这一层规范统一了应用程序的调用接口,对于 TI 不同类型的芯片平台它们在这一层给出的接口都是一样的,应用层都是调用相同的接口来实现 UART 功能。这样做的好处是增强了程序的可移植性,不管你的平台怎么换,应用程序都是不变的。 | + | 图 1 可以看出应用程序开发者只需要直接调用中间件层的驱动接口(例如:UART_init、UART_open 等等)就可以实现 UART 驱动功能。这里的中间件层就是程序中的 UART.c 和 UART.h 所在层。 |
+ | |||
+ | 中间件层规范统一了应用程序的调用接口,对于 TI 不同类型的芯片平台它们在这一层给出的接口都是一样的,应用层都是调用相同的接口来实现 UART 功能。这样做的好处是增强了程序的可移植性,不管你的平台怎么换,应用程序都是不变的。 | ||
中间件层往下就是业务逻辑层,从业务逻辑层开始往下根据不同的芯片平台其接口封装实现就不尽相同了。以 CC26XX 芯片平台为例,业务逻辑层就位于 UARTCC26XX.c 和 UARTCC26XX.h 所在的层。这一层主要是调用下一层驱动库中的函数进行一些逻辑操作、实现相应驱动功能接口的封装。需要注意的是这一层封装的驱动接口函数被全部放在一个函数指针结构体中。 | 中间件层往下就是业务逻辑层,从业务逻辑层开始往下根据不同的芯片平台其接口封装实现就不尽相同了。以 CC26XX 芯片平台为例,业务逻辑层就位于 UARTCC26XX.c 和 UARTCC26XX.h 所在的层。这一层主要是调用下一层驱动库中的函数进行一些逻辑操作、实现相应驱动功能接口的封装。需要注意的是这一层封装的驱动接口函数被全部放在一个函数指针结构体中。 | ||
+ | |||
如清单 1 所示,中间件层不直接调用这些驱动接口,而是通过一个配置文件( CC2640R2_LAUNCHXL.c )将装有驱动接口指针的结构体指针注册到 UART_config 中。 | 如清单 1 所示,中间件层不直接调用这些驱动接口,而是通过一个配置文件( CC2640R2_LAUNCHXL.c )将装有驱动接口指针的结构体指针注册到 UART_config 中。 | ||
+ | |||
如清单 2 所示,这样中间件层通过调用 UART_config 中的结构体指针就可以调用业务逻辑层的驱动接口了。 | 如清单 2 所示,这样中间件层通过调用 UART_config 中的结构体指针就可以调用业务逻辑层的驱动接口了。 | ||
行 101: | 行 107: | ||
`.object` 是存放 UART 的各种参数数据。例如控制参数、读写参数等。 | `.object` 是存放 UART 的各种参数数据。例如控制参数、读写参数等。 | ||
* ** .hwAttrs ** | * ** .hwAttrs ** | ||
- | `.hwAttrs `是存放 UART 硬件配置参数的数组。如清单 3 所示,这些硬件参数是需要在使用 UART 之前配置好的。 | + | `.hwAttrs ` 是存放 UART 硬件配置参数的数组。如清单 3 所示,这些硬件参数是需要在使用 UART 之前配置好的。 |
## UART 驱动接口函数 ## | ## UART 驱动接口函数 ## | ||
- | 在应用程序层实现UART功能的时候能够调用中间件层的接口函数有11个。其功能,形参以及返回值如下表所示 | + | 在应用程序层实现 UART 功能的时候能够调用中间件层的接口函数有 11 个。其功能、形参以及返回值如下所示 |
1. `void UART_init(void)` | 1. `void UART_init(void)` | ||
+ | |||
* 函数功能:根据配置信息对UART模块进行初始化 | * 函数功能:根据配置信息对UART模块进行初始化 | ||
* 形参:无 | * 形参:无 | ||
* 返回值:无 | * 返回值:无 | ||
- | * 注意事项:在调用此函数之前,UART_config参数必须配置完成,在调用该函数之后才能调用其他UART接口函数 | + | * 注意事项:在调用此函数之前,UART_config 参数必须配置完成,在调用该函数之后才能调用其他 UART 接口函数 |
2. `void UART_Params_init(UART_Params *params)` | 2. `void UART_Params_init(UART_Params *params)` | ||
- | * 函数功能:将UART_Params结构体中的参数初始化为默认值 | + | |
- | * 形参:`params`,UART_Params类型的结构体指针,存放UART的相关参数 | + | * 函数功能:将 UART_Params 结构体中的参数初始化为默认值 |
+ | * 形参: `params` | ||
* 返回值:无 | * 返回值:无 | ||
- | * 注意事项:该函数将UART_Params结构体中的参数全部初始化为默认值,在接下来的程序中你可以根据具体应用的需要修改这些参数值 | + | * 注意事项:该函数将 UART_Params 结构体中的参数全部初始化为默认值,在接下来的程序中你可以根据具体应用的需要修改这些参数值 |
3. `UART_Handle UART_open(uint_least8_t index, UART_Params *params)` | 3. `UART_Handle UART_open(uint_least8_t index, UART_Params *params)` | ||
- | * 函数功能:初始化并打开指定的UART外设接口 | + | |
- | * 形参:`index`UART外设接口的索引;`params`UART_Params类型的结构体指针,存放UART的相关参数 | + | * 函数功能:初始化并打开指定的 UART 外设接口 |
- | * 返回值:`UART_Handle`如果成功打开UART外设接口就返回该接口配置数组(UART_config)的句柄,如果发生错误或者需要打开的UART外设接口已经被打开,则会返回NULL指针 | + | * 形参:`index` UART 外设接口的索引;`params` UART_Params 类型的结构体指针,存放 UART 的相关参数 |
+ | * 返回值:`UART_Handle` 如果成功打开UART 外设接口就返回该接口配置数组(UART_config)的句柄,如果发生错误或需要打开的 UART 外设接口已经被打开,则会返回 NULL 指针 | ||
4. `int_fast16_t UART_control(UART_Handle handle, uint_fast16_t cmd, void *arg)` | 4. `int_fast16_t UART_control(UART_Handle handle, uint_fast16_t cmd, void *arg)` | ||
- | * 函数功能:通过给定的UART_Handle来处理相应的命令事务 | + | |
- | * 形参:`handle`UART_open中返回的句柄;`cmd`需要处理的命令事务;`arg`不用命令事务可能需要的不同类型的参数指针 | + | * 函数功能:通过给定的 UART_Handle 来处理相应的命令事务 |
- | * 返回值:处理特定命令返回的值,如果操作失败,会返回一个负值 | + | * 形参:`handle` UART_open 中返回的句柄;`cmd` 需要处理的命令事务;`arg` 不用命令事务可能需要的不同类型的参数指针 |
- | * 注意事项:必须在UART_open调用之后才能调用此函数 | + | * 返回值:处理特定命令返回的值。如果操作失败,会返回一个负值 |
+ | * 注意事项:必须在 UART_open 调用之后才能调用此函数 | ||
5. `void UART_close(UART_Handle handle)` | 5. `void UART_close(UART_Handle handle)` | ||
- | * 函数功能:关闭UART_Handle指定的UART外设接口 | + | |
- | * 形参:`handle`从UART_open()中返回的UART外设接口配置数组的句柄,以此来关闭外设接口 | + | * 函数功能:关闭 UART_Handle 指定的 UART 外设接口 |
+ | * 形参:`handle` 从 UART_open() 中返回的 UART 外设接口配置数组的句柄,以此来关闭外设接口 | ||
* 返回值:无 | * 返回值:无 | ||
- | * 注意事项:必须在UART_open()调用之后才能调用此函数,在调用该函数之前必须先调用UART_readCancel()或UART_writeCancel()分别取消正在进行的异步读取或写入 | + | * 注意事项:必须在 UART_open() 调用之后才能调用此函数,在调用该函数之前必须先调用 UART_readCancel() 或 UART_writeCancel() |
6. `int_fast32_t UART_write(UART_Handle handle, const void *buffer, size_t size)` | 6. `int_fast32_t UART_write(UART_Handle handle, const void *buffer, size_t size)` | ||
+ | |||
* 函数功能:通过使能中断来向串口写入数据 | * 函数功能:通过使能中断来向串口写入数据 | ||
- | * 形参:`handle`UART_open中返回的句柄;`buffer`一个只读指针,其中包含了将要写入的数据;`size`需要写入数据的字节数 | + | * 形参:`handle`UART_open 中返回的句柄;`buffer` 一个只读指针,其中包含了将要写入的数据;`size` 需要写入数据的字节数 |
- | * 返回值:返回已经写入串口的字节数,如果发生错误,则返回UART_ERROR. | + | * 返回值:返回已经写入串口的字节数,如果发生错误,则返回 UART_ERROR |
- | * 注意事项:在UART_MODE_CALLBACK下返回值始终为0 | + | * 注意事项:在 UART_MODE_CALLBACK 下返回值始终为 0 |
7. `int_fast32_t UART_writePolling(UART_Handle handle, const void *buffer, size_t size)` | 7. `int_fast32_t UART_writePolling(UART_Handle handle, const void *buffer, size_t size)` | ||
- | * 函数功能:利用轮询的方式写入数据,不使能中断,与UART_write()的使用是互斥的。 | + | |
- | * 形参:`handle`从UART_open()中返回的UART外设接口配置数组的句柄; | + | * 函数功能:利用轮询的方式写入数据,不使能中断。与 UART_write() 的使用是互斥的 |
- | * 返回值:返回已经写入UART外设接口的字节数,如果发生错误,则返回UART_ERROR. | + | * 形参:`handle` 从 UART_open() 中返回的 UART 外设接口配置数组的句柄; |
- | * 注意事项:在所有的数据都被写入UART外设接口之前,该函数不会返回值 | + | * 返回值:返回已经写入 UART 外设接口的字节数。如果发生错误,则返回 UART_ERROR |
+ | * 注意事项:在所有的数据都被写入 UART 外设接口之前,该函数不会返回值 | ||
8. `void UART_writeCancel(UART_Handle handle)` | 8. `void UART_writeCancel(UART_Handle handle)` | ||
- | * 函数功能:取消UART_write()函数调用的功能 | + | |
- | * 形参:`handle`从UART_open()中返回的UART外设接口配置数组的句柄 | + | * 函数功能:取消 UART_write() 函数调用的功能 |
+ | * 形参:`handle` 从 UART_open() 中返回的 UART 外设接口配置数组的句柄 | ||
* 返回值:无 | * 返回值:无 | ||
- | * 注意事项:在函数只适用于在UART_MODE_CALLBACK模式下取消异步UART_write()操作。 | + | * 注意事项:函数只适用于在 UART_MODE_CALLBACK 模式下取消异步 UART_write() 操作。 |
9. `int_fast32_t UART_read(UART_Handle handle, void *buffer, size_t size)` | 9. `int_fast32_t UART_read(UART_Handle handle, void *buffer, size_t size)` | ||
- | * 函数功能:通过使能中断来读取UART外设接口的数据 | + | |
- | * 形参:`handle`从UART_open()中返回的UART外设接口配置数组的句柄; | + | * 函数功能:通过使能中断来读取 UART 外设接口的数据 |
- | * 返回值:返回从UART外设接口读取的字节数,如果发生错误则返回UART_ERROR | + | * 形参:`handle` 从 UART_open() 中返回的UART外设接口配置数组的句柄; |
- | * 注意事项:在**UART_MODE_BLOCKING**模式下,UART_read()会阻止任务的执行,直到缓冲区的数据被读完。在 | + | * 返回值:返回从 UART 外设接口读取的字节数。如果发生错误则返回 UART_ERROR |
+ | * 注意事项:在** UART_MODE_BLOCKING **模式下,UART_read() 会阻止任务的执行,直到缓冲区的数据被读完。在 | ||
10. `int_fast32_t UART_readPolling(UART_Handle handle, void *buffer, size_t size)` | 10. `int_fast32_t UART_readPolling(UART_Handle handle, void *buffer, size_t size)` | ||
- | * 函数功能:使用轮询的方式读取数据,不使能中断,与UART_write()的使用是互斥的 | + | |
- | * 形参:`handle`从UART_open()中返回的UART外设接口配置数组的句柄; | + | * 函数功能:使用轮询的方式读取数据,不使能中断,与 UART_write() 的使用是互斥的 |
- | * 返回值:返回从UART外设接口读取的字节数,如果发生错误则返回UART_ERROR | + | * 形参:`handle` 从 UART_open() 中返回的 UART 外设接口配置数组的句柄; |
- | * 注意事项:在指定的数据被读取完之前,UART_readPolling不会返回 | + | * 返回值:返回从 UART 外设接口读取的字节数。如果发生错误则返回 UART_ERROR |
+ | * 注意事项:在指定的数据被读取完之前,UART_readPolling 不会返回。 | ||
11. `void UART_readCancel(UART_Handle handle)` | 11. `void UART_readCancel(UART_Handle handle)` | ||
- | * 函数功能:取消UART_read()函数的功能 | + | |
- | * 形参:`handle`从UART_open()中返回的UART外设接口配置数组的句柄 | + | * 函数功能:取消 UART_read() 函数的功能 |
+ | * 形参:`handle` 从 UART_open() 中返回的 UART 外设接口配置数组的句柄 | ||
* 返回值:无 | * 返回值:无 | ||
- | * 注意事项:仅适用于在UART_MODE_CALLBACK模式下取消异步UART_read()函数的功能 | + | * 注意事项:仅适用于在 UART_MODE_CALLBACK 模式下取消异步 UART_read() 函数的功能。 |
+ | |||
+ | ## 利用 UART 串口实现数据的打印 ## | ||
+ | |||
+ | 接下来调用中间件层提供的 UART 接口建立一个独立的线程,实现 “hello world!” 的串口打印。这里直接给出主线程的接口调用例程,如清单4所示: | ||
+ | |||
+ | 清单4:UART 外设接口打印主线程代码实现 | ||
- | ## 利用UART串口实现数据的打印 ## | ||
- | 下面我们调用中间件层提供的UART接口来建立一个独立的线程,实现“hello world!”的串口打印。这里我们直接给出主线程的接口调用例程,如List4所示: | ||
- | List4:UART外设接口打印主线程代码实现 | ||
```C | ```C | ||
/* | /* | ||
行 222: | 行 243: | ||
} | } | ||
``` | ``` | ||
- | 1. 我们可以看到在**mainThread**中首先调用`UART_init()`来初始化UART外设接口配置,这里的配置信息是在配置文件CC2640R2_LAUNCHXL.c中设置的,上文**UART的驱动配置**中有讲到,所以在我们调用`UART_init()`之前,必须要在CC2640R2_LAUNCHXL.c中完成所有的配置。 | ||
- | 2. 调用`UART_Params_init()`将uartParams结构体中的参数全部初始化为默认值。 | ||
- | 3. 初始化UART_Params参数后,根据需要我们可以对一些参数进行重新赋值。 | ||
- | 4. 在UART外设接口参数设置完成之后,我们就可以调用UART_open()来开启我们指定的UART外设接口了,这里我们需要指定某个定义的UART外设接口,在我们的例程中是打开的**Board_UART0**,如果指定UART外设接口打开成功,则会返回一个句柄,以后我们就通过这个句柄来执行UART外设接口的相关操作了。如果UART外设接口打开失败或者指定的UART外设接口已经被打开使用则会返回一个空指针。 | ||
- | 5. 成功打开UART外设接口之后我们就可以操作UART外设接口读写数据了,这里我们首先调用`UART_write()`将字符串`hello world!`打印出来。然后进入无限循环一直执行接收串口数据,又将串口数据打印出来的操作。 | ||
- | 下面我们看一下如何编译,利用串口工具调试串口功能: | + | 1. 可以看到,在** mainThread **中首先调用 `UART_init()` 来初始化 UART 外设接口配置,配置信息是在配置文件 CC2640R2_LAUNCHXL.c 中设置的。上文** UART 的驱动配置**中有讲到,在调用 `UART_init()` 之前,必须要在 CC2640R2_LAUNCHXL.c 中完成所有的配置。 |
- | 1. 新建一个`.c`文件,将该段代码拷贝到`.c`文件中,这里我们给该`.c`文件命名为`uartdebug.c`。 | + | 2. 调用 `UART_Params_init()` 将 uartParams 结构体中的参数全部初始化为默认值。 |
- | 2. 将`uartdebug.c`文件保存在`C: | + | 3. 初始化 UART_Params 参数后,根据需要对一些参数进行重新赋值。 |
- | 3. 在`C: | + | 4. 在 UART 外设接口参数设置完成之后,就可以调用 UART_open() 开启指定的 UART 外设接口。这里需要指定某个定义的 UART 外设接口,在例程中打开的是** Board_UART0 **。如果指定 UART 外设接口打开成功,则会返回一个句柄,以后通过这个句柄就可以执行 UART 外设接口的相关操作。如果 UART 外设接口打开失败或者指定的 UART 外设接口已经被打开使用则会返回一个空指针。 |
+ | 5. 成功打开 UART 外设接口之后就能用 UART 外设接口读写数据了。首先调用 `UART_write()` 将字符串 `hello world!` 打印出来,然后进入无限循环一直执行接收串口数据,再将串口数据打印出来的操作。 | ||
+ | |||
+ | 下面看一下如何编译,先利用串口工具调试串口功能: | ||
+ | |||
+ | 1. 新建一个 `.c` 文件,将该段代码拷贝到 `.c` 文件中,假设给该 `.c` 文件命名为 `uartdebug.c` 。 | ||
+ | 2. 将 `uartdebug.c` 文件保存在 `C: | ||
+ | 3. 在 `C: | ||
+ | |||
+ | 图2. IAR 工程目录 | ||
![](http:// | ![](http:// | ||
- | 4. 选中`uartcho.c`文件,点击右键,选择**remove**,这时你可以看到`uartcho.c`文件被移出工程。 | + | 4. 选中 `uartcho.c` 文件,点击右键,选择** remove **。此时可以看到 `uartcho.c` 文件被移出工程。 |
- | 5. 在工程目录下选中`source files`文件夹,选择**Add**条目下的**Add Files...**,然后将我们存放的`uartdebug.c`添加进工程项目, | + | 5. 在工程目录下选中 `source files` 文件夹,选择** Add **条目下的** Add Files... **,然后将存放的 `uartdebug.c` 添加进工程项目如图 3 。 |
+ | |||
+ | 图3. IAR 添加文件 | ||
![](http:// | ![](http:// | ||
- | 6. 选中工程文件`uartecho-Debug`点击右键,选择`Rebuild All`编译工程。 | + | 6. 选中工程文件 `uartecho-Debug` 点击右键,选择 `Rebuild All` 编译工程。 |
- | 7. 保证已经下载了蓝牙协议栈镜像文件的调试板接入电脑,点击“编译调试”按钮,如图4所示,将程序下载到调试板中。 | + | 7. 保证调试板接入电脑,点击“编译调试”按钮,如图 4 所示将程序下载到调试板中。 |
+ | |||
+ | 图4. 调试板程序下载 | ||
![](http:// | ![](http:// | ||
- | 8. 打开串口调试工具,接入相应串口,点击运行按钮,如图4所示。 | + | |
+ | 8. 打开串口调试工具,接入相应串口,点击运行按钮,如图 | ||
+ | |||
+ | 图5. 串口调试工具调试环境 | ||
![](http:// | ![](http:// | ||
- | 9. 在串口调试界面,可以看到`hello world!`被打印出来,如图5所示。 | + | |
+ | 9. 在串口调试界面,可以看到 `hello world!` 被打印出来,如图 | ||
+ | |||
+ | 图6. 串口调试工具打印效果 | ||
![](http:// | ![](http:// | ||
- | 10. 利用串口调试工具向串口发送字符串`test`,如图6所示。 | + | |
+ | 10. 利用串口调试工具向串口发送字符串 `test` | ||
+ | |||
+ | 图7. 串口调试工具发送字符 | ||
![](http:// | ![](http:// | ||
- | 11. 我们在程序最后的无限循环里不断在读取串口数据,并将其打印出来,上一步发送了`test`之后,字符串就会被读取然后在串口调试工具中打印出来,如图7所示。 | + | |
+ | 11. 在程序最后的无限循环里不断在读取串口数据,并将其打印出来。上一步发送了 `test` 之后,字符串就会被读取然后在串口调试工具中打印出来,如图 | ||
+ | |||
+ | 图8. 串口调试工具不断读取打印字符 | ||
![](http:// | ![](http:// | ||
- | 12. 至此,我们就利用串口进行了数据的收发 | + | |
+ | 12. 至此,利用串口进行数据的收发就完成了。 | ||
## 加入我们 ## | ## 加入我们 ## | ||
+ | |||
文章所有代码、工具、文档开源。加入我们[**QQ群 591679055**](http:// | 文章所有代码、工具、文档开源。加入我们[**QQ群 591679055**](http:// | ||
<div> | <div> |