nRF52832——串口 UART 和 UARTE 外设应用
nRF52832——串口 UART 和 UARTE 外设应用
- UART 和 UARTE 原理
- UART 功能描述
- UARTE 功能介绍
- 应用实例
- 串口打印实例
- 串口输入与回环
- UART 模式串口中断
UART 和 UARTE 原理
UART 功能描述
串口 UART 也称为通用异步收发器。是各种处理器中常用的通信接口,在 nRF52 芯片中,UART 具有以下特点:
- 全双工操作
- 自动流控
- 奇偶校验产生第九位数据
根据 PSELRXD、PSELCTS、PSELRTS、PSELTXD 寄存器的配置可以将对应的 RXD、CTS(发送清除、低位有效)、TXD、RTS(发送请求,低位有效)映射到物理引脚上。如果这些寄存器的任意一个设为 0xffffffff,相关的 UART 信号就不会连接到任何物理引脚上。这四个寄存器及配置只能在 UART 使能时可用,可以在芯片为系统 ON 模式时保持。为了在系统处于 OFF 关闭模式时通过 UART 确保引脚上的信号电平正确,必须按照 GPIO 外设中的说明在 GPIO 外设中配置引脚。
管脚 | 系统 ON 模式下使能 UART | 系统 OFF 模式下 GPIO 配置 |
---|---|---|
PSELRXD | RXD 串口接收端 | 输入、无输出值 |
PSELCTS | 流量控制发送清除,低位有效 | 输入、无输出值 |
PSELRTS | 流量控制发送请求,低位有效 | 输出、高电平输出 1 |
PSELTXD | TXD 串口发送端 | 输出,高电平输出 1 |
上图是 UART 模块内部结构图。
UART 发送
通过触发 STARTTX 任务启动 UART 出传输序列。然后通过写入 TXD 寄存器来发送字节。成功发送一个字节后,UART 将产生一个 TXDRDY 事件,之后可以将一个新字节写入 TXD 寄存器。通过触发 STOPTX 任务立即停止 UART 传输序列。如果启用流量控制,则在 CTS 取消激活时将自动暂停传输,并在再次激活 CTS 时恢复。在 CTS 被停用时正在传输的字节将在传输暂停之前被完全传输。
UART 接收
通过触发 STARTRX 任务启动 UART 接受序列。UART 接收器连接了一个 FIFO,能够在数据被覆盖之前存储六个传入的 RXD 字节。通过读取 RXD 寄存器从该 FIFO 中提取字节。当从 FIFO 中提取一个字节时,FIFO 中待处理的新字节将被移动到 RXD 寄存器。每次将新字节移入 RXD 寄存器时,UART 都将产生 RXDRDY 事件。
当启用流量控制时,如果接收器 FIFO 中只有 4 个字节的空间时,UART 将禁用 RTS 信号。启用流量控制状态下在重写数据之前,发送器能够在 RTS 信号激活之后发生多达 4 个字节。因此为防止覆盖 FIFO 中的数据,对应的 UART 发送器必须确保 RTS 线停用后在四个字节时间内停止发送数据。当 FIFO 清空后,首次再次激活 RTS 信号,CPU 读取 FIFO 中的所有字节,接收器通过 STOPRX 任务停止时,RTS 信号也将被禁止。
为了防止输入数据丢失,必须在每次 RXDRDY 事件后读取 RXD 寄存器一次。为了确保 CPU 可以通过 RXDRDY 事件寄存器检测所有输入的 RXDRDY 事件,必须在读取 RXD 寄存器之前清零 RXDRDY 事件寄存器。这样做的原因是允许 UART 将新字节写入 RXD 寄存器,在 CPU 读取(清空)RXD 寄存器后立即生成新事件。
UART 挂起
UART 串口可以通过触发 SUPSPEND 寄存器任务来挂起。SUPSPEND 将影响 UART 发送器和 UART 接收器,设置后使发生器停止发送,接收器停止接收。在 UART 挂起后,通过相应的触发 STARTTX 和 STARTRX 就可以重新开启发送和接收。
当触发 SUSPEND 任务时,UART 接收器和触发 STOPRX 任务一样的工作;
当触发 SUSPEND 任务时,正在进行的 TXD 字节传输将在 UART 挂起前完成。
错误条件
在一个错误帧出现的情况下,如果在此帧中没有检测到有效的停止位将会产生一个 ERROR 事件。另外,在中断时,如果 RXD 保持低电平超过一个数据帧长度时,也会产生一个 ERROR 事件。
流量控制
nRF52 芯片的 UART 可以分为带流控和不带流控两种方式。
- 带流控:有 CTS、RTS 加上 TX、RX 四个引脚组成。RTS 引脚作为输出,由 UART 硬件模块自动控制。与接收寄存器的多级硬件缓冲 BUFF 协调工作。当 BUFF 缓冲数据满时会自动停下发送工作直到缓冲数据被读出后回复有效信号才再次开始发送数据
- 不带流控:只有 TX、RX 两个引脚组成
UARTE 功能介绍
UARTE 就是带有 EasyDMA 的通用异步收发器 UART。提供快速、全双工、异步的串行通信,内置流量控制(CTS、RTS)支持硬件,速率高达 1Mbps。
这里列出的是 UARTE 的主要功能:
- 全双工操作
- 自动硬件流控制
- 生成 9 位数据待奇偶校验
- easyDMA
- 波特率高达 1Mbps
- 在支持的事务之间返回 IDLE (使用 HW 流控制时)
- 一个停止位
- 最低有效位(LSB)优先
UARTE 的内部结构如下图。用于每个 UART 接口的 GPIO 可以从设备上的任何 GPIO 来选择并且独立可配置。这使得能够在器件的引脚和有效地利用电路板空间和信号路由很打的灵活性。
内部寄存器说明:
UARTE 实现 easyDMA 读取和写入,并存入 RAM。如果 TXD.PTR 和 RXD.PTR 没有指向数据 RAM 区,easyDMA 传递可能导致 HardFault 或 RAM 损坏。
.PTR 和 .MAXCNT 寄存器是双缓冲的。他们可以在收到 RXSTARTED/TXSTARTED 事件后立即进行更新,并在接下来的 RX/TX 传送准备。所述 ENDRX/ENDTX 事件表示 easyDMA 已完成访问分别在 RAM 中的 RX/TX 缓冲器。
UARTE 发送
- 存储的字节导发送缓冲器和配置 easyDMA。通过写起始地址导指针 TXD.PTR,并在 RAM 缓冲器放置 TXD.MAXCNT 大小的字节数来实现。
- 串口 UARTE 的发送是通过触发 STARTTX 任务开始,之后的每个字节在 TXD 线上发送时,会产生一个 TXDRDY 事件。
- 当 TXD 缓冲器中的所有字节(在 TXD.MAXCNT 寄存器中指定书目)已被传送时,UARTE 传输将自动结束,并且将产生一个 ENDTX 事件。
- 通过触发 STOPTX 任务来停止 UARTE 发送序列,当 UARTE 发射机已经停止,将产生一个 TXSTOPPED 事件。如果在 UARTE 发射机已经停下来但尚未产生 ENDTX 事件时,UARTE 将明确产生一个 ENDTX 事件,即使在 TXD 缓冲区中的所有字节(TXD.MAXCNT 寄存器指定)还没有被发送。
- 如果启用了流量控制,则在 CTS 取消激活时将自动暂停传输,并在再次激活 CTS 时恢复。在 CTS 被停用时正在传输的字节将在传输暂停之前被完全传输。
UARTE 接收
- 通过触发 STARTRX 任务启动 UARTE 接收器
- UARTE 接收器使用 easyDMA 将输入数据存储在 RAM 中的 RX 缓冲区中。RX 缓冲区位于 RXD.PTR 寄存器中指定的地址。RXD.PTR 寄存器是双缓冲,可以在生产 RXSTARTED 事件后立即更新并为下一个 STARTRX 任务做好准备。
- RX 缓冲区的大小在 RXD.MAXCNT 寄存器中指定,UARTE 在填充 RX 缓冲区时将生成 ENDRX 事件。
- 对于通过 RXD 线接收的每个字节,都将生成 RXDRDY 事件。在将相应的数据传输到数据 RAM 之前,可能会发生此事件。在 ENDRX 事件之后可以查询到 RXD.AMOUNT 寄存器来查看上次 ENDRX 事件以来有多少新字节已经传输到 RAM 中的 RX 缓冲区。
- 通过触发 STOPRX 任务来停止 UARTE 接收器。UARTE 停止会生成 RXTO 事件。UARTE 将确保在生成 RXTO 事件之前生产即将发生的 ENDRX 事件。这意味着 UARTE 将保证在 RXTO 之后不会生成 ENDRX 事件,除非重新启动 UARTE 或在生成 RXTO 事件后发出 FLUSHRX 命令。
重要提示:
如果在 UARTE 接收器停止时尚未生成 ENDRX 事件,这意味着 RX FIFO 中的所有待处理内容都已移至 RX 缓冲区,则 UARTE 将显式生成 ENDRX 事件,即使 RX 缓冲区未满。 在这种情况下,将在生成 RXTO 事件之前生成 ENDRX 事件。
为了能够知道实际接收到 RX 缓冲区的字节数,CPU 可以在 ENDRX 事件或 RXTO 事件之后读取RXD.AMOUNT 寄存器。只要在 RTS 信号被禁用后立即连续发送,UARTE 就可以在 STOPRX 任务被触发后接收最多四个字节。这是可能的,因为在 RTS 取消激活后,UARTE 能够在一段延长的时间内接收字节,该时间等于在配置的波特率上发送 4 个字节所需的时间。生成 RXTO 事件后,内部RX FIFO 可能仍包含数据,要将此数据移至 RAM,必须触发 FLUSHRX 任务。
为确保此数据不会覆盖 RX 缓冲区中的数据,应在 FLUSHRX 任务被触发之前清空 RX 缓冲区或更新 RXD.PTR。为确保 RX FIFO 中的所有数据都移至 RX 缓冲区,RXD.MAXCNT 寄存器必须设置为 RXD.MAXCNT> 4,通过 STOPRX 强制停止的 UARTE 接收。即使 RX FIFO 为空或 RX 缓 冲区未填满,UARTE 也会在完成 FLUSHRX 任务后生成 ENDRX 事件。 为了能够知道在这种情况 下实际接收到 RX 缓冲区的字节数,CPU 可以在 ENDRX 事件之后读取 RXD.AMOUNT 寄存器。
如果启用了 HW 流量控制,当接收器通过 STOPRX 任务停止或 UARTE 只能在其内部 RX FIFO 中接收 4 个字节时,RTS 信号将被禁用。禁用流量控制后,UARTE 将以与启用流量控制时相同的 方式运行,但不会使用 RTS 线路。这意味着当 UARTE 达到只能在其内部 RX FIFO 中接收四个字节 的点时,不会产生任何信号。内部 RX FIFO 填满时接收的数据将丢失。UARTE 接收器将处于最低 活动水平,并在停止时消耗最少的能量,即在通过 STARTRX 启动之前或通过 STOPRX 停止并且已 生成 RXTO 事件之后。
应用实例
串口打印实例
硬件连接方面,通过高质量芯片 CH340T 把串口信号转换成 usb 输出, TXD–接端口 P0.09 端 RXD–接端口 P0.11 端 CTS–接端口 P0.08 端 RTS–接端口 P0.10 端,其中数据口 TXD 和 RXD 分别 接 1K 电阻上拉,提高驱动能力。
类似前面的实例,这里创建如下的工程结构:
nrf_drv_uart.c
文件和 app_uart_fifi.c
文件是官方编写好的驱动库文件。这两个文件在后面编写带协议栈的 BLE 应用时,是可以直接用于其中配置串口功能的。因此理解这两个文件提供的 API 函数是利用组件编写串口的必由之路
在 app_uart.h
中提供了两键的 uart
函数 APP_UART_FIFO_INIT
和 APP_UART_INIT
,一个是带 FIFO 缓冲的初始化串口函数,一个是不带 FIFO 缓冲的初始化函数,一般情况下使用带软件缓冲的 FIF0 的函数,减小数据溢出错误的发生几率。配置代码具体如下:
//声明参数结构体
const app_uart_comm_params_t comm_params =
{RX_PIN_NUMBER,TX_PIN_NUMBER,RTS_PIN_NUMBER,CTS_PIN_NUBMER,//串口配置管脚APP_UART_FLOW_CONTROL_DISABLED,//流控设置false,UART_BAUDRATE_BAUDRATE_Baud115200 //波特率
};APP_UART_FIFO_INIT(&comm_params, //串口参数UART_RX_BUF_SIZE, //RX 缓存大小UART_TX_BUF_SIZE, //TX 缓存大小uart_error_handle, //错误处理APP_IRQ_PRIORITY_LOW, //中断优先级err_code);//配置串口
这里的 APP_UART_FIFO_INIT
其实是一个宏,其定义如下:
/**@brief Macro for safe initialization of the UART module in a single user instance when using* a FIFO together with UART.** @param[in] P_COMM_PARAMS Pointer to a UART communication structure: app_uart_comm_params_t* @param[in] RX_BUF_SIZE Size of desired RX buffer, must be a power of 2 or ZERO (No FIFO).* @param[in] TX_BUF_SIZE Size of desired TX buffer, must be a power of 2 or ZERO (No FIFO).* @param[in] EVT_HANDLER Event handler function to be called when an event occurs in the* UART module.* @param[in] IRQ_PRIO IRQ priority, app_irq_priority_t, for the UART module irq handler.* @param[out] ERR_CODE The return value of the UART initialization function will be* written to this parameter.** @note Since this macro allocates a buffer and registers the module as a GPIOTE user when flow* control is enabled, it must only be called once.*/
#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)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. 配置 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. 配置 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;}
}
具体 API 介绍如下:
工程建立后,在工程编译之前,还需要在 sdk_config.h
文件中配置使能下面几个功能:
- 外设共用源的使能、新串口驱动使能、老板串口驱动使能、串口 FIFO 缓冲库使能、串口驱动 库使能、错误检测使能、重定位库使能。
- 可以直接打开
sdk_config.h
文件中的configuration Wizard 向导
进行勾选,如下图所示。
本例使用 printf()函数是格式化输出函数,一般用于向标准输出设备按规定格式输出信息。本格式的输出是 c 语言中产生格式化输出的函数(在 stdio.h 中定义)。用于向终端(显示器、控制台等)输出字符。格式控制由要输出的文字和数据格式说明组成。要输出的文字除了可以使用字母、数字、空格和一些数字符号以外,还可以使用一些转义字符表示特殊的含义。因此,使用之前除了 要使能重定向以外,还需要在 options for Target 选项卡中,选择 Target 后,勾选 Use MicroLIB 库,如下图所示:
主函数这里就很简单了,如下 main.c
#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};//串口初始化(FIFO)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(" 2020.08.1 Hello world!\r\n");nrf_delay_ms(500);}
}
串口输入与回环
前面的串口打印实现了串口数据的输出功能,这里添加串口输入功能实现串口的回环。
先来了解一个 API 函数:
app_uart_get()
app_uart_put()
操作代码如下:
#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);}
}static void uart_loopback_test()
{while (true){uint8_t cr;while(app_uart_get(&cr) != NRF_SUCCESS);while(app_uart_put(cr) != NRF_SUCCESS);if (cr == 'q' || cr == 'Q'){printf(" \n\rExit!\n\r");while (true){// Do nothing.}}}}/*** @brief Function for main application entry.*/
int main(void)
{LEDS_CONFIGURE(LEDS_MASK);LEDS_OFF(LEDS_MASK);uint32_t err_code;const app_uart_comm_params_t comm_params ={RX_PIN_NUMBER,TX_PIN_NUMBER,RTS_PIN_NUMBER,CTS_PIN_NUMBER,APP_UART_FLOW_CONTROL_DISABLED,false,UART_BAUDRATE_BAUDRATE_Baud115200};APP_UART_FIFO_INIT(&comm_params,UART_RX_BUF_SIZE,UART_TX_BUF_SIZE,uart_error_handle,APP_IRQ_PRIORITY_LOW,err_code);APP_ERROR_CHECK(err_code);while (1){uart_loopback_test();}
}
UART 模式串口中断
UARTE 和 UARTE 共享大部分寄存器设备,区别就是 UARTE 通过 EasyDMA 参与到数据的收发上。DMA 是 Direct Memory Access 的英文简写,直接内存存取。可以不需要 CPU 参与。普通传输中,CPU 需要从源位置把每一片段的数据复制到目的寄存器,然后把它们再次写回到新的地方。 在这个时间中,CPU 对于其他的工作来说就无法使用。
EasyDMA 使得外围设备可以通过 DMA 控制器直接访问内存,与此同时,CPU 可以继续执行程序。EasyDMA 传输将数据从一个地址空间复制到另外一个地址空间。当 CPU 初始化这个传输动 作,传输动作本身是由 EasyDMA 来实行和完成。所有我们需要在 sdk_config.h 文件中勾选 UARTE 功能,如下图所示:
这里处理 UART irq 的数据类型有以下几种:
/**@brief Enumeration which defines events used by the UART module upon data reception or error.** @details The event type is used to indicate the type of additional information in the event* @ref app_uart_evt_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;
这里参考对应的处理流程,编写主函数操作如下 main.c
#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"
#include "nrf_uarte.h"#define MAX_TEST_DATA_BYTES (15U) /*用于tx和rx的最大测试字节数 */
#define UART_TX_BUF_SIZE 256 /*UART TX缓冲区大小 */
#define UART_RX_BUF_SIZE 256 /*UART RX缓冲区大小 */void uart_Interrupt_handle(app_uart_evt_t * p_event)
{uint8_t RX;//通信错误事件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);}//串口接收事件else if (p_event->evt_type == APP_UART_DATA_READY){//从FIFO中读取数据 app_uart_get(&RX); //串口输出数据 printf("%c",RX); }//串口发送完成事件else if (p_event->evt_type == APP_UART_TX_EMPTY){nrf_gpio_pin_toggle(LED_1);} }/***主函数*/
int main(void)
{LEDS_CONFIGURE(LEDS_MASK);LEDS_OFF(LEDS_MASK);uint32_t err_code;const app_uart_comm_params_t comm_params ={RX_PIN_NUMBER,TX_PIN_NUMBER,RTS_PIN_NUMBER,CTS_PIN_NUMBER,APP_UART_FLOW_CONTROL_DISABLED,false,UART_BAUDRATE_BAUDRATE_Baud115200};APP_UART_FIFO_INIT(&comm_params,UART_RX_BUF_SIZE,UART_TX_BUF_SIZE,uart_Interrupt_handle,APP_IRQ_PRIORITY_LOW,err_code);APP_ERROR_CHECK(err_code);while (1){}
}
相关文章:

nRF52832——串口 UART 和 UARTE 外设应用
nRF52832——串口 UART 和 UARTE 外设应用 UART 和 UARTE 原理UART 功能描述UARTE 功能介绍 应用实例串口打印实例串口输入与回环UART 模式串口中断 UART 和 UARTE 原理 UART 功能描述 串口 UART 也称为通用异步收发器。是各种处理器中常用的通信接口,在 nRF52 芯…...

String 底层为什么使用 final 修饰?
1、典型回答 对于这个问题,Java之父詹姆斯 高斯林(James Gosling) 是这样回答的: I would use an immutable whenever I can 翻译为中文:只要允许,我就会使用不可变对象 而作为普通人的我们来说࿰…...

NIN网络中的网络
是什么 intro LeNet→AlexNet→VGG→NiN→GoogLeNet→ResNetLeNet→AlexNet→VGG 卷积层模块充分抽取空间特征全连接层输出分类结果AlexNet & VGG 改进在于把两个模块加宽 、加深(加宽指增加通道数,那加深呢?(层数增加叭 Ni…...

Cloudflare Tunnel:无惧DDOS_随时随地安全访问局域网Web应用
利用此方法,您可以在局域网(尤其是NAS)上搭建的Web应用支持公网访问,成本低而且操作简单! 如果这是博客的话,它还可以有效防止DDOS攻击! 准备工作: 需要一个域名(推荐N…...

高质量快刊!中科院1区TOP,Elsevier出版社,最快2个月23天录用!20天见刊!
【SciencePub学术】 01 期刊基本信息 【期刊简介】IF:11.0-11.5,JCR1区,中科院1区TOP 【出版社】Elsevier出版社 【版面情况】正刊,2023.3.31截稿 【检索情况】SCIE&EI双检,预计3个月左右录用 【征稿领域】…...

C++感受2-逐字逐句,深入理解C++最小例程
以 “Hello World” 例程为载体、线索,在完成 “间接名字空间限定” 写法转换到“直接名字空间限定”的过程,同时掌握函数、主函数、函数调用、级联操作、声明、类型、int、字符串类型、头文件包含、行为数据、流输出操作符、标准输出流对象、标准库名字…...

RabbitMQ 面试题及答案整理,最新面试题
RabbitMQ的核心组件有哪些? RabbitMQ的核心组件包括: 1、生产者(Producer): 生产者是发送消息到RabbitMQ的应用程序。 2、消费者(Consumer): 消费者是接收RabbitMQ消息的应用程序…...
字节算法-链表翻转与变形
文章目录 题目与变形解法 题目与变形 字节一面中关于 K个一组链表反转 的题目变形。 K个一组链表反转。K个一组链表反转,链表尾不足K个的元素也需要反转。K个一组链表反转,但是从链表尾部开始反转。反转从位置 left 到位置 right 的链表节点 解法 四…...
十一、软考-系统架构设计师笔记-未来信息综合技术
1、信息物理系统技术概述 信息物理系统的概念 信息物理系统(Cyber-Physical Systems,CPS)通过集成先进的感知、计算、通信、控制等信息技术和自动控制技术,构建了物理空间与信息空间中人、机、物、环境、信息等要素相互映射、适时交互、高效协同的复杂系…...

非同源点云尺度对齐及点云配准(cloudcompare软件)
1.点云裁减与尺度缩放 发现口扫stl转为的点云尺度是原始点云的1000倍 打开meshlab,通过“Filters” > “Mesh Layer” > “Transform: Scale”缩放1000倍,得到以米为单位的真实尺寸 此时在meshlab中进行点云手动裁减后效果 将ply文件转为xyz文件…...

体检业务数字化管理平台,健康体检管理系统(PEIS)源码
健康体检管理系统(PEIS)源码,自动生成体检报告,提供查询、统计和分析功能 健康体检管理系统(PEIS)可以建立完整的健康档案,系统实现了与HIS系统的无缝连接,着重于临床信息系统的应用…...

【SpringCloud微服务实战04】Nacos 配置中心
一、Nacos配置添加 二、Nacos配置读取 1、引入Nacos的配置管理客户端依赖: <!--nacos配置管理依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</arti…...

无雀新功能宣传板之视频直播+Teambition
1. 今日新功能 钉钉视频会议新功能 视频会议功能,打造了一系列独具特色的通话海报模板供用户选择。其中引人瞩目的是为龙年限定的新春主题通话海报,它巧妙地融入了中国传统文化元素,将庄重且喜庆的龙年新春气息浓缩在画面之中。 自定义通话…...

学生选课系统的最简逻辑--一个学生选一门课
需求:设计一个学生选课系统,要求如下:有一个学生类,有一个课程类,还有一个Teacher类。。学生类包括姓名、学号、已选课程。课程类包括课程名称、授课老师属性。 老师包括老师的名字、老师的电话,老师的课程…...

波司登高德康:以有“韧性”的创新应变市场新浪潮
伴随着消费升级,羽绒服市场需求日益旺盛。愈发多元化的需求对于企业发展也有着更高的要求。如何更好推动行业多元化发展,可以从波司登的品牌升级、产品创新、模式创新、数字技术创新、绿色发展创新等方面窥得一二。 高德康总裁接受新华网主持人采访 对此…...
装饰你的APP:使用Lottie-Android创建动画效果
1. Lottie-Android简介 Lottie-Android是一个强大的开源库,由Airbnb开发,旨在帮助开发者轻松地在Android应用中添加高质量的动画效果。它基于Adobe After Effects软件中的Bodymovin插件,通过解析导出的JSON文件来渲染并播放复杂的矢量动画。 Lottie-Android提供了许多令人…...

成都爱尔林江院长解析巩膜镜是什么?它适合哪些人群
巩膜镜,全称为硬性透氧性巩膜接触镜,它有着特殊设计,大直径镜片像桥梁一样呈拱形覆盖角膜及角巩膜缘,从角膜上方横跨而过完全无接触、无任何机械性摩擦,最终贴合于巩膜。 巩膜镜的作用原理 光学成像: 配戴…...

苹果cms模板保护设置,防止被扒
苹果cms模板保护设置,防止被扒 如今互联网时代,网站模板前端被扒是常有的事,如何防止模板数据被扒? 保护设置方法: 登录宝塔 找到安装模板的网站 设置禁止访问文件 方法参考截图后缀填:php|html 目录填&a…...

Claude3、GPT-4、Gemini、Sora VS :谁将成为下一代科研利器?
2023年随着OpenAI开发者大会的召开,最重磅更新当属GPTs,多模态API,未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义,不亚于互联网和个人电脑的问世。360创始人周鸿祎认为未来各行各业如果不能搭上这班车…...
vue 函数防抖
背景 一个页面使用监听器,监听了页面的三个参数,页面初始化的时候,三个参数都发生了变化。发送了三次请求,页面却使用的是第二次请求的数据。希望短时间内发生多次变化的时候,只发送一次请求 思路 这个需求可以通过使用…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...