14、nRF52xx蓝牙学习(串口 UART 和 UARTE 外设应用)







#define APP_UART_FIFO_INIT(P_COMM_PARAMS, RX_BUF_SIZE, TX_BUF_SIZE, EVT_HANDLER, IRQ_PRIO, ERR_CODE) \do \{ \app_uart_buffers_t buffers; \static uint8_t rx_buf[RX_BUF_SIZE]; \static uint8_t tx_buf[TX_BUF_SIZE]; \\buffers.rx_buf = rx_buf; \buffers.rx_buf_size = sizeof (rx_buf); \buffers.tx_buf = tx_buf; \buffers.tx_buf_size = sizeof (tx_buf); \ERR_CODE = app_uart_init(P_COMM_PARAMS, &buffers, EVT_HANDLER, IRQ_PRIO); \} while (0)
代码理解:
代码概述 此代码定义了一个名为 APP_UART_FIFO_INIT 的宏,其用途是初始化一个基于 FIFO(先进先出)机制的 UART(通用异步收发传输器)通信。借助这个宏,你能够轻松地设置 UART 通信所需的参数,包含接收缓冲区、发送缓冲区、事件处理函数以及中断优先级等。
宏定义参数
• P_COMM_PARAMS:指向 UART 通信参数结构体的指针,该结构体里包含了波特率、数据位、停止位等 UART 通信所需的基本参数。
结构体定义如下 :
typedef struct
{uint32_t rx_pin_no; /**< RX pin number. */uint32_t tx_pin_no; /**< TX pin number. */uint32_t rts_pin_no; /**< RTS pin number, only used if flow control is enabled. */uint32_t cts_pin_no; /**< CTS pin number, only used if flow control is enabled. */app_uart_flow_control_t flow_control; /**< Flow control setting, if flow control is used, the system will use low power UART mode, based on CTS signal. */bool use_parity; /**< Even parity if TRUE, no parity if FALSE. */uint32_t baud_rate; /**< Baud rate configuration. */
} app_uart_comm_params_t;
结构体解析:用于配置 UART(通用异步收发传输器)通信参数。下面解释结构体中每个成员的作用:
// 定义一个名为 app_uart_comm_params_t 的结构体,用于配置 UART 通信参数
typedef struct
{// RX 引脚编号,用于接收数据uint32_t rx_pin_no; /**< RX pin number. */// TX 引脚编号,用于发送数据uint32_t tx_pin_no; /**< TX pin number. */// RTS(请求发送)引脚编号,仅在启用流控制时使用uint32_t rts_pin_no; /**< RTS pin number, only used if flow control is enabled. */// CTS(清除发送)引脚编号,仅在启用流控制时使用uint32_t cts_pin_no; /**< CTS pin number, only used if flow control is enabled. */// 流控制设置,如果使用流控制,系统将基于 CTS 信号使用低功耗 UART 模式app_uart_flow_control_t flow_control; /**< Flow control setting, if flow control is used, the system will use low power UART mode, based on CTS signal. */// 是否使用奇偶校验,TRUE 表示使用偶校验,FALSE 表示不使用奇偶校验bool use_parity; /**< Even parity if TRUE, no parity if FALSE. */// 波特率配置,用于设置数据传输的速率uint32_t baud_rate; /**< Baud rate configuration. */
} app_uart_comm_params_t;
其中:app_uart_flow_control_t(控制流)是一个枚举类型,其定义如下:
typedef enum
{
APP_UART_FLOW_CONTROL_DISABLED, /**< UART Hw Flow Control is disabled. */
APP_UART_FLOW_CONTROL_ENABLED, /**< Standard UART Hw Flow Control is enabled. */
} app_uart_flow_control_t;
// 定义 app_uart_flow_control_t 枚举类型,用于表示 UART 硬件流控制状态
typedef enum
{
// UART 硬件流控制禁用
APP_UART_FLOW_CONTROL_DISABLED, /**< UART Hw Flow Control is disabled. */
// 标准 UART 硬件流控制启用
APP_UART_FLOW_CONTROL_ENABLED, /**< Standard UART Hw Flow Control is enabled. */
} app_uart_flow_control_t;
再回到开始的宏参数:
• RX_BUF_SIZE:接收缓冲区的大小,也就是用于存储从 UART 接收到的数据的缓冲区大小。 • TX_BUF_SIZE:发送缓冲区的大小,即用于存储要通过 UART 发送出去的数据的缓冲区大小。 • EVT_HANDLER:UART 事件处理函数的指针,当 UART 发生特定事件(像数据接收、发送完成等)时,会调用这个函数。
• IRQ_PRIO:UART 中断的优先级,用于设置 UART 中断在系统中的优先级。
• ERR_CODE:用于存储 UART 初始化的错误码,若初始化成功,该变量会被赋值为 0;若失败,则会被赋值为相应的错误码。
代码详细解析
#define APP_UART_FIFO_INIT(P_COMM_PARAMS, RX_BUF_SIZE, TX_BUF_SIZE, EVT_HANDLER, IRQ_PRIO, ERR_CODE) \
do \
{ \
app_uart_buffers_t buffers; \
static uint8_t rx_buf[RX_BUF_SIZE]; \
static uint8_t tx_buf[TX_BUF_SIZE]; \
\
buffers.rx_buf = rx_buf; \
buffers.rx_buf_size = sizeof (rx_buf); \
buffers.tx_buf = tx_buf; \
buffers.tx_buf_size = sizeof (tx_buf); \
ERR_CODE = app_uart_init(P_COMM_PARAMS, &buffers, EVT_HANDLER, IRQ_PRIO); \
} while (0)
1. 定义缓冲区和变量:
app_uart_buffers_t buffers;:定义一个 app_uart_buffers_t 类型的结构体变量 buffers,该结构体用于存储接收和发送缓冲区的信息。
app_uart_buffers_t 类型的结构体定义如下 :
typedef struct
{
uint8_t * rx_buf; /**< Pointer to the RX buffer. */
uint32_t rx_buf_size; /**< Size of the RX buffer. */
uint8_t * tx_buf; /**< Pointer to the TX buffer. */
uint32_t tx_buf_size; /**< Size of the TX buffer. */
} app_uart_buffers_t;
static uint8_t rx_buf[RX_BUF_SIZE];:定义一个静态的接收缓冲区数组 rx_buf,其大小由 RX_BUF_SIZE 决定。
static uint8_t tx_buf[TX_BUF_SIZE];:定义一个静态的发送缓冲区数组 tx_buf,其大小由 TX_BUF_SIZE 决定。
2. 初始化缓冲区信息:
buffers.rx_buf = rx_buf;:把 rx_buf 数组的地址赋值给 buffers 结构体的 rx_buf 成员。
buffers.rx_buf_size = sizeof (rx_buf);:把 rx_buf 数组的大小赋值给 buffers 结构体的 rx_buf_size 成员。
buffers.tx_buf = tx_buf;:把 tx_buf 数组的地址赋值给 buffers 结构体的 tx_buf 成员。
buffers.tx_buf_size = sizeof (tx_buf);:把 tx_buf 数组的大小赋值给 buffers 结构体的 tx_buf_size 成员。
3 调用 UART 初始化函数:
ERR_CODE = app_uart_init(P_COMM_PARAMS, &buffers, EVT_HANDLER, IRQ_PRIO);:调用 app_uart_init 函数来初始化 UART 通信,将初始化的错误码存储在 ERR_CODE 变量中。
下面是一个简单的使用示例:
#include <stdio.h>
// 假设的 UART 通信参数结构体
typedef struct {
int baud_rate;
// 其他参数...
} app_uart_comm_params_t;
// 假设的 UART 缓冲区结构体
typedef struct {
uint8_t *rx_buf;
size_t rx_buf_size;
uint8_t *tx_buf;
size_t tx_buf_size;
} app_uart_buffers_t;
// 假设的 UART 初始化函数
int app_uart_init(app_uart_comm_params_t *p_comm_params, app_uart_buffers_t *p_buffers, void (*evt_handler)(void), int irq_prio) {
// 实际的初始化代码
return 0; // 假设初始化成功
}
// 假设的 UART 事件处理函数
void uart_evt_handler(void) {
// 处理 UART 事件
}
// 定义宏
#define APP_UART_FIFO_INIT(P_COMM_PARAMS, RX_BUF_SIZE, TX_BUF_SIZE, EVT_HANDLER, IRQ_PRIO, ERR_CODE) \
do \
{ \
app_uart_buffers_t buffers; \
static uint8_t rx_buf[RX_BUF_SIZE]; \
static uint8_t tx_buf[TX_BUF_SIZE]; \
\
buffers.rx_buf = rx_buf; \
buffers.rx_buf_size = sizeof (rx_buf); \
buffers.tx_buf = tx_buf; \
buffers.tx_buf_size = sizeof (tx_buf); \
ERR_CODE = app_uart_init(P_COMM_PARAMS, &buffers, EVT_HANDLER, IRQ_PRIO); \
} while (0)
int main() {
app_uart_comm_params_t comm_params = {115200}; // 波特率设置为 115200
int err_code;
APP_UART_FIFO_INIT(&comm_params, 256, 256, uart_evt_handler, 1, err_code);
if (err_code == 0) {
printf("UART initialization successful.\n");
} else {
printf("UART initialization failed with error code: %d\n", err_code);
}
return 0;
}
在这个示例中,我们定义了一个简单的 UART 通信系统,并且使用 APP_UART_FIFO_INIT 宏来初始化 UART 通信。若初始化成功,会输出相应的提示信息;若失败,则会输出错误码。
(2)app_uart_init函数学习
uint32_t app_uart_init(const app_uart_comm_params_t * p_comm_params,app_uart_buffers_t * p_buffers,app_uart_event_handler_t event_handler,app_irq_priority_t irq_priority)
{uint32_t err_code;m_event_handler = event_handler;if (p_buffers == NULL){return NRF_ERROR_INVALID_PARAM;}// Configure buffer RX buffer.err_code = app_fifo_init(&m_rx_fifo, p_buffers->rx_buf, p_buffers->rx_buf_size);VERIFY_SUCCESS(err_code);// Configure buffer TX buffer.err_code = app_fifo_init(&m_tx_fifo, p_buffers->tx_buf, p_buffers->tx_buf_size);VERIFY_SUCCESS(err_code);nrf_drv_uart_config_t config = NRF_DRV_UART_DEFAULT_CONFIG;config.baudrate = (nrf_uart_baudrate_t)p_comm_params->baud_rate;config.hwfc = (p_comm_params->flow_control == APP_UART_FLOW_CONTROL_DISABLED) ?NRF_UART_HWFC_DISABLED : NRF_UART_HWFC_ENABLED;config.interrupt_priority = irq_priority;config.parity = p_comm_params->use_parity ? NRF_UART_PARITY_INCLUDED : NRF_UART_PARITY_EXCLUDED;config.pselcts = p_comm_params->cts_pin_no;config.pselrts = p_comm_params->rts_pin_no;config.pselrxd = p_comm_params->rx_pin_no;config.pseltxd = p_comm_params->tx_pin_no;err_code = nrf_drv_uart_init(&app_uart_inst, &config, uart_event_handler);VERIFY_SUCCESS(err_code);m_rx_ovf = false;// Turn on receiver if RX pin is connectedif (p_comm_params->rx_pin_no != UART_PIN_DISCONNECTED){return nrf_drv_uart_rx(&app_uart_inst, rx_buffer,1);}else{return NRF_SUCCESS;}
}
(a)app_uart_init(const app_uart_comm_params_t * p_comm_params,
app_uart_buffers_t * p_buffers,
app_uart_event_handler_t event_handler,
app_irq_priority_t irq_priority)
{
* 此函数用于初始化 UART 通信,配置通信参数、缓冲区、事件处理函数和中断优先级。
*
* @param p_comm_params 指向 app_uart_comm_params_t 结构体的指针,包含 UART 通信参数,如引脚编号、流控制设置、奇偶校验和波特率等。
* @param p_buffers 指向 app_uart_buffers_t 结构体的指针,该结构体应包含用于 UART 数据收发的缓冲区。
* @param event_handler 指向 UART 事件处理函数的指针,当 UART 发生特定事件(如接收数据、发送完成等)时会调用此函数。
* @param irq_priority UART 中断的优先级,用于确定 UART 中断在系统中的处理顺序。
*
* @return 函数返回值类型未给出,一般可能返回一个状态码,用于表示初始化是否成功。
*/
由于不清楚 app_uart_buffers_t、app_uart_event_handler_t 和 app_irq_priority_t 的具体定义,下面给出一个简单的模拟实现:
#include <stdio.h>
#include <stdint.h>
// 假设 app_uart_flow_control_t 定义如下
typedef enum
{
APP_UART_FLOW_CONTROL_DISABLED, /**< UART Hw Flow Control is disabled. */
APP_UART_FLOW_CONTROL_ENABLED, /**< Standard UART Hw Flow Control is enabled. */
} app_uart_flow_control_t;
// 假设 app_uart_comm_params_t 定义如下
typedef struct
{
uint32_t rx_pin_no; /**< RX pin number. */
uint32_t tx_pin_no; /**< TX pin number. */
uint32_t rts_pin_no; /**< RTS pin number, only used if flow control is enabled. */
uint32_t cts_pin_no; /**< CTS pin number, only used if flow control is enabled. */
app_uart_flow_control_t flow_control; /**< Flow control setting, if flow control is used, the system will use low power UART mode, based on CTS signal. */
bool use_parity; /**< Even parity if TRUE, no parity if FALSE. */
uint32_t baud_rate; /**< Baud rate configuration. */
} app_uart_comm_params_t;
// 假设 app_uart_buffers_t 定义如下
typedef struct
{
uint8_t *rx_buffer;
uint8_t *tx_buffer;
size_t rx_buffer_size;
size_t tx_buffer_size;
} app_uart_buffers_t;
// 假设 app_uart_event_handler_t 是一个函数指针类型
typedef void (*app_uart_event_handler_t)(void);
// 假设 app_irq_priority_t 是一个枚举类型
typedef enum
{
APP_IRQ_PRIORITY_LOW,
APP_IRQ_PRIORITY_MEDIUM,
APP_IRQ_PRIORITY_HIGH
} app_irq_priority_t;
// 模拟实现 app_uart_init 函数
int app_uart_init(const app_uart_comm_params_t * p_comm_params,
app_uart_buffers_t * p_buffers,
app_uart_event_handler_t event_handler,
app_irq_priority_t irq_priority)
{
if (p_comm_params == NULL || p_buffers == NULL || event_handler == NULL)
{
return -1; // 输入参数无效
}
// 模拟配置 UART 通信参数
printf("Initializing UART with the following parameters:\n");
printf("RX Pin: %u\n", p_comm_params->rx_pin_no);
printf("TX Pin: %u\n", p_comm_params->tx_pin_no);
printf("Flow Control: %s\n", p_comm_params->flow_control == APP_UART_FLOW_CONTROL_ENABLED ? "Enabled" : "Disabled");
printf("Parity: %s\n", p_comm_params->use_parity ? "Even" : "None");
printf("Baud Rate: %u\n", p_comm_params->baud_rate);
// 模拟配置缓冲区
printf("RX Buffer Size: %zu\n", p_buffers->rx_buffer_size);
printf("TX Buffer Size: %zu\n", p_buffers->tx_buffer_size);
// 模拟设置事件处理函数
// 这里可以保存 event_handler 指针,在 UART 事件发生时调用
printf("Event handler set.\n");
// 模拟设置中断优先级
printf("Interrupt priority set to ");
switch (irq_priority)
{
case APP_IRQ_PRIORITY_LOW:
printf("LOW\n");
break;
case APP_IRQ_PRIORITY_MEDIUM:
printf("MEDIUM\n");
break;
case APP_IRQ_PRIORITY_HIGH:
printf("HIGH\n");
break;
default:
printf("UNKNOWN\n");
break;
}
return 0; // 初始化成功
}
使用示例
int main()
{
app_uart_comm_params_t comm_params = {
.rx_pin_no = 1,
.tx_pin_no = 2,
.rts_pin_no = 3,
.cts_pin_no = 4,
.flow_control = APP_UART_FLOW_CONTROL_ENABLED,
.use_parity = false,
.baud_rate = 115200
};
uint8_t rx_buffer[100];
uint8_t tx_buffer[100];
app_uart_buffers_t buffers = {
.rx_buffer = rx_buffer,
.tx_buffer = tx_buffer,
.rx_buffer_size = sizeof(rx_buffer),
.tx_buffer_size = sizeof(tx_buffer)
};
void dummy_event_handler()
{
// 处理 UART 事件的代码
}
app_irq_priority_t irq_priority = APP_IRQ_PRIORITY_MEDIUM;
int result = app_uart_init(&comm_params, &buffers, dummy_event_handler, irq_priority);
if (result == 0)
{
printf("UART initialization successful.\n");
}
else
{
printf("UART initialization failed.\n");
}
return 0;
}
上述代码中,首先为 app_uart_init 函数声明添加了详细注释,然后模拟实现了该函数,最后给出了一个使用示例,展示了如何调用 app_uart_init 函数进行 UART 初始化。
(b)app_fifo_init函数
uint32_t app_fifo_init(app_fifo_t * p_fifo, uint8_t * p_buf, uint16_t buf_size)
{// Check buffer for null pointer.if (p_buf == NULL){return NRF_ERROR_NULL;}// Check that the buffer size is a power of two.if (!IS_POWER_OF_TWO(buf_size)){return NRF_ERROR_INVALID_LENGTH;}p_fifo->p_buf = p_buf;p_fifo->buf_size_mask = buf_size - 1;p_fifo->read_pos = 0;p_fifo->write_pos = 0;return NRF_SUCCESS;
}
app_fifo_t是一个结构体:
typedef struct
{
uint8_t * p_buf; /**< Pointer to FIFO buffer memory. */
uint16_t buf_size_mask; /**< Read/write index mask. Also used for size checking. */
volatile uint32_t read_pos; /**< Next read position in the FIFO buffer. */
volatile uint32_t write_pos; /**< Next write position in the FIFO buffer. */
} app_fifo_t;
1.uint8_t * p_buf:这是一个指向 uint8_t 类型的指针,其作用是指向 FIFO 缓冲区的内存起始地址。
2. uint16_t buf_size_mask:这是一个 uint16_t 类型的变量,作为读写索引掩码使用,同时也用于检查缓冲区的大小。
3. volatile uint32_t read_pos:这是一个 volatile uint32_t 类型的变量,代表 FIFO 缓冲区里下一次读取的位置。
4. volatile uint32_t write_pos:这是一个 volatile uint32_t 类型的变量,代表 FIFO 缓冲区里下一次写入的位置。
以下是使用这个结构体的简单示例代码:
#include <stdio.h>
#include <stdint.h>
typedef struct
{
uint8_t * p_buf; /**< Pointer to FIFO buffer memory. */
uint16_t buf_size_mask; /**< Read/write index mask. Also used for size checking. */
volatile uint32_t read_pos; /**< Next read position in the FIFO buffer. */
volatile uint32_t write_pos; /**< Next write position in the FIFO buffer. */
} app_fifo_t;
#define BUFFER_SIZE 16
// 初始化 FIFO
void fifo_init(app_fifo_t *fifo, uint8_t *buffer) {
fifo->p_buf = buffer;
fifo->buf_size_mask = BUFFER_SIZE - 1;
fifo->read_pos = 0;
fifo->write_pos = 0;
}
// 向 FIFO 写入数据
void fifo_write(app_fifo_t *fifo, uint8_t data) {
fifo->p_buf[fifo->write_pos & fifo->buf_size_mask] = data;
fifo->write_pos++;
}
// 从 FIFO 读取数据
uint8_t fifo_read(app_fifo_t *fifo) {
uint8_t data = fifo->p_buf[fifo->read_pos & fifo->buf_size_mask];
fifo->read_pos++;
return data;
}
int main() {
uint8_t buffer[BUFFER_SIZE];
app_fifo_t fifo;
fifo_init(&fifo, buffer);
// 写入数据
fifo_write(&fifo, 10);
fifo_write(&fifo, 20);
// 读取数据
uint8_t data1 = fifo_read(&fifo);
uint8_t data2 = fifo_read(&fifo);
printf("Read data: %d, %d\n", data1, data2);
return 0;
}
在这个示例中,我们实现了 FIFO 的初始化、写入和读取功能。你可以根据需求对代码进行修改和扩展。
#define IS_POWER_OF_TWO(A) ( ((A) != 0) && ((((A) - 1) & (A)) == 0) )
(c)nrf_drv_uart_config_t结构体
typedef struct
{uint32_t pseltxd; ///< TXD pin number.uint32_t pselrxd; ///< RXD pin number.uint32_t pselcts; ///< CTS pin number.uint32_t pselrts; ///< RTS pin number.void * p_context; ///< Context passed to interrupt handler.nrf_uart_hwfc_t hwfc; ///< Flow control configuration.nrf_uart_parity_t parity; ///< Parity configuration.nrf_uart_baudrate_t baudrate; ///< Baudrate.uint8_t interrupt_priority; ///< Interrupt priority.
#if defined(NRF_DRV_UART_WITH_UARTE) && defined(NRF_DRV_UART_WITH_UART)bool use_easy_dma;
#endif
} nrf_drv_uart_config_t;
(d)NRF_DRV_UART_DEFAULT_CONFIG宏
#define NRF_DRV_UART_DEFAULT_CONFIG \
{ \.pseltxd = NRF_UART_PSEL_DISCONNECTED, \.pselrxd = NRF_UART_PSEL_DISCONNECTED, \.pselcts = NRF_UART_PSEL_DISCONNECTED, \.pselrts = NRF_UART_PSEL_DISCONNECTED, \.p_context = NULL, \.hwfc = (nrf_uart_hwfc_t)UART_DEFAULT_CONFIG_HWFC, \.parity = (nrf_uart_parity_t)UART_DEFAULT_CONFIG_PARITY, \.baudrate = (nrf_uart_baudrate_t)UART_DEFAULT_CONFIG_BAUDRATE, \.interrupt_priority = UART_DEFAULT_CONFIG_IRQ_PRIORITY, \NRF_DRV_UART_DEFAULT_CONFIG_USE_EASY_DMA \
}
函数总体解析:
uint32_t app_uart_init(const app_uart_comm_params_t * p_comm_params,app_uart_buffers_t * p_buffers,app_uart_event_handler_t event_handler,app_irq_priority_t irq_priority)
{uint32_t err_code;// 保存事件处理函数m_event_handler = event_handler;// 检查 p_buffers 是否为 NULL,如果为 NULL 则返回错误码if (p_buffers == NULL){return NRF_ERROR_INVALID_PARAM;}// 配置接收 FIFO 缓冲区err_code = app_fifo_init(&m_rx_fifo, p_buffers->rx_buf, p_buffers->rx_buf_size);// 检查初始化是否成功,如果失败则返回错误码VERIFY_SUCCESS(err_code);// 配置发送 FIFO 缓冲区err_code = app_fifo_init(&m_tx_fifo, p_buffers->tx_buf, p_buffers->tx_buf_size);// 检查初始化是否成功,如果失败则返回错误码VERIFY_SUCCESS(err_code);// 使用默认配置初始化 UART 配置结构体nrf_drv_uart_config_t config = NRF_DRV_UART_DEFAULT_CONFIG;// 设置波特率config.baudrate = (nrf_uart_baudrate_t)p_comm_params->baud_rate;// 根据传入的流控制参数设置硬件流控制config.hwfc = (p_comm_params->flow_control == APP_UART_FLOW_CONTROL_DISABLED) ?NRF_UART_HWFC_DISABLED : NRF_UART_HWFC_ENABLED;// 设置中断优先级config.interrupt_priority = irq_priority;// 根据传入的奇偶校验参数设置奇偶校验config.parity = p_comm_params->use_parity ? NRF_UART_PARITY_INCLUDED : NRF_UART_PARITY_EXCLUDED;// 设置 CTS 引脚号config.pselcts = p_comm_params->cts_pin_no;// 设置 RTS 引脚号config.pselrts = p_comm_params->rts_pin_no;// 设置 RX 引脚号config.pselrxd = p_comm_params->rx_pin_no;// 设置 TX 引脚号config.pseltxd = p_comm_params->tx_pin_no;// 初始化 UART 驱动err_code = nrf_drv_uart_init(&app_uart_inst, &config, uart_event_handler);// 检查初始化是否成功,如果失败则返回错误码VERIFY_SUCCESS(err_code);// 初始化接收溢出标志m_rx_ovf = false;// 如果 RX 引脚已连接,则开启接收功能if (p_comm_params->rx_pin_no != UART_PIN_DISCONNECTED){return nrf_drv_uart_rx(&app_uart_inst, rx_buffer,1);}else{return NRF_SUCCESS;}
}
代码逻辑总结
1. 参数检查:检查 p_buffers 是否为 NULL,若为 NULL 则返回错误码。
2. FIFO 缓冲区配置:对接收和发送的 FIFO 缓冲区进行初始化。
3. UART 配置:依据传入的参数对 UART 的配置结构体进行设置。
4. UART 驱动初始化:对 UART 驱动进行初始化,并且注册事件处理函数。
5. 接收功能开启:若 RX 引脚已连接,就开启接收功能。


/******************** (C) COPYRIGHT 2023 青风电子 ********************* 文件名 :main* 出品论坛 :www.qfv8.com * 实验平台:青云nRF52xx蓝牙开发板* 描述 :串口输出* 作者 :青风* 店铺 :qfv5.taobao.com
**********************************************************************/#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "app_uart.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "nrf.h"
#include "bsp.h"
#if defined (UART_PRESENT)
#include "nrf_uart.h"
#endif
#if defined (UARTE_PRESENT)
#include "nrf_uarte.h"
#endif//#define ENABLE_LOOPBACK_TEST /**< if defined, then this example will be a loopback test, which means that TX should be connected to RX to get data loopback. */#define MAX_TEST_DATA_BYTES (15U) /**< max number of test bytes to be used for tx and rx. */
#define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE 256 /**< UART RX buffer size. */void uart_error_handle(app_uart_evt_t * p_event)
{if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR){APP_ERROR_HANDLER(p_event->data.error_communication);}else if (p_event->evt_type == APP_UART_FIFO_ERROR){APP_ERROR_HANDLER(p_event->data.error_code);}
}#define UART_HWFC APP_UART_FLOW_CONTROL_DISABLED/*** @brief Function for main application entry.*/
int main(void)
{uint32_t err_code;const app_uart_comm_params_t comm_params ={RX_PIN_NUMBER,TX_PIN_NUMBER,RTS_PIN_NUMBER,CTS_PIN_NUMBER,UART_HWFC,false,
#if defined (UART_PRESENT)NRF_UART_BAUDRATE_115200
#elseNRF_UARTE_BAUDRATE_115200
#endif};APP_UART_FIFO_INIT(&comm_params,UART_RX_BUF_SIZE,UART_TX_BUF_SIZE,uart_error_handle,APP_IRQ_PRIORITY_LOWEST,err_code);APP_ERROR_CHECK(err_code);while (1){printf(" 2023.3.1 青风!\r\n");nrf_delay_ms(500);}}/** @} */
(1)app_uart_evt_t结构体定义如下:
typedef struct
{app_uart_evt_type_t evt_type; /**< Type of event. */union{uint32_t error_communication; /**< Field used if evt_type is: APP_UART_COMMUNICATION_ERROR. This field contains the value in the ERRORSRC register for the UART peripheral. The UART_ERRORSRC_x defines from nrf5x_bitfields.h can be used to parse the error code. See also the \nRFXX Series Reference Manual for specification. */uint32_t error_code; /**< Field used if evt_type is: NRF_ERROR_x. Additional status/error code if the error event type is APP_UART_FIFO_ERROR. This error code refer to errors defined in nrf_error.h. */uint8_t value; /**< Field used if evt_type is: NRF_ERROR_x. Additional status/error code if the error event type is APP_UART_FIFO_ERROR. This error code refer to errors defined in nrf_error.h. */} data;
} app_uart_evt_t;
(2)app_uart_evt_type_t枚举类型:
typedef enum
{APP_UART_DATA_READY, /**< An event indicating that UART data has been received. The data is available in the FIFO and can be fetched using @ref app_uart_get. */APP_UART_FIFO_ERROR, /**< An error in the FIFO module used by the app_uart module has occured. The FIFO error code is stored in app_uart_evt_t.data.error_code field. */APP_UART_COMMUNICATION_ERROR, /**< An communication error has occured during reception. The error is stored in app_uart_evt_t.data.error_communication field. */APP_UART_TX_EMPTY, /**< An event indicating that UART has completed transmission of all available data in the TX FIFO. */APP_UART_DATA, /**< An event indicating that UART data has been received, and data is present in data field. This event is only used when no FIFO is configured. */
} app_uart_evt_type_t;
(3)APP_ERROR_HANDLER宏
#define APP_ERROR_HANDLER(ERR_CODE) \do \{ \app_error_handler_bare((ERR_CODE)); \} while (0)
(4)app_error_handler_bare函数
void app_error_handler_bare(ret_code_t error_code)
{error_info_t error_info ={.line_num = 0,.p_file_name = NULL,.err_code = error_code,};app_error_fault_handler(NRF_FAULT_ID_SDK_ERROR, 0, (uint32_t)(&error_info));UNUSED_VARIABLE(error_info);
}
(5)error_info_t结构体
typedef struct
{uint32_t line_num; /**< The line number where the error occurred. */uint8_t const * p_file_name; /**< The file in which the error occurred. */uint32_t err_code; /**< The error code representing the error that occurred. */
} error_info_t;