NRF52832串口作为NRF52832的一个重要外设,经常被用于与外部设备进行通信,但是,作为低功耗应用的场景,开启串口意味着设备功耗的大幅增加。于是一个大胆的猜想便引发出来,如何能使串口在使用的时候才打开,不使用的时候关闭从而实现低功耗呢?这个猜想的主要问题是我们串口的使用是不能人为的预测的(这里说的是串口接收,串口发送可以知道)。要解决这个问题,关键是解决串口接收时才打开串口这个问题。进一步分析,串口接收数据时,串口RX引脚电平会变化,于是,一个方案便应运而生,我们把串口RX引脚配置成中断引脚,当有接收数据来时,我们打开串口外设,当没有数据了,我们关闭串口外设,经过反复尝试和优化,证明了这个方案的可行,实现了串口的低功耗。主要源码分享如下:
系统复位时只初始化串口RX引脚为中断引脚,RX引脚中断配置如下:
void bsp_uart_rx_pin_init(void)
{
ret_code_t err_code;
err_code = nrf_drv_gpiote_init(); /*初始化GPIOTE模块*/
APP_ERROR_CHECK(err_code);
/*RX 任意电平事件*/
nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);
in_config.pull = NRF_GPIO_PIN_NOPULL;
err_code = nrf_drv_gpiote_in_init(RX_PIN_NUMBER,&in_config,in_pin_handler);
NRF_LOG_INFO("err_code:%d\r\n",err_code);
APP_ERROR_CHECK(err_code);
/*使能事件触发*/
nrf_drv_gpiote_in_event_enable(RX_PIN_NUMBER,true);
}
接着当RX引脚上有接收数据来时,触发RX中断回调函数 in_pin_handler,回调中主要是RX引脚中断失能,初始化串口,然后开始RX定时器,这个定时器是一个单次定时器,定时时间到后关闭串口外设,这个定时器的定时时间我这里设置的是100ms,
static void in_pin_handler(nrf_drv_gpiote_pin_t pin,nrf_gpiote_polarity_t action)
{
ret_code_t err_code;
NRF_LOG_INFO("rx gpiote.\r\n");
nrf_drv_gpiote_in_event_disable(RX_PIN_NUMBER); /*失能RX引脚中断*/
bsp_uart_init(); /*初始化串口*/
uart_rx_timers_stop();
uart_rx_timers_start();
}
串口初始化程序跟平时使用的一样:
void bsp_uart_init(void)
{
uint32_t err_code;
const app_uart_comm_params_t comm_params =
{
.rx_pin_no = RX_PIN_NUMBER,
.tx_pin_no = TX_PIN_NUMBER,
.rts_pin_no = RTS_PIN_NUMBER,
.cts_pin_no = CTS_PIN_NUMBER,
.flow_control = APP_UART_FLOW_CONTROL_DISABLED,
.use_parity = false,
.baud_rate = UART_BAUDRATE_BAUDRATE_Baud115200
//.baud_rate = UART_BAUDRATE_BAUDRATE_Baud9600
};
APP_UART_FIFO_INIT(&comm_params,
UART_RX_BUF_SIZE,
UART_TX_BUF_SIZE,
uart_event_handle,
APP_IRQ_PRIORITY_LOWEST,
err_code);
APP_ERROR_CHECK(err_code);
}
如下是定时器回调函数,主要实现功能是关闭串口外设,然后从新使能串口rx引脚为中断引脚,
void uart_rx_timeout_handler(void * p_context)
{
app_uart_close();
nrf_drv_gpiote_in_event_enable(RX_PIN_NUMBER,true);
}
如此便实现了串口接收数据才打开外设,没使用时关闭外设,关于发送,这个就很easy了发送时初始化一遍串口,发送完重新配置RX引脚为中断引脚即可。