1.目的
分析蓝牙串口的例子
2.分析
在实际应用中经常使用串口,下面我们就来分析下串口例子
3.平台:
sofeDevice : s110_nrf51_8.0.0_softdevice.hex
协议栈版本:SDK10.0.0
编译软件:keil 5.12
硬件平台:nrf51822最小系统
例子:SDK 10.0.0\examples\ble_peripheral\ble_app_uart\pca10028\s110\arm4
4.步骤
int main(void) { uint32_t err_code; bool erase_bonds; uint8_t start_string[] = START_STRING; // Initialize. APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false); uart_init(); buttons_leds_init(&erase_bonds); ble_stack_init(); gap_params_init(); services_init(); advertising_init(); conn_params_init(); printf("%s",start_string); err_code = ble_advertising_start(BLE_ADV_MODE_FAST); APP_ERROR_CHECK(err_code); // Enter main loop. for (;;) { power_manage(); } }a.串口初始化
uart_init();
把APP_UART_FLOW_CONTROL_ENABLED ==》APP_UART_FLOW_CONTROL_DISABLED 不使用流控
在pca10028.h 中定义串口的管脚,如下:
#define RX_PIN_NUMBER 11
#define TX_PIN_NUMBER 9
#define CTS_PIN_NUMBER 10
#define RTS_PIN_NUMBER 8
#define HWFC false
static void uart_init(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, APP_UART_FLOW_CONTROL_DISABLED,// APP_UART_FLOW_CONTROL_ENABLED false, UART_BAUDRATE_BAUDRATE_Baud38400 }; APP_UART_FIFO_INIT( &comm_params, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE, uart_event_handle, APP_IRQ_PRIORITY_LOW, err_code); APP_ERROR_CHECK(err_code); }
定义了接收和发送缓冲区的大小:
#define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE 256 /**< UART RX buffer size. */
然后初始化哪个串口,串口发送和接收缓冲区,串口回调函数,串口优先级,代码如下
#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. err_code = app_fifo_init(&m_rx_fifo, p_buffers->rx_buf, p_buffers->rx_buf_size); if (err_code != NRF_SUCCESS) { // Propagate error code. return err_code; } // Configure buffer TX buffer. err_code = app_fifo_init(&m_tx_fifo, p_buffers->tx_buf, p_buffers->tx_buf_size); if (err_code != NRF_SUCCESS) { // Propagate error code. return 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(&config, uart_event_handler); if (err_code != NRF_SUCCESS) { return err_code; } nrf_drv_uart_rx_enable(); return nrf_drv_uart_rx(rx_buffer,1); }
配置发送 接收缓冲区,配置具体的寄存器,开中断等等。
看nrf_drv_uart_init();
把 m_cb.handler = event_handler; m_cb.handler 指向回调函数
ret_code_t nrf_drv_uart_init(nrf_drv_uart_config_t const * p_config, nrf_uart_event_handler_t event_handler) { if (m_cb.state != NRF_DRV_STATE_UNINITIALIZED) { return NRF_ERROR_INVALID_STATE; } if (p_config == NULL) { p_config = &m_default_config; } #ifdef NRF52 m_cb.use_easy_dma = p_config->use_easy_dma; #endif apply_config(p_config); m_cb.handler = event_handler; m_cb.p_context = p_config->p_context; if (m_cb.handler) { interrupts_enable(p_config->interrupt_priority); } uart_enable(); m_cb.rx_buffer_length = 0; m_cb.tx_buffer_length = 0; m_cb.state = NRF_DRV_STATE_INITIALIZED; m_cb.rx_enabled = false; return NRF_SUCCESS; }
串口中断函数 因为没有定义UARTE_IN_USE 也没有定义 UART_IN_USE
所以只有 CODE_FOR_UART定义了
#if (defined(UARTE_IN_USE) && defined(UART_IN_USE)) // UARTE and UART combined #define CODE_FOR_UARTE(code) if (m_cb.use_easy_dma) { code } #define CODE_FOR_UART(code) else { code } #elif (defined(UARTE_IN_USE) && !defined(UART_IN_USE)) // UARTE only #define CODE_FOR_UARTE(code) { code } #define CODE_FOR_UART(code) #elif (!defined(UARTE_IN_USE) && defined(UART_IN_USE)) // UART only #define CODE_FOR_UARTE(code) #define CODE_FOR_UART(code) { code } #else #error "Wrong configuration." #endif
void UART0_IRQHandler(void) { CODE_FOR_UARTE ( if (nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_ERROR)) { nrf_drv_uart_event_t event; nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_ERROR); event.type = NRF_DRV_UART_EVT_ERROR; event.data.error.error_mask = nrf_uarte_errorsrc_get_and_clear(NRF_UARTE0); event.data.error.rxtx.bytes = nrf_uarte_rx_amount_get(NRF_UARTE0); event.data.error.rxtx.p_data = m_cb.p_rx_buffer; //abort transfer m_cb.rx_buffer_length = 0; m_cb.handler(&event,m_cb.p_context); } else if (nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_ENDRX)) { nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_ENDRX); uint8_t amount = nrf_uarte_rx_amount_get(NRF_UARTE0); if (amount == m_cb.rx_buffer_length) { rx_done_event(amount); } } if (nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_RXTO)) { nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_RXTO); if (m_cb.rx_buffer_length) { rx_done_event(nrf_uarte_rx_amount_get(NRF_UARTE0)); } } if (nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_ENDTX)) { nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_ENDTX); if (m_cb.tx_buffer_length) { tx_done_event(nrf_uarte_tx_amount_get(NRF_UARTE0)); } } ) CODE_FOR_UART( if (nrf_uart_int_enable_check(NRF_UART0, NRF_UART_INT_MASK_ERROR) && nrf_uart_event_check(NRF_UART0, NRF_UART_EVENT_ERROR)) { nrf_drv_uart_event_t event; nrf_uart_event_clear(NRF_UART0, NRF_UART_EVENT_ERROR); nrf_uart_int_disable(NRF_UART0, NRF_UART_INT_MASK_RXDRDY | NRF_UART_INT_MASK_ERROR); if (!m_cb.rx_enabled) { nrf_uart_task_trigger(NRF_UART0, NRF_UART_TASK_STOPRX); } event.type = NRF_DRV_UART_EVT_ERROR; event.data.error.error_mask = nrf_uart_errorsrc_get_and_clear(NRF_UART0); event.data.error.rxtx.bytes = m_cb.rx_buffer_length; event.data.error.rxtx.p_data = m_cb.p_rx_buffer; //abort transfer m_cb.rx_buffer_length = 0; m_cb.handler(&event,m_cb.p_context); } else if (nrf_uart_int_enable_check(NRF_UART0, NRF_UART_INT_MASK_RXDRDY) && nrf_uart_event_check(NRF_UART0, NRF_UART_EVENT_RXDRDY)) { rx_byte(); if (m_cb.rx_buffer_length == m_cb.rx_counter) { if (!m_cb.rx_enabled) { nrf_uart_task_trigger(NRF_UART0, NRF_UART_TASK_STOPRX); } nrf_uart_int_disable(NRF_UART0, NRF_UART_INT_MASK_RXDRDY | NRF_UART_INT_MASK_ERROR); rx_done_event(m_cb.rx_counter); } } if (nrf_uart_event_check(NRF_UART0, NRF_UART_EVENT_TXDRDY)) { if ((m_cb.tx_buffer_length > m_cb.tx_counter)) { tx_byte(); } else { nrf_uart_event_clear(NRF_UART0, NRF_UART_EVENT_TXDRDY); if (m_cb.tx_buffer_length) { tx_done_event(m_cb.tx_buffer_length); } } } if (nrf_uart_event_check(NRF_UART0, NRF_UART_EVENT_RXTO)) { nrf_uart_event_clear(NRF_UART0, NRF_UART_EVENT_RXTO); // RXTO event may be triggered as a result of abort call. In th if (m_cb.rx_enabled) { nrf_uart_task_trigger(NRF_UART0, NRF_UART_TASK_STARTRX); } if (m_cb.rx_buffer_length) { rx_done_event(m_cb.rx_counter); } } ) }发送数据并且缓冲区没有满的时候就是产生超时事件,
然后调用 rx_done_event(m_cb.rx_counter);
__STATIC_INLINE void rx_done_event(uint8_t bytes) { nrf_drv_uart_event_t event; event.type = NRF_DRV_UART_EVT_RX_DONE; event.data.rxtx.bytes = bytes; event.data.rxtx.p_data = m_cb.p_rx_buffer; m_cb.rx_buffer_length = 0; m_cb.handler(&event,m_cb.p_context); }
所以这里会产生uart_event_handle();函数
看回调函数uart_event_handle();
当有数据来了并且已“\n” 数据长度大于20,就会通过串口服务发送出去。
在这里我们添加一天串口打印数据语句,printf("%s",data_array);
void uart_event_handle(app_uart_evt_t * p_event) { static uint8_t data_array[BLE_NUS_MAX_DATA_LEN]; static uint8_t index = 0; uint32_t err_code; switch (p_event->evt_type) { case APP_UART_DATA_READY: UNUSED_VARIABLE(app_uart_get(&data_array[index])); index++; if ((data_array[index - 1] == '\n') || (index >= (BLE_NUS_MAX_DATA_LEN))) {
printf("%s",data_array); //添加发送语句
err_code = ble_nus_string_send(&m_nus, data_array, index); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } index = 0; } break; case APP_UART_COMMUNICATION_ERROR: APP_ERROR_HANDLER(p_event->data.error_communication); break; case APP_UART_FIFO_ERROR: APP_ERROR_HANDLER(p_event->data.error_code); break; default: break; } }
实验:download the code 可以看到打印出 Start... 表示发送成功。
串口发送框写“abcdefghijklmnopqrst\n” (注意“\n”结尾并且发送数据的长度要大约等于20,这样程序才会返回,具体看uart_event_handle()函数)点击发送,
可以看到数据显示框里显示 “abcdefghijklmnopqrst” 程序里面发送什么 回复什么。现在发送和回复一致 ,表示正确
OK。。。。实验完成。。。。。